[
  {
    "path": ".gitignore",
    "content": "*.sdf\n*.suo\n*.opensdf\n*.user\n*.dll\n*.exe\n*.o\nUAlbertaBot/UAB_ErrorLog.txt\nUAlbertaBot/UAB_ErrorLog.txt\n*.pd_\nUAlbertaBot/UAB_ErrorLog.txt\nBOSS/VisualStudio/BOSS.VC.db\n*.bwta\n*.db\n*.ipch\n*.opendb\n*.db-shm\n*.db-wal\n*.json\n*.zip\n*.iobj\n*.ipdb\n*.map\n*.pdb\n*.ilk\n"
  },
  {
    "path": "BOSS/.gitignore",
    "content": "VisualStudio/Release\nVisualStudio/Debug\nVisualStudio/ipch\nVisualStudio/*.txt\nVisualStudio/*.vsp\nemscripten/*.js\nemscripten/*.mem\nemscripten/*.data\nbin/*.exe\nbin/*.pdb\nbin/*.ilk\nbin/*.txt\nbin/*.map\nbin/*.bsc\nbin/*.lib\nbin/*.gpl\nbin/*.zip\nbin/qtdeploy/*\nbin/deploy/*\nbin/gnuplot/*\nsource/*.o\nqtgui/*\nbuild-BOSSGUI-Desktop_Qt_5_6_0_MSVC2013_32bit-Release"
  },
  {
    "path": "BOSS/Makefile",
    "content": "SHELL=C:/Windows/System32/cmd.exe\nCC=em++\nCFLAGS=-O3 -Wno-tautological-constant-out-of-range-compare\nLDFLAGS=-O3 -s ALLOW_MEMORY_GROWTH=1 --llvm-lto 1 -s DISABLE_EXCEPTION_CATCHING=0 \nINCLUDES=-Isource/rapidjson -Isource -Isource/bwapidata/include\nSOURCES=$(wildcard source/*.cpp source/bwapidata/include/*.cpp) \nOBJECTS=$(SOURCES:.cpp=.o)\n\nHTMLFLAGS=-s EXPORTED_FUNCTIONS=\"['_main', '_ResetExperiment']\" --preload-file asset -s LEGACY_GL_EMULATION=1\n\nall:emscripten/BOSS.html\n\nemscripten/BOSS.html:$(OBJECTS) Makefile\n\t$(CC) $(OBJECTS) -o $@ $(LDFLAGS) $(HTMLFLAGS)\n\n.cpp.o:\n\t$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@\n\nclean:\n\trm $(OBJECTS)\n    "
  },
  {
    "path": "BOSS/Qt/BOSSGUI.pro",
    "content": "#-------------------------------------------------\n#\n# Project created by QtCreator 2016-04-20T14:07:30\n#\n#-------------------------------------------------\n\nQT       += core gui\n\ngreaterThan(QT_MAJOR_VERSION, 4): QT += widgets\n\nTARGET = BOSSGUI\nTEMPLATE = app\n\nINCLUDEPATH += C:\\\\libraries\\\\BWAPI_412\\\\include\\\\\nINCLUDEPATH += d:\\\\ualbertabot\\\\BOSS\\\\source\\\\\n\nSOURCES += main.cpp\\\n        mainwindow.cpp\n\nHEADERS  += mainwindow.h\n\nFORMS    += mainwindow.ui\n\nwin32:RC_ICONS += Protoss_Probe.ico\n\nLIBS += -L$$PWD/../bin/ -lBOSS\nLIBS += -LC:/libraries/BWAPI_412/lib/ -lBWAPI\n\nDESTDIR = $$PWD/../../bin/\n"
  },
  {
    "path": "BOSS/Qt/main.cpp",
    "content": "#include \"mainwindow.h\"\n#include <QApplication>\n\n#include \"BOSS.h\"\n\nint main(int argc, char *argv[])\n{\n    srand(time(NULL));\n\n    QCoreApplication::addLibraryPath(\"./\");\n    BOSS::init();\n\n    QApplication a(argc, argv);\n    MainWindow w;\n    w.setWindowTitle(\"StarCraft Build-Order Visualization\");\n    w.show();\n\n    return a.exec();\n}\n"
  },
  {
    "path": "BOSS/Qt/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\n#include <QMessageBox>\n#include <QFileDialog>\n\n#include \"BOSS.h\"\n#include \"BuildOrderPlot.h\"\n#include \"BOSSException.h\"\n\nstd::map<std::string, QIcon> iconMap;\nstd::map<std::string, QListWidgetItem> itemMap;\nstd::map<std::string, QImage> imageMap;\n\nMainWindow::MainWindow(QWidget *parent) :\n    QMainWindow(parent),\n    ui(new Ui::MainWindow)\n{\n    for (size_t r(0); r < BOSS::Races::NUM_RACES; ++r)\n    {\n        const std::vector<BOSS::ActionType> & actions = BOSS::ActionTypes::GetAllActionTypes((r));\n\n        for (size_t a(0); a < actions.size(); ++a)\n        {\n            const std::string & name = actions[a].getName();\n            QString imageFile = getImageName(actions[a]);\n\n            iconMap[name] = QIcon(imageFile);\n            itemMap[name] = QListWidgetItem(iconMap[name], QString::fromStdString(name));\n            imageMap[name] = QImage(imageFile);\n        }\n    }\n\n    ui->setupUi(this);\n\n    ui->raceComboBox->addItem(iconMap[\"Protoss_Probe\"], \"Protoss\");\n    ui->raceComboBox->addItem(iconMap[\"Terran_SCV\"], \"Terran\");\n    ui->raceComboBox->addItem(iconMap[\"Zerg_Drone\"], \"Zerg\");\n\n    ui->armyValueGraph->setToolTip(\"Visualizes sum of resouces spent on fighting units over time.\\n\\nWorkers are not counted.\");\n    ui->resourceGraphButton->setToolTip(\"Visualizes resource totals over time.\\n\\nWill create separate graphs for minerals and gas collected.\\n\\nAppends _minerals and _gas to file chosen.\");\n    ui->visualizeButton->setToolTip(\"Visualizes build order concurrency and timings.\");\n}\n\nMainWindow::~MainWindow()\n{\n    delete ui;\n}\n\nvoid MainWindow::on_deleteItemsButton_clicked()\n{\n    qDeleteAll(ui->buildOrderList->selectedItems());\n}\n\nvoid MainWindow::on_addToBuildOrderButton_clicked()\n{\n    const QString & actionName = ui->actionTypeComboBox->currentText();\n    addToList(ui->buildOrderList, actionName.toStdString());\n\n    //ui->buildOrderList->addItem();\n    ui->buildOrderList->scrollToBottom();\n}\n\nvoid MainWindow::on_addToStateButton_clicked()\n{\n    const QString & actionName = ui->actionTypeComboBox->currentText();\n    addToList(ui->initialStateList, actionName.toStdString());\n\n    //ui->buildOrderList->addItem();\n    ui->initialStateList->scrollToBottom();\n}\n\nvoid MainWindow::setInitialState(const std::string & raceString)\n{\n    BOSS::RaceID race = BOSS::Races::GetRaceID(raceString);\n    ui->initialStateList->clear();\n\n    // set the initial state items to the default starting state\n    addToList(ui->initialStateList, BOSS::ActionTypes::GetWorker(race));\n    addToList(ui->initialStateList, BOSS::ActionTypes::GetWorker(race));\n    addToList(ui->initialStateList, BOSS::ActionTypes::GetWorker(race));\n    addToList(ui->initialStateList, BOSS::ActionTypes::GetWorker(race));\n    addToList(ui->initialStateList, BOSS::ActionTypes::GetResourceDepot(race));\n\n    if (race == BOSS::Races::Zerg)\n    {\n        addToList(ui->initialStateList, BOSS::ActionTypes::GetSupplyProvider(race));\n    }\n}\n\nvoid MainWindow::setInitialBuildOrder(const std::string & raceString)\n{\n    BOSS::RaceID race = BOSS::Races::GetRaceID(raceString);\n    ui->buildOrderList->clear();\n\n    // add a sample build order to the build order list\n    addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race));\n    addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race));\n    addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race));\n    addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race));\n    addToList(ui->buildOrderList, BOSS::ActionTypes::GetSupplyProvider(race));\n    addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race));\n    addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race));\n\n    if (race == BOSS::Races::Protoss)\n    {\n        addToList(ui->buildOrderList, BOSS::ActionTypes::GetActionType(\"Protoss_Gateway\"));\n    }\n    else if (race == BOSS::Races::Terran)\n    {\n        addToList(ui->buildOrderList, BOSS::ActionTypes::GetActionType(\"Terran_Barracks\"));\n    }\n    else if (race == BOSS::Races::Zerg)\n    {\n        addToList(ui->buildOrderList, BOSS::ActionTypes::GetActionType(\"Zerg_Spawning_Pool\"));\n    }\n}\n\nvoid MainWindow::on_raceComboBox_currentIndexChanged(const QString &arg1)\n{\n    std::string raceString = arg1.toStdString();;\n\n    BOSS::RaceID race = BOSS::Races::GetRaceID(raceString);\n\n    ui->actionTypeComboBox->clear();\n    ui->initialStateList->clear();\n    ui->mineralsSpinBox->setValue(50);\n    ui->gasSpinBox->setValue(0);\n\n    setInitialState(raceString);\n    setInitialBuildOrder(raceString);\n\n    const auto & actionTypes = BOSS::ActionTypes::GetAllActionTypes(race);\n\n    for (const auto & type : actionTypes)\n    {\n        if (type.getName() == \"Zerg_Larva\") continue;\n        if (type.getName() == \"Protoss_Dark_Archon\") continue;\n        if (type.getName() == \"Protoss_Archon\") continue;\n\n        ui->actionTypeComboBox->addItem(iconMap[type.getName()], QString::fromStdString(type.getName()));\n    }\n}\n\nvoid MainWindow::addToList(QListWidget * list, const BOSS::ActionType & type)\n{\n    list->insertItem(list->count(), new QListWidgetItem(itemMap[type.getName()]));\n}\n\nvoid MainWindow::addToList(QListWidget * list, const std::string & typeName)\n{\n    list->insertItem(list->count(), new QListWidgetItem(itemMap[typeName]));\n}\n\nvoid MainWindow::on_clearAllItems_clicked()\n{\n    ui->buildOrderList->clear();\n}\n\nvoid MainWindow::on_deleteItemsButtonState_clicked()\n{\n    qDeleteAll(ui->initialStateList->selectedItems());\n}\n\nvoid MainWindow::on_clearAllItemsState_clicked()\n{\n    ui->initialStateList->clear();\n}\n\nvoid MainWindow::on_actionTypeComboBox_currentIndexChanged(const QString &arg1)\n{\n    if (arg1.length() == 0)\n    {\n        return;\n    }\n\n    BOSS::ActionType type = BOSS::ActionTypes::GetActionType(arg1.toStdString());\n\n    std::stringstream minerals, gas, buildTime, builder, hpShield;\n    minerals << type.mineralPrice()/1000;\n    gas << type.gasPrice()/1000;\n    buildTime << type.buildTime();\n    builder << type.whatBuildsActionType().getName();\n\n    if (type.isUnit())\n    {\n        hpShield << type.getUnitType().maxHitPoints() << \" / \" << type.getUnitType().maxShields();\n    }\n    else\n    {\n        hpShield << \"N/A\";\n    }\n\n    ui->itemInformationLabel->setText(arg1);\n    ui->mineralCost->setText(QString::fromStdString(minerals.str()));\n    ui->gasCost->setText(QString::fromStdString(gas.str()));\n    ui->buildTime->setText(QString::fromStdString(buildTime.str()));\n    ui->builder->setText(QString::fromStdString(builder.str()));\n    ui->hpShield->setText(QString::fromStdString(hpShield.str()));\n\n    ui->imageLabel->setPixmap(QPixmap::fromImage(imageMap[type.getName()]));\n}\nBOSS::GameState MainWindow::getState()\n{\n    BOSS::GameState state(BOSS::Races::GetRaceID(ui->raceComboBox->currentText().toStdString()));\n    state.setMinerals(ui->mineralsSpinBox->value());\n    state.setGas(ui->gasSpinBox->value());\n\n    for(int row = 0; row < ui->initialStateList->count(); row++)\n    {\n        state.addCompletedAction(BOSS::ActionTypes::GetActionType(ui->initialStateList->item(row)->text().toStdString()));\n    }\n\n    return state;\n}\n\nBOSS::BuildOrder MainWindow::getBuildOrder()\n{\n    BOSS::BuildOrder buildOrder;\n\n    for(int row = 0; row < ui->buildOrderList->count(); row++)\n    {\n        buildOrder.add(BOSS::ActionTypes::GetActionType(ui->buildOrderList->item(row)->text().toStdString()));\n    }\n\n    return buildOrder;\n}\n\nQString MainWindow::getImageName(const BOSS::ActionType & type)\n{\n    std::string filename = \"images/\";\n\n    if (type.isUnit())\n    {\n        filename += \"units/\" + type.getName() + \".png\";\n    }\n    else if (type.isUpgrade() || type.isTech())\n    {\n        filename += \"command_icons/\" + type.getName() + \".png\";\n    }\n\n    return QString::fromStdString(filename);\n}\n\nvoid MainWindow::on_visualizeButton_clicked()\n{\n    generatePlot(PlotTypes::BuildOrderPlot);\n}\n\nvoid MainWindow::on_resourceGraphButton_clicked()\n{\n    generatePlot(PlotTypes::ResourcePlot);\n}\n\nvoid MainWindow::on_armyValueGraph_clicked()\n{\n    generatePlot(PlotTypes::ArmyPlot);\n}\n\n\nvoid MainWindow::generatePlot(int plotType)\n{\n    try\n    {\n        BOSS::GameState state = getState();\n        BOSS::BuildOrder buildOrder = getBuildOrder();\n\n        if (buildOrder.size() == 0)\n        {\n            QMessageBox::information(this, tr(\"BOSS Visualization Error\"), tr(\"Cannot visualize an empty build order. Try adding some units.\") );\n            return;\n        }\n\n        if (buildOrder.isLegalFromState(state))\n        {\n            QString file = QFileDialog::getSaveFileName(this, tr(\"Save Visualization Gnuplot File\"), QDir::currentPath(), tr(\"gnuplot files (*.gpl);;All files (*.*)\"));\n\n            BOSS::BuildOrderPlot plot(state, buildOrder);\n\n            if (plotType == PlotTypes::BuildOrderPlot)\n            {\n                plot.writeRectanglePlot(file.toStdString());\n            }\n            else if (plotType == PlotTypes::ArmyPlot)\n            {\n                plot.writeArmyValuePlot(file.toStdString());\n            }\n            else if (plotType == PlotTypes::ResourcePlot)\n            {\n                plot.writeResourcePlot(file.toStdString());\n            }\n        }\n        else\n        {\n            std::string why = buildOrder.whyIsNotLegalFromState(state);\n\n            QMessageBox::information(this, tr(\"BOSS Visualization Error\"), tr(why.c_str()) );\n        }\n    }\n    catch (BOSS::BOSSException e)\n    {\n        std::stringstream ss;\n        ss << \"Build-Order Exception Thrown\\n\\nPlease contact author with error details\\n\\n\" << e.what();\n\n        QMessageBox::information(this, \"BOSS Visualization Error\", ss.str().c_str());\n    }\n}\n\nvoid MainWindow::on_loadBuildOrderButton_clicked()\n{\n    QString file = QFileDialog::getOpenFileName(this, tr(\"Load Build-Order File\"), QDir::currentPath(), tr(\"Text Files (*.txt);;All files (*.*)\"));\n    if (file.size() == 0) return;\n\n    std::ifstream fin(file.toStdString());\n\n    std::string line;\n    std::string raceString;\n\n    // read the first line of the file which should be the race\n    std::getline(fin, raceString);\n    BOSS::RaceID race = BOSS::Races::GetRaceID(raceString);\n    if (race == BOSS::Races::None)\n    {\n        QMessageBox::information(this, tr(\"BOSS Visualization Error\"), tr(\"First line of the build-order file was not a valid race.\\n\\nIt must be Protoss, Terran, or Zerg.\") );\n        return;\n    }\n\n    size_t lineNum = 1;\n    std::vector<BOSS::ActionType> types;\n\n    // read the remaining lines which each should be one build-order item\n    while (std::getline(fin, line))\n    {\n        // break when we reach a blank line\n        if (line.size() == 0)\n        {\n            break;\n        }\n\n        ++lineNum;\n        if (!BOSS::ActionTypes::TypeExists(line))\n        {\n            std::stringstream ss;\n            ss << \"Line \" << lineNum << \" of the build order file was not a valid Build-Order ActionType.\";\n\n            QMessageBox::information(this, tr(\"BOSS Visualization Error\"), tr(ss.str().c_str()) );\n            return;\n        }\n\n        BOSS::ActionType type = BOSS::ActionTypes::GetActionType(line);\n\n        if (type.getRace() != race)\n        {\n            std::stringstream ss;\n            ss << \"Build order file specifies \" << raceString << \" race.\\n\\nLine \" << lineNum << \": \" << type.getName() << \" is not a \" << raceString << \" unit.\";\n            ss << \"\\n\\nPlease ensure all units are of the same race and try again.\";\n\n            QMessageBox::information(this, tr(\"BOSS Visualization Error\"), tr(ss.str().c_str()) );\n            return;\n        }\n\n        types.push_back(type);\n    }\n\n    // we must change the selected race to the race loaded\n    if (raceString != ui->raceComboBox->currentText().toStdString())\n    {\n        for (int i=0; i < ui->raceComboBox->count(); ++i)\n        {\n            std::string itemRace = ui->raceComboBox->itemText(i).toStdString();\n\n            if (itemRace == raceString)\n            {\n                ui->raceComboBox->setCurrentIndex(i);\n                break;\n            }\n        }\n    }\n\n    ui->buildOrderList->clear();\n\n    for (const auto & type : types)\n    {\n        addToList(ui->buildOrderList, type.getName());\n    }\n\n    fin.close();\n\n    ui->buildOrderList->scrollToBottom();\n}\n\nvoid MainWindow::on_saveBuildOrderButton_clicked()\n{\n    QString file = QFileDialog::getSaveFileName(this, tr(\"Save Build-Order\"), QDir::currentPath(), tr(\"Text Files (*.txt);;All files (*.*)\"));\n    if (file.size() == 0) return;\n\n    std::ofstream fout(file.toStdString());\n\n    fout << ui->raceComboBox->currentText().toStdString() << \"\\n\";\n    for(int row = 0; row < ui->buildOrderList->count(); row++)\n    {\n        fout << ui->buildOrderList->item(row)->text().toStdString() << \"\\n\";\n    }\n\n    ui->buildOrderList->scrollToBottom();\n    fout.close();\n}\n\nvoid MainWindow::on_actionAbout_triggered()\n{\n    QMessageBox msgBox(this);\n    msgBox.setWindowTitle(\"About\");\n    msgBox.setIconPixmap(QPixmap::fromImage(imageMap[\"Protoss_Probe\"]));\n    msgBox.setTextFormat(Qt::RichText);   //this is what makes the links clickable\n    msgBox.setText(\"StarCraft Build-Order Visualizer<br><br>Written by <a href=\\\"http://webdocs.cs.ualberta.ca/~cdavid/\\\">David Churchill</a><br><br>Source and details available on <a href=\\\"https://github.com/davechurchill/ualbertabot\\\">GitHub</a><br><br>To view output graphs, use <a href=\\\"http://www.gnuplot.info/\\\">gnuplot</a>\");\n    msgBox.exec();\n}\n\nvoid MainWindow::on_loadStateButton_clicked()\n{\n    QString file = QFileDialog::getOpenFileName(this, tr(\"Load State File\"), QDir::currentPath(), tr(\"Text Files (*.txt);;All files (*.*)\"));\n    if (file.size() == 0) return;\n\n    std::ifstream fin(file.toStdString());\n\n    std::string line;\n    std::string raceString;\n\n    // read the first line of the file which should be the race\n    std::getline(fin, raceString);\n    BOSS::RaceID race = BOSS::Races::GetRaceID(raceString);\n    if (race == BOSS::Races::None)\n    {\n        QMessageBox::information(this, tr(\"BOSS Visualization Error\"), tr(\"First line of the state file was not a valid race.\\n\\nIt must be Protoss, Terran, or Zerg.\") );\n        return;\n    }\n\n    size_t lineNum = 1;\n    std::vector<BOSS::ActionType> types;\n\n    // read the remaining lines which each should be one build-order item\n    while (std::getline(fin, line))\n    {\n        // break when we reach a blank line\n        if (line.size() == 0)\n        {\n            break;\n        }\n\n        ++lineNum;\n        if (!BOSS::ActionTypes::TypeExists(line))\n        {\n            std::stringstream ss;\n            ss << \"Line \" << lineNum << \" of the state file was not a valid ActionType.\";\n\n            QMessageBox::information(this, tr(\"BOSS Visualization Error\"), tr(ss.str().c_str()) );\n            return;\n        }\n\n        BOSS::ActionType type = BOSS::ActionTypes::GetActionType(line);\n\n        if (type.getRace() != race)\n        {\n            std::stringstream ss;\n            ss << \"State file specifies \" << raceString << \" race.\\n\\nLine \" << lineNum << \": \" << type.getName() << \" is not a \" << raceString << \" unit.\";\n            ss << \"\\n\\nPlease ensure all units are of the same race and try again.\";\n\n            QMessageBox::information(this, tr(\"BOSS Visualization Error\"), tr(ss.str().c_str()) );\n            return;\n        }\n\n        types.push_back(type);\n    }\n\n    // we must change the selected race to the race loaded\n    if (raceString != ui->raceComboBox->currentText().toStdString())\n    {\n        for (int i=0; i < ui->raceComboBox->count(); ++i)\n        {\n            std::string itemRace = ui->raceComboBox->itemText(i).toStdString();\n\n            if (itemRace == raceString)\n            {\n                ui->raceComboBox->setCurrentIndex(i);\n                break;\n            }\n        }\n    }\n\n    ui->initialStateList->clear();\n\n    for (const auto & type : types)\n    {\n        addToList(ui->initialStateList, type.getName());\n    }\n\n    fin.close();\n\n    ui->initialStateList->scrollToBottom();\n}\n\nvoid MainWindow::on_saveStateButton_clicked()\n{\n    QString file = QFileDialog::getSaveFileName(this, tr(\"Save State\"), QDir::currentPath(), tr(\"Text Files (*.txt);;All files (*.*)\"));\n    if (file.size() == 0) return;\n\n    std::ofstream fout(file.toStdString());\n\n    fout << ui->raceComboBox->currentText().toStdString() << \"\\n\";\n    for(int row = 0; row < ui->initialStateList->count(); row++)\n    {\n        fout << ui->initialStateList->item(row)->text().toStdString() << \"\\n\";\n    }\n\n    fout.close();\n}\n\n\nvoid MainWindow::on_viewStateButton_clicked()\n{\n    BOSS::GameState state = getState();\n    QMessageBox::about(this, \"State Details\", state.toString().c_str());\n}\n\nvoid MainWindow::on_buildOrderDetails_clicked()\n{\n    std::stringstream ss;\n\n    BOSS::GameState state = getState();\n    BOSS::BuildOrder buildOrder = getBuildOrder();\n\n    if (buildOrder.isLegalFromState(state))\n    {\n        ss << \"Build-Order can be built from the chosen initial state.\\n\\n\";\n\n        buildOrder.doActions(state);\n        int totalFrames = state.getLastActionFinishTime();\n\n        ss << \"Total time to completion: \" << totalFrames << \" frames \" << \" (\" << (totalFrames / (60 * 24)) << \"m \" << ((totalFrames / 24) % 60) << \"s)\\n\\n\";\n\n        int totalMinerals = 0;\n        int totalGas = 0;\n        for (size_t a(0); a < buildOrder.size(); ++a)\n        {\n            totalMinerals += buildOrder[a].mineralPrice();\n            totalGas+= buildOrder[a].gasPrice();\n        }\n\n        ss << \"Total Minerals Gathered: \" << (state.getMinerals() + totalMinerals)/BOSS::Constants::RESOURCE_SCALE << \"\\n\";\n        ss << \"Total Gas Gathered: \" << (state.getGas() + totalGas)/BOSS::Constants::RESOURCE_SCALE << \"\\n\\n\";\n    }\n    else\n    {\n        ss << buildOrder.whyIsNotLegalFromState(state);\n    }\n\n    QMessageBox::about(this, \"Build-Order Details\", ss.str().c_str() );\n}\n\nvoid MainWindow::on_viewFinalStateButton_clicked()\n{\n    std::stringstream ss;\n    BOSS::GameState state = getState();\n    BOSS::BuildOrder buildOrder = getBuildOrder();\n\n    if (buildOrder.isLegalFromState(state))\n    {\n        ss << \"Final state after build-order has completed:\\n\";\n\n        buildOrder.doActions(state);\n\n        state.fastForward(state.getLastActionFinishTime());\n\n        ss << state.toString() << \"\\n\";\n\n        int totalMinerals = 0;\n        int totalGas = 0;\n        for (size_t a(0); a < buildOrder.size(); ++a)\n        {\n            totalMinerals += buildOrder[a].mineralPrice();\n            totalGas+= buildOrder[a].gasPrice();\n        }\n\n        ss << \"Total Minerals Gathered: \" << (state.getMinerals() + totalMinerals)/BOSS::Constants::RESOURCE_SCALE << \"\\n\";\n        ss << \"Total Gas Gathered: \" << (state.getGas() + totalGas)/BOSS::Constants::RESOURCE_SCALE << \"\\n\\n\";\n    }\n    else\n    {\n        ss << buildOrder.whyIsNotLegalFromState(state);\n    }\n\n    QMessageBox::about(this, \"Final State Details\", ss.str().c_str() );\n}\n"
  },
  {
    "path": "BOSS/Qt/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n\n#include <QMainWindow>\n#include <QListWidget>\n#include \"BOSS.h\"\n\nnamespace PlotTypes\n{\n    enum { BuildOrderPlot, ArmyPlot, ResourcePlot };\n}\n\nnamespace Ui\n{\n    class MainWindow;\n}\n\nclass MainWindow : public QMainWindow\n{\n    Q_OBJECT\n\npublic:\n    explicit MainWindow(QWidget *parent = 0);\n    ~MainWindow();\n\nprivate slots:\n\n    void on_deleteItemsButton_clicked();\n    void on_addToBuildOrderButton_clicked();\n    void on_visualizeButton_clicked();\n    void on_raceComboBox_currentIndexChanged(const QString &arg1);\n    void on_addToStateButton_clicked();\n    void on_clearAllItems_clicked();\n    void on_deleteItemsButtonState_clicked();\n    void on_clearAllItemsState_clicked();\n    void on_actionTypeComboBox_currentIndexChanged(const QString &arg1);\n    void on_saveBuildOrderButton_clicked();\n    void on_resourceGraphButton_clicked();\n    void on_armyValueGraph_clicked();\n    void on_actionAbout_triggered();\n    void on_loadStateButton_clicked();\n    void on_saveStateButton_clicked();\n\n    QString getImageName(const BOSS::ActionType & type);\n    BOSS::GameState getState();\n    BOSS::BuildOrder getBuildOrder();\n    void generatePlot(int plotType);\n\n    void on_loadBuildOrderButton_clicked();\n\n    void setInitialState(const std::string & raceString);\n    void setInitialBuildOrder(const std::string & raceString);\n    void addToList(QListWidget * list, const BOSS::ActionType & type);\n    void addToList(QListWidget * list, const std::string & typeName);\n\n\n    void on_viewStateButton_clicked();\n\n    void on_buildOrderDetails_clicked();\n\n    void on_viewFinalStateButton_clicked();\n\nprivate:\n    Ui::MainWindow *ui;\n};\n\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "BOSS/Qt/mainwindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>640</width>\n    <height>480</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"minimumSize\">\n   <size>\n    <width>640</width>\n    <height>480</height>\n   </size>\n  </property>\n  <property name=\"maximumSize\">\n   <size>\n    <width>640</width>\n    <height>480</height>\n   </size>\n  </property>\n  <property name=\"windowTitle\">\n   <string>MainWindow</string>\n  </property>\n  <widget class=\"QWidget\" name=\"centralWidget\">\n   <widget class=\"QPushButton\" name=\"addToBuildOrderButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>20</x>\n      <y>70</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Add to Build Order</string>\n    </property>\n   </widget>\n   <widget class=\"QComboBox\" name=\"actionTypeComboBox\">\n    <property name=\"geometry\">\n     <rect>\n      <x>20</x>\n      <y>40</y>\n      <width>211</width>\n      <height>22</height>\n     </rect>\n    </property>\n   </widget>\n   <widget class=\"QComboBox\" name=\"raceComboBox\">\n    <property name=\"geometry\">\n     <rect>\n      <x>120</x>\n      <y>10</y>\n      <width>111</width>\n      <height>22</height>\n     </rect>\n    </property>\n   </widget>\n   <widget class=\"QListWidget\" name=\"buildOrderList\">\n    <property name=\"geometry\">\n     <rect>\n      <x>20</x>\n      <y>150</y>\n      <width>211</width>\n      <height>231</height>\n     </rect>\n    </property>\n    <property name=\"selectionMode\">\n     <enum>QAbstractItemView::MultiSelection</enum>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"deleteItemsButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>20</x>\n      <y>390</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Clear Selected </string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"label_2\">\n    <property name=\"geometry\">\n     <rect>\n      <x>20</x>\n      <y>10</y>\n      <width>91</width>\n      <height>21</height>\n     </rect>\n    </property>\n    <property name=\"font\">\n     <font>\n      <family>Arial</family>\n      <pointsize>12</pointsize>\n     </font>\n    </property>\n    <property name=\"text\">\n     <string>Select Race</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"clearAllItems\">\n    <property name=\"geometry\">\n     <rect>\n      <x>130</x>\n      <y>390</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Clear All</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"buildOrderLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>20</x>\n      <y>120</y>\n      <width>91</width>\n      <height>21</height>\n     </rect>\n    </property>\n    <property name=\"font\">\n     <font>\n      <family>Arial</family>\n      <pointsize>12</pointsize>\n     </font>\n    </property>\n    <property name=\"text\">\n     <string>Build-Order</string>\n    </property>\n   </widget>\n   <widget class=\"QListWidget\" name=\"initialStateList\">\n    <property name=\"geometry\">\n     <rect>\n      <x>250</x>\n      <y>150</y>\n      <width>211</width>\n      <height>231</height>\n     </rect>\n    </property>\n    <property name=\"selectionMode\">\n     <enum>QAbstractItemView::MultiSelection</enum>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"addToStateButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>130</x>\n      <y>70</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Add to Initial State</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"initialStateLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>250</x>\n      <y>120</y>\n      <width>101</width>\n      <height>21</height>\n     </rect>\n    </property>\n    <property name=\"font\">\n     <font>\n      <family>Arial</family>\n      <pointsize>12</pointsize>\n     </font>\n    </property>\n    <property name=\"text\">\n     <string>Initial State</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"deleteItemsButtonState\">\n    <property name=\"geometry\">\n     <rect>\n      <x>250</x>\n      <y>390</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Clear Selected</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"clearAllItemsState\">\n    <property name=\"geometry\">\n     <rect>\n      <x>360</x>\n      <y>390</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Clear All</string>\n    </property>\n   </widget>\n   <widget class=\"QSpinBox\" name=\"mineralsSpinBox\">\n    <property name=\"geometry\">\n     <rect>\n      <x>490</x>\n      <y>170</y>\n      <width>121</width>\n      <height>22</height>\n     </rect>\n    </property>\n    <property name=\"alignment\">\n     <set>Qt::AlignCenter</set>\n    </property>\n    <property name=\"maximum\">\n     <number>99999</number>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"mineralsLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>510</x>\n      <y>150</y>\n      <width>91</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Starting Minerals</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"gasLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>520</x>\n      <y>200</y>\n      <width>91</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Starting Gas</string>\n    </property>\n   </widget>\n   <widget class=\"QSpinBox\" name=\"gasSpinBox\">\n    <property name=\"geometry\">\n     <rect>\n      <x>490</x>\n      <y>220</y>\n      <width>121</width>\n      <height>22</height>\n     </rect>\n    </property>\n    <property name=\"alignment\">\n     <set>Qt::AlignCenter</set>\n    </property>\n    <property name=\"maximum\">\n     <number>99999</number>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"itemInformationLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>250</x>\n      <y>10</y>\n      <width>241</width>\n      <height>21</height>\n     </rect>\n    </property>\n    <property name=\"font\">\n     <font>\n      <family>Arial</family>\n      <pointsize>12</pointsize>\n     </font>\n    </property>\n    <property name=\"text\">\n     <string>Item:</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"mineralCostLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>250</x>\n      <y>60</y>\n      <width>71</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Minerals:</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"gasCostLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>250</x>\n      <y>80</y>\n      <width>51</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Gas:</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"label_4\">\n    <property name=\"geometry\">\n     <rect>\n      <x>340</x>\n      <y>60</y>\n      <width>61</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Build Time:</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"mineralCost\">\n    <property name=\"geometry\">\n     <rect>\n      <x>310</x>\n      <y>60</y>\n      <width>31</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>0</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"gasCost\">\n    <property name=\"geometry\">\n     <rect>\n      <x>310</x>\n      <y>80</y>\n      <width>31</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>0</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"buildTime\">\n    <property name=\"geometry\">\n     <rect>\n      <x>410</x>\n      <y>60</y>\n      <width>51</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>0</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"producerLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>250</x>\n      <y>40</y>\n      <width>51</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Producer:</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"builder\">\n    <property name=\"geometry\">\n     <rect>\n      <x>310</x>\n      <y>40</y>\n      <width>131</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>0</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"label_6\">\n    <property name=\"geometry\">\n     <rect>\n      <x>340</x>\n      <y>80</y>\n      <width>61</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>HP / Shield:</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"hpShield\">\n    <property name=\"geometry\">\n     <rect>\n      <x>410</x>\n      <y>80</y>\n      <width>51</width>\n      <height>16</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>0</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"imageLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>470</x>\n      <y>10</y>\n      <width>161</width>\n      <height>121</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Image Here</string>\n    </property>\n    <property name=\"alignment\">\n     <set>Qt::AlignCenter</set>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"visualizeButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>490</x>\n      <y>420</y>\n      <width>121</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Build-Order Graph</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"saveBuildOrderButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>130</x>\n      <y>420</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Save Build-Order</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"loadBuildOrderButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>20</x>\n      <y>420</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Load Build-Order</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"saveStateButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>360</x>\n      <y>420</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Save State</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"loadStateButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>250</x>\n      <y>420</y>\n      <width>101</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Load State</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"initialStateLabel_2\">\n    <property name=\"geometry\">\n     <rect>\n      <x>490</x>\n      <y>330</y>\n      <width>131</width>\n      <height>21</height>\n     </rect>\n    </property>\n    <property name=\"font\">\n     <font>\n      <family>Arial</family>\n      <pointsize>12</pointsize>\n     </font>\n    </property>\n    <property name=\"text\">\n     <string>Generate Graphs</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"resourceGraphButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>490</x>\n      <y>390</y>\n      <width>121</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Resource Graphs</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"armyValueGraph\">\n    <property name=\"geometry\">\n     <rect>\n      <x>490</x>\n      <y>360</y>\n      <width>121</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>Army Value Graph</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"viewStateButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>380</x>\n      <y>120</y>\n      <width>81</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>View Details</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"buildOrderDetails\">\n    <property name=\"geometry\">\n     <rect>\n      <x>150</x>\n      <y>120</y>\n      <width>81</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>View Details</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"viewFinalStateButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>490</x>\n      <y>280</y>\n      <width>121</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>View Final State</string>\n    </property>\n   </widget>\n  </widget>\n  <widget class=\"QMenuBar\" name=\"menuBar\">\n   <property name=\"geometry\">\n    <rect>\n     <x>0</x>\n     <y>0</y>\n     <width>640</width>\n     <height>21</height>\n    </rect>\n   </property>\n   <widget class=\"QMenu\" name=\"menuHelp\">\n    <property name=\"title\">\n     <string>Help</string>\n    </property>\n    <addaction name=\"actionAbout\"/>\n   </widget>\n   <addaction name=\"menuHelp\"/>\n  </widget>\n  <action name=\"actionAbout\">\n   <property name=\"text\">\n    <string>About</string>\n   </property>\n  </action>\n </widget>\n <layoutdefault spacing=\"6\" margin=\"11\"/>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "BOSS/VisualStudio/BOSS.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 2013\nVisualStudioVersion = 12.0.40629.0\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"BOSS\", \"BOSS.vcxproj\", \"{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"BOSS_main\", \"BOSS_main.vcxproj\", \"{25544976-2D9A-4669-8EF6-B622C3B5A42E}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127} = {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}\n\tEndProjectSection\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Win32 = Debug|Win32\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|Win32 = Release|Win32\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|x64.ActiveCfg = Debug|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Win32.Build.0 = Release|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|x64.ActiveCfg = Release|Win32\n\t\t{25544976-2D9A-4669-8EF6-B622C3B5A42E}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{25544976-2D9A-4669-8EF6-B622C3B5A42E}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{25544976-2D9A-4669-8EF6-B622C3B5A42E}.Debug|x64.ActiveCfg = Debug|Win32\n\t\t{25544976-2D9A-4669-8EF6-B622C3B5A42E}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{25544976-2D9A-4669-8EF6-B622C3B5A42E}.Release|Win32.Build.0 = Release|Win32\n\t\t{25544976-2D9A-4669-8EF6-B622C3B5A42E}.Release|x64.ActiveCfg = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "BOSS/VisualStudio/BOSS.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\source\\ActionInProgress.h\" />\n    <ClInclude Include=\"..\\source\\ActionSet.h\" />\n    <ClInclude Include=\"..\\source\\ActionType.h\" />\n    <ClInclude Include=\"..\\source\\ActionTypeData.h\" />\n    <ClInclude Include=\"..\\source\\Array.hpp\" />\n    <ClInclude Include=\"..\\source\\BaseTypes.h\" />\n    <ClInclude Include=\"..\\source\\BOSSAssert.h\" />\n    <ClInclude Include=\"..\\source\\BOSSException.h\" />\n    <ClInclude Include=\"..\\source\\BuildOrder.h\" />\n    <ClInclude Include=\"..\\source\\BuildOrderPlot.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearch_BestResponse.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearch_BestResponseData.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearch_Bucket.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearch_BucketData.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearch_IntegralData.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearch_Integral.h\" />\n    <ClInclude Include=\"..\\source\\Constants.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearch.h\" />\n    <ClInclude Include=\"..\\source\\BOSS.h\" />\n    <ClInclude Include=\"..\\source\\BuildingData.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearchParameters.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearchResults.h\" />\n    <ClInclude Include=\"..\\source\\Common.h\" />\n    <ClInclude Include=\"..\\source\\BuildOrderSearchGoal.h\" />\n    <ClInclude Include=\"..\\source\\DFBB_BuildOrderSearchParameters.h\" />\n    <ClInclude Include=\"..\\source\\DFBB_BuildOrderSearchResults.h\" />\n    <ClInclude Include=\"..\\source\\DFBB_BuildOrderSmartSearch.h\" />\n    <ClInclude Include=\"..\\source\\DFBB_BuildOrderStackSearch.h\" />\n    <ClInclude Include=\"..\\source\\Eval.h\" />\n    <ClInclude Include=\"..\\source\\GraphViz.hpp\" />\n    <ClInclude Include=\"..\\source\\GameState.h\" />\n    <ClInclude Include=\"..\\source\\HatcheryData.h\" />\n    <ClInclude Include=\"..\\source\\BOSSLogger.h\" />\n    <ClInclude Include=\"..\\source\\JSONTools.h\" />\n    <ClInclude Include=\"..\\source\\NaiveBuildOrderSearch.h\" />\n    <ClInclude Include=\"..\\source\\PrerequisiteSet.h\" />\n    <ClInclude Include=\"..\\source\\Timer.hpp\" />\n    <ClInclude Include=\"..\\source\\Tools.h\" />\n    <ClInclude Include=\"..\\source\\UnitData.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\source\\ActionInProgress.cpp\" />\n    <ClCompile Include=\"..\\source\\ActionSet.cpp\" />\n    <ClCompile Include=\"..\\source\\ActionType.cpp\" />\n    <ClCompile Include=\"..\\source\\ActionTypeData.cpp\" />\n    <ClCompile Include=\"..\\source\\BOSSAssert.cpp\" />\n    <ClCompile Include=\"..\\source\\BOSSException.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildOrder.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildOrderPlot.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearch.cpp\" />\n    <ClCompile Include=\"..\\source\\BOSS.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildingData.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearch_BestResponse.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearch_BestResponseData.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearch_Bucket.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearch_BucketData.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearch_IntegralData.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearchParameters.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearchResults.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearch_Integral.cpp\" />\n    <ClCompile Include=\"..\\source\\Constants.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildOrderSearchGoal.cpp\" />\n    <ClCompile Include=\"..\\source\\DFBB_BuildOrderSearchParameters.cpp\" />\n    <ClCompile Include=\"..\\source\\DFBB_BuildOrderSearchResults.cpp\" />\n    <ClCompile Include=\"..\\source\\DFBB_BuildOrderSmartSearch.cpp\" />\n    <ClCompile Include=\"..\\source\\DFBB_BuildOrderStackSearch.cpp\" />\n    <ClCompile Include=\"..\\source\\Eval.cpp\" />\n    <ClCompile Include=\"..\\source\\GameState.cpp\" />\n    <ClCompile Include=\"..\\source\\HatcheryData.cpp\" />\n    <ClCompile Include=\"..\\source\\BOSSLogger.cpp\" />\n    <ClCompile Include=\"..\\source\\JSONTools.cpp\" />\n    <ClCompile Include=\"..\\source\\NaiveBuildOrderSearch.cpp\" />\n    <ClCompile Include=\"..\\source\\PrerequisiteSet.cpp\" />\n    <ClCompile Include=\"..\\source\\Tools.cpp\" />\n    <ClCompile Include=\"..\\source\\UnitData.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"ClassDiagram.cd\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>StarcraftBuildOrderSearch</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v142</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v142</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <OutDir>../bin/</OutDir>\n    <TargetName>$(ProjectName)_d</TargetName>\n    <TargetExt>.lib</TargetExt>\n    <IntDir>$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>../bin/</OutDir>\n    <IntDir>$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)/include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <MinimalRebuild>false</MinimalRebuild>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>../../bwapidata/lib/bwapidatad_$(PlatformToolset).lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>Full</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <BrowseInformation>true</BrowseInformation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>../../bwapidata/lib/bwapidata_$(PlatformToolset).lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateMapFile>true</GenerateMapFile>\n    </Link>\n    <Bscmake>\n      <PreserveSbr>true</PreserveSbr>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "BOSS/VisualStudio/BOSS.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\source\\BOSS.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\ActionInProgress.cpp\">\n      <Filter>engine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BuildingData.cpp\">\n      <Filter>engine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\GameState.cpp\">\n      <Filter>engine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearch.cpp\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\UnitData.cpp\">\n      <Filter>engine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Eval.cpp\">\n      <Filter>search\\util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\ActionType.cpp\">\n      <Filter>engine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\ActionTypeData.cpp\">\n      <Filter>engine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearchResults.cpp\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearchParameters.cpp\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\PrerequisiteSet.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\ActionSet.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Tools.cpp\">\n      <Filter>search\\util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\DFBB_BuildOrderSmartSearch.cpp\">\n      <Filter>search\\BuildOrderSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\DFBB_BuildOrderSearchParameters.cpp\">\n      <Filter>search\\BuildOrderSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\DFBB_BuildOrderSearchResults.cpp\">\n      <Filter>search\\BuildOrderSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\DFBB_BuildOrderStackSearch.cpp\">\n      <Filter>search\\BuildOrderSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Constants.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\HatcheryData.cpp\">\n      <Filter>engine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BOSSLogger.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\JSONTools.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\NaiveBuildOrderSearch.cpp\">\n      <Filter>search\\NaiveSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BuildOrderSearchGoal.cpp\">\n      <Filter>search\\util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BuildOrder.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearch_Integral.cpp\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearch_BucketData.cpp\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearch_IntegralData.cpp\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearch_Bucket.cpp\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearch_BestResponse.cpp\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BuildOrderPlot.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearch_BestResponseData.cpp\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BOSSAssert.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BOSSException.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\source\\Timer.hpp\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Common.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BOSS.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\ActionInProgress.h\">\n      <Filter>engine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BuildingData.h\">\n      <Filter>engine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\GameState.h\">\n      <Filter>engine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearch.h\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Array.hpp\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\UnitData.h\">\n      <Filter>engine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Eval.h\">\n      <Filter>search\\util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BaseTypes.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\ActionType.h\">\n      <Filter>engine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\ActionTypeData.h\">\n      <Filter>engine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\GraphViz.hpp\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearchResults.h\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearchParameters.h\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Constants.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\PrerequisiteSet.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\ActionSet.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Tools.h\">\n      <Filter>search\\util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\DFBB_BuildOrderSmartSearch.h\">\n      <Filter>search\\BuildOrderSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\DFBB_BuildOrderSearchParameters.h\">\n      <Filter>search\\BuildOrderSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\DFBB_BuildOrderSearchResults.h\">\n      <Filter>search\\BuildOrderSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\DFBB_BuildOrderStackSearch.h\">\n      <Filter>search\\BuildOrderSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\HatcheryData.h\">\n      <Filter>engine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BOSSLogger.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\JSONTools.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\NaiveBuildOrderSearch.h\">\n      <Filter>search\\NaiveSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BuildOrderSearchGoal.h\">\n      <Filter>search\\util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BuildOrder.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearch_Integral.h\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearch_BucketData.h\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearch_IntegralData.h\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearch_Bucket.h\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearch_BestResponse.h\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BuildOrderPlot.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearch_BestResponseData.h\">\n      <Filter>search\\CombatSearch</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BOSSAssert.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BOSSException.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"util\">\n      <UniqueIdentifier>{c90b8009-1e1e-42e5-a28e-017e8e72cfe1}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"common\">\n      <UniqueIdentifier>{f458ce38-5149-4277-8582-e76bc9eaab52}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"search\">\n      <UniqueIdentifier>{0f8d0d91-8735-4269-b306-24e4a55588ad}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"search\\util\">\n      <UniqueIdentifier>{e1d1becf-4265-4c2c-aa97-d66a9a961a6d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"search\\CombatSearch\">\n      <UniqueIdentifier>{c231a723-7f0a-4414-bbef-4928739d854e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"search\\BuildOrderSearch\">\n      <UniqueIdentifier>{be1fbb05-de74-477b-9915-4a5ef14b38db}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"search\\NaiveSearch\">\n      <UniqueIdentifier>{533866dc-7d6d-4bc0-a795-ae6e41d9eac0}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"engine\">\n      <UniqueIdentifier>{975df5db-5385-4879-9a2a-e0f7d4354574}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"ClassDiagram.cd\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "BOSS/VisualStudio/BOSS_combatsearch.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\source\\BOSSExperiments.cpp\" />\n    <ClCompile Include=\"..\\source\\BOSSVisExperiment.cpp\" />\n    <ClCompile Include=\"..\\source\\GUI.cpp\" />\n    <ClCompile Include=\"..\\source\\GUITools.cpp\" />\n    <ClCompile Include=\"..\\source\\BOSS_main.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildOrderTester.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\source\\BOSSExperiments.h\" />\n    <ClInclude Include=\"..\\source\\BOSSVisExperiment.h\" />\n    <ClInclude Include=\"..\\source\\GUI.h\" />\n    <ClInclude Include=\"..\\source\\GUITools.h\" />\n    <ClInclude Include=\"..\\source\\BuildOrderTester.h\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{25544976-2D9A-4669-8EF6-B622C3B5A42E}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>StarcraftBuildOrderSearch</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <OutDir>$(SolutionDir)..\\bin\\</OutDir>\n    <TargetName>$(ProjectName)_d</TargetName>\n    <IntDir>$(Configuration)\\BOSS_main\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)..\\bin\\</OutDir>\n    <IntDir>$(Configuration)\\BOSS_main\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)/include;$(SDL_IMAGE_DIR)/include;$(SDL_DIR)/include;../source/rapidjson;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>$(BWAPI_DIR)/lib/BWAPId.lib;$(SolutionDir)\\$(Configuration)\\BOSS\\BOSS_d.lib;../lib/opengl32.lib;../lib/SDL2.lib;../lib/SDL2_image.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)/include;$(SDL_IMAGE_DIR)/include;$(SDL_DIR)/include;../source/rapidjson;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>$(BWAPI_DIR)/lib/BWAPI.lib;$(SolutionDir)\\$(Configuration)\\BOSS\\BOSS.lib;../lib/opengl32.lib;../lib/SDL2.lib;../lib/SDL2_image.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateMapFile>true</GenerateMapFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "BOSS/VisualStudio/BOSS_main.psess",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<VSPerformanceSession Version=\"1.00\">\n  <Options>\n    <Solution>BOSS.sln</Solution>\n    <CollectionMethod>Sampling</CollectionMethod>\n    <AllocationMethod>None</AllocationMethod>\n    <AddReport>true</AddReport>\n    <ResourceBasedAnalysisSelected>true</ResourceBasedAnalysisSelected>\n    <UniqueReport>Timestamp</UniqueReport>\n    <SamplingMethod>Cycles</SamplingMethod>\n    <CycleCount>10000000</CycleCount>\n    <PageFaultCount>10</PageFaultCount>\n    <SysCallCount>10</SysCallCount>\n    <SamplingCounter Name=\"\" ReloadValue=\"00000000000f4240\" DisplayName=\"\" />\n    <RelocateBinaries>false</RelocateBinaries>\n    <HardwareCounters EnableHWCounters=\"false\" />\n    <EtwSettings />\n    <PdhSettings>\n      <PdhCountersEnabled>false</PdhCountersEnabled>\n      <PdhCountersRate>500</PdhCountersRate>\n      <PdhCounters>\n        <PdhCounter>\\Memory\\Pages/sec</PdhCounter>\n        <PdhCounter>\\PhysicalDisk(_Total)\\Avg. Disk Queue Length</PdhCounter>\n        <PdhCounter>\\Processor(_Total)\\% Processor Time</PdhCounter>\n      </PdhCounters>\n    </PdhSettings>\n  </Options>\n  <ExcludeSmallFuncs>true</ExcludeSmallFuncs>\n  <InteractionProfilingEnabled>false</InteractionProfilingEnabled>\n  <JScriptProfilingEnabled>false</JScriptProfilingEnabled>\n  <PreinstrumentEvent>\n    <InstrEventExclude>false</InstrEventExclude>\n  </PreinstrumentEvent>\n  <PostinstrumentEvent>\n    <InstrEventExclude>false</InstrEventExclude>\n  </PostinstrumentEvent>\n  <Binaries>\n    <ProjBinary>\n      <Path>..\\bin\\BOSS_main.exe</Path>\n      <ArgumentTimestamp>01/01/0001 00:00:00</ArgumentTimestamp>\n      <Instrument>true</Instrument>\n      <Sample>true</Sample>\n      <ExternalWebsite>false</ExternalWebsite>\n      <InteractionProfilingEnabled>false</InteractionProfilingEnabled>\n      <IsLocalJavascript>false</IsLocalJavascript>\n      <IsWindowsStoreApp>false</IsWindowsStoreApp>\n      <IsWWA>false</IsWWA>\n      <LaunchProject>true</LaunchProject>\n      <OverrideProjectSettings>false</OverrideProjectSettings>\n      <LaunchMethod>Executable</LaunchMethod>\n      <ExecutablePath>..\\bin\\BOSS_main.exe</ExecutablePath>\n      <StartupDirectory>..\\bin</StartupDirectory>\n      <Arguments>\n      </Arguments>\n      <NetAppHost>IIS</NetAppHost>\n      <NetBrowser>InternetExplorer</NetBrowser>\n      <ExcludeSmallFuncs>true</ExcludeSmallFuncs>\n      <JScriptProfilingEnabled>false</JScriptProfilingEnabled>\n      <PreinstrumentEvent>\n        <InstrEventExclude>false</InstrEventExclude>\n      </PreinstrumentEvent>\n      <PostinstrumentEvent>\n        <InstrEventExclude>false</InstrEventExclude>\n      </PostinstrumentEvent>\n      <ProjRef>{25544976-2D9A-4669-8EF6-B622C3B5A42E}|BOSS_main.vcxproj</ProjRef>\n      <ProjPath>BOSS_main.vcxproj</ProjPath>\n      <ProjName>BOSS_main</ProjName>\n    </ProjBinary>\n  </Binaries>\n  <Reports>\n    <Report>\n      <Path>BOSS_main150112.vsp</Path>\n    </Report>\n  </Reports>\n  <Launches>\n    <ProjBinary>\n      <Path>:PB:{25544976-2D9A-4669-8EF6-B622C3B5A42E}|BOSS_main.vcxproj</Path>\n    </ProjBinary>\n  </Launches>\n</VSPerformanceSession>"
  },
  {
    "path": "BOSS/VisualStudio/BOSS_main.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\source\\BOSSExperiments.cpp\" />\n    <ClCompile Include=\"..\\source\\BOSSParameters.cpp\" />\n    <ClCompile Include=\"..\\source\\BOSSPlotBuildOrders.cpp\" />\n    <ClCompile Include=\"..\\source\\CombatSearchExperiment.cpp\" />\n    <ClCompile Include=\"..\\source\\BOSS_main.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildOrderTester.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\source\\BOSSExperiments.h\" />\n    <ClInclude Include=\"..\\source\\BOSSParameters.h\" />\n    <ClInclude Include=\"..\\source\\BOSSPlotBuildOrders.h\" />\n    <ClInclude Include=\"..\\source\\CombatSearchExperiment.h\" />\n    <ClInclude Include=\"..\\source\\BuildOrderTester.h\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{25544976-2D9A-4669-8EF6-B622C3B5A42E}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>StarcraftBuildOrderSearch</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <OutDir>$(SolutionDir)..\\bin\\</OutDir>\n    <TargetName>$(ProjectName)_d</TargetName>\n    <IntDir>$(Configuration)\\BOSS_main\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)..\\bin\\</OutDir>\n    <IntDir>$(Configuration)\\BOSS_main\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)/include;../source/rapidjson;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>$(BWAPI_DIR)/lib/BWAPId.lib;../bin/BOSS_d.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)/include;../source/rapidjson;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <DisableSpecificWarnings>4996;4099</DisableSpecificWarnings>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <BrowseInformation>true</BrowseInformation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>$(BWAPI_DIR)/lib/BWAPI.lib;../bin/BOSS.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateMapFile>true</GenerateMapFile>\n    </Link>\n    <Bscmake>\n      <PreserveSbr>true</PreserveSbr>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "BOSS/VisualStudio/BOSS_main.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\source\\BOSS_main.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildOrderTester.cpp\">\n      <Filter>testing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\CombatSearchExperiment.cpp\">\n      <Filter>experiments</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BOSSPlotBuildOrders.cpp\">\n      <Filter>experiments</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BOSSParameters.cpp\">\n      <Filter>experiments</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BOSSExperiments.cpp\">\n      <Filter>experiments</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"experiments\">\n      <UniqueIdentifier>{1d1bf021-f0f5-44d7-abf5-ded9f0d6ed4d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"testing\">\n      <UniqueIdentifier>{b8dbb056-eafb-4ae0-8475-538af1b4bae4}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\source\\BuildOrderTester.h\">\n      <Filter>testing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\CombatSearchExperiment.h\">\n      <Filter>experiments</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BOSSPlotBuildOrders.h\">\n      <Filter>experiments</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BOSSParameters.h\">\n      <Filter>experiments</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BOSSExperiments.h\">\n      <Filter>experiments</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "BOSS/bin/buildorders/Protoss_DarkTemplarRush.txt",
    "content": "Protoss\nProtoss_Probe\nProtoss_Probe\nProtoss_Probe\nProtoss_Probe\nProtoss_Pylon\nProtoss_Probe\nProtoss_Gateway\nProtoss_Probe\nProtoss_Assimilator\nProtoss_Probe\nProtoss_Cybernetics_Core\nProtoss_Probe\nProtoss_Citadel_of_Adun\nProtoss_Probe\nProtoss_Templar_Archives\nProtoss_Gateway\nProtoss_Dark_Templar\nProtoss_Dark_Templar\nProtoss_Pylon\nProtoss_Dark_Templar\nProtoss_Dark_Templar\nProtoss_Probe\nProtoss_Pylon\nProtoss_Probe"
  },
  {
    "path": "BOSS/bin/buildorders/Protoss_DragoonRange.txt",
    "content": "Protoss\nProtoss_Probe\nProtoss_Probe\nProtoss_Probe\nProtoss_Probe\nProtoss_Pylon\nProtoss_Probe\nProtoss_Probe\nProtoss_Gateway\nProtoss_Probe\nProtoss_Assimilator\nProtoss_Probe\nProtoss_Probe\nProtoss_Cybernetics_Core\nProtoss_Probe\nProtoss_Probe\nProtoss_Gateway\nSingularity_Charge\nProtoss_Dragoon\nProtoss_Gateway\nProtoss_Pylon\nProtoss_Dragoon\nProtoss_Dragoon\nProtoss_Probe\nProtoss_Gateway\nProtoss_Pylon\nProtoss_Probe\nProtoss_Dragoon\nProtoss_Dragoon\nProtoss_Dragoon"
  },
  {
    "path": "BOSS/bin/buildorders/Terran_TankPush.txt",
    "content": "Terran\nTerran_SCV\nTerran_SCV\nTerran_SCV\nTerran_SCV\nTerran_SCV\nTerran_Supply_Depot\nTerran_SCV\nTerran_Barracks\nTerran_Refinery\nTerran_SCV\nTerran_SCV\nTerran_SCV\nTerran_SCV\nTerran_Factory\nTerran_Factory\nTerran_SCV\nTerran_SCV\nTerran_SCV\nTerran_SCV\nTerran_Machine_Shop\nTerran_Machine_Shop\nTerran_Supply_Depot\nTank_Siege_Mode\nTerran_Siege_Tank_Tank_Mode\nTerran_Siege_Tank_Tank_Mode\nTerran_Siege_Tank_Tank_Mode\nTerran_Siege_Tank_Tank_Mode"
  },
  {
    "path": "BOSS/bin/buildorders/Zerg_2HatchHydra.txt",
    "content": "Zerg\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Overlord\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Hatchery\nZerg_Spawning_Pool\nZerg_Drone\nZerg_Extractor\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Hydralisk_Den\nZerg_Drone\nZerg_Overlord\nZerg_Drone\nZerg_Drone\nZerg_Drone\nGrooved_Spines\nZerg_Hydralisk\nZerg_Hydralisk\nZerg_Hydralisk\nZerg_Hydralisk\nZerg_Overlord\nZerg_Hydralisk\nZerg_Hydralisk\nZerg_Hydralisk\nZerg_Hydralisk\nZerg_Overlord\nZerg_Hydralisk\nZerg_Hydralisk\nZerg_Hydralisk\nZerg_Hydralisk"
  },
  {
    "path": "BOSS/bin/buildorders/Zerg_3HatchMuta.txt",
    "content": "Zerg\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Overlord\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Hatchery\nZerg_Spawning_Pool\nZerg_Drone\nZerg_Drone\nZerg_Hatchery\nZerg_Extractor\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Overlord\nZerg_Lair\nZerg_Extractor\nZerg_Drone\nZerg_Drone\nZerg_Zergling\nZerg_Zergling\nZerg_Zergling\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Overlord\nZerg_Drone\nZerg_Overlord\nZerg_Drone\nZerg_Overlord\nZerg_Spire\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Drone\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk\nZerg_Mutalisk"
  },
  {
    "path": "BOSS/bin/images/command_icons/fix.bat",
    "content": "for %%f in (*.png) DO ( convert \"%%f\" -strip -resize 32x32! \"%%f\" )\n"
  },
  {
    "path": "BOSS/bin/images/units/fix.bat",
    "content": "for %%f in (*.png) DO ( convert \"%%f\" -strip \"%%f\" )\n"
  },
  {
    "path": "BOSS/emscripten/BOSS.html",
    "content": "<!doctype html>\n<html lang=\"en-us\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <title>Emscripten-Generated Code</title>\n    <style>\n      body {\n        font-family: arial;\n        margin: 0;\n        padding: none;\n      }\n\n      .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }\n      div.emscripten { text-align: center; }      \n      div.emscripten_border { border: 1px solid black; }\n      /* the canvas *must not* have any border or padding, or mouse coords will be wrong */\n      canvas.emscripten { border: 0px none; }\n\n      #emscripten_logo {\n        display: inline-block;\n        margin: 0;\n      }\n\n      .spinner {\n        height: 30px;\n        width: 30px;\n        margin: 0;\n        margin-top: 20px;\n        margin-left: 20px;\n        display: inline-block;\n        vertical-align: top;\n\n        -webkit-animation: rotation .8s linear infinite;\n        -moz-animation: rotation .8s linear infinite;\n        -o-animation: rotation .8s linear infinite;\n        animation: rotation 0.8s linear infinite;\n\n        border-left: 5px solid rgb(235, 235, 235);\n        border-right: 5px solid rgb(235, 235, 235);\n        border-bottom: 5px solid rgb(235, 235, 235);\n        border-top: 5px solid rgb(120, 120, 120);\n        \n        border-radius: 100%;\n        background-color: rgb(189, 215, 46);\n      }\n\n      @-webkit-keyframes rotation {\n        from {-webkit-transform: rotate(0deg);}\n        to {-webkit-transform: rotate(360deg);}\n      }\n      @-moz-keyframes rotation {\n        from {-moz-transform: rotate(0deg);}\n        to {-moz-transform: rotate(360deg);}\n      }\n      @-o-keyframes rotation {\n        from {-o-transform: rotate(0deg);}\n        to {-o-transform: rotate(360deg);}\n      }\n      @keyframes rotation {\n        from {transform: rotate(0deg);}\n        to {transform: rotate(360deg);}\n      }\n\n      #status {\n        display: inline-block;\n        vertical-align: top;\n        margin-top: 30px;\n        margin-left: 20px;\n        font-weight: bold;\n        color: rgb(120, 120, 120);\n      }\n\n      #progress {\n        height: 20px;\n        width: 30px;\n      }\n\n      #controls {\n        display: inline-block;\n        float: right;\n        vertical-align: top;\n        margin-top: 30px;\n        margin-right: 20px;\n      }\n\n      #output {\n        width: 100%;\n        height: 200px;\n        margin: 0 auto;\n        margin-top: 10px;\n        display: block;\n        background-color: black;\n        color: white;\n        font-family: 'Lucida Console', Monaco, monospace;\n        outline: none;\n      }\n    </style>\n  </head>\n  <body>\n    <a href=\"http://emscripten.org\">\n      <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><svg\n   version=\"1.1\"\n   id=\"Layer_1\"\n   x=\"0px\"\n   y=\"0px\"\n   width=\"296px\" \n   height=\"78px\" \n   viewBox=\"420 120 100 170\"\n   enable-background=\"new 0 0 900 400\"\n   xml:space=\"preserve\"\n   inkscape:version=\"0.48.4 r9939\"\n   sodipodi:docname=\"emscripten_powered_by_logo.svg\"><metadata\n   id=\"metadata345\"><rdf:RDF><cc:Work\n       rdf:about=\"\"><dc:format>image/svg+xml</dc:format><dc:type\n         rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" /></cc:Work></rdf:RDF></metadata><defs\n   id=\"defs343\"><linearGradient\n     y2=\"247.6265\"\n     x2=\"225.1929\"\n     y1=\"152.499\"\n     x1=\"225.1929\"\n     gradientUnits=\"userSpaceOnUse\"\n     id=\"linearGradient5104\"><stop\n   id=\"stop5106\"\n   style=\"stop-color:#C1D72F\"\n   offset=\"0.3227531\" /><stop\n   id=\"stop5108\"\n   style=\"stop-color:#BCD631\"\n   offset=\"0.45119295\" /><stop\n   id=\"stop5110\"\n   style=\"stop-color:#AFD136\"\n   offset=\"0.64491969\" /><stop\n   id=\"stop5112\"\n   style=\"stop-color:#ABD037\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#C1D72F\"\n   offset=\"0.0123\" /><a:midPointStop\n   style=\"stop-color:#C1D72F\"\n   offset=\"0.3086\" /><a:midPointStop\n   style=\"stop-color:#ABD037\"\n   offset=\"1\" /></linearGradient><linearGradient\n     inkscape:collect=\"always\"\n     xlink:href=\"#SVGID_2_\"\n     id=\"linearGradient5120\"\n     x1=\"397.56918\"\n     y1=\"128.12726\"\n     x2=\"397.56918\"\n     y2=\"166.25996\"\n     gradientUnits=\"userSpaceOnUse\"\n     gradientTransform=\"matrix(1.103059,0,0,1.103059,-38.997823,3.1312145)\" /><filter\n     inkscape:collect=\"always\"\n     id=\"filter5126\"><feGaussianBlur\n       inkscape:collect=\"always\"\n       stdDeviation=\"0.56377237\"\n       id=\"feGaussianBlur5128\" /></filter><linearGradient\n     inkscape:collect=\"always\"\n     xlink:href=\"#SVGID_2_\"\n     id=\"linearGradient5134\"\n     gradientUnits=\"userSpaceOnUse\"\n     gradientTransform=\"matrix(1.103059,0,0,1.103059,-38.997823,3.1312145)\"\n     x1=\"397.56918\"\n     y1=\"128.12726\"\n     x2=\"397.56918\"\n     y2=\"166.25996\" /></defs><sodipodi:namedview\n   pagecolor=\"#ffffff\"\n   bordercolor=\"#666666\"\n   borderopacity=\"1\"\n   objecttolerance=\"10\"\n   gridtolerance=\"10\"\n   guidetolerance=\"10\"\n   inkscape:pageopacity=\"0\"\n   inkscape:pageshadow=\"2\"\n   inkscape:window-width=\"1440\"\n   inkscape:window-height=\"838\"\n   id=\"namedview341\"\n   showgrid=\"false\"\n   inkscape:zoom=\"0.63555556\"\n   inkscape:cx=\"224.82424\"\n   inkscape:cy=\"-52.085109\"\n   inkscape:window-x=\"-8\"\n   inkscape:window-y=\"-8\"\n   inkscape:window-maximized=\"1\"\n   inkscape:current-layer=\"Layer_1\" /><g\n   id=\"g5130\"\n   transform=\"matrix(0.91591318,0,0,0.91591318,28.176953,14.143571)\"><path\n     transform=\"matrix(1.103059,0,0,1.103059,-35.073492,-16.03923)\"\n     id=\"path5122\"\n     style=\"fill:#383838;fill-opacity:0.34705882;stroke:none;filter:url(#filter5126)\"\n     d=\"m 494.39333,173.6323 c 0.57407,0.28703 1.87073,1.00226 2.89426,1.02855 0.55732,0.0143 1.14006,-0.1672 1.60262,-0.4784 1.20466,-0.81046 2.23561,-2.03031 2.72683,-3.39661 0.19424,-0.54027 0.0238,-1.72222 0.0238,-1.72222 l -3.82713,-14.06478 -1.98533,0 0.50231,-2.67891 6.36261,0 2.55939,12.22285 4.78392,-9.68746 -2.00924,0 0,-2.65498 7.19979,0 -11.00301,22.38875 -1.69829,1.91358 -2.29628,1.3395 -2.46371,0.26312 -2.29628,-0.21528 -2.79859,-1.36342 z m -12.0637,-14.56445 c -0.93698,1.88565 -1.70261,4.35262 -0.81842,6.26333 0.36549,0.78976 1.35098,1.19428 2.192,1.41737 0.60934,0.16133 1.29167,0.0999 1.88775,-0.10468 0.48126,-0.1655 0.8829,-0.5224 1.255,-0.8697 0.40341,-0.3768 0.77723,-0.80461 1.03505,-1.29262 0.21864,-0.41395 0.40236,-0.84786 0.49325,-1.30698 0.20667,-1.0485 0.35879,-2.1079 0.33583,-3.17631 -0.0184,-0.87403 -0.0789,-1.87107 -0.47711,-2.64959 -0.26344,-0.51379 -0.77017,-0.71849 -1.33113,-0.85633 -0.42395,-0.10479 -0.81432,-0.0626 -1.21773,0.10517 -0.65479,0.27273 -1.2544,0.5311 -1.82112,0.95764 -0.57331,0.4317 -1.21403,0.86959 -1.53337,1.5127 z m 0.65588,-4.31208 c 0,0 2.19341,-1.80738 3.45549,-2.27082 0.71718,-0.26365 3.45363,-0.65258 4.15,-0.3378 1.47292,0.66633 2.26103,1.57529 2.7222,2.60001 0.46118,1.02472 0.69944,2.59956 0.79701,3.73627 0.13278,1.55027 -0.13682,3.77629 -0.53404,5.74843 -0.30079,1.49256 -1.01883,2.74423 -1.83478,3.92156 -1.06526,1.5373 -1.82382,2.15116 -3.66756,2.46594 -0.98864,0.16889 -1.93845,0.46787 -3.25466,0.0928 -1.4384,-0.40963 -2.35273,-0.81244 -3.39599,-1.63337 -0.72524,-0.57054 -1.16043,-1.54043 -1.16043,-1.54043 l 0,2.82636 -4.8903,0 3.39872,-23.01602 -1.92242,-0.85888 0.0403,-2.38127 7.25847,0.0534 z m -23.77803,2.20447 c 0.29175,1.49273 0.0813,4.83252 -0.86111,6.69751 -0.3062,0.60617 -0.94813,1.32967 -1.55479,1.6983 -1.01515,0.61713 -2.21688,1.21322 -3.3966,1.07639 -0.47944,-0.0541 -0.97036,-0.34348 -1.24383,-0.74151 -0.47686,-0.69328 -0.43621,-1.55032 -0.45448,-2.39198 -0.024,-1.06873 0.13137,-2.23775 0.38272,-3.277 0.18705,-0.7744 0.4229,-1.58254 0.86111,-2.24844 0.39037,-0.59323 0.92628,-1.12617 1.55478,-1.45909 0.54854,-0.29014 1.19695,-0.38467 1.81791,-0.40664 0.63637,-0.0231 1.3031,0.0385 1.88966,0.28704 0.3875,0.16453 0.92361,0.3524 1.00463,0.76542 z m 1.29312,-9.69052 -0.64254,6.12262 c 0,0 -1.68393,-0.96858 -2.605,-1.25148 -0.73032,-0.22434 -1.50312,-0.36654 -2.26624,-0.33838 -0.97069,0.0345 -1.91182,0.22099 -2.81751,0.57088 -0.9185,0.35497 -1.78344,0.94565 -2.49338,1.62792 -0.88025,0.84538 -1.51404,1.90455 -2.02977,3.0106 -0.39653,0.84993 -0.69517,1.75284 -0.87975,2.67232 -0.22875,1.14241 -0.44415,2.38719 -0.43937,3.55197 0.01,1.44865 0.0623,2.89489 0.54092,4.26214 0.25525,0.72907 0.71643,1.40578 1.28572,1.9283 0.56835,0.52207 1.29566,0.87604 2.02935,1.11621 0.41072,0.13491 0.85346,0.17274 1.28579,0.16935 1.00285,-0.01 2.03715,-0.0883 2.97671,-0.43999 0.66497,-0.2489 1.21759,-0.73399 1.79298,-1.1502 0.75304,-0.54475 2.16476,-1.86006 2.16476,-1.86006 l 0,1.62374 -0.5751,0 0,1.48807 6.86709,0 0,-2.84135 -1.92841,0 3.21374,-23.57782 -7.37422,0 0,2.33412 z m -93.60062,7.55781 2.33363,15.57933 6.23084,0 4.04243,-11.34169 1.62654,11.34169 5.88425,0 7.05633,-16.38872 0,-2.0141 -6.1713,0 0,2.82349 1.88966,0 -4.04243,10.16973 -0.74151,0 -1.29167,-12.55773 -5.38194,0 -4.7361,12.50989 -1.55478,-12.94538 -6.86496,0 0,2.82349 z m -12.15,0.72146 c -0.56264,0.0892 -1.03524,0.17358 -1.53086,0.45447 -0.737,0.41808 -1.46132,0.95771 -1.91357,1.67437 -0.44123,0.70048 -0.53204,1.57581 -0.66975,2.39196 -0.1751,1.04003 -0.20064,2.10306 -0.19136,3.15741 0.01,0.81614 -0.0138,1.66577 0.35879,2.39197 0.1904,0.37315 0.52874,0.80945 0.88503,1.02855 0.56015,0.34453 1.06632,0.55494 1.72222,0.598 0.72597,0.0483 1.48801,-0.18852 2.10493,-0.57408 0.59422,-0.37072 1.03334,-0.97401 1.38735,-1.5787 0.46117,-0.78744 0.70905,-1.69257 0.90895,-2.58334 0.20377,-0.90704 0.33579,-1.84565 0.28703,-2.77468 -0.0491,-0.92714 -0.18211,-1.88434 -0.57407,-2.72684 -0.2728,-0.58681 -0.70954,-1.00753 -1.29166,-1.29165 -0.44403,-0.21628 -0.99455,-0.24402 -1.48303,-0.16744 z m -6.62442,-0.73581 c 0.65404,-0.6664 1.4072,-1.25479 2.23273,-1.69161 1.0305,-0.54505 2.16429,-0.92749 3.31518,-1.11604 1.51307,-0.24806 3.09342,-0.2847 4.60036,0 0.88055,0.16632 1.78322,0.44742 2.50307,0.98113 0.77409,0.57312 1.35279,1.40936 1.79291,2.26639 0.42901,0.83457 0.6828,1.77223 0.77798,2.70605 0.16564,1.61985 0.024,3.29135 -0.37201,4.87103 -0.33328,1.33759 -0.88436,2.64754 -1.65745,3.78889 -0.67549,0.99679 -1.52894,1.91262 -2.53721,2.5709 -0.89957,0.58746 -1.9718,0.87641 -3.01035,1.15006 -0.87153,0.22963 -1.77166,0.4095 -2.67235,0.40576 -1.21068,-0.01 -2.47998,-0.0817 -3.58589,-0.57511 -1.09854,-0.48896 -1.89728,-1.32739 -2.60455,-2.30013 -0.61123,-0.83995 -1.02561,-1.59975 -1.31932,-2.87516 -0.2125,-0.9233 -0.40006,-2.19912 -0.37215,-3.14592 0.0335,-1.16537 0.3568,-2.74121 0.83416,-3.80434 0.52547,-1.17098 1.17609,-2.3161 2.07489,-3.2319 z m 94.95184,13.82318 c -2.20516,1.01761 -4.61429,1.69636 -7.02343,1.69636 -5.32726,0 -7.22678,-3.12145 -7.22678,-7.22678 0,-7.1251 4.54685,-11.19645 10.0772,-11.19645 3.7324,0 5.56453,1.69625 5.56453,4.47856 0,4.85189 -5.12329,6.27735 -10.41633,6.82001 0.10168,1.73076 0.81446,3.32485 3.3592,3.32485 1.2218,0 2.88401,-0.37315 4.91982,-1.22099 z m -3.22292,-11.77374 c 0,-0.81423 -0.57695,-1.28891 -1.62876,-1.28891 -1.89988,0 -3.46041,1.66212 -3.96978,4.34287 1.45897,-0.20368 5.59854,-0.91613 5.59854,-3.05396 z m -30.33408,11.77374 c -2.2054,1.01761 -4.61457,1.69636 -7.02371,1.69636 -5.32653,0 -7.22671,-3.12145 -7.22671,-7.22678 0,-7.1251 4.54679,-11.19645 10.07785,-11.19645 3.73175,0 5.56382,1.69625 5.56382,4.47856 0,4.85189 -5.12273,6.27735 -10.41568,6.82001 0.10142,1.73076 0.81422,3.32485 3.35884,3.32485 1.22158,0 2.8842,-0.37315 4.91994,-1.22099 z m -3.22305,-11.77374 c 0,-0.81423 -0.57638,-1.28891 -1.62883,-1.28891 -1.89959,0 -3.46023,1.66212 -3.96971,4.34287 1.4591,-0.20368 5.59854,-0.91613 5.59854,-3.05396 z m -82.36051,20.5268 -0.0679,-0.13571 0.98406,-5.66614 2.10303,-15.16698 c 0.0687,-0.40664 -0.0332,-0.61046 -0.30522,-0.71214 l -1.66259,-0.61111 0.37379,-2.57855 6.78556,0 -0.40663,2.71427 0.10142,0.0335 c 2.0016,-1.86631 4.10566,-3.08743 6.24306,-3.08743 2.91821,0 4.95366,1.86577 4.95366,6.78561 0,4.68241 -1.83206,11.6379 -8.14271,11.6379 -2.20534,0 -3.42694,-0.84825 -4.68256,-1.73039 l -0.74621,5.08917 c -0.0341,0.37361 0.0326,0.50898 0.47457,0.54273 l 3.42697,0.33969 -0.37385,2.5447 -9.0589,0 z m 6.78613,-12.04485 c 0.84787,0.71258 1.96788,1.32305 3.22348,1.32305 2.74798,0 3.76601,-3.86811 3.76601,-6.85368 0,-2.002 -0.47476,-3.32542 -1.76432,-3.32542 -1.35696,0 -3.08763,1.4591 -4.30913,2.54506 z m 81.08934,4.85147 0.33969,-2.54464 1.56064,-0.2038 c 0.47498,-0.0683 0.5429,-0.1695 0.61084,-0.67837 l 1.42466,-10.34864 c 0.0335,-0.37315 -0.0335,-0.61046 -0.33914,-0.71214 l -1.69691,-0.61111 0.37365,-2.57855 6.71797,0 -0.44097,3.05395 0.10191,0.0679 c 1.32326,-1.89982 3.22359,-3.46042 5.39485,-3.46042 0.7463,0 2.0359,0.13582 2.61295,0.30538 l -0.84863,6.17508 -3.96972,-0.13582 -0.10157,-1.76443 c -0.0335,-0.30537 -0.10223,-0.40701 -0.37391,-0.40701 -0.64452,0 -1.69636,0.78027 -2.64651,1.76455 l -1.18674,8.61817 c -0.0687,0.54303 -0.0334,0.64474 0.47477,0.67874 l 3.22351,0.27142 -0.37384,2.51081 -10.8575,0 z\"\n     inkscape:connector-curvature=\"0\"\n     sodipodi:nodetypes=\"cssscccccccccccccccccssssssssccssscssssscsssccccccccsssssssssccsccsssssssssscsscccccccccccccccccccccccccccccccsssscsssssscscsssssssscsssssssssscsssscsccsscscsssscsccsscsccccccccccsssccccccccssscccccccccccccsccccsccccccc\" /><path\n     sodipodi:nodetypes=\"cssscccccccccccccccccssssssssccssscssssscsssccccccccsssssssssccsccsssssssssscsscccccccccccccccccccccccccccccccsssscsssssscscsssssssscsssssssssscsssscsccsscscsssscsccsscsccccccccccsssccccccccssscccccccccccccsccccsccccccc\"\n     inkscape:connector-curvature=\"0\"\n     d=\"m 509.55935,174.26011 c 0.63327,0.31663 2.06355,1.10555 3.19256,1.13455 0.61476,0.0158 1.25757,-0.18443 1.76781,-0.5277 1.3288,-0.89397 2.46618,-2.23946 3.00784,-3.74661 0.21419,-0.59598 0.0258,-1.89972 0.0258,-1.89972 l -4.22153,-15.51428 -2.18993,0 0.55406,-2.95501 7.01835,0 2.82313,13.48255 5.27696,-10.68586 -2.21631,0 0,-2.92858 7.94179,0 -12.13698,24.69605 -1.87332,2.11078 -2.5329,1.4776 -2.71762,0.29022 -2.53295,-0.23748 -3.08699,-1.50392 z m -13.30698,-16.06545 c -1.0335,2.08005 -1.87803,4.80122 -0.90274,6.90883 0.4032,0.87116 1.49018,1.31738 2.4179,1.56347 0.67214,0.17793 1.42477,0.1102 2.08233,-0.11548 0.53084,-0.1826 0.97383,-0.5762 1.38432,-0.9593 0.44502,-0.4157 0.85733,-0.8875 1.14176,-1.42582 0.24113,-0.45665 0.44375,-0.93526 0.54404,-1.44168 0.22797,-1.1566 0.3958,-2.3252 0.37043,-3.50371 -0.0204,-0.96413 -0.0869,-2.06387 -0.52631,-2.92259 -0.29054,-0.56679 -0.84946,-0.79259 -1.46826,-0.94463 -0.46761,-0.11559 -0.89829,-0.0686 -1.34322,0.11597 -0.72226,0.30083 -1.38368,0.5859 -2.00879,1.05634 -0.63242,0.4762 -1.33915,0.9593 -1.69146,1.6686 z m 0.72346,-4.75648 c 0,0 2.41951,-1.99358 3.81169,-2.50482 0.79109,-0.29085 3.80953,-0.71977 4.57766,-0.3726 1.6247,0.73503 2.49408,1.73759 3.00274,2.86791 0.50868,1.13043 0.77154,2.86756 0.87911,4.12137 0.14648,1.71007 -0.15092,4.16549 -0.58904,6.34083 -0.33179,1.64636 -1.12383,3.02703 -2.02388,4.32576 -1.17506,1.6957 -2.01178,2.37286 -4.04556,2.72004 -1.09051,0.18629 -2.13814,0.51607 -3.59006,0.10268 -1.5866,-0.45183 -2.59522,-0.89615 -3.74599,-1.8017 -0.79994,-0.62933 -1.28003,-1.6992 -1.28003,-1.6992 l 0,3.11766 -5.39426,0 3.74898,-25.38802 -2.12052,-0.94738 0.0443,-2.62669 8.00657,0.0587 z m -26.22853,2.43167 c 0.32185,1.64663 0.0893,5.33062 -0.9498,7.38781 -0.33781,0.66857 -1.04588,1.46667 -1.7151,1.8733 -1.11975,0.68073 -2.44527,1.33822 -3.7466,1.18729 -0.52883,-0.0601 -1.07036,-0.37888 -1.37203,-0.81791 -0.52601,-0.76478 -0.48121,-1.71012 -0.50128,-2.63848 -0.0263,-1.17893 0.14487,-2.46835 0.42212,-3.6147 0.20635,-0.8543 0.4665,-1.74564 0.94981,-2.48024 0.43067,-0.65433 1.02178,-1.24217 1.71508,-1.60939 0.60504,-0.32004 1.32025,-0.42437 2.00521,-0.44854 0.70197,-0.0251 1.4374,0.0425 2.08446,0.31654 0.4274,0.18153 1.01882,0.3888 1.10813,0.84432 z m 1.42642,-10.68922 -0.70874,6.75362 c 0,0 -1.85753,-1.06838 -2.8735,-1.38048 -0.80562,-0.24744 -1.65802,-0.40424 -2.49984,-0.37318 -1.07069,0.0382 -2.10882,0.24369 -3.1078,0.62968 -1.01321,0.39157 -1.96724,1.04315 -2.75039,1.79572 -0.97095,0.93248 -1.67003,2.10085 -2.23897,3.3208 -0.43738,0.93753 -0.76677,1.93354 -0.9704,2.94777 -0.2523,1.26016 -0.4899,2.63324 -0.48461,3.91802 0.011,1.59795 0.0683,3.19329 0.59661,4.70144 0.28155,0.80417 0.79028,1.55058 1.41822,2.127 0.62695,0.57587 1.4292,0.96634 2.23856,1.23121 0.45301,0.14881 0.94135,0.19054 1.41828,0.18685 1.10615,-0.011 2.24705,-0.0973 3.28346,-0.48539 0.73352,-0.2745 1.34304,-0.80959 1.97773,-1.2687 0.83064,-0.60085 2.38786,-2.05176 2.38786,-2.05176 l 0,1.79104 -0.63429,0 0,1.64147 7.57478,0 0,-3.13415 -2.12721,0 3.54494,-26.00772 -8.13411,0 0,2.57462 z m -103.24702,8.33671 2.57413,17.18493 6.87304,0 4.45903,-12.51049 1.79414,12.51049 6.49065,0 7.78353,-18.07772 0,-2.2217 -6.8073,0 0,3.11449 2.08446,0 -4.45903,11.21783 -0.8179,0 -1.42488,-13.85193 -5.93654,0 -5.2242,13.79919 -1.71497,-14.27958 -7.57246,0 0,3.11449 z m -13.4021,0.79586 c -0.62064,0.0982 -1.14194,0.19148 -1.68866,0.50127 -0.813,0.46118 -1.61192,1.05641 -2.11077,1.84697 -0.48673,0.77268 -0.58683,1.73821 -0.73875,2.63846 -0.1932,1.14723 -0.22134,2.31976 -0.21116,3.48281 0.011,0.90024 -0.0148,1.83747 0.39579,2.63847 0.21,0.41165 0.58324,0.89285 0.97623,1.13455 0.61796,0.38003 1.17622,0.61214 1.89972,0.6596 0.80077,0.0533 1.64141,-0.20792 2.32189,-0.63318 0.65546,-0.40892 1.13978,-1.07441 1.53029,-1.7414 0.50878,-0.86864 0.78215,-1.86707 1.00265,-2.84964 0.22477,-1.00044 0.37039,-2.03585 0.31663,-3.06058 -0.0541,-1.02274 -0.20091,-2.07854 -0.63327,-3.00784 -0.3009,-0.64731 -0.78264,-1.11143 -1.42476,-1.42485 -0.48983,-0.23858 -1.09705,-0.26912 -1.63583,-0.18464 z m -7.30711,-0.81171 c 0.72143,-0.735 1.55219,-1.38409 2.46282,-1.86591 1.1367,-0.60125 2.38729,-1.02309 3.65678,-1.23104 1.66908,-0.27366 3.41222,-0.314 5.07446,0 0.97135,0.18342 1.96702,0.49352 2.76107,1.08223 0.85389,0.63222 1.49219,1.55466 1.97771,2.49999 0.47321,0.92057 0.7531,1.95483 0.85808,2.98495 0.18274,1.78675 0.0263,3.63055 -0.41031,5.37303 -0.36757,1.47539 -0.97545,2.92034 -1.82825,4.17929 -0.74509,1.09959 -1.68654,2.10982 -2.79871,2.8359 -0.99227,0.64796 -2.175,0.96671 -3.32055,1.26856 -0.96139,0.25333 -1.95426,0.4517 -2.94774,0.44756 -1.33549,-0.011 -2.73559,-0.0897 -3.9555,-0.63431 -1.21174,-0.53936 -2.09278,-1.46419 -2.87295,-2.53723 -0.67423,-0.92645 -1.13131,-1.76457 -1.45532,-3.17146 -0.2344,-1.0184 -0.44126,-2.42572 -0.41044,-3.47012 0.0365,-1.28547 0.39349,-3.02371 0.92005,-4.19644 0.57967,-1.29168 1.29729,-2.5548 2.2888,-3.565 z m 104.73744,15.24778 c -2.43247,1.12251 -5.0899,1.87126 -7.74734,1.87126 -5.87626,0 -7.97147,-3.44315 -7.97147,-7.97158 0,-7.8594 5.0154,-12.35035 11.11569,-12.35035 4.11711,0 6.13803,1.87105 6.13803,4.94016 0,5.35189 -5.65129,6.92425 -11.48983,7.52281 0.11219,1.90916 0.89836,3.66755 3.7054,3.66755 1.3477,0 3.18121,-0.41165 5.42682,-1.34689 z m -3.55513,-12.98704 c 0,-0.89823 -0.63635,-1.42181 -1.79655,-1.42181 -2.09568,0 -3.81712,1.83342 -4.37899,4.79047 1.60937,-0.22468 6.17554,-1.01053 6.17554,-3.36866 z m -33.46028,12.98704 c -2.4327,1.12251 -5.09006,1.87126 -7.74751,1.87126 -5.87553,0 -7.97151,-3.44315 -7.97151,-7.97158 0,-7.8594 5.01539,-12.35035 11.11645,-12.35035 4.11635,0 6.13722,1.87105 6.13722,4.94016 0,5.35189 -5.65062,6.92425 -11.48908,7.52281 0.11182,1.90916 0.89812,3.66755 3.70494,3.66755 1.34748,0 3.1815,-0.41165 5.42704,-1.34689 z m -3.55514,-12.98704 c 0,-0.89823 -0.63578,-1.42181 -1.79674,-1.42181 -2.09539,0 -3.81683,1.83342 -4.37881,4.79047 1.60951,-0.22468 6.17555,-1.01053 6.17555,-3.36866 z m -90.84852,22.6422 -0.0749,-0.14971 1.08546,-6.25004 2.31984,-16.73008 c 0.0757,-0.44854 -0.0367,-0.67336 -0.33673,-0.78554 l -1.83388,-0.67411 0.41228,-2.84425 7.48486,0 -0.44853,2.99397 0.11182,0.0371 c 2.2079,-2.05871 4.52887,-3.40563 6.88646,-3.40563 3.21901,0 5.46427,2.05807 5.46427,7.48491 0,5.16501 -2.02094,12.8373 -8.98192,12.8373 -2.43264,0 -3.78014,-0.93565 -5.16516,-1.90869 l -0.82311,5.61357 c -0.0376,0.41212 0.0356,0.56148 0.52347,0.59873 l 3.78017,0.37469 -0.41234,2.8069 -9.9925,0 z m 7.48553,-13.28615 c 0.93528,0.78598 2.17068,1.45946 3.55568,1.45946 3.03118,0 4.15411,-4.26682 4.15411,-7.56009 0,-2.2083 -0.52366,-3.66812 -1.94612,-3.66812 -1.49686,0 -3.40583,1.6095 -4.75323,2.80736 z m 89.44624,5.35147 0.37469,-2.80694 1.72154,-0.2248 c 0.52388,-0.0753 0.5988,-0.1869 0.67374,-0.74827 l 1.57152,-11.41514 c 0.0365,-0.41155 -0.0368,-0.67336 -0.3741,-0.78554 l -1.87181,-0.67411 0.41215,-2.84425 7.41037,0 -0.48647,3.36865 0.11241,0.0749 c 1.45966,-2.09562 3.55581,-3.81702 5.95085,-3.81702 0.8232,0 2.2457,0.14982 2.88225,0.33688 l -0.93613,6.81148 -4.37882,-0.14982 -0.11196,-1.94633 c -0.0371,-0.33677 -0.11284,-0.44891 -0.41252,-0.44891 -0.71092,0 -1.87116,0.86067 -2.91921,1.94635 l -1.30904,9.50637 c -0.0757,0.59903 -0.0368,0.71124 0.52367,0.74874 l 3.55571,0.29932 -0.41234,2.76961 -11.9765,0 z\"\n     style=\"fill:url(#linearGradient5134);fill-opacity:1;stroke:none\"\n     id=\"path5080\" /></g><path\n   fill=\"#E2E2E2\"\n   d=\"M256.023,135.437H196.36c-16.432,0-29.8,13.368-29.8,29.8v73.527c0,16.432,13.368,29.8,29.8,29.8h59.663  c16.433,0,29.801-13.368,29.801-29.8v-73.527C285.824,148.805,272.456,135.437,256.023,135.437z M191.561,165.236  c0-2.646,2.153-4.8,4.8-4.8h59.663c2.647,0,4.801,2.153,4.801,4.8v73.527c0,2.646-2.153,4.8-4.801,4.8H196.36  c-2.646,0-4.8-2.153-4.8-4.8V165.236z\"\n   id=\"path3\" /><path\n   d=\"m 531.664,250.155 h 18.498 l -2.809,18.064 h 5.59 37.586 l 2.6,-17.718 c 4.98,-1.091 9.133,-3.455 12.512,-6.693 3.084,4.075 8.566,7.37 18.252,7.37 6.338,0 12.775,-1.807 17.174,-3.687 4.254,2.399 9.463,3.687 15.459,3.687 3.088,0 6.236,-0.355 9.426,-1.023 h 67.135 l 3.354,-24.827 -5.445,-0.764 1.879,-13.356 c 0.371,-2.386 0.449,-4.66 0.449,-6.156 l -0.008,-0.375 c -0.457,-12.191 -8.139,-19.765 -20.045,-19.765 -2.404,0 -4.623,0.314 -6.676,0.852 h -34.189 l -0.035,0.244 c -2.527,-0.701 -5.41,-1.096 -8.686,-1.096 -3.801,0 -7.406,0.555 -10.76,1.598 l 0.105,-0.746 h -12.467 l 1.826,-12.951 H 615.08 l -1.846,7.658 c -1.373,5.704 -2.213,5.793 -4.453,6.03 l -4.508,0.477 c -3.049,-1.424 -6.357,-2.065 -9.602,-2.065 -2.135,0 -4.275,0.284 -6.416,0.852 h -19.291 c 0.502,-1.772 0.775,-3.674 0.775,-5.678 0,-9.601 -6.846,-16.305 -16.646,-16.305 -11.055,0 -18.775,7.721 -18.775,18.776 0,0.951 0.082,1.869 0.219,2.764 -2.135,-0.288 -4.277,-0.409 -5.553,-0.409 -2.053,0 -4.072,0.288 -6.045,0.852 h -31.342 c -2.74,-0.553 -5.641,-0.852 -8.537,-0.852 -7.138,0 -13.492,1.674 -18.808,4.723 l -3.451,-1.461 c -3.711,-1.571 -11.232,-3.262 -18.979,-3.262 -8.933,0 -16.383,2.56 -21.576,7.016 -3.265,-4.473 -8.523,-7.016 -15.228,-7.016 -4.822,0 -9.021,1.477 -12.572,3.44 -2.996,-2.204 -6.796,-3.44 -11.115,-3.44 -2.327,0 -4.48,0.315 -6.476,0.852 h -33.963 l -0.035,0.245 c -2.526,-0.702 -5.41,-1.097 -8.687,-1.097 -20.458,0 -35.307,16.031 -35.307,38.117 0,17.363 10.785,28.149 28.148,28.149 3.087,0 6.236,-0.356 9.426,-1.023 h 88.816 c 3.706,0.676 7.669,1.023 11.154,1.023 8.907,0 16.278,-2.375 21.51,-6.593 4.872,4.252 11.585,6.593 19.728,6.593 3.053,0 6.206,-0.368 9.286,-1.023 h 44.664 2.069 z\"\n   id=\"path5\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#e2e2e2\" /><path\n   fill=\"#F5F5F5\"\n   d=\"M255.023,133.437H195.36c-16.432,0-29.8,13.368-29.8,29.8v73.527c0,16.432,13.368,29.8,29.8,29.8h59.663  c16.433,0,29.801-13.368,29.801-29.8v-73.527C284.824,146.805,271.456,133.437,255.023,133.437z M190.561,163.236  c0-2.646,2.153-4.8,4.8-4.8h59.663c2.647,0,4.801,2.153,4.801,4.8v73.527c0,2.646-2.153,4.8-4.801,4.8H195.36  c-2.646,0-4.8-2.153-4.8-4.8V163.236z\"\n   id=\"path7\" /><g\n   id=\"g9\"><g\n   id=\"g11\"><path\n   fill=\"#FBFDF8\"\n   d=\"M195.361,251.626c-8.161,0-14.8-6.64-14.8-14.8v-73.527c0-8.161,6.639-14.8,14.8-14.8h59.663    c8.161,0,14.8,6.639,14.8,14.8v73.527c0,8.16-6.639,14.8-14.8,14.8H195.361z\"\n   id=\"path13\" /><path\n   fill=\"#F0F4E1\"\n   d=\"M255.024,152.499c5.964,0,10.8,4.835,10.8,10.8v73.527c0,5.965-4.835,10.8-10.8,10.8h-59.663    c-5.964,0-10.8-4.835-10.8-10.8v-73.527c0-5.964,4.835-10.8,10.8-10.8H255.024 M255.024,144.499h-59.663    c-10.366,0-18.8,8.434-18.8,18.8v73.527c0,10.366,8.434,18.8,18.8,18.8h59.663c10.366,0,18.8-8.434,18.8-18.8v-73.527    C273.824,152.933,265.391,144.499,255.024,144.499L255.024,144.499z\"\n   id=\"path15\" /></g><defs\n   id=\"defs17\"><filter\n   id=\"Adobe_OpacityMaskFilter\"\n   filterUnits=\"userSpaceOnUse\"\n   x=\"176.562\"\n   y=\"144.499\"\n   width=\"97.263\"\n   height=\"111.127\"><feColorMatrix\n   type=\"matrix\"\n   values=\"-1 0 0 0 1  0 -1 0 0 1  0 0 -1 0 1  0 0 0 1 0\"\n   color-interpolation-filters=\"sRGB\"\n   result=\"source\"\n   id=\"feColorMatrix20\" /></filter></defs><mask\n   maskUnits=\"userSpaceOnUse\"\n   x=\"176.562\"\n   y=\"144.499\"\n   width=\"97.263\"\n   height=\"111.127\"\n   id=\"SVGID_1_\"><g\n   filter=\"url(#Adobe_OpacityMaskFilter)\"\n   id=\"g23\"><image\n   overflow=\"visible\"\n   width=\"422\"\n   height=\"480\"\n   xlink:href=\"data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEBLAEsAAD/7AARRHVja3kAAQAEAAAAHgAA/+4AIUFkb2JlAGTAAAAAAQMA EAMCAwYAAAg2AAAQ4QAAF1b/2wCEABALCwsMCxAMDBAXDw0PFxsUEBAUGx8XFxcXFx8eFxoaGhoX Hh4jJSclIx4vLzMzLy9AQEBAQEBAQEBAQEBAQEABEQ8PERMRFRISFRQRFBEUGhQWFhQaJhoaHBoa JjAjHh4eHiMwKy4nJycuKzU1MDA1NUBAP0BAQEBAQEBAQEBAQP/CABEIAeMBqQMBIgACEQEDEQH/ xACjAAEAAgMBAQAAAAAAAAAAAAAABQYBAwQHAgEBAQAAAAAAAAAAAAAAAAAAAAEQAAEDAQQKAwAC AwEAAAAAAAABAwQCMRMUBRBQEjMVJQYWNgcgESEwI5AiMkARAAEBAwsEAQIFAwUBAAAAAAABMQID EFAycqOz0wQ0RaURIXGRIEFRMGEiExRAgRKh0SMzQxUSAQAAAAAAAAAAAAAAAAAAAJD/2gAMAwEA AhEDEQAAANUJsrZYFfFgV8WBXxYEL0ki5fo6GjJuaRuaRuaRuaRuaRuaRuaRuaRuaRuaRuaRuaRu aRuaMHQ5dR3ojnJ9XxYFfFgV8WD0jxf2AodbslbAD6mDhlpLvI/qkuiovZL7CGzNfRCJwQacEGnB Bp0QSdEEnRBJ0QSdEEnRBJ3BBpwQacEHidwQXzPfBA6bBqK5w2nlKVH3iJitt+gAeweP+wFDrdkr Y+vmaN02k6+e3d2Gjo6N0c2zoyaM7xozuGluGluGluGluGluGluGluGluGluGluGluGnG8c/z1YO PVIfJF80xoIGPsfBVVrl6hIrD7+B7B4/7AUOt2StnXaYyxHTJ6ZKvrqb4x9MgAAAAAAAAAAAAAAA DGR8692Dh4pbkIKJscTVNiLdVY1+weP+wFDgJ+JLJORs3XbIc3dGz6ZAAAAAAAAAAAAAAAAAAAPn R0ayMi5uLqv1S51eIT2Dx/2AofB38Ra5uIm6kOzm6o+gAAAAAAAAAAAAAAAAAAAPj7+TkjJWNIOt 2et1WfYPH/YIofH2cZcJyEnKkenn6IyAAAAAAAAAAAAAAAAAAABjODmjZONIWt2WtVWPYPH/AGCK Hx9nIXGcg5ypLfo3xkAAAAAAAAAAAAAAAAAAADGcHPGyUaQ1astaqseweP8AsEUPk6+QuM7BTtSW 7TujIAAAAAAAAAAAAAAAAAAAGM4OeOkY4hqzZqzVY9g8f9gih8nXyFxnYKdqS3ad0ZAAAAAAAAAA AAAAAAAAAAxnBzx0jHENWbNWarHsHj/sEUPk6+QuM7BTtSW7TujIAAAAAAAAAAAAAAAAAAAGM4Oe OkY4hqzZqzVY9g8f9gih8nXyFxnYKdqS3ad0ZAAAAAAAAAAAAAAAAAAAAxnBzx0jHENWbNWarHsH j/sEUPk6+QuM7BTtSW7TujIAAAAAAAAAAAAAAAAAAAGM4OeOkY4hqzZqzVY9g8f9gih8nXyFxnYK dqS3ad0ZAAAAAAAAAAAAAAAAAAAAxnBzx0jHENWbNWarHsHj/sEUPk6+QuM7BTtSW7TujIAAAAAA AAAAAAAAAAAAAGM4OeOkY4hqzZqzVY9g8f8AYIofJ18hcZ2Cnakt2ndGQAAAAAAAAAAAAAAAAAAA MZwc8dIxxDVmzVmqx7B4/wCwRQ+Tr5C4zsFO1JbtO6MgAAAAAAAAAAAAAAAAAAAYzg546RjiGrNm rNVj2Dx/2CKHydfIXGdgp2pLdp3RkAAAAAAAAAAAAAAAAAAADGcHPHSMcQ1Zs1ZqseweP+wRQ+Tr 5C4zsFO1JbtO6MgAAAAAAAAAAAAAAAAAAAYzg546RjiGrNmrNVj2Dx/2CKHydfIXGdgp2pLdp3Rk AAAAAAAAAAAAAAAAAAADGcHPHSMcQ1Zs1ZqseweP+wRQ+Tr5C4zsFO1JbtO6MgAAAAAAAAAAAAAA AAAAAYzg546RjiGrNmrNVj2Dx/2CKHydfIXGdgp2pLdp3RkAAAAAAAAAAAAAAAAAAADGcHPHSMcQ 1Zs1ZqseweP+wRQ+Tr4y5TkHOVJb9G+MgAAAAAAAAAAAAAAAAAAAYzg542SjSGrVlrVVj2Dx/wBg ih8fZxlxnIKcqT6ObpjIAAAAAAAAAAAAAAAAAAAGM4OeNkY0h61Za1VY9g8f9gih8Xbwlxm4GbqW 6uLrj7AAAAAAAAAAAAAAAAAAAA+fr5OaNkI0ia1Y61Vb9g8f9gihxknCl1m65N1OdsZ3x0ZxkAAA AAAAAAAAAAAAAAAAx8fek5ozui6jazYKsRPsHj/sEUOu2Ktlqn6XZ6scjBSRLbOPpjYxkAAAAAAA AAAAAAAAAAYfJjm+uM0xXVE1xVOZr0Y9g8f9gKHW7JWz7s1W6i9SdYlasXXB9pLbI7fHY5/s3NeT 7fGT6fI+nyPp8j6fI+nyPp8j6fI+nyPp8j6fI+nyPp8D7x8fJtxp1m7Tp5jbw/MfWIjbXTk5SHsH j/sBQ63ZK2AdthqO8vXbUZWrJ0V/oJ7ZB7Sa+ofJMIkS6IySyJRLIkSyJEsiRLIkSyJEsiRLIkSy JVLYiRLYicEr8xfwSemN0kjy8PIdkfxQp0xWEAPYPH/YCh1uyVsAAz08ome2si37qZkumaULspIu 2aRkuyki7KSLspIuyki7KSLspIuyki7KSLtilC6qSLtilC6fNNFu5qz8k7wcI+vkAAHsHj/sBWoQ AAAAAAAAAAAAAAAAAAAAAAAAAHpAf//aAAgBAgABBQD/ACi//9oACAEDAAEFAP8AKL//2gAIAQEA AQUA6w6rz/LM+776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvv qs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qz vvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++ qzvvqs776rMfLPYHlHyRFUbivuDeUv1FOSVKJkRwE4CcAOAHADgBwA4AcAOAHADgBwA4AcAOAHAD gBwA4AcAOAHADgBwA4AcAOAnARciFyRUK8ndQcgyGxaaqf4fYHlHwRFUjZe68RsqbpGoKIUQkKYY kISEYJDAmBMCYEwJgTAmBMCYEwJgTAmBMCYEwJgTAmBMCYEwJgTAmCQWELCKoSFcNByEhIyxusk5 VVQV0VUL8vYHlGltupyqDlaIMREQaijcUoilMUSKgkZDDIYZDDIYZDDIYZDDIYZDDIYZDDIYZDDI YZDDIYZDDIYZDDIYZDDIYZDDIYZDDIYZDDILGQWKVRSuKORR2KPRCZltDiSYrjFXx9geUaG26nKs vy9KEjxhmONRxuOUMFLAjIjJdF0XRdIXSF0hdF0XRdF0XRdF0XRdF0XRdF0XRdIXSF0hdIXRdCsi sisFTBXHHY49GH4xMhU10y4tTFfw9geUCJ9rlcL6SNHGGBlgbZKGilsShDZQ+kPr/wBX0fSGygtC CtoVNDjI6wPsElgzCGjlLrdTden2B5QZfGvnYbCIkdkYZGmihsSn61ItJXQOtD7JIZJTBm0X6+Hs DyhP1cpjbLcVojtDLY3QIn1qZU+yugebJDRKaJ7CVUvtq27o9geURaLx6C19JFbI7Y1QU0/WqFQd oH6CS2TG/wAzZrZd0ewPKMqo2n4VH5FoGKBunVTifj9JJpJdBnVH+mj2B5RkqfdcOki0jFJQn5qm pPx5CTSS6TOKf6tHsDyjI0/2hIRU/GUKbNU1DyfklCWhm6f06PYHlGRf9QkIqfjKCWapWx4kkszj daPYHlGQ2wrItjImqlseJJMM43Wj2B5RkNsEjWNarUeJJMM43Oj2B5RkNsEjWNarUeJJMM43Oj2B 5RkNsGyLY1qtR6ySTDONzo9geUZDbBsi2NarUesk2TDON1o9geUZDbBsjWNarUesk2TDON1o9geU ZDbBsjWNarUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDb BsjWNarUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsj WNarUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNa rUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUe skkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUeskk wzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUeskkwzj daPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUeskkwzjdaP YHlGQ2wbI1jWq1HrJNkwzjdaPYHlGQ2wbItjWq1HrJNkwzjdaPYHlGQ2wbItjWq1HrJJMM43Oj2B 5RkNsGyNY1qtR4kkwzjc6PYHlGQ2wSNY1qtR4kkwzjc6PYHlGQ2wrItjImqlseJJMM43Wj2B5RkV sJSKv4yolmqVseJJLM43Wj2B5Rkf/UJSKv4ypTZqmoeX8kqS1M43Oj2B5Rki/wC0Koi1DKlC/mqa h5SSpLUzdf6tHsDyjJ6/p2HURaxiobX81TWv4/USaiXUZy59N6PYHlGXubEiE5+RaxisaqEXVCjl Q/WSayXX+Zy59ro9geUUVbNeXPpVRFdI7gzWUVfeqK6h2skOElwmu/ST3bx/R7A8oMpk/SxHiM8M OjThTX9iLqWqr6HHB50kOkp4zSVsUVKqro9geUDLit15fLSumM+MPjTw26UuCVH2moPsWoqcK3R1 4feJD5MkIiTpKvO6fYHlGiFLViuHLSpGJAzIGnyh8peKXRHEEcQ20NtDbQ2kNpDaQ2kNpDaQ2kNp DaQ2kNpDaQ2kNpDaQ2kNpDaQ2kNpDaQ20NtDbQVxBXEFdKnit8cfHpA/IJMn6TMp+0vw9geUaYU+ pmqJNprRmUNSRuSUSSmQgkgSQI+X5fl+X5fl+X5fl+X5fl+X5fl+X5fl+X5fl+X5fl+X4r4sgWQV SCuSOSR2SPSiRLREzDMlUVVVfh7A8o+EeW4wsTNKKxmYijcsollMspliSxJZjDGIYxDGIYxDGIYx DGIYxDGIYxDGIYxDGIYxDGIYxDGIYxDGIYxDGIYxDGIYxBZYssqllUsrljksdmISsxooSVmLjyqq r8vYHlHxRVRWZ77QznNI3mzSlGZUKU5hSJmKHEUOIocRQ4jScRQ4ihxFDiKHEUOIocRQ4ihxFDiK HEUOIocRQ4ihxFDiKHEUOIocRpOIocRQ4ihxFBcxQXMEKsxpHM1aQezmhB/M3nCquqtfn7A8o/hS utC9dL50vnS/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/ eL50vnS9dLytT7X+PrDhvHuTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOT HJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY/pP/aAAgBAgIGPwBR f//aAAgBAwIGPwBRf//aAAgBAQEGPwCPk8jmv2su47DV1z9uE90V5xHl7vuKrTXWMHDNdYwcM11j BwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHD NdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11 jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMH DNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDP+z/AEd/2MzUhXbvz7H6XVO/ Y7vFJSkpSUpKUlKSlJSkpSUpKUlKSlJSkpSUpKUlKSlJSkpSUpKUlKSlJSkpSUpKUlKSlJSkp+le p3d6ndOn4OZqQrt349EOqp0QT9PVfzGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGC9X RVh9/wAjo8nRfnmakK7d+H+LqdVEefTqonYYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBg wYMGDBeqd/uKip2+/wAszUhXbsqOutURVT9SidhgwYMlZ/XsGDBgvYVFQVOnb6fHM1IV27J0QR95 O6idhOwyaWC9hU6d/oK6v0+GZqQrt2RFVOyCdhBJrUU/cRO6N+GZqQrt06CL07qIJNiijydGjzsu ZqQrt0dd/MRBBJsUUU/y+8uZqQrt06/YQQSbFFFOv2WXM1IV26KIJNyij0uZqQrt0e8iCTcoo/Lm akK7dHvIggk2KKKPy5mpCu3R7yIJNyij8uZqQrt0e8iCTcoo/LmakK7dHvIgk3KKPy5mpCu3R7yI JNyij8uZqQrt0e8iCTaooo/LmakK7dHvIgk3KKPy5mpCu3R7yIJNyij8uZqQrt0e8iCCTaoo/Lma kK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu3R7y IIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCCTaoo /LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu 3R7yIIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCC Taoo/LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCTcoo/LmakK7dHvIgk2qKKPy5m pCu3R7yIJNyij8uZqQrt0e8iCTcoo/LmakK7dHvIgk3KKPy5mpCu3R7yIJNyij8uZqQrt0e8iCCT aoo/LmakK7dHvIgk3KKPy5mpCu3R4QSblFHpczUhXboqfcQQSbVFFT7y5mpCu3RPzEEEmxRRRHZc zUhXbojyfRR1RBJsUUUX7JLmakK7dk/bVfAgk2KKL37qwVV+suZqQrt2RHk+giook2L3F7i9GJ8M zUhXbsqItFRFRRO40aNmVo0aL3FhuL5+OZqQrt34I69REVFGjRo0aNGjf6po0aNGjRo0XuK5DXv9 zqrV+OZqQrt349UXt9hEVeijRo0aNGjRo0aNGjRo0aNGjRo0aNGjRo0aNGjRo0aNGjRo0Xq9/YVH V6OnVflmakK7d+XVOw3qh0e7FM7PJ7KQ0aNGjRo0aNGjRo0aNGjRo0aNGjRo0aNGjRpSKaH6V6nR 3sh1eXr+BmakK7d/C7KqFJfZTX2U19lNfZTX2U19lN72U3vZTe9lN72U3vZTe9lN72U3vZTe9lN7 2U3vZTe9lN72U3vZTe9lN72U3vZTe9lN72U19lNfZTX2U19lNfZSX2d3l/Ej/wAj/wCf+7/jD6/y f5/7tBOnX+L/AMfr+5tPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPK m08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptP Km08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKn/jan//Z\"\n   transform=\"matrix(0.24 0 0 0.24 174.5615 142.499)\"\n   id=\"image25\"></image></g></mask><g\n   opacity=\"0.09\"\n   mask=\"url(#SVGID_1_)\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   id=\"g27\"><path\n   fill=\"#1D2915\"\n   a:adobe-blending-mode=\"normal\"\n   a:adobe-opacity-share=\"0\"\n   d=\"M195.361,251.626    c-8.161,0-14.8-6.64-14.8-14.8v-73.527c0-8.161,6.639-14.8,14.8-14.8h59.663c8.161,0,14.8,6.639,14.8,14.8v73.527    c0,8.16-6.639,14.8-14.8,14.8H195.361z\"\n   id=\"path29\" /><path\n   fill=\"#1D2915\"\n   a:adobe-blending-mode=\"normal\"\n   a:adobe-opacity-share=\"0\"\n   d=\"M255.024,152.499    c5.964,0,10.8,4.835,10.8,10.8v73.527c0,5.965-4.835,10.8-10.8,10.8h-59.663c-5.964,0-10.8-4.835-10.8-10.8v-73.527    c0-5.964,4.835-10.8,10.8-10.8H255.024 M255.024,144.499h-59.663c-10.366,0-18.8,8.434-18.8,18.8v73.527    c0,10.366,8.434,18.8,18.8,18.8h59.663c10.366,0,18.8-8.434,18.8-18.8v-73.527C273.824,152.933,265.391,144.499,255.024,144.499    L255.024,144.499z\"\n   id=\"path31\" /></g></g><g\n   id=\"g33\"><g\n   id=\"g35\"><linearGradient\n   id=\"SVGID_2_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"225.1929\"\n   y1=\"152.499\"\n   x2=\"225.1929\"\n   y2=\"247.6265\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#C1D72F\"\n   id=\"stop38\" /><stop\n   offset=\"0.1394\"\n   style=\"stop-color:#BCD631\"\n   id=\"stop40\" /><stop\n   offset=\"0.5859\"\n   style=\"stop-color:#AFD136\"\n   id=\"stop42\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#ABD037\"\n   id=\"stop44\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#C1D72F\" /><a:midPointStop\n   offset=\"0.3086\"\n   style=\"stop-color:#C1D72F\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#ABD037\" /></linearGradient><path\n   d=\"M184.562,236.826c0,5.965,4.835,10.8,10.8,10.8h59.663c5.964,0,10.8-4.835,10.8-10.8v-73.527    c0-5.964-4.835-10.8-10.8-10.8h-59.663c-5.964,0-10.8,4.835-10.8,10.8V236.826z\"\n   id=\"path46\"\n   fill=\"url(#SVGID_2_)\" /></g><defs\n   id=\"defs48\"><filter\n   id=\"Adobe_OpacityMaskFilter_1_\"\n   filterUnits=\"userSpaceOnUse\"\n   x=\"184.562\"\n   y=\"152.499\"\n   width=\"81.263\"\n   height=\"95.127\"><feColorMatrix\n   type=\"matrix\"\n   values=\"-1 0 0 0 1  0 -1 0 0 1  0 0 -1 0 1  0 0 0 1 0\"\n   color-interpolation-filters=\"sRGB\"\n   result=\"source\"\n   id=\"feColorMatrix51\" /></filter></defs><mask\n   maskUnits=\"userSpaceOnUse\"\n   x=\"184.562\"\n   y=\"152.499\"\n   width=\"81.263\"\n   height=\"95.127\"\n   id=\"SVGID_3_\"><g\n   filter=\"url(#Adobe_OpacityMaskFilter_1_)\"\n   id=\"g54\"><image\n   overflow=\"visible\"\n   width=\"356\"\n   height=\"414\"\n   xlink:href=\"data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEBLAEsAAD/7AARRHVja3kAAQAEAAAAHgAA/+4AIUFkb2JlAGTAAAAAAQMA EAMCAwYAAAXBAAALIQAAEOP/2wCEABALCwsMCxAMDBAXDw0PFxsUEBAUGx8XFxcXFx8eFxoaGhoX Hh4jJSclIx4vLzMzLy9AQEBAQEBAQEBAQEBAQEABEQ8PERMRFRISFRQRFBEUGhQWFhQaJhoaHBoa JjAjHh4eHiMwKy4nJycuKzU1MDA1NUBAP0BAQEBAQEBAQEBAQP/CABEIAaEBawMBIgACEQEDEQH/ xACYAAEAAgMBAQAAAAAAAAAAAAAABAcBBQYDAgEBAAAAAAAAAAAAAAAAAAAAABAAAAMIAwEAAgMB AAAAAAAAAAIGATIDBBQFFjZQMwcRECKQMRMSEQABAgQEBgEBBwQDAQAAAAAAAQIxcgMEEFCRsyGC M6PTNBFBIGFxEiIyE1GB0UKhscFiEgEAAAAAAAAAAAAAAAAAAACQ/9oADAMBAAIRAxEAAADy0npz Z0Dnx0DS7Q9kr0IKcIKeICeICeICeICeICeICeICeICeICeICeICeICfggp2CElQD1aXxOgc+O1s um7kKj5vpObG6d2Q9zspRA9JmSGmCHmWIiWIiWIiWIiWIiWIiWIiWIiWIiWIiWIiWIaYIeJo1sPe 4OK5C2tCVS3OmN5clN3IVHod9EOv6zWb0zkAAAAAAAAAAAAAAAAAMRJnwcVXltVuetyU3chUfp5+ 5YexhTgAAAAAAAAAAAAAAAAABjODUVxZNbnjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwaut rJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAA AAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjy Cx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1t ZNbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAA AAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQ WPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautr JrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAAA AAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyC x5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZ NbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAA AAAAAAABjODV1tZNbHjclN3IVH7+HqWTO1uxMgAAAAAAAAAAAAAAAAAYzg1Vb2NXB5XJTdyFRx5G jLc3XG9SS2MgAAAAAAAAAAAAAAAAD4+ohqq47GvTa3JTdyFR830nNm/7qp+gLVk8fuDcZgehLRBL RBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBKQohP0MbkT40OcG8uSm7kKj5vpObAJm45sd n98SO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3xxI7PX84JcQAN5 clN3IAAAAAAAAAAAAAAAAAAAAAAAf//aAAgBAgABBQD+G3//2gAIAQMAAQUA/ht//9oACAEBAAEF AFgq7/bL9narGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxn arGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qx narGdqsZ2qxnarCYVyhn78PQNo/MCUmJhssm48QEScNrGJGEMQgjEIIxCCMQgjEIIxCCMQgjEIIx CCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIQakYQOlI bGTCajw2R5SPLm/KK2gegbR+LVYzzDZGzFKyBaysYS3FYGSBBQkFCQUJBQkFCQUJBQkFCQUJBQkF CQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQNkCA9uK0R7WVrJ+ykMy6WI8BrW NY0IraB6BtAsdqbMHtttYxkvKFKxhCs4JpCtExKFMy5W5jWX22NgRAitoHoG0SsBsePZZFhSSkuw peFm5dhi3qRKYk1BbAjoraB6BtCcl/8ASYtUBjCkL8Lwp2fS3WCxpVDA/wA5lFbQPQNoShGNLbif CcM3+roX9VQz4ZFbQPQNoSLP0t7P04e5uql5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW 0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5F bQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnk VtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqe RW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp 5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6q nkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubq qeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5u qp5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m 6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5FbQPQNoSLlvb+nD3N1UvIraB6BtCTN8Jbj /ScM3+rob9VQ36ZFbQPQNoTUx/xGtcdjSlb9ZwsRvwt1jMYVRR/+5hFbQPQNokZinmbPOsaWVjsM XhZuOwpbxOsYWcjtjzCK2gegbQLDdv8ANtuuDGsgTJTMYZjeCaZjBHmSlZcbgxjL9dGxDBFbQPQN oDGtK2z31pBJXYrWQLmVrCz5Whk8QVpBWkFaQVpBWkFaQVpBWkFaQVpBWkFaQVpBWkFaQVpBWkFa QVpBWkFaQVpBWkFaQVpBWkFaQVpBWkDZ4gNPkYI9zKxk7dysZdr80zTGaZoRW0D0DaPzK3Oalmyy oYwEVEv8yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGV S4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXB1RL/JlUMMyauU1Mt/KK2gegbRxaK2jj/wD/ 2gAIAQICBj8AG3//2gAIAQMCBj8AG3//2gAIAQEBBj8Ar2djdfxW7G01az+Ok74VzEcvF7FWJ73Z o+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+ M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M9 7s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s 0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+Ms7O7u/5Leq5yVGfx0m/KIxzotYixTC5kpbbfsfFJir 9/0EWo74+5qHH8y/3IO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1U g7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1U4fmT+5803fP3Kn+D4qsVP v+n2LCd22/C5kpbbcUqVkX4+jf8AIiI34QTgQIECBAgQIECBAgQIECBAgQIECBAgQIECBAgQIEBe AqK1FRfuFqUE/SkWf4PhY4WE7tt+FzJS224JWqJw+f0ov/YnATgcMi4i8BeAtdifpX9yf+4WE7tt +FzJS22jKSfVeP4DUROCCcMmXgORU4KPpL/qvD8CwndtvwuZKW20dUVIcEE4Hxkyi8BHon7uC/2L Cd22/C5kpbbT5/8AoTKFG/iWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttp zKJlCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+Fz JS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzKJlCjZiwndtvwuZKW205lEyhRsxYTu 234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFG zFhO7bfhcyUttpzKJlCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZ RMoUbMWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzKJlCjZiwndtvwuZK W205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+FzJS22nMomUKNmLCd22 /C5kpbbTmUTKFGzFhO7bfhcyUttpzKJlCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2Y sJ3bb8LmSlttOZRMoUbMWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzKJ lCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+FzJS2 2nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzCZQo38SwndtvwuZKW20dTVfvQQ+cmUXiI xFhxUsJ3bb8LmSlttGVPp8/C/go1fkTjky8RyqsB9T6KvD8CwndtvwuZKW23BKNR3wqftX+qCcRO JwyLiLxF4i0Ka8V/cuFhO7bfhcyUttuCKi/CpBRtOs74cnBF/qJ+oiRIkSJEiRIkSJEiRIkSJEiR IkSJEiRIkSJEiRIkReIv6hadFfl31d9EFc5flViuFhO7bfhcyUttv2ERrvzNT/VT4qIrf+TqIdVD qodVDqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTq pqdVNTqpqdVNTqpqdVDqodVDqC/xorl0F/O74av+qfYsJ3bb8LmSlttyywndtvzD/9k=\"\n   transform=\"matrix(0.24 0 0 0.24 182.5615 150.499)\"\n   id=\"image56\"></image></g></mask><g\n   opacity=\"0.35\"\n   mask=\"url(#SVGID_3_)\"\n   a:adobe-opacity-share=\"1\"\n   id=\"g58\"><path\n   a:adobe-opacity-share=\"0\"\n   d=\"M184.562,236.826c0,5.965,4.835,10.8,10.8,10.8h59.663    c5.964,0,10.8-4.835,10.8-10.8v-73.527c0-5.964-4.835-10.8-10.8-10.8h-59.663c-5.964,0-10.8,4.835-10.8,10.8V236.826z\"\n   id=\"path60\"\n   fill=\"#1D2915\" /></g></g><linearGradient\n   id=\"SVGID_4_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"226.1924\"\n   y1=\"159.7139\"\n   x2=\"226.1924\"\n   y2=\"200\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop63\" /><stop\n   offset=\"0.3788\"\n   style=\"stop-color:#F8FBF3\"\n   id=\"stop65\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop67\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.4383\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></linearGradient><polygon\n   fill=\"url(#SVGID_4_)\"\n   points=\"221.189,159.714 214.142,180.951 224.048,180.951 214.142,200 238.243,173.61   227.655,173.61 236.978,159.714 \"\n   id=\"polygon69\" /><g\n   id=\"g71\"><g\n   id=\"g73\"><g\n   id=\"g75\"><image\n   overflow=\"visible\"\n   opacity=\"0.75\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   width=\"392\"\n   height=\"242\"\n   xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYwAAAD2CAYAAADF97BZAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAHohJREFUeNrsnYlu40gSBZMU5Z75 /4+dbUsiFwtY2JrqvIqHSEoRACFZPtqk3BV8WVcvAAAACXouAQAAIAwAAEAYAADwWgYuwSp0XAKA wzJxCRAGIgCANf8fIxaE8RIxIBaA8yeMDokgjLkNfLfyzwOAfWTRNX49EkEY5h9N6+sIAuC8/++n mXKZjJ/5UfIYPuyPRXut9WOEAXDuxOGJYEqKZPpEebyjMOYKoTO+BmEAfIYwSjG0JJFaHm8rjncS RkYE2uutwkAgAO8liezzTPqY3jl1vIMwooa+fi0SRvQzshIBgHMKYwpez5Su3jJ1nFUYLWWlznne KpHW5AEAx5fF5Aijfi0jDy91nFocZxRGJgnUMvDkkf3arDiQCMD+YshIwxKE93xy5CGJ1HFqcZxJ GEsE4b0WHa3JA2EAHEcYU8PjlJREdESp47TiOIMwIlG0yqEPPl4iDmQBcCxpZMtOmWNs+Fy2n6M7 kzSOLIy5oogk0SsfZwWCNADeSxhZMYzGYy2I8uslIY5TpY2jCiMzsikjCO2xDz4fiaNFGggDYD9h LJGF9uh9rq8+7hxxWLI4vDiOJozsKCdPFJoc5ry2JG0gDYDzJouxOrTXLJHUsuiKz4uROurS1GHL VEcShpcqNGFoZSZLBBfla6zXO0MeGXGQMgCOkyyyopgCMfzveDifs44yRdQlLKtEdei0cRRhaLKI UkXZoFtCeH7uUn3dJfF9UV8HwgA4tzDG6nktjYfy/OF8zhJLZ0hjEns01SHTxt7C8EpQmdKTlhQu lSguxmu1TLSfNac8hTQAji+MMZEsahHUx6g8743v1aQxOudzSGnsKYyoBOUlCk0StQQGRRrW4aUO bWRVpj8DYQDsI4xaFJEwPFk8FGHcDYGUR1/Jon7uzf84bIlqL2FkS1BWP8XFSRKDIozBEclgiMPq CJ8rDSQCsI0cWmWRTRaWDO7BYy2OXhFH2SE+BudymLSxhzAsWbSkCk8S3vNBkUdGGJE06pTUIgTE AbCOKLRylCYNqxyVTRV347gYX9sr4nhUotDKVPXw292l8WphtMrCSxWeEOrjqghDE0hUlrKkYaUL ZACwj1S8lBGli1oYWpL433Eznl8qWdxFL2trfRsiev/GIaTxSmFkJ99po5+0RBHJoXy8Bt+j9WmU /743qU/E7vxGGgD7JBBrCRCvs9sqRd2NZHErRDEY4iiTxV1p72ppiPx/IqDVr7GbNF4ljBZZaKnC E0UtBu3jq5E0PGFcgpJUH8gCcQDsJworXWQTRiSMWyWM5/Oheu3ZltzFLmk/lPbhkCOoXiEMreHM 9FVYsrhWz8vjS3lNE8dglKiyHd9ewqAsBbB/KcoThjbvwhpCG6WL8vgu2pRb0XbdnGpFKY26vbCG 3u4mja2Fkemz8EpQZWOulZq+gkdNIlFZaq4wBGkAHFYWIm2d3lG6uFeiKNPFt9Ku3ESfEOyJY3TS xi7S2FIYc2ThpQpLFF/Bx6U4auFckiWpFlkgCoBjiCPb8T01Jow6WVx/JHEtZPEt+oCaaD6XRUYa b1OSapXFEJSdsodVporKUZlRUpEsEAbAcaWhpYx6WK02lPamSKOWxVBIo1UY3QJpbC6PrYTROhLK SxW1LH5VUvhlvG5JQ0sXWv/FReYNp0UaAPvKYq4wxoQwvIQRlbojYayRNDaVxhbCaFmKXJNFPcrp q5LFL0UUGWlE6UJ7Y7MT9hAGwDmFEaUMb/5F3X/hjb70hulnZVFL4/Sd3l2iLNUHsrBKUL+M48v4 2EoX0ZvqlaIEYQCcWhalNKwNkrz5GPeftuRWtCk30ed8aUsYzU0WdZoo25ZaHJsJZMuSVMs8i6iv opbEX4FAnt+jdXZnZaEtby6IAuBtUsac/oxaGoPy6A2mWZoupiJldK8uTa0pjLmlKK2DOxLFX8br WllKG5Lbsn4UO+0BII1B/uzLqG9Av+XPKQHZNsU7H22IcF2e0qRx2ISRkYU1g3sISlB/KY9/OUlD 67vIyOKSKEO1JAzEAbCfKFqF4c0CL1PGUKSNm9hr1LXchHYJWYjoy4RYZSnZQhxbz8OIRDEYwvhl SOIvQxh/KenC6+hu7eSOpIEwAM4hjCXSuBRp47lW1F1p16wtoFvShSYLa++MUV7Un7GGMFpKUV66 qPssaln8bUijFoY1u9vbOGnp8NkucX0A4LWyEGmbCT6KvnzIWMjiUcgjsyGbdQOa+V0nyW/p2r2i NLVmSWqJLLR0Ycnib6ck5U3S85JFy8KCSzq5kQfA9pJokUX52AdJo6/EkVmwdM6ci2nG0TmyWE0c S4URDaPN9ltkZPG3U5bS5l1kFhecu2w55SeAfcl0FncJgXh9G30hivqxXIE2Gl3ZO6KIymPZo0xI m/VjrFWSmjsqanBkYfVd/K2kC6uj25JFZ7yxraJAEADHF8pUvTYFjbZUd+5T0UY8hfEQfapAZnRl lCpG0eeHaB/XKcOS5CriGFZ6Qyx5aPMuhiBZ/FJkoaUMTRblMNpoFvfS3fOQBcB55DEp/3e9DuJa GE9ZWO1bpvRkNeZWp7u1Z0emNDUp579YGsOCNyBKF9HIqEFp7K1U4Q2lteZcWOu4tM6xoAQF8H7S EKN0Uz9qd/B90Xh3ku+r6IxUMTpHuWWsdvRGacrr09g9YWTnW7RM0rPKU9oyIN7CgpYs1twxD3EA HJcp+f9UuxPvFGnMFUUXpANLGJ5Qyu+t/+1Ddnp3iXKUNu/iy0gYvyQ/Qa8cGaUt+5FJFiJtI5+Q A8D50kVGIpNy0zgtkIYY/0b5PLOnuHZcqpTRK0nIK0+9TBjZLVfnzOrOJI0vQxbafAuvzyJbfmK4 LMB7JAzv/+zU8H+9lEZL2zApopgMcURHVJrqRO+72a0Pw0oX0YZIVsKIylDWkuVav0UpK2upj7mi QA4A504YnkCmoLpQfm/r3hbWarmRHJ5rV3kpwytNaalqljiGhRc+U4qKNkb6ctJFnSa0uRaaLC7J ZEEZCgCBRCOoLHFMxd19JuVEndyeMLIpo98yZcwtSWWXL5/bf/El9kioL7H3tYhmW1rpYm4pCgDe RyCt4pCigRaxZ297w2fHIFWU6aJ8HOTf61uVbd5mKWOYcVFb08Wc/bm1RQTrVFH3WViy6INUgSgA oEUcWn9HL7kFEOtS1BiIojy+5P97cdSlqUfVDnspYzZLh9Vq+3Rn5mBcE6KwtlgtReEli16YiAcA 64vDayt65XszQ2ejhFFu3FTuxfFQksYo+kitXfowOrFHSnmlqGgLVi9daEt9ZCbmibAzHgBsK46u kIFUlY3pp416CmNIlqNulShuRVtYbuB0r26aR6MsNYm/d8aqwpi7DEhm74urU36K9rTQ1p23Fg9E FgCwpjjqmeFdlTK8ctS1eNT2DP+qZPFVSOMm+grcUV/G4s7v1j6MOcuYe3MwNGl8KV8b7cFd/w4i /pR8RAEAc8QRSUOqlPH8+jpljEVJqZbGl5Iq6qPc7e9eScPry5AlKWONeRjeUNpLUI7SEsUg9sxt bwZ3L/RVAMBr04bXCT5Wpam6XF+WpK7y7z6Ka5EqynQxiL2DaC/xaKnNJ+5Fayi1jpQagtKTNXN7 SKSLaClhZAEAa6cNSxrlXX5fpYyxaNdqadyVdnBuyli187ufeaG0foJMyhgMMdSlp0wZykoXIu3b qAIAzE0b2nNtBGl2YdbBaRsHJ2W0rMg9q23sGy5My2S9PnExhsTFyG6BmHkDAQBeLRFNGpeqNOXt RJppG7Wb6i6Qxiz6hpP3RNIHCSNj0swF6WaUopAFALwyZWRvri1xXIL2sWVqQbR67qrCaEkaLUNr 6wtxCWRh7ZVryQFJAMAe0ojazWe7dWlsI6/JhKG1l6KUoma1lf3Ci2RdiGyyuIg+CspbRLA3TD7n jQQA2EIe0Y21Nw1hUB6z0sgkDC8dLRZGNlVkR0hZpSdLFpfkBVhkTgCADVJGZoM5qyLjyaN1o7hV +jH6mTHL2gcjugjWBfHKUN1WJw8AsFG6iGSRLeNn2spoFOlqbWXfeDG6IHK1ysI76cyOeaQLADhr maqfIY2L5Pt5rQ7vzYfVZspUfXC0CsLq5LbGEgMAnC1laP0Z1giqls7ubBl/k07vaOiYtp6TdjKa JKJJJ9n5FqQLADhj2vCG20Y33NlSVNfwu62SMLqkNb2E0SviyMzgXrUOBwDw4pThrY6R6QPOVmo2 7fvNTNzrgs9F9bhIHH3ihC07C+kCAE4mE00ctUCiakymhN+vfZPdz4gm2fHFXSALK0V409pFWPID AM6XNrwUklnANSpZzRlS29x+zllLqiVpZBKHNwoqE6OQBgAcXRTeIoCd0x564siW8K2RUs0MMy9E 9tBOwNv4KFtjQxwA8C5C8drOLlmlya4h5a21Fy513q948llbdo48okglQn8FAJxLCt68Ma1Bt9pD 7fW1O7q7LYQRxausLaPaGivPAsC7yyTbZnZiTznIyENk4UipfuZJtp68VXLyxJGZoEfaAIAzSaJl TtuaCWOVdrJ18UHrJCNZRFErU3ZCCgDwjglDa+u6GQkjszjr5sLIJI2oA8dLGtKYMBAHAJxVDJ4s Mmv1ZWURlaNeKgxJnmBmT9kueZFFKEEBwGdJJjui9CU7j/YrnJTX6Gcn3m1SbwMAOEnyyDT4SxNF tGrtLGF4nc3euN7MbMKsGDIlKMQCAO8kjeyNdIs0Vm0vt+jDiGQS2TVbtgIAOKMkoopMa5uaEc4q 9C+8EF4UmyMpAIB3Tx4tfcGb32T3G52sVzN7iQkBAA4ogJYbbetjbxe9zFp8s8v8/Y4XCQAAkeiN uwSJQiQ3qbn1Jn/zhNHNuDCR5RAKAHyKLDKfjxJG9t/YpdNbpH1/7ZY4BgDw6TKJSvWtW0Espt/g ROes/eQtxYtQAAAOsJFc/6KTmxPJAADAF8RL29F+5xMHAEAGfz5fvHfFFu1tf8ILCgDwbrLIrAi+ xs/+CGEAACCX/FpTm9x4IwwAgPMkka2+/jDCoJwEAPAGbSoJAwDgwxr+owuDlAEAcHJIGAAAgDAA AD6At5jpDQAAJAwAAPikdIEwAAAAYQAAAMIAAACEAQAACAMAABAGAAAgDAAAAIQBAAAIAwAAEAYA ACAMAABAGAAAgDAAAABhAAAAIAwAAEAYAACAMAAAAGEAAADCAAAAhAEAAAgDAAAAYQAAAMIAAACE AQAACAMAABAGAAAgDAAAQBgAAAAIAwAAEAYAACAMAABAGAAAgDAAAABhAAAAwgAAAEAYAACAMAAA AGEAAADCAAAAhAEAAAgDAAAQBgAAAMIAAACEAQDwMUwIAwAASBgAAHDOlIEwAADgUMKYuNQAAOdu F0kYAABwGGGQLgAA1mtHd2tTSRgAAOeThvX58vhYYZBSAOBTJDAl0sXU0EauJhESBgDA/tKoG/U1 GvnVk0a/08UhNQAArJtENqff4KQydbTpyBcFAODA0titA7xf+MtPM09YuwDT1nEKAOCEaSLqw5he 1Wb2K51c5hedErYkUQDAJ0ohalen4KZ9esXN9h4zvefIBQDgE6QxSVyJmSRXllq9xN9vdBEiM2ai FwDAp0hjMm6sWxKGN9oqandTbW+/0clnkkXr8DFkAgBnl8KcG+dJ/AFFU9DGZqUQ3uT3G1yUKGJ5 1pyEkVIA8BkCySSOKHVMiTZ2tfazn3liU/IEopPPXBhkAQDvKIu5N9JTcGx2o903xpLopDIXyJNB JIgp+XsCAJxBHNkb6czN+ZT8Ppl7Q96vcNItJxHZUoKTRBAA8K4CiYbIPp+PDW1t5qb+ZcKQwIxZ C3oJA2kAwLumi0w7OiqSGKWtI3yV9rNPntyc2KQdkRk9cQAAvIscJidZWG3mqHy89IZ804SR6Zix RDFWJzlK23Axz4zIBQDOJBCRuDQ/OqLItKOrDx5asw/DkoRmxFH5mlH8OhzDbQHg3WQRtZuZhDE6 clky9201YURlqDFIGGODGT0rAwCcVRxRKX9MtJ8tJarF7WffcIJZY3mmtKJVFK+s+AYAcBYxRJ+L Sk5jcMzp12iq2myVMFpO0CpXtdoRgQDAGSQSdW5bCePRII1R8h3tL1lLaq4kyhN/SNwhHtkaUQDA UdOFVRXxkoUmh0fQfmZK/SILy/t94mS9dUsiI3on6J209jNF4o5w5AEAZxFHNM/iURxLZbFKGT+7 ltSUSBjRCKjoRB/BBaQjHADOKAmvKqP1UTyM9jFqQz2BaL/D6sJoPenROdHoKC+EVdfLCAJ5AMCR xJGpzHg32I9EW9pSltosYXiiECNWRXW4R0PUmrOoFgDAEdOFJpEoSTyPe/U4VxpzfvdFCSNKGi1W fF6Au7T1a7SsagsAsHe6EMmVo7yb63tSFF5ZalHq6Gc2utnRUZEkshdgSpw8ogCAI6YLWUEUd+fj pQkj3W6uMXEvEkdWEnfR63abxSsAgBeki7k32Hfj0BJH3W5uMlqqbzh5TyCtUSpzEVpKU6QMADhi uvCE8VBuqj1R3IMb72iY7WLmrlabnXuRsWXGng/xZ4KTMgDgiOlCGiowLdKIOr6jzetm7ZGx1bDa TN/F87glLkhLR44IczQAYL90kZnYbI2EqtvEW4M8Mqt/L2of+4YLEfVfaOb0TvJWXIybcWE8e86Z owEAsJUsrOkGmVLUXZFG1D5mb7BXm4vRz7worQkjEsVNsanVqROtzLjYogAAM2URdXA/GtrIW0Ic L524Nyy4UJm+jEdwEerj+vM4/DxeiuN/P6P7kdz487z7ed4rF6P7ea0rfueOv3EA2KAMJZLbEygr iqjNbE0X2u/YfEM9JC9MV/3gLlGWsmpz1vH98/uUx70QRl8cXXFIJY5IGoI4AGBFWbR0cFtTDeo2 8ltpH7W+jUyHt7fH92YJY3JEkZFFfVG+fxLFd5EsbkXCGKqEEQmjThmlLOp0QdoAgLVkUYujbrSt AUC3QBLWa9mEYW0V8fKSVH1xygbbGjJWlppuijQG5Yhk0SmJoa+k4EmDtAEAS0RRPnorz1ojoer2 sD40aUQDgzJbts5KGUPDxeoco0bjiy9KuhgUWVyLz1+MhOEJoyt+v1H5Gk0SpA0AyIoiksUYVFse jizqR00ac6YeTMnzWj1haHfpVsdOb0SwoUgadbK4FsmiTBnZhNFVKUNDEwdpAwCyohCZtyzSwyhD 1cdvI2lEKcOTxSpTEJb0YZSNb1mailLGUxpRGWqoRKHJonMa+k7aO8ERBwCiiEShVVesEaLlTbM1 2Oe3IwpLGLdkyvDKaZsnDE0cXSGLTMrISKNMFhdHFpYwpkIWnZM4InEgDwBEYcnCWnVWW+LDE0Ut jUgcmc7uVdeQWiIMcS5iJmXcqpLTt/w5IqpFFlGjXs/b6BrEQeoAQBTRpLxphiwsUXji8EpSWv+F yEqd3XOFMTl34V7KuFelpUtwaGWovlEW5UXqg5SRKU1NhmQA4NyCyIpCjGShDZ3V5lV8B3L4bXzu OyhFeSOkWs5/s4RhDVEt7+QfRUNfSqNMGV6qqKXRBymjlsTFKFPV3zsVH7eUpqagzAUAxxRDNmFk k8XDSBfaCKhaCv/5OTxpRB3eXt/FquvtrdGHUd+p18t2PIqGXytNXZTk4U3Sy7zxtTiespjEHmk1 JctVmWQDAOcSibXQamYDJGvobCmL34njP+L3YWRLUasOpS25zPy+srPZKhFpX+Md3pDZqA+j5Y9k 6UXrFn4eAPZPGNnyU3borCaLm1KG+k+VLLzDG17rSWOTdLFEGCJ+B7IllEgCEryWbaCjWZlrxVlE AXA+cSyRxST6sFlNFjdHFnU5yhPGb0cW1gipTSofwwpvRl3S0dZ+19JEn0waljCiIW7Px6EqS12K z2n9IyL+pEBGTQGcUxaZ5T2iDm5v8yNtUp7VZ/FPQ7Lw9gpqWdJ8t+XNPVlIUhqZklSXSBGj2JNn roU0xh9ZjIU4ns9HRxzWo9dBjlAAjlOGmgJJiCzbz8KSxbfofRSRLH47Zaho7oXIhpvKrTUPo1N+ wbFoOLPSyAgjMw66vJClLMpjlD9HYdXikMSjJocu+SYhFYBlMmhJFa2y0EZCZWRxE33IbC2Hf6rH WhatI6M230RurZKUNcy2FkerNLw33lvw6/mmXos3tlyj6iH6aKw+WRaLZIEgAPYTSKs0rEUEvdFQ 1uZH2qQ8r5/iH4k7uVtGRmlltdVYM2FYb9RYNbgZaXiNq/amWtseatJ4iD9JcKk0WjrnAWB7aXhr QXk3oJP4o6G0mdzakh9WZ/c/Ys/DiFanrTdM8q7BoUpSUWmqbOSz0rB+flSGeiSkcRF7rw1vhrlI bhgx0gDYVxhT0GjWd+FjsmJxF31TuGg2dzSk9rdRjlpj7+7DJYxsaapMG1oDG02Es5ZR90RRvsHP pdOfW79mpZFdUh1hABxfGN5EvKws6r6Let8Kq/8imt3tLWWe2fNis1LUFgnDeyNHpeF8JGThJYxo 8kx5J3AtJHFVUoa1LIkmjH6mMJAFwPbCyHZyjzOqFlay0Pa1aJnR7Y2KinbV82SxujS2Kklpo4Qm RRwtPzsShZUqvooL/0wX9QZN1gq5njhE2kZSIQ2A7WQxNT5qZai6P3SU3G559RIgVsqwEoW1wGA0 jFacEtQpEoYnjXLOQ7bxzAyh9UYtfBXiuMq/d/UbnKShiWOuNJAFwHGkYQnj0ZAublU5yts5L1qy /DuQRVSCispzpyhJlfLwImGLLKw+DC8yluIYKnFo0uiN8hTSAHgfYYwSz+HKlqIyW61qaULbqzsq Q2X7LTaTx7DRm9gF4sjKQpKi8IRx/XkjalnUfRmeNCxhRP0ZCAPgGMLwZDGJP4imlsXdKEdF+3Pf xO+rqDu4DyWLLRNG1J8RScMaAjc69UUrXVyrhOGVpYbGlIEwAM6TLsZkwshULW4N0rgpj9oM7nr4 bKss3qIkNVcaIvl16LWRUc9SVJkwhiphWH0ZLSlj7dngANAuCi1R1M+z6WIUe85FnTK+FWnclBRR J4rspLwWWWwujuGFb3KLNDL9F1Z0/DJKUbUwWstSnjSQBcDxpRHJIprRHaWMmyEIL1FEqSLb0X36 Tu9SFFlpTOKvSZ8dVntVRKEJo+78tvYWvyQSBsIAOFZJKhKG1p6MTtXCGimlPY9E8RB9BvdDkdok L1qN9ggJo0Ua2T0vvIRxlT/7MKwSVDS8NprINzdlIA6AdUQRJYy6HOUtLGi1KZnSlCWSjChaS1C7 yGKPklQkDS1teEnjUr3JQ/H4nKh3q4RxUaRxCRJGZngtHd8Ax0oYmXJUZq+LaB0p77WHxP0UD4nX htqlz2IvYWSkMUnbHhhjII5aCjcjTXjlqOxcjEgaiAJge3FkN0NqmYORKU9ZcmhJFNYM7sPI4tXC mFue0t703hFH+ca2pIkoXWRkkU0ZHogFoK1BbNk9L+rH8OZ5ZYRgPc+Iwis/7S6LPYThSUOTxyh/ 7hNei6N+oy/y7z0v7skk4fVdZIWxRBaIAmC+OLKyyHZ+eyth3wOpRENkWzc/OoQs9hJGNmlMSmNc v+F9lTZ6+fduehdFHPXn+oQoMsIQsffKQAwA24ukRRqZlOF1hkevWf0To1IWkzPIYk9hlCffGc8l SBudkjaejXmdNHrjMRLEnHSBMAD2k4WIP2CmRRqePEbxl/Cw0kRUftp1nsWRhdFaotI6xbW00RWl qmfi0NJDS5pAGADnF4ZIbk0pSxjWx1lJjOL3URwyVRxNGFrasGRRp43668dKFmVD/0gKwtqiNdrn m/kXAPsJQyS3rPmkNN7185bDks00s/R0WFkcSRiiJAxLIJNxh1+nkzFICr3zemY01JzlzZEGwD7C kERpKtv4j4mUUm9L3ZImpqNe+OHAfwzRwoWROLoqcXTiL1MepYmlu+0hCoDXlaZapZFJHlMghslJ FJnf7dCyOKoworSREYcYAukqeWTkQKoAeO+kIQl5eK+PkptDccpUcRZhiPgjqTKd4p2TRGSGIJYI A2kAbC+LrDBE8qOpWo45SWI6y0UfTvbHEZWp6mSSafQzH4vkJ+chDIB9hRHdxWdGKUWL/0Wd2G8l irMJQ5OBKOnDk4bX6GdSw1qLCyINgNcKo0UakUhE5o1yOrUozioMcWTRkjqyKSGbJOjgBjiuSLyG u6V/YU5fxFuI4szC0N6MOaljmiGDTOkJUQAcM31MM59PC37GW4jiXYShiUMkP7JK+16SBMBnp45s w9/6McI48B9GlDrq2eNTQjgIA+D9hLH11yCME6cOCdJHy89AGADnFEbm89PCr0UYb5A6ZIFAsn8o SATguIJo+fppxX8HYZz8D6n75DcfAGE0ff3HtxEDf1ipdNDyh9LxhwVwOmkgB4Sx6h9Kxx8aAGJB GLDmHxb9FwCIAGEAf6gA8Ln0XAIAAEAYAACAMAAAAGEAAADCAACAs/JfAQYAL3iXmIlSiu4AAAAA SUVORK5CYII=\"\n   transform=\"matrix(0.24 0 0 0.24 179.2061 198.1514)\"\n   id=\"image77\"></image><g\n   id=\"g79\"><radialGradient\n   id=\"SVGID_5_\"\n   cx=\"225.1929\"\n   cy=\"226.1387\"\n   r=\"30.8299\"\n   gradientTransform=\"matrix(1 0 0 0.75 0 56.5347)\"\n   gradientUnits=\"userSpaceOnUse\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop82\" /><stop\n   offset=\"0.4828\"\n   style=\"stop-color:#FDFEFB\"\n   id=\"stop84\" /><stop\n   offset=\"0.7611\"\n   style=\"stop-color:#F8FBF3\"\n   id=\"stop86\" /><stop\n   offset=\"0.989\"\n   style=\"stop-color:#F2F8E8\"\n   id=\"stop88\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop90\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.8025\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></radialGradient><path\n   fill=\"url(#SVGID_5_)\"\n   d=\"M186.706,235.825c0,5.965,4.835,10.801,10.799,10.801h55.374c5.965,0,10.801-4.836,10.801-10.801      v-19.373c0-5.965-4.836-10.801-10.801-10.801h-55.374c-5.964,0-10.799,4.836-10.799,10.801V235.825z\"\n   id=\"path92\" /><path\n   fill=\"none\"\n   stroke=\"#EDF5E5\"\n   stroke-width=\"5\"\n   stroke-miterlimit=\"10\"\n   d=\"M186.706,235.825      c0,5.965,4.835,10.801,10.799,10.801h55.374c5.965,0,10.801-4.836,10.801-10.801v-19.373c0-5.965-4.836-10.801-10.801-10.801      h-55.374c-5.964,0-10.799,4.836-10.799,10.801V235.825z\"\n   id=\"path94\" /></g></g><path\n   opacity=\"0.74\"\n   fill=\"#FFFFFF\"\n   a:adobe-blending-mode=\"lighten\"\n   d=\"M263.623,229.595c0.037-0.364,0.057-0.734,0.057-1.107    v-13.375c0-5.965-4.836-10.799-10.801-10.799h-55.374c-5.964,0-10.799,4.834-10.799,10.799v7.324    c7.545-1.012,15.699-1.566,24.213-1.566C231.959,220.87,250.812,224.252,263.623,229.595z\"\n   id=\"path96\" /><linearGradient\n   id=\"SVGID_6_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"225.1929\"\n   y1=\"204.3135\"\n   x2=\"225.1929\"\n   y2=\"246.626\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF;stop-opacity:0\"\n   id=\"stop99\" /><stop\n   offset=\"0.0141\"\n   style=\"stop-color:#FDFDFC;stop-opacity:2.231669e-04\"\n   id=\"stop101\" /><stop\n   offset=\"0.1344\"\n   style=\"stop-color:#BEBEAF;stop-opacity:0.0148\"\n   id=\"stop103\" /><stop\n   offset=\"0.2565\"\n   style=\"stop-color:#94957C;stop-opacity:0.0297\"\n   id=\"stop105\" /><stop\n   offset=\"0.3796\"\n   style=\"stop-color:#747759;stop-opacity:0.0446\"\n   id=\"stop107\" /><stop\n   offset=\"0.5029\"\n   style=\"stop-color:#5D633F;stop-opacity:0.0596\"\n   id=\"stop109\" /><stop\n   offset=\"0.6263\"\n   style=\"stop-color:#4D552E;stop-opacity:0.0746\"\n   id=\"stop111\" /><stop\n   offset=\"0.75\"\n   style=\"stop-color:#414B23;stop-opacity:0.0896\"\n   id=\"stop113\" /><stop\n   offset=\"0.8742\"\n   style=\"stop-color:#3B461E;stop-opacity:0.1047\"\n   id=\"stop115\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#38441C;stop-opacity:0.12\"\n   id=\"stop117\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF;stop-opacity:0\" /><a:midPointStop\n   offset=\"0.2901\"\n   style=\"stop-color:#FFFFFF;stop-opacity:0\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#38441C;stop-opacity:0.12\" /></linearGradient><path\n   fill=\"url(#SVGID_6_)\"\n   a:adobe-blending-mode=\"darken\"\n   d=\"M263.68,221.954v13.871c0,5.965-4.836,10.801-10.801,10.801    h-55.374c-5.964,0-10.799-4.836-10.799-10.801v-13.871l0.038-7.704c0,0,0.923-9.937,11.173-9.937h54.962    c0,0,10.063,0.328,10.801,10.799V221.954z\"\n   id=\"path119\" /></g><g\n   id=\"g121\"><g\n   id=\"g123\"><image\n   overflow=\"visible\"\n   opacity=\"0.25\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   width=\"30\"\n   height=\"30\"\n   xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAuJJREFUeNrsl9trE0EUxjO7m5vW tKFN1RqLCmqlIvjgkz5I/cOFIqLggw9KsRHxUo1IdEtactG9+A1+A8dxNrsxK/rgwI9lt5ueb875 ZuZspfJ//Bhqjvc0AfCIHClIQEzSMkUoBqyCJbAKWrxXQoBmBL6AQzChmGQREWbmNQY/DS6Aa6AL mtZvdcDPoEcOQEgxUV5mVMYzH5wCZ8FFcJ0CLoN1UHeIGII34AV4BvbBW4qbzsqKctzruq+ALXAL 3ABXwAafNyjS9sQ3cAwG4BXYA0/AU/AejLOE+I4MtME22AH3wE2wyedNivSFQT3eB/y79kwHnGE2 v4IjinCaNrBEtJiBu2SLs686VkRWGRt8/wTL5jFwxIxMbSGB+Ac1qtcluEMBbWslFDV7QBFdlmBE bwxZtthVDn1dpgF3WIIOhakF9iCf2ajQK32W5hcRJgvnmYHb9ECzQAnyhif8o7PxkWImsiQeRSyJ fWCjJAGy5G2usKtgzc6wx5dWxT6wYhm2jKNBm/UcV90m/aLsdLVoonX+QJV8RvmcXNflNVOOKktQ Fz4p+6AMrBg/GUeeFWUHd51HyuXevz7+GRELNSRzjMwYnmhI5Laa/gEBYxEjskVE7Ih67AeOi3ZE BYc55j+xxzjgpBMpImZL1mNDMuDxm5aYBT2x1+wx+vZJ6lt94kl2Ux1uWl4JWZhy9g/AQ/DOPjt8 q0ULuLebhiRYYO8wPUTIdm+X1zDrKE/FKjH95TL3eP83MiIF7FHAY2ZkYpfadxhoRE80WJ66EKIK BE9YAiPgPkW8dPUSFUfDGnMpHVmKvQJCEoofcsamBLs0fOgSUMnomo2QQ66UAbMTi4+hmOk2mGZW B39OE+rgj5iBcNb3h5qxk9boDb1SLrEh2c75+NlnCfT1A4OP8nZiVeAT0IhZY0Ni+gHP8oEpQ59Z HHP2uRtfkeUnxTj7AWHqMU0ZiRVX2ld5kZ4jnSewHN8FGACSOOKkAlOGAAAAAABJRU5ErkJggg==\"\n   transform=\"matrix(0.24 0 0 0.24 199.0298 216.5547)\"\n   id=\"image125\"></image><g\n   id=\"g127\"><radialGradient\n   id=\"SVGID_7_\"\n   cx=\"202.6289\"\n   cy=\"219.7041\"\n   r=\"2.9995\"\n   gradientTransform=\"matrix(1 0 0 0.75 0 54.926)\"\n   gradientUnits=\"userSpaceOnUse\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop130\" /><stop\n   offset=\"0.4235\"\n   style=\"stop-color:#FAFCF6\"\n   id=\"stop132\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop134\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.6235\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></radialGradient><circle\n   fill=\"url(#SVGID_7_)\"\n   cx=\"202.629\"\n   cy=\"219.704\"\n   r=\"2.999\"\n   id=\"circle136\" /></g></g><g\n   id=\"g138\"><image\n   overflow=\"visible\"\n   opacity=\"0.25\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   width=\"30\"\n   height=\"30\"\n   xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAtFJREFUeNrsmP1LFEEYx292Ts3V 9ujFrCiwFyPShH4I+imoiPqbhYKIoKigN0W8SulNIrOU63S921u/A9+BYdm9mbndg4IGPiynuzOf eea52WeuVvvf/Joo8VwA6rxm+0lBD3R5TYctpu6XYBRE4DiYzMhpqRbYBDtgHyQ+gsIzQmMUOg3O gzkwzciZTUXqO1gCH8E3CsauERSOUiOgAc6AC2ABXAYXwZECsV/gPVgBb8AH8AVsg45NTjhKTYGr 4Aa4AmYZqYjLmpdj+4ySilwTLIOn4C34YZOTjlLXwH1wC8xzKSMureQym0g+O85ITxP1uU3hPS6r t5j63zFK3QM3uYwNQ0g45KUSPMSJNLjsLS71blHUZJ9Ox5lDSuo2k32SHYsBvslKcAIc5jJvUK7r I1ZntK6Du8yryBJhW9P73hi3jg2ym7ek0hKtO0z4E5xx2RYYOany7DPYyotaUPCwyoVL3KemKpLS TX+h5jhGI88jT0x9/U9yrzoHwoL7ykQtZN8LHGvURUxy05xhntWH8I7WOTzDsaSLmOAMQl6DIYgF mTGEi5iWEyWqD9dtpHCMoPaXtn9KrHSR59CsYxSJ6SKv1e9FW6L1MmM4iXWMIu8ri7u04mjF7HuJ Y3VcxLqciaqfVlnYJRWKJexzlWNs5r2SZMGMNOp1cRYc5atEVBCtPVazD8AzHzHdQUKZUyzywoIT kY9Uh9XrC4o1WTimPmI9ouv9iAXfIHKm1GtKvSyKlq2C1Una5sMTLBRHPN4MOvIxpV6BRfCEJU/s W8Ganf4xzoaCf5dGaS36JHnMKnWNUg/BY35uD1rza7ku5bY4658cMDHkEt6nUZP4TQG1dI/Ic/CJ /SVVHHglS2J94pnluXLecuB9x3Nlk5+3jUlV9hOBMAQjCpn1lMikgFrCdQrtGEKp62CDlCtaMLQc eNu+QmV/7XGp2cyN2rsdCDAAoyXZx8WJpTUAAAAASUVORK5CYII=\"\n   transform=\"matrix(0.24 0 0 0.24 213.9448 216.5547)\"\n   id=\"image140\"></image><g\n   id=\"g142\"><radialGradient\n   id=\"SVGID_8_\"\n   cx=\"217.5439\"\n   cy=\"219.7041\"\n   r=\"2.9995\"\n   gradientTransform=\"matrix(1 0 0 0.75 0 54.926)\"\n   gradientUnits=\"userSpaceOnUse\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop145\" /><stop\n   offset=\"0.4235\"\n   style=\"stop-color:#FAFCF6\"\n   id=\"stop147\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop149\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.6235\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></radialGradient><circle\n   fill=\"url(#SVGID_8_)\"\n   cx=\"217.544\"\n   cy=\"219.704\"\n   r=\"2.999\"\n   id=\"circle151\" /></g></g><g\n   id=\"g153\"><image\n   overflow=\"visible\"\n   opacity=\"0.25\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   width=\"30\"\n   height=\"30\"\n   xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAttJREFUeNrsmO9r00Acxptc1m6d Fn9M125sU4RVpyjiSwXB/9wXulciiE4dhpUMpwzFUa02XdP4HDwHR7hcLk0mCh58WOnI9548973k uTYa/0e54c15nQ8E8TJ1UpKQ2Z8QJgUtgDa4CC6AliZOiYrBCfgGfoLTsgK9OQStgE2wDa6DDv+v hhQwBAdgH0TgS1mBLsIEBV0F18BNcJvC1sCyQdgIHFHYG/AODMAxBSZVhQXgHJ15AO5T2Aa4TMHC 0GMJBXwFhxT2Erygkz/AtGhim1NS1A3wCDwGO+AKBS3QKS+nrlp6eQProKe5G4LvNucCS0+1uXQP wRNwj6JaFkH6SgitNxeJ0BwNueSzMsIC3ulduiX/roJmpp9cWkVQ1CrrqB17ws+TPGdM3y3Rftnk fTpVVlS2ZpN1+qy7znl8V2HSrUvcdbKnutryVRk+63RZd5vzBC7ClFvyMXALbHEDiJreNGpDbbH+ Wp5rJmEd7sQ+n13NCq8uU881WbfPeTquwtq0u1ezW1nXepyn7SJM9dgSCc4oPBTO4Rus9jKJwatZ lGeZy+rYXzH+GWEpXxEq5Kl8VecwBcnURVjMgCcZn5GwsTZH7CJMD3khL5zWLGzKuiHnGZpe5CZh I6bO9wx7v+bN7YYxY70j1o/yEoZpKSdMmntMoMq1tIYlVG7ts/4x50tddmXCEDfgxRETZ1JRWMI6 EesObGFRWCyfaa+oDl8jQd4DscApJUr21S54Dj7wu1JBUW2Ct1rybDDRntditUtPnWor8Aw8Zd2h rXdFQdGYd6WfbPTYnOeeEiSv/cTDyC5FvbL1luspSSXPFUYUmaHu8KS0yfjdMpySYp6QIop6TZdC njEnRTvdpVc8Lt0yBW4wS+04HHj3+Fg4pKARnUxdJnVNBL7hSNal4OxPBFLAZ/CRzumn8NR1wrKR xdfy1KLlwDvmw3RaRlDVX3s8h8dGWiUE/BZgAMf82R9IYLF+AAAAAElFTkSuQmCC\"\n   transform=\"matrix(0.24 0 0 0.24 228.8599 216.5547)\"\n   id=\"image155\"></image><g\n   id=\"g157\"><radialGradient\n   id=\"SVGID_9_\"\n   cx=\"232.459\"\n   cy=\"219.7041\"\n   r=\"2.9995\"\n   gradientTransform=\"matrix(1 0 0 0.75 0 54.926)\"\n   gradientUnits=\"userSpaceOnUse\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop160\" /><stop\n   offset=\"0.4235\"\n   style=\"stop-color:#FAFCF6\"\n   id=\"stop162\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop164\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.6235\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></radialGradient><circle\n   fill=\"url(#SVGID_9_)\"\n   cx=\"232.459\"\n   cy=\"219.704\"\n   r=\"2.999\"\n   id=\"circle166\" /></g></g><g\n   id=\"g168\"><image\n   overflow=\"visible\"\n   opacity=\"0.25\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   width=\"30\"\n   height=\"30\"\n   xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAt9JREFUeNrsl91rE0EUxTOzm69a 05YmVWsUFdRKRfDBJ32Q+ocLRUTBBx+UYiOitlqRaEos2UT3w3P1jIzrbHZNVuiDAz9CNru5Z+69 M3O2Uvk/fg414zOCDzSxRwJiEJGkTBGKAatgEayCFr8rS4AwAp/BIRhTTDyPCDPzGoOfAhfANdAF zdT/SMBPoEf2wYBiQldmVAEBHjgJzoCL4DoFXAZroO4QMQRvwAvwDOyCtxQ3SWdF5QiQui+DDXAL 3ABXwDqvNygy3RPfwBHog1dgBzwBT8E7ENhCvJwMrIBNsAXugZvgPK83KdKzGlTzu8/fpWc64DSz +RV8oYhfTetPEdFiBu6SDc6+6lgRWZNo8P4Flk0zcMiMSGkSP+MPalQvJbhDASuplVB0RfkU0WUJ RuyNIcsWucoh15bYgFssQYfC1Bz7kcdsVNgrByzNHyJMFs4xA7fZA80CJcgb2uofycYHihlrh4hF ax9YL0mAGT7LKivsKmjLpLXjplVrH1ie0ryzlkWa9SxXnWR5QTv6ocUmWuMDqlLu8Di5ruk1Vzmq LEGdD5QtQln7yI8YespZUXbwzBi6cgzGsRTx14ZkxvFbDJeI9Laa/AMBgRUjTIsI6Yh69ANH0xzR DMMc8x/pMcTwjNIiIlqyHg1Jn8dvUmIWZGKv6THk/Jh4GWqFE3RTHW5auoQsTDj7B+Ah2JOzI8vU RNxQ2pYh8efYO4yHGNDubfNzkHWUJ9YqMf5yiZ7AmyEjtoAdCnjMjIj5TbycBhqxJxosT90SogoE j1kCI+A+Rbw0XmKaxzQlCXjz2GpOXUBITPFDztiUYJsNPzAC8kQklpBDrpQ+sxNZL0MR020wZlaC P2cTSvBHzMAg/f6hCu6qNfaGrJRLNCSbOS8/uyyBfL5n8JFrJy7a7Solpk1DYrynTvWBKcMBsxhw 9nEZL8S2GNtzuJo6YFOG1oor7a28iOdI8gLb47sAAwCDFN6m03jgxgAAAABJRU5ErkJggg==\"\n   transform=\"matrix(0.24 0 0 0.24 243.7749 216.5547)\"\n   id=\"image170\"></image><g\n   id=\"g172\"><radialGradient\n   id=\"SVGID_10_\"\n   cx=\"247.374\"\n   cy=\"219.7041\"\n   r=\"2.9995\"\n   gradientTransform=\"matrix(1 0 0 0.75 0 54.926)\"\n   gradientUnits=\"userSpaceOnUse\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop175\" /><stop\n   offset=\"0.4235\"\n   style=\"stop-color:#FAFCF6\"\n   id=\"stop177\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop179\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.6235\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></radialGradient><circle\n   fill=\"url(#SVGID_10_)\"\n   cx=\"247.374\"\n   cy=\"219.704\"\n   r=\"2.999\"\n   id=\"circle181\" /></g></g><g\n   id=\"g183\"><image\n   overflow=\"visible\"\n   opacity=\"0.25\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   width=\"30\"\n   height=\"30\"\n   xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAn9JREFUeNrsl+lrE0EYxvdKjSZW YxEPxBsVrNdHQTxA/KMFBRGPDwoVVIpoq3jUeJUG25qk2fVZ+A28WTabxG4lHzrwgxw78z7zzMw7 73reBDR/jOcCUREhn21LRCy6osfn0kT4BN0h9oiDoiGmTN8Efoum+CHWEBRvRoSbeZXgR8QZcVEc F7syfTcI/kq8Fgviu1jlv3hcET627xXHxFlxWZwXJ8RMxgmPIKkTn8UbMSdeinfiq1hnmUYS4QTs F5fENQSc4rfUgahgT7TFivgk5sVj8VQs4kqukGiAgCviDiKOijr/BUOWL7t/9uGaVyTEighYggsI uI79NQYfdY9FPF8x/WL2xiJLk9hOoelcJehtcYslqI8hYNDGrvP9G5t1PbtRQ+NIg/W/KWaxNNpk DnK5JZ35TzbuCq70ibAu3BBXxWHW1i8hGbpc0+akNLNuBDAtTopz4kBJAuxEC8cPzIlI88BpOoQl Xw1TuDtLsqvZkxbwUA2FjZxEVJYbdROj4mWOpVuzCMoWYGPlxggm4SrfFmFFJOTzDUi2KFY8KIYT sUoSWRadLRDSM0XPMgVPn4guOT0tSN6KVtHd/w8tYWJfqDHeM+m+jBkTeIEaoEmKTUp0oXD80Kjt kU4PkVSqJWTOhIDpFf5APBFLOOPliYhxZgYR00MKmVEEuKWeQ8Q8ruRe5Xb3po7s5CqvDSjnxhVw XzzjFu3k5XTbuuziNYLvZolCk+KHBU8n8QcBL8Rd8VB8yCto8kTEDNBCTIdBg4wQvyD4L6rsdOb3 xKNhhW44IKm4wZaghSAnoIdrHWhz/m3wlOfiI86OXPJPzMvPxLwG/tcX4u3m2l8BBgBQ/dU5d1Za tAAAAABJRU5ErkJggg==\"\n   transform=\"matrix(0.24 0 0 0.24 199.0298 230.2217)\"\n   id=\"image185\"></image><g\n   id=\"g187\"><radialGradient\n   id=\"SVGID_11_\"\n   cx=\"202.6289\"\n   cy=\"233.3711\"\n   r=\"2.999\"\n   gradientTransform=\"matrix(1 0 0 0.75 0 58.3428)\"\n   gradientUnits=\"userSpaceOnUse\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop190\" /><stop\n   offset=\"0.4235\"\n   style=\"stop-color:#FAFCF6\"\n   id=\"stop192\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop194\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.6235\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></radialGradient><circle\n   fill=\"url(#SVGID_11_)\"\n   cx=\"202.629\"\n   cy=\"233.37\"\n   r=\"2.999\"\n   id=\"circle196\" /></g></g><g\n   id=\"g198\"><image\n   overflow=\"visible\"\n   opacity=\"0.25\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   width=\"30\"\n   height=\"30\"\n   xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNrsmM9r1EAUx3cz2XW1 il2wLLagIh5aeilUBC967EX/XA/1It5aUaiC2JNY/EWp0lZkG3c3id+Bz0AIaXayibKHDnzIJfPm s29eZl/Sas3paNeYZ0SHaz5OKmIx5pr+azF7fyh6oi+WxXURZGJZiUScim/iWERiUkWwXTFDlxG6 I1bFBnKd3P1jpPbEvviE4JlvBtueUl1xQ9wVa2ITsdtkzOTmxGTsALE34oP4KH6I0TS5tofUJXFT PBCPxToZ67OlZTUWkSmbsffipXglvos/ZXLGI1N2qx6Kp+KRuFcgVYRh/oJYEgNxle08EUNqsbJY SDAnZa8r1FlYoQzc02sFF5n/W/wskzMlAReopydkaoVtDWocL1bqGtv8Bblx0YSgJFt9xNbJXLfG uZctjQEx11gj9M2YDXCFiVviflmAGeQCYtlt/MxTOvbJmEFkFZqSyu9GNr7xEXNP4gbnVK/mFhZl rUdsd0B3fcQCDs3lcw7PJobJrRH4iE37g24qa6VrBK05HRdiTYjVbvI8xtQ1isSyTd4pE5secW6N xEdslGnyDmhd0oazFRF7j7VGPmIxPdQ+HNMWNzUmBfFj3+7C1YDtMG7RT3UaONMS+jErtC1e05tV EksyPdkAyToHbsqW2e51R7ygs42qNooJaU/oPF2TF8wgl2SkdsVz8Y5sJVXFUvryX6TfNXld5HwE U37cWUbqGdfDsto1njVxQjscQ8jc8+SckO25jqipHTK1i+Ro1peR7FM6pKH7StAhC7uam7CQI+J+ J7RNTb0lU7Vf3+b6hXeuPxH8948qF6Pq+CvAAGGezDColMK7AAAAAElFTkSuQmCC\"\n   transform=\"matrix(0.24 0 0 0.24 213.9448 230.2217)\"\n   id=\"image200\"></image><g\n   id=\"g202\"><radialGradient\n   id=\"SVGID_12_\"\n   cx=\"217.5439\"\n   cy=\"233.3711\"\n   r=\"2.999\"\n   gradientTransform=\"matrix(1 0 0 0.75 0 58.3428)\"\n   gradientUnits=\"userSpaceOnUse\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop205\" /><stop\n   offset=\"0.4235\"\n   style=\"stop-color:#FAFCF6\"\n   id=\"stop207\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop209\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.6235\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></radialGradient><circle\n   fill=\"url(#SVGID_12_)\"\n   cx=\"217.544\"\n   cy=\"233.37\"\n   r=\"2.999\"\n   id=\"circle211\" /></g></g><g\n   id=\"g213\"><image\n   overflow=\"visible\"\n   opacity=\"0.25\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   width=\"30\"\n   height=\"30\"\n   xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlRJREFUeNrsmM9LG0EUx5PdjTTW otDYWmoOQm2M/YGXnrxI/3IvnnoRW7TagocotqjQtLYp5pffgc/CECc7u+uGpuDAB2Y32Tff9+bN 7Jstlaa0lXM+E4gIAsd/BqIHpj+cpLBY0Ix4JBbhwYg4I+SvOIdf4jqrwHIOQUvihXgtVsWCQ9gP 8UV8El/Ft6wCyyl+DxH0XLwUb8UbxD0V1RE7ZtCO+I6oj2JPHIlTBPZ94sqe3yIi0hCb4h1Reibm iOK4HDPRuRJnRO+D2BGHRLSXJC7yRGpeNMV7sYXAeQSFCU6FRHIGB56IGveMI/uIGxu5JGFzTN0W wpqIijIsmpDFYZ55hah4xRpxP7MIM4NWWHEbTGGDKY1ybi8VKyVM/l2wYjtM+S1xrvww9x6KulgX K0QqvOOeGafGCnbrjOPScOtmnPA1Hm7Sr+TcjF2Rq2F3nb4zNVzCZsWyWMOr2XFe5WgB9urYX+ba KywkF1bJh8d4WWSrYLdhbdBhmohVrddNtYApLOUZI0jxgp6EMO8YQWlK272wuwobFlHkeVqqMVzC OlaR15mQMO8Yo8L6VpFnypNL0S1YWBe7h4wTVxneiP0RJ+KzaHE9KEjUAHst7J9wnWoqe7z9TVly QL9bwJQOsXOB3X36vbTVhfHqN16Zh49F2xXujK2PnWPsthhnkLYeiz0ziblrVZ55CkV7Ftrk1Q52 z5NmIkowdsUBIrIqz7SltR2la0vUNhxhP3PNP7RCf4CouPIs4jDS9p2U/svj21QfeKf6E8E/+ahy 37K2GwEGAJb/2mQI89WQAAAAAElFTkSuQmCC\"\n   transform=\"matrix(0.24 0 0 0.24 228.8599 230.2217)\"\n   id=\"image215\"></image><g\n   id=\"g217\"><radialGradient\n   id=\"SVGID_13_\"\n   cx=\"232.459\"\n   cy=\"233.3711\"\n   r=\"2.999\"\n   gradientTransform=\"matrix(1 0 0 0.75 0 58.3428)\"\n   gradientUnits=\"userSpaceOnUse\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop220\" /><stop\n   offset=\"0.4235\"\n   style=\"stop-color:#FAFCF6\"\n   id=\"stop222\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop224\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.6235\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></radialGradient><circle\n   fill=\"url(#SVGID_13_)\"\n   cx=\"232.459\"\n   cy=\"233.37\"\n   r=\"2.999\"\n   id=\"circle226\" /></g></g><g\n   id=\"g228\"><image\n   overflow=\"visible\"\n   opacity=\"0.25\"\n   a:adobe-blending-mode=\"multiply\"\n   a:adobe-opacity-share=\"1\"\n   width=\"30\"\n   height=\"30\"\n   xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnpJREFUeNrsl2lrE1EUhmdLjSZ2 sYgL4lqsYN0+CuIC4o8WFERcPii0YEsQtYpL3cVgW7PMjO+F55ZhmMlMzATyoRceSDKZc957zplz zzjOBCz3P+/xRE34fE6uWESiJ0I+VybCxekeMSMOizkxlbATwx/xRXwXWwiKRhFhd17H+TFxVlwU J8W+lJ0+zlfFmngjvolNrkXDinAJ+6w4IRbFZXFenBLzqUg4ODGR+CheimXxQrwWn8U2aSolwgo4 KC6Jawg4w28mAsGAmuiI3+KDaInH4qlYJyo7QoISAq6IO4g4Lppc8wrSl66fA0TNSQvJE+GRggsI uE74GxgvW8gB/68l7ouojXVSE/s5N9dxelvcIgXNIQTkFXaT718pViMiyjIa8OiZ/N8US4Q0GLEf 2d5iauYHhWtqpu8PiMINcVUcJbduBY3R9poOT4rpJdteRi1Mi9PinDhUkQC7/Cz7aRH2iTB9YIEb /IqPiSmiu0Sza3gZf2qgcC6jEVUVjWbCR83LOR8CqFpAMu07PrxJOMp3ReSJiOnnfYjH5DdK+sgS sUkT+SW6YxASJoYe46OXFtGjp5uB5JVop8/+EVfMxj4xY7w1m/YywtRmGmqhtlNhNMIs+36O2pB2 fYSmUq+gc8ZsyBzhD8QTsWEikyciomjnETFdMMiUEWBTvYyIFlGJ/ILqNRHZy1HeyBnnhhVwXzzj FO06BSHuUcVbON9Piuy7hlvCudnEXwSsiLvioXhnB5oiEREG2ojpYtRLCXEHOP/JlG12fk88yhp0 /RJNxRrbgDaCrICQqHWhw/OfdG54Lt4T2dIj/8S8/EzMa+DYX4h3l13/BBgABM7SO70ZkkMAAAAA SUVORK5CYII=\"\n   transform=\"matrix(0.24 0 0 0.24 243.7749 230.2217)\"\n   id=\"image230\"></image><g\n   id=\"g232\"><radialGradient\n   id=\"SVGID_14_\"\n   cx=\"247.374\"\n   cy=\"233.3711\"\n   r=\"2.999\"\n   gradientTransform=\"matrix(1 0 0 0.75 0 58.3428)\"\n   gradientUnits=\"userSpaceOnUse\"><stop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\"\n   id=\"stop235\" /><stop\n   offset=\"0.4235\"\n   style=\"stop-color:#FAFCF6\"\n   id=\"stop237\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\"\n   id=\"stop239\" /><a:midPointStop\n   offset=\"0.0123\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"0.6235\"\n   style=\"stop-color:#FFFFFF\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#F2F7E8\" /></radialGradient><circle\n   fill=\"url(#SVGID_14_)\"\n   cx=\"247.374\"\n   cy=\"233.37\"\n   r=\"2.999\"\n   id=\"circle241\" /></g></g></g></g><path\n   d=\"m 529.664,248.155 h 18.498 l -2.809,18.064 h 5.59 37.586 l 2.6,-17.718 c 4.98,-1.091 9.133,-3.455 12.512,-6.693 3.084,4.075 8.566,7.37 18.252,7.37 6.338,0 12.775,-1.807 17.174,-3.687 4.254,2.399 9.463,3.687 15.459,3.687 3.088,0 6.236,-0.355 9.426,-1.023 h 67.135 l 3.354,-24.827 -5.445,-0.764 1.879,-13.356 c 0.371,-2.386 0.449,-4.66 0.449,-6.156 l -0.008,-0.375 c -0.457,-12.191 -8.139,-19.765 -20.045,-19.765 -2.404,0 -4.623,0.314 -6.676,0.852 h -34.189 l -0.035,0.244 c -2.527,-0.701 -5.41,-1.096 -8.686,-1.096 -3.801,0 -7.406,0.555 -10.76,1.598 l 0.105,-0.746 h -12.467 l 1.826,-12.951 H 613.08 l -1.846,7.658 c -1.373,5.704 -2.213,5.793 -4.453,6.03 l -4.508,0.477 c -3.049,-1.424 -6.357,-2.065 -9.602,-2.065 -2.135,0 -4.275,0.284 -6.416,0.852 h -19.291 c 0.502,-1.772 0.775,-3.674 0.775,-5.678 0,-9.601 -6.846,-16.305 -16.646,-16.305 -11.055,0 -18.775,7.721 -18.775,18.776 0,0.951 0.082,1.869 0.219,2.764 -2.135,-0.288 -4.277,-0.409 -5.553,-0.409 -2.053,0 -4.072,0.288 -6.045,0.852 h -31.342 c -2.74,-0.553 -5.641,-0.852 -8.537,-0.852 -7.138,0 -13.492,1.674 -18.808,4.723 l -3.451,-1.461 c -3.711,-1.571 -11.232,-3.262 -18.979,-3.262 -8.933,0 -16.383,2.56 -21.576,7.016 -3.265,-4.473 -8.523,-7.016 -15.228,-7.016 -4.822,0 -9.021,1.477 -12.572,3.44 -2.996,-2.204 -6.796,-3.44 -11.115,-3.44 -2.327,0 -4.48,0.315 -6.476,0.852 h -33.963 l -0.035,0.245 c -2.526,-0.702 -5.41,-1.097 -8.687,-1.097 -20.458,0 -35.307,16.031 -35.307,38.117 0,17.363 10.785,28.149 28.148,28.149 3.087,0 6.236,-0.356 9.426,-1.023 h 88.816 c 3.706,0.676 7.669,1.023 11.154,1.023 8.907,0 16.278,-2.375 21.51,-6.593 4.872,4.252 11.585,6.593 19.728,6.593 3.053,0 6.206,-0.368 9.286,-1.023 h 44.664 2.069 z\"\n   id=\"path243\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#f5f5f5\" /><g\n   id=\"g245\"\n   transform=\"translate(0,16)\"><g\n   id=\"g247\"><path\n   d=\"m 340.308,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.095,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z\"\n   id=\"path249\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /><path\n   d=\"m 394.07,221.7 -0.171,-0.255 1.789,-10.055 2.642,-18.063 c 0.512,-3.749 0.341,-5.623 -1.96,-5.623 -2.642,0 -5.794,2.727 -9.372,5.879 l -2.727,19.512 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 -0.852,6.305 h -18.404 l -0.171,-0.341 1.875,-10.82 2.471,-17.212 c 0.512,-3.237 0.682,-5.453 -1.789,-5.453 -3.238,0 -7.413,3.664 -9.714,5.709 l -2.642,19.512 c -0.17,1.363 -0.17,1.534 1.108,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.767,-1.789 l -4.176,-1.534 0.938,-6.476 h 16.871 l -0.938,6.987 0.256,0.085 c 4.43,-3.749 9.116,-7.924 15.592,-7.924 4.687,0 7.839,2.641 8.18,7.753 l 0.256,0.086 c 4.175,-3.664 9.202,-7.839 15.252,-7.839 6.22,0 8.775,3.152 8.946,9.202 0,1.618 -0.171,3.493 -0.426,5.538 l -3.067,21.897 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.175,0.597 -0.852,6.305 H 394.07 z\"\n   id=\"path251\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /><path\n   d=\"m 443.995,190.771 -0.17,-4.431 c 0,-0.682 -0.085,-1.108 -1.022,-1.363 -1.022,-0.256 -2.642,-0.427 -4.771,-0.427 -3.579,0 -6.391,1.108 -6.391,4.09 0,2.727 2.982,3.749 6.731,5.027 6.05,2.045 13.888,4.431 13.888,13.463 0,11.076 -9.372,15.592 -20.193,15.592 -8.009,0 -14.91,-1.959 -16.273,-2.981 l 1.618,-12.355 8.691,0.512 0.255,4.941 c 0,0.597 0.171,1.108 0.938,1.363 1.278,0.427 3.238,0.768 6.05,0.768 4.687,0 7.327,-1.79 7.327,-4.687 0,-3.408 -3.152,-4.175 -8.009,-5.624 -6.135,-1.874 -12.78,-4.26 -12.78,-13.206 0,-10.48 9.116,-14.996 19.597,-14.996 6.646,0 12.866,1.533 15.081,2.471 l -1.704,12.354 -8.863,-0.511 z\"\n   id=\"path253\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /><path\n   d=\"m 489.748,218.548 c -4.175,2.386 -10.395,4.175 -16.444,4.175 -13.036,0 -18.575,-7.583 -18.575,-18.574 0,-18.83 11.588,-27.691 25.988,-27.691 6.475,0 11.843,1.874 14.229,3.578 l -1.874,13.377 -8.691,-0.426 -0.255,-5.794 c 0,-0.597 -0.086,-0.938 -0.597,-1.192 -1.022,-0.427 -2.557,-0.597 -4.175,-0.597 -5.624,0 -11.418,4.601 -11.418,17.382 0,7.839 3.493,10.395 8.436,10.395 4.346,0 8.436,-1.448 11.247,-2.556 l 2.129,7.923 z\"\n   id=\"path255\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /><path\n   d=\"m 491.364,221.7 0.853,-6.39 3.919,-0.512 c 1.193,-0.17 1.363,-0.426 1.534,-1.704 l 3.578,-25.987 c 0.086,-0.938 -0.085,-1.534 -0.852,-1.789 l -4.261,-1.534 0.938,-6.476 h 16.87 l -1.107,7.669 0.256,0.17 c 3.323,-4.771 8.095,-8.69 13.548,-8.69 1.874,0 5.112,0.341 6.561,0.767 l -2.13,15.507 -9.969,-0.341 -0.256,-4.431 c -0.086,-0.767 -0.256,-1.022 -0.938,-1.022 -1.619,0 -4.26,1.96 -6.646,4.431 l -2.981,21.643 c -0.171,1.363 -0.085,1.619 1.192,1.704 l 8.095,0.682 -0.938,6.305 h -27.266 z\"\n   id=\"path257\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /><path\n   d=\"m 536.094,221.7 -0.17,-0.426 2.045,-11.503 3.152,-22.749 c 0.17,-0.938 -0.086,-1.534 -0.853,-1.79 l -4.175,-1.448 0.852,-6.476 h 18.149 l -5.027,35.786 c -0.171,1.363 -0.085,1.534 1.192,1.704 l 4.09,0.597 -0.852,6.305 h -18.403 z m 5.879,-57.598 c 0,-5.453 3.238,-8.775 8.776,-8.775 4.175,0 6.646,2.215 6.646,6.305 0,5.368 -3.322,8.861 -8.861,8.861 -4.176,-0.001 -6.561,-2.387 -6.561,-6.391 z\"\n   id=\"path259\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /><path\n   d=\"m 556.796,239.764 -0.17,-0.341 2.471,-14.229 5.282,-38.087 c 0.171,-1.022 -0.085,-1.534 -0.767,-1.789 l -4.175,-1.534 0.938,-6.476 h 17.041 l -1.022,6.816 0.255,0.085 c 5.027,-4.686 10.311,-7.753 15.678,-7.753 7.328,0 12.44,4.686 12.44,17.041 0,11.758 -4.601,29.225 -20.449,29.225 -5.538,0 -8.605,-2.13 -11.759,-4.345 l -1.874,12.78 c -0.085,0.938 0.085,1.278 1.192,1.363 l 8.606,0.853 -0.938,6.39 h -22.749 z m 17.041,-30.247 c 2.13,1.789 4.942,3.322 8.095,3.322 6.901,0 9.458,-9.713 9.458,-17.211 0,-5.027 -1.193,-8.351 -4.431,-8.351 -3.408,0 -7.754,3.664 -10.821,6.391 l -2.301,15.849 z\"\n   id=\"path261\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /><path\n   d=\"m 635.777,219.4 c -3.749,1.789 -9.458,3.322 -14.229,3.322 -8.521,0 -12.099,-2.981 -12.099,-9.969 0,-1.107 0.085,-2.386 0.256,-3.749 l 3.066,-22.323 c 0.086,-0.512 0.086,-0.853 -0.511,-0.853 h -5.879 l 1.107,-7.839 c 7.242,-0.767 10.906,-4.431 13.122,-13.633 h 7.924 l -1.704,12.1 c -0.085,0.596 -0.085,0.852 0.597,0.852 h 11.758 l -1.193,8.521 h -12.439 l -2.812,20.364 c -0.171,1.107 -0.256,1.96 -0.256,2.727 0,2.982 1.278,4.26 4.942,4.26 2.385,0 4.771,-0.596 6.816,-1.363 l 1.534,7.583 z\"\n   id=\"path263\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /><path\n   d=\"m 671.817,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.094,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z\"\n   id=\"path265\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /><path\n   d=\"m 703.596,221.7 -0.17,-0.255 1.874,-10.396 2.471,-17.723 c 0.512,-3.578 0.341,-5.879 -2.215,-5.879 -3.664,0 -8.18,3.578 -11.077,6.135 l -2.641,19.512 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.768,-1.789 l -4.175,-1.534 0.938,-6.476 h 16.87 l -0.937,6.987 0.255,0.085 c 4.771,-4.09 9.373,-7.924 16.02,-7.924 6.475,0 9.798,3.322 10.054,10.139 0,1.363 -0.085,3.067 -0.341,4.687 l -3.067,21.812 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 L 722,221.7 h -18.404 z\"\n   id=\"path267\"\n   inkscape:connector-curvature=\"0\"\n   style=\"fill:#383838\" /></g><g\n   id=\"g269\"><linearGradient\n   id=\"SVGID_15_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"324.1611\"\n   y1=\"239.7637\"\n   x2=\"324.1611\"\n   y2=\"155.3275\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop272\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop274\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 340.308,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.095,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z\"\n   id=\"path276\"\n   style=\"fill:url(#SVGID_15_)\"\n   inkscape:connector-curvature=\"0\" /><linearGradient\n   id=\"SVGID_16_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"377.45459\"\n   y1=\"239.7637\"\n   x2=\"377.45459\"\n   y2=\"155.3277\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop279\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop281\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 394.07,221.7 -0.171,-0.255 1.789,-10.055 2.642,-18.063 c 0.512,-3.749 0.341,-5.623 -1.96,-5.623 -2.642,0 -5.794,2.727 -9.372,5.879 l -2.727,19.512 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 -0.852,6.305 h -18.404 l -0.171,-0.341 1.875,-10.82 2.471,-17.212 c 0.512,-3.237 0.682,-5.453 -1.789,-5.453 -3.238,0 -7.413,3.664 -9.714,5.709 l -2.642,19.512 c -0.17,1.363 -0.17,1.534 1.108,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.767,-1.789 l -4.176,-1.534 0.938,-6.476 h 16.871 l -0.938,6.987 0.256,0.085 c 4.43,-3.749 9.116,-7.924 15.592,-7.924 4.687,0 7.839,2.641 8.18,7.753 l 0.256,0.086 c 4.175,-3.664 9.202,-7.839 15.252,-7.839 6.22,0 8.775,3.152 8.946,9.202 0,1.618 -0.171,3.493 -0.426,5.538 l -3.067,21.897 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.175,0.597 -0.852,6.305 H 394.07 z\"\n   id=\"path283\"\n   style=\"fill:url(#SVGID_16_)\"\n   inkscape:connector-curvature=\"0\" /><linearGradient\n   id=\"SVGID_17_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"435.17719\"\n   y1=\"239.7637\"\n   x2=\"435.17719\"\n   y2=\"155.3275\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop286\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop288\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 443.995,190.771 -0.17,-4.431 c 0,-0.682 -0.085,-1.108 -1.022,-1.363 -1.022,-0.256 -2.642,-0.427 -4.771,-0.427 -3.579,0 -6.391,1.108 -6.391,4.09 0,2.727 2.982,3.749 6.731,5.027 6.05,2.045 13.888,4.431 13.888,13.463 0,11.076 -9.372,15.592 -20.193,15.592 -8.009,0 -14.91,-1.959 -16.273,-2.981 l 1.618,-12.355 8.691,0.512 0.255,4.941 c 0,0.597 0.171,1.108 0.938,1.363 1.278,0.427 3.238,0.768 6.05,0.768 4.687,0 7.327,-1.79 7.327,-4.687 0,-3.408 -3.152,-4.175 -8.009,-5.624 -6.135,-1.874 -12.78,-4.26 -12.78,-13.206 0,-10.48 9.116,-14.996 19.597,-14.996 6.646,0 12.866,1.533 15.081,2.471 l -1.704,12.354 -8.863,-0.511 z\"\n   id=\"path290\"\n   style=\"fill:url(#SVGID_17_)\"\n   inkscape:connector-curvature=\"0\" /><linearGradient\n   id=\"SVGID_18_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"474.83691\"\n   y1=\"239.7637\"\n   x2=\"474.83691\"\n   y2=\"155.3275\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop293\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop295\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 489.748,218.548 c -4.175,2.386 -10.395,4.175 -16.444,4.175 -13.036,0 -18.575,-7.583 -18.575,-18.574 0,-18.83 11.588,-27.691 25.988,-27.691 6.475,0 11.843,1.874 14.229,3.578 l -1.874,13.377 -8.691,-0.426 -0.255,-5.794 c 0,-0.597 -0.086,-0.938 -0.597,-1.192 -1.022,-0.427 -2.557,-0.597 -4.175,-0.597 -5.624,0 -11.418,4.601 -11.418,17.382 0,7.839 3.493,10.395 8.436,10.395 4.346,0 8.436,-1.448 11.247,-2.556 l 2.129,7.923 z\"\n   id=\"path297\"\n   style=\"fill:url(#SVGID_18_)\"\n   inkscape:connector-curvature=\"0\" /><linearGradient\n   id=\"SVGID_19_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"512.28223\"\n   y1=\"239.7637\"\n   x2=\"512.28223\"\n   y2=\"155.3277\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop300\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop302\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 491.364,221.7 0.853,-6.39 3.919,-0.512 c 1.193,-0.17 1.363,-0.426 1.534,-1.704 l 3.578,-25.987 c 0.086,-0.938 -0.085,-1.534 -0.852,-1.789 l -4.261,-1.534 0.938,-6.476 h 16.87 l -1.107,7.669 0.256,0.17 c 3.323,-4.771 8.095,-8.69 13.548,-8.69 1.874,0 5.112,0.341 6.561,0.767 l -2.13,15.507 -9.969,-0.341 -0.256,-4.431 c -0.086,-0.767 -0.256,-1.022 -0.938,-1.022 -1.619,0 -4.26,1.96 -6.646,4.431 l -2.981,21.643 c -0.171,1.363 -0.085,1.619 1.192,1.704 l 8.095,0.682 -0.938,6.305 h -27.266 z\"\n   id=\"path304\"\n   style=\"fill:url(#SVGID_19_)\"\n   inkscape:connector-curvature=\"0\" /><linearGradient\n   id=\"SVGID_20_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"546.65918\"\n   y1=\"239.7637\"\n   x2=\"546.65918\"\n   y2=\"155.32719\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop307\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop309\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 536.094,221.7 -0.17,-0.426 2.045,-11.503 3.152,-22.749 c 0.17,-0.938 -0.086,-1.534 -0.853,-1.79 l -4.175,-1.448 0.852,-6.476 h 18.149 l -5.027,35.786 c -0.171,1.363 -0.085,1.534 1.192,1.704 l 4.09,0.597 -0.852,6.305 h -18.403 z m 5.879,-57.598 c 0,-5.453 3.238,-8.775 8.776,-8.775 4.175,0 6.646,2.215 6.646,6.305 0,5.368 -3.322,8.861 -8.861,8.861 -4.176,-0.001 -6.561,-2.387 -6.561,-6.391 z\"\n   id=\"path311\"\n   style=\"fill:url(#SVGID_20_)\"\n   inkscape:connector-curvature=\"0\" /><linearGradient\n   id=\"SVGID_21_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"580.69629\"\n   y1=\"239.7637\"\n   x2=\"580.69629\"\n   y2=\"155.32719\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop314\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop316\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 556.796,239.764 -0.17,-0.341 2.471,-14.229 5.282,-38.087 c 0.171,-1.022 -0.085,-1.534 -0.767,-1.789 l -4.175,-1.534 0.938,-6.476 h 17.041 l -1.022,6.816 0.255,0.085 c 5.027,-4.686 10.311,-7.753 15.678,-7.753 7.328,0 12.44,4.686 12.44,17.041 0,11.758 -4.601,29.225 -20.449,29.225 -5.538,0 -8.605,-2.13 -11.759,-4.345 l -1.874,12.78 c -0.085,0.938 0.085,1.278 1.192,1.363 l 8.606,0.853 -0.938,6.39 h -22.749 z m 17.041,-30.247 c 2.13,1.789 4.942,3.322 8.095,3.322 6.901,0 9.458,-9.713 9.458,-17.211 0,-5.027 -1.193,-8.351 -4.431,-8.351 -3.408,0 -7.754,3.664 -10.821,6.391 l -2.301,15.849 z\"\n   id=\"path318\"\n   style=\"fill:url(#SVGID_21_)\"\n   inkscape:connector-curvature=\"0\" /><linearGradient\n   id=\"SVGID_22_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"622.7832\"\n   y1=\"239.7637\"\n   x2=\"622.7832\"\n   y2=\"155.3268\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop321\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop323\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 635.777,219.4 c -3.749,1.789 -9.458,3.322 -14.229,3.322 -8.521,0 -12.099,-2.981 -12.099,-9.969 0,-1.107 0.085,-2.386 0.256,-3.749 l 3.066,-22.323 c 0.086,-0.512 0.086,-0.853 -0.511,-0.853 h -5.879 l 1.107,-7.839 c 7.242,-0.767 10.906,-4.431 13.122,-13.633 h 7.924 l -1.704,12.1 c -0.085,0.596 -0.085,0.852 0.597,0.852 h 11.758 l -1.193,8.521 h -12.439 l -2.812,20.364 c -0.171,1.107 -0.256,1.96 -0.256,2.727 0,2.982 1.278,4.26 4.942,4.26 2.385,0 4.771,-0.596 6.816,-1.363 l 1.534,7.583 z\"\n   id=\"path325\"\n   style=\"fill:url(#SVGID_22_)\"\n   inkscape:connector-curvature=\"0\" /><linearGradient\n   id=\"SVGID_23_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"655.6709\"\n   y1=\"239.7637\"\n   x2=\"655.6709\"\n   y2=\"155.3275\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop328\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop330\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 671.817,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.094,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z\"\n   id=\"path332\"\n   style=\"fill:url(#SVGID_23_)\"\n   inkscape:connector-curvature=\"0\" /><linearGradient\n   id=\"SVGID_24_\"\n   gradientUnits=\"userSpaceOnUse\"\n   x1=\"697.92969\"\n   y1=\"239.7637\"\n   x2=\"697.92969\"\n   y2=\"155.3277\"><stop\n   offset=\"0\"\n   style=\"stop-color:#000000\"\n   id=\"stop335\" /><stop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   id=\"stop337\" /><a:midPointStop\n   offset=\"0\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"0.6933\"\n   style=\"stop-color:#000000\" /><a:midPointStop\n   offset=\"1\"\n   style=\"stop-color:#000000;stop-opacity:0\" /></linearGradient><path\n   d=\"m 703.596,221.7 -0.17,-0.255 1.874,-10.396 2.471,-17.723 c 0.512,-3.578 0.341,-5.879 -2.215,-5.879 -3.664,0 -8.18,3.578 -11.077,6.135 l -2.641,19.512 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.768,-1.789 l -4.175,-1.534 0.938,-6.476 h 16.87 l -0.937,6.987 0.255,0.085 c 4.771,-4.09 9.373,-7.924 16.02,-7.924 6.475,0 9.798,3.322 10.054,10.139 0,1.363 -0.085,3.067 -0.341,4.687 l -3.067,21.812 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 L 722,221.7 h -18.404 z\"\n   id=\"path339\"\n   style=\"fill:url(#SVGID_24_)\"\n   inkscape:connector-curvature=\"0\" /></g></g><g\n   id=\"g4141\"\n   transform=\"matrix(0.81856441,0,0,0.81856441,79.234731,-94.128741)\"><g\n   id=\"g4143\"></g><g\n   id=\"g4165\"><linearGradient\n   y2=\"155.3275\"\n   x2=\"324.1611\"\n   y1=\"239.7637\"\n   x1=\"324.1611\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4167\"><stop\n   id=\"stop4169\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4171\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient><linearGradient\n   y2=\"155.3277\"\n   x2=\"377.45459\"\n   y1=\"239.7637\"\n   x1=\"377.45459\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4175\"><stop\n   id=\"stop4177\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4179\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient><linearGradient\n   y2=\"155.3275\"\n   x2=\"435.17719\"\n   y1=\"239.7637\"\n   x1=\"435.17719\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4183\"><stop\n   id=\"stop4185\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4187\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient><linearGradient\n   y2=\"155.3275\"\n   x2=\"474.83691\"\n   y1=\"239.7637\"\n   x1=\"474.83691\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4191\"><stop\n   id=\"stop4193\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4195\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient><linearGradient\n   y2=\"155.3277\"\n   x2=\"512.28223\"\n   y1=\"239.7637\"\n   x1=\"512.28223\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4199\"><stop\n   id=\"stop4201\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4203\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient><linearGradient\n   y2=\"155.32719\"\n   x2=\"546.65918\"\n   y1=\"239.7637\"\n   x1=\"546.65918\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4207\"><stop\n   id=\"stop4209\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4211\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient><linearGradient\n   y2=\"155.32719\"\n   x2=\"580.69629\"\n   y1=\"239.7637\"\n   x1=\"580.69629\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4215\"><stop\n   id=\"stop4217\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4219\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient><linearGradient\n   y2=\"155.3268\"\n   x2=\"622.7832\"\n   y1=\"239.7637\"\n   x1=\"622.7832\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4223\"><stop\n   id=\"stop4225\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4227\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient><linearGradient\n   y2=\"155.3275\"\n   x2=\"655.6709\"\n   y1=\"239.7637\"\n   x1=\"655.6709\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4231\"><stop\n   id=\"stop4233\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4235\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient><linearGradient\n   y2=\"155.3277\"\n   x2=\"697.92969\"\n   y1=\"239.7637\"\n   x1=\"697.92969\"\n   gradientUnits=\"userSpaceOnUse\"\n   id=\"linearGradient4239\"><stop\n   id=\"stop4241\"\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><stop\n   id=\"stop4243\"\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0\" /><a:midPointStop\n   style=\"stop-color:#000000\"\n   offset=\"0.6933\" /><a:midPointStop\n   style=\"stop-color:#000000;stop-opacity:0\"\n   offset=\"1\" /></linearGradient></g></g></svg>\n    </a>\n\n    <div class=\"spinner\" id='spinner'></div>\n    <div class=\"emscripten\" id=\"status\">Downloading...</div>\n\n<span id='controls'>\n  <span><input type=\"checkbox\" id=\"resize\">Resize canvas</span>\n  <span><input type=\"checkbox\" id=\"pointerLock\" checked>Lock/hide mouse pointer &nbsp;&nbsp;&nbsp;</span>\n  <span><input type=\"button\" value=\"Fullscreen\" onclick=\"Module.requestFullScreen(document.getElementById('pointerLock').checked, \n                                                                            document.getElementById('resize').checked)\">\n  </span>\n</span>\n\n    <div class=\"emscripten\">\n      <progress value=\"0\" max=\"100\" id=\"progress\" hidden=1></progress>\n    </div>\n\n    \n    <div class=\"emscripten_border\">\n      <canvas class=\"emscripten\" id=\"canvas\" oncontextmenu=\"event.preventDefault()\"></canvas>\n    </div>\n    <textarea id=\"output\" rows=\"8\"></textarea>\n\n    <script type='text/javascript'>\n      var statusElement = document.getElementById('status');\n      var progressElement = document.getElementById('progress');\n      var spinnerElement = document.getElementById('spinner');\n\n      var Module = {\n        preRun: [],\n        postRun: [],\n        print: (function() {\n          var element = document.getElementById('output');\n          if (element) element.value = ''; // clear browser cache\n          return function(text) {\n            text = Array.prototype.slice.call(arguments).join(' ');\n            // These replacements are necessary if you render to raw HTML\n            //text = text.replace(/&/g, \"&amp;\");\n            //text = text.replace(/</g, \"&lt;\");\n            //text = text.replace(/>/g, \"&gt;\");\n            //text = text.replace('\\n', '<br>', 'g');\n            console.log(text);\n            if (element) {\n              element.value += text + \"\\n\";\n              element.scrollTop = element.scrollHeight; // focus on bottom\n            }\n          };\n        })(),\n        printErr: function(text) {\n          text = Array.prototype.slice.call(arguments).join(' ');\n          if (0) { // XXX disabled for safety typeof dump == 'function') {\n            dump(text + '\\n'); // fast, straight to the real console\n          } else {\n            console.error(text);\n          }\n        },\n        canvas: (function() {\n          var canvas = document.getElementById('canvas');\n\n          // As a default initial behavior, pop up an alert when webgl context is lost. To make your\n          // application robust, you may want to override this behavior before shipping!\n          // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2\n          canvas.addEventListener(\"webglcontextlost\", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);\n\n          return canvas;\n        })(),\n        setStatus: function(text) {\n          if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };\n          if (text === Module.setStatus.text) return;\n          var m = text.match(/([^(]+)\\((\\d+(\\.\\d+)?)\\/(\\d+)\\)/);\n          var now = Date.now();\n          if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon\n          if (m) {\n            text = m[1];\n            progressElement.value = parseInt(m[2])*100;\n            progressElement.max = parseInt(m[4])*100;\n            progressElement.hidden = false;\n            spinnerElement.hidden = false;\n          } else {\n            progressElement.value = null;\n            progressElement.max = null;\n            progressElement.hidden = true;\n            if (!text) spinnerElement.style.display = 'none';\n          }\n          statusElement.innerHTML = text;\n        },\n        totalDependencies: 0,\n        monitorRunDependencies: function(left) {\n          this.totalDependencies = Math.max(this.totalDependencies, left);\n          Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');\n        }\n      };\n      Module.setStatus('Downloading...');\n      window.onerror = function(event) {\n        // TODO: do not warn on ok events like simulating an infinite loop or exitStatus\n        Module.setStatus('Exception thrown, see JavaScript console');\n        spinnerElement.style.display = 'none';\n        Module.setStatus = function(text) {\n          if (text) Module.printErr('[post-exception status] ' + text);\n        };\n      };\n    </script>\n    <script async type=\"text/javascript\" src=\"BOSS.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "BOSS/emscripten/BOSS2.html",
    "content": "<!doctype html>\n<html lang=\"en-us\">\n  <head>\n    <script async type=\"text/javascript\" src=\"BOSS.js\"></script>\n    <script type=\"text/javascript\" src=\"jquery-1.11.2.min.js\"></script>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <title>BOSS Test</title>\n    <style>\n      .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }\n      textarea.params { overflow: auto; }\n      textarea.emscripten { font-family: monospace; width: 1280px; background-color:#000000; color:#ffffff;}\n      iframe.params { display: none; }\n      div.emscripten { text-align: center; }\n      div.emscripten_border { border: 0px solid black; }\n      /* the canvas *must not* have any border or padding, or mouse coords will be wrong */\n      canvas.emscripten { border: 0px none; }\n    </style>\n  </head>\n  <body>\n  \n  <center>\n  <div class=\"emscripten\">\n    <button id='configbutton' onclick=\"jQuery('#configframe').toggle('show'); configShow=!configShow; $('#configbutton').text(configShow ? 'Hide Config' : 'Show Config');\">Show Config</button>\n    <button onclick=\"Module.ccall('ResetExperiment', 'string', ['string'], [$('#configframe').contents().find('#textparams').val()]);\">Run New Config</button>\n    <button onclick=\"jQuery('#canvas').toggle('show');\">Toggle Canvas</button>\n    <button onclick=\"jQuery('#output').toggle('show');\">Toggle Console</button>\n    \n      <input type=\"checkbox\" id=\"resize\">Resize canvas\n      <input type=\"checkbox\" id=\"pointerLock\">Lock/hide mouse pointer\n      &nbsp;&nbsp;&nbsp;\n      <input type=\"button\" value=\"Fullscreen\" onclick=\"Module.requestFullScreen(document.getElementById('pointerLock').checked, \n                                                                                document.getElementById('resize').checked)\">\n    </div>\n    \n    <br>\n    \n    <iframe class=\"params\" id=\"configframe\" width=\"1280px\" frameBorder=\"0\" height=\"300\" wrap='off' src=\"config.html\"></iframe>\n    \n  </center>\n    <div class=\"emscripten\" id=\"status\">Downloading...</div>\n    <div class=\"emscripten\">\n      <progress value=\"0\" max=\"100\" id=\"progress\" hidden=1></progress>  \n    </div>\n    <div class=\"emscripten_border\">\n      <canvas class=\"emscripten\" id=\"canvas\" oncontextmenu=\"event.preventDefault()\"></canvas>\n    </div>\n    \n\t<br>\n    <textarea class=\"emscripten\" id=\"output\" rows=\"8\"></textarea>\n    \n    <script type='text/javascript'>\n    \n      var configShow = false;\n    \n      // connect to canvas\n      var Module = {\n        preRun: [],\n        postRun: [],\n        print: (function() {\n          var element = document.getElementById('output');\n          element.value = ''; // clear browser cache\n          return function(text) {\n            text = Array.prototype.slice.call(arguments).join(' ');\n            element.value += text + \"\\n\";\n            element.scrollTop = element.scrollHeight; // focus on bottom\n          };\n        })(),\n        printErr: function(text) {\n          text = Array.prototype.slice.call(arguments).join(' ');\n          if (0) {\n            dump(text + '\\n'); \n          } else {\n            console.log(text);\n          }\n        },\n        canvas: document.getElementById('canvas'),\n        setStatus: function(text) {\n          if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };\n          if (text === Module.setStatus.text) return;\n          var m = text.match(/([^(]+)\\((\\d+(\\.\\d+)?)\\/(\\d+)\\)/);\n          var now = Date.now();\n          if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon\n          var statusElement = document.getElementById('status');\n          var progressElement = document.getElementById('progress');\n          if (m) {\n            text = m[1];\n            progressElement.value = parseInt(m[2])*100;\n            progressElement.max = parseInt(m[4])*100;\n            progressElement.hidden = false;\n          } else {\n            progressElement.value = null;\n            progressElement.max = null;\n            progressElement.hidden = true;\n          }\n          statusElement.innerHTML = text;\n        },\n        totalDependencies: 0,\n        monitorRunDependencies: function(left) {\n          this.totalDependencies = Math.max(this.totalDependencies, left);\n          Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');\n        }\n      };\n      Module.setStatus('Downloading...');\n      \n      jQuery.get('config.txt', function(data) { $(\"#paraminput\").val(data);; });\n    \n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "BOSS/emscripten/config.html",
    "content": "<!doctype html>\n<html lang=\"en-us\">\n  <head>\n    <script type=\"text/javascript\" src=\"jquery-1.11.2.min.js\"></script>\n    \n    <style>\n        body {  }\n        \n    </style>\n    \n    <script type='text/javascript'>\n    jQuery.get('config.txt', function(data) { jQuery('#textparams').val(data); });\n   </script>\n  </head>\n  <body>\n   <textarea class=\"params\" id=\"textparams\" style=\"width: 100%; height: 280px; font-family: monospace; background-color:#dddddd; box-sizing: border-box;\" wrap=\"off\">Text</textarea>\n  </body>\n</html>"
  },
  {
    "path": "BOSS/emscripten/config.txt",
    "content": "{\n    \"Experiments\" : \n    {        \n        \"Visualize Build Orders\" :   \n        {   \n            \"run\" : true, \n            \"type\" : \"BuildOrderVisualization\", \n            \"fps\" : 1000, \n            \"outputFile\" : \"UAB_Openers.txt\", \n            \"scenarios\"     :   \n            [ \n                { \"state\":\"Protoss Start State\", \"buildOrder\" : \"UAB DT Rush\" },\n                { \"state\":\"Zerg Start State\", \"buildOrder\" : \"3 Hatch Muta\" }\n            ] \n        }\n    },\n\n    \"States\" : \n    {\n        \"Protoss Start State\"   : { \"race\" : \"Protoss\", \"minerals\" : 50, \"gas\" : 0, \"units\" : [ [\"Protoss_Probe\", 4], [\"Protoss_Nexus\", 1] ] },\n        \"Zerg Start State\"      : { \"race\" : \"Zerg\",    \"minerals\" : 50, \"gas\" : 0, \"units\" : [ [\"Zerg_Drone\", 4], [\"Zerg_Hatchery\", 1], [\"Zerg_Overlord\", 1] ] },\n        \"Terran Start State\"    : { \"race\" : \"Terran\",  \"minerals\" : 50, \"gas\" : 0, \"units\" : [ [\"Terran_SCV\", 4], [\"Terran_Command_Center\", 1] ] }\n    },\n    \n    \"Build Orders\" :\n    {\n        \"3 Hatch Muta\"          : [ \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Overlord\", \"Zerg_Drone\", \n                                    \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Hatchery\", \"Zerg_Spawning_Pool\", \"Zerg_Drone\", \n                                    \"Zerg_Drone\", \"Zerg_Hatchery\", \"Zerg_Extractor\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Overlord\", \n                                    \"Zerg_Lair\", \"Zerg_Extractor\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Zergling\", \"Zerg_Zergling\", \"Zerg_Zergling\", \n                                    \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Overlord\", \"Zerg_Drone\", \"Zerg_Overlord\", \"Zerg_Drone\", \n                                    \"Zerg_Overlord\", \"Zerg_Spire\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Drone\", \"Zerg_Mutalisk\", \n                                    \"Zerg_Mutalisk\", \"Zerg_Mutalisk\", \"Zerg_Mutalisk\", \"Zerg_Mutalisk\", \"Zerg_Mutalisk\", \"Zerg_Mutalisk\", \"Zerg_Mutalisk\", \n                                    \"Zerg_Mutalisk\", \"Zerg_Mutalisk\", \"Zerg_Mutalisk\", \"Zerg_Mutalisk\" ],\n\n        \"UAB Zealot Rush\"       : [ \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Pylon\", \"Protoss_Probe\", \"Protoss_Gateway\", \n                                    \"Protoss_Gateway\", \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Zealot\", \"Protoss_Pylon\", \"Protoss_Zealot\", \"Protoss_Zealot\", \n                                    \"Protoss_Probe\", \"Protoss_Zealot\", \"Protoss_Zealot\", \"Protoss_Probe\", \"Protoss_Pylon\", \"Protoss_Zealot\", \"Protoss_Gateway\", \n                                    \"Protoss_Probe\", \"Protoss_Pylon\", \"Protoss_Probe\", \"Protoss_Zealot\", \"Protoss_Probe\", \"Protoss_Zealot\", \"Protoss_Zealot\", \n                                    \"Protoss_Zealot\", \"Protoss_Zealot\", \"Protoss_Pylon\", \"Protoss_Probe\", \"Protoss_Zealot\", \"Protoss_Zealot\", \"Protoss_Zealot\" ],\n        \"UAB DT Rush\"           : [ \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Pylon\", \"Protoss_Probe\", \"Protoss_Gateway\", \n                                    \"Protoss_Probe\", \"Protoss_Assimilator\", \"Protoss_Probe\", \"Protoss_Cybernetics_Core\", \"Protoss_Probe\", \"Protoss_Citadel_of_Adun\", \n                                    \"Protoss_Probe\", \"Protoss_Templar_Archives\", \"Protoss_Gateway\", \"Protoss_Dark_Templar\", \"Protoss_Dark_Templar\", \"Protoss_Pylon\", \n                                    \"Protoss_Dark_Templar\", \"Protoss_Dark_Templar\", \"Protoss_Probe\", \"Protoss_Pylon\", \"Protoss_Probe\"],\n        \"UAB Dragoon Rush\"      : [ \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Pylon\", \"Protoss_Probe\", \"Protoss_Probe\", \n                                    \"Protoss_Gateway\", \"Protoss_Probe\", \"Protoss_Assimilator\", \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Cybernetics_Core\", \n                                    \"Protoss_Probe\", \"Protoss_Probe\", \"Protoss_Gateway\", \"Singularity_Charge\", \"Protoss_Dragoon\", \"Protoss_Gateway\", \"Protoss_Pylon\", \n                                    \"Protoss_Dragoon\", \"Protoss_Dragoon\", \"Protoss_Probe\", \"Protoss_Gateway\", \"Protoss_Pylon\", \"Protoss_Probe\", \"Protoss_Dragoon\", \n                                    \"Protoss_Dragoon\", \"Protoss_Dragoon\"]\n    }\n}"
  },
  {
    "path": "BOSS/make_windows.bat",
    "content": "@echo off\n\nset original_dir=%CD%\n\necho.\necho *********************************************\necho * COMPILING BOSS WITH EMSCRIPTEN            *\necho *********************************************\necho.\n\nmake -j 8"
  },
  {
    "path": "BOSS/source/ActionInProgress.cpp",
    "content": "#include \"ActionInProgress.h\"\n\nusing namespace BOSS;\n\nActionsInProgress::ActionsInProgress() \n    : _numProgress(Constants::MAX_ACTIONS, 0)\n{\n\t\n}\n\t\t\nUnitCountType ActionsInProgress::numInProgress(const ActionType & a) const\n{\n\treturn _numProgress[a.ID()];\t\n}\n\t\nvoid ActionsInProgress::addAction(const ActionType & action, FrameCountType time)\n{\n\t// deprecated, code below should be faster\n    //inProgress.push_back(ActionInProgress(a, (unsigned short)time));\n    //inProgress.sort();\n\t\n    // inProgress should always be sorted, so add the action in its place\n    _inProgress.addSorted(ActionInProgress(action, time));\n\n\t// increase the specific count of a\n\t_numProgress[action.ID()]++;\n}\n\t\nvoid ActionsInProgress::popNextAction()\t\n{\n\tBOSS_ASSERT(_inProgress.size() > 0, \"Can't pop from empty set\");\n\t\n\t// there is one less of the last unit in progress\n\t_numProgress[_inProgress[_inProgress.size()-1]._action.ID()]--;\n\t\n\t// the number of things in progress goes down\n    _inProgress.pop_back();\n}\n\t\nbool ActionsInProgress::isEmpty() const\n{\n\treturn _inProgress.size() == 0;\n}\n\t\nFrameCountType ActionsInProgress::nextActionFinishTime() const\n{\n\tBOSS_ASSERT(_inProgress.size() > 0, \"Set is empty\");\n\t\t\n\treturn _inProgress[_inProgress.size()-1]._time;\n}\n\t\nconst UnitCountType ActionsInProgress::size() const\n{\n\treturn _inProgress.size();\n}\n\t\nFrameCountType ActionsInProgress::getLastFinishTime() const\n{\n\tif (_inProgress.size() == 0)\n\t{\n\t\treturn 0;\n\t}\n\t\t\n\treturn _inProgress[0]._time;\n}\n\t\nFrameCountType ActionsInProgress::nextActionFinishTime(const ActionType & a) const\n{\n\tBOSS_ASSERT(numInProgress(a) > 0, \"Tried to get next finish time from empty set\");\n\t\t\n\tfor (size_t i=_inProgress.size()-1; i >=0; --i)\n\t{\n\t\tif (_inProgress[i]._action == a)\n\t\t{\n\t\t\treturn _inProgress[i]._time;\n\t\t}\n\t}\n\t\t\n    BOSS_ASSERT(false, \"Next Action Finish Time didn't find anything\");\n\n\treturn -1;\n}\n\nFrameCountType ActionsInProgress::nextBuildingFinishTime() const\n{\n    BOSS_ASSERT(_inProgress.size() > 0, \"There are no buildings in progress\");\n\n\tfor (size_t i(0); i<_inProgress.size(); ++i)\n\t{\n        size_t ri = _inProgress.size()-1-i;\n\t\tif (_inProgress[ri]._action.isBuilding() && !_inProgress[ri]._action.isAddon() && !_inProgress[ri]._action.isMorphed())\n\t\t{\n\t\t\treturn _inProgress[ri]._time;\n\t\t}\n\t}\n\n    for (size_t i(0); i<_inProgress.size(); ++i)\n\t{\n        size_t ri = _inProgress.size()-1-i;\n\t\tstd::cout << _inProgress[ri]._action.getName() << std::endl;\n\t}\n\t\t\n    BOSS_ASSERT(false, \"There were no buildings in progress\");\n\n\treturn -1;\n}\n\t\nconst ActionType & ActionsInProgress::getAction(const UnitCountType i) const\n{\n    BOSS_ASSERT(i < (int)_inProgress.size(), \"index out of bounds\");\n\n\treturn _inProgress[i]._action;\n}\n\t\nFrameCountType ActionsInProgress::getTime(const UnitCountType i) const\n{\n    BOSS_ASSERT(i < (int)_inProgress.size(), \"index out of bounds\");\n\n\treturn _inProgress[i]._time;\n}\n\t\nconst ActionType & ActionsInProgress::nextAction() const\n{\n\tBOSS_ASSERT(_inProgress.size() > 0, \"Tried to get nextAction() from empty set\");\n\t\n\treturn _inProgress[_inProgress.size()-1]._action;\n}\n\t\nvoid ActionsInProgress::printActionsInProgress()\n{\n\tfor (int i(0); i<Constants::MAX_ACTIONS; ++i)\n\t{\n\t\tif (_numProgress[i] > 0)\n\t\t{\n\t\t\tprintf(\"Progress: %d %d %d\\n\", i, (int)_numProgress[i], (int)_inProgress[i]._time);\n\t\t}\n\t}\n}\n\n//bool ActionsInProgress::willBuildingFinsishBeforeRefinery()\n//{\n//    int firstBuildingIndex = 100000;\n//    int lastRefineryIndex = 0;\n//\n//    for (size_t i(0); i < _inProgress.size(); ++i)\n//    {\n//        if (_inProgress.)\n//    }\n//}\n\t\nFrameCountType ActionsInProgress::whenActionsFinished(const PrerequisiteSet & actions) const\n{\n\tBOSS_ASSERT(!actions.isEmpty(), \"Action set is empty!\");\n\t\n\t// the maximum of the (minimums for each action)\n\tint totalMax = 0;\n\t\n\t// if there are actions still left\n\tfor (UnitCountType uc(0); uc < (int)actions.size(); ++uc)\n\t{\t\n\t\t// pop an action off the set\n\t\tconst ActionType & a = actions.getActionType(uc);\n\t\t\t\n\t\t// define a new minimum\n\t\tint actionMin = std::numeric_limits<int>::max();\n\t\t\n\t\t// for each unit in our progress vector\n\t\tfor (size_t i(0); i<_inProgress.size(); ++i) \n\t\t{\n\t\t\t// if the action matches\n\t\t\tif (_inProgress[i]._action == a) \n\t\t\t{\n\t\t\t\t// check to see if we have a new minimum\n\t\t\t\tactionMin = (_inProgress[i]._time < actionMin) ? _inProgress[i]._time : actionMin;\n\t\t\t}\n\t\t}\n\t\t\t\n\t\t// if we found a new minimum\n\t\tif (actionMin < std::numeric_limits<int>::max())\n\t\t{\n\t\t\t// check to see if we have a new maximum\n\t\t\ttotalMax = (actionMin > totalMax) ? actionMin : totalMax;\n\t\t}\n\t}\n\t\t\n\t// return the new maximum\n\treturn totalMax;\n}\n\t"
  },
  {
    "path": "BOSS/source/ActionInProgress.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include <string.h>\n#include <queue>\n#include <algorithm>\n#include <limits>\n\n#include \"PrerequisiteSet.h\"\n#include <math.h>\n#include \"Array.hpp\"\n#include \"ActionType.h\"\n\nnamespace BOSS\n{\n\nclass ActionInProgress\n{\n\npublic:\n\n\tActionType \t\t_action;\n\tFrameCountType \t_time;\n\t\n\tActionInProgress() \n        : _time(0) \n    {  \n    }\n\t\n    ActionInProgress(const ActionType & action, FrameCountType t) \n        : _action(action)\n        , _time(t) \n    {\n    }\n\t\n\n\t// we want to sort these in descending order in ActionsInProgress\n\tconst bool operator < (const ActionInProgress & rhs) const \n    { \n        return _time > rhs._time; \n    }\n};\n\nclass ActionsInProgress\n{\n\tVec<ActionInProgress, Constants::MAX_PROGRESS>\t    _inProgress;\n    Vec<UnitCountType, Constants::MAX_ACTIONS>          _numProgress;\t// how many of each unit are in progress\n\t\npublic:\n\n\tActionsInProgress();\n\t\n\tUnitCountType operator [] (const ActionType & action) const;\n\tUnitCountType numInProgress(const ActionType & action) const;\n\t\n\tvoid addAction(const ActionType & a, int time);\n\tvoid popNextAction();\n\tbool isEmpty() const;\n\tconst UnitCountType size() const;\n\n    //bool willBuildingFinsishBeforeRefinery();\n\t\n\tFrameCountType getLastFinishTime() const;\n\tFrameCountType nextActionFinishTime(const ActionType & a) const;\n\tFrameCountType getTime(const UnitCountType i) const;\n\tFrameCountType nextActionFinishTime() const;\n    FrameCountType nextBuildingFinishTime() const;\n\tFrameCountType whenActionsFinished(const PrerequisiteSet & actions) const;\n\t\n\tconst ActionType & getAction(const UnitCountType index) const;\n\tconst ActionType & nextAction() const;\n\t\n\tvoid printActionsInProgress();\n};\n}\n\n"
  },
  {
    "path": "BOSS/source/ActionSet.cpp",
    "content": "#include \"ActionSet.h\"\n\nusing namespace BOSS;\n\nActionSet::ActionSet()\n{\n\n}\n\nconst size_t ActionSet::size() const\n{\n    return _actionTypes.size();\n}\n\nconst bool ActionSet::isEmpty() const\n{\n    return size() == 0;\n}\n\nconst ActionType & ActionSet::operator [] (const size_t & index) const\n{\n    return _actionTypes[index];\n}\n\nActionType & ActionSet::operator [] (const size_t & index)\n{\n    return _actionTypes[index];\n}\n\nconst bool ActionSet::contains(const ActionType & action) const\n{\n    return _actionTypes.contains(action);\n}\n\nvoid ActionSet::add(const ActionType & action)\n{\n    _actionTypes.push_back(action);\n}\n\nvoid ActionSet::remove(const ActionType & action)\n{\n    for (size_t i(0); i<_actionTypes.size(); ++i)\n    {\n        if (_actionTypes[i] == action)\n        {\n            _actionTypes.removeByShift(i);\n            return;\n        }\n    }\n}\n\nvoid ActionSet::clear()\n{\n    _actionTypes.clear();\n}"
  },
  {
    "path": "BOSS/source/ActionSet.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Constants.h\"\n#include \"Array.hpp\"\n#include \"ActionType.h\"\n\nnamespace BOSS\n{\n\nclass ActionSet\n{\n\tVec<ActionType, Constants::MAX_ACTION_TYPES> _actionTypes;\n\npublic:\n\n\tActionSet();\n\n    const size_t size() const;\n    const bool isEmpty() const;\n    const bool contains(const ActionType & type) const;\n\n    const ActionType & operator [] (const size_t & index) const;\n    ActionType & operator [] (const size_t & index);\n\n    void add(const ActionType & action);\n    void addAllActions(const RaceID & race);\n    void remove(const ActionType & action);\n    void clear();\n};\n\n}"
  },
  {
    "path": "BOSS/source/ActionType.cpp",
    "content": "#include \"ActionType.h\"\n\n#include \"ActionTypeData.h\"\n#include \"ActionSet.h\"\n\nusing namespace BOSS;\n\nActionType::ActionType()\n: _race(Races::None)\n, _id(0)\n{\n\n}\n\nActionType::ActionType(const RaceID & race, const ActionID & id)\n: _race(race)\n, _id(id)\n{\n\n}\n\nActionType::ActionType(const ActionType & type)\n: _race(type._race)\n, _id(type._id)\n{\n\n}\n\nActionType::ActionType(const BWAPI::UnitType & type)\n    : _race(ActionTypeData::GetRaceID(type.getRace()))\n    , _id(ActionTypeData::GetActionID(type))\n{\n\n}\n\nActionType::ActionType(const BWAPI::UpgradeType & type)\n    : _race(ActionTypeData::GetRaceID(type.getRace()))\n    , _id(ActionTypeData::GetActionID(type))\n{\n\n}\n\nActionType::ActionType(const BWAPI::TechType & type)\n    : _race(ActionTypeData::GetRaceID(type.getRace()))\n    , _id(ActionTypeData::GetActionID(type))\n{\n\n}\n\nActionType & ActionType::operator = (const ActionType & rhs)\n{\n    if (this != &rhs)\n    {\n        new (this) ActionType(rhs);\n    }\n\n    return *this;\n}   \n\nconst ActionID              ActionType::ID()                    const { return _id; }\nconst RaceID                ActionType::getRace()               const { return _race; }\n\nBWAPI::UnitType             ActionType::getUnitType()           const { return ActionTypeData::GetActionTypeData(_race, _id).getUnitType(); }\nBWAPI::UpgradeType          ActionType::getUpgradeType()        const { return ActionTypeData::GetActionTypeData(_race, _id).getUpgradeType(); }\nBWAPI::TechType             ActionType::getTechType()           const { return ActionTypeData::GetActionTypeData(_race, _id).getTechType(); }\n\nBWAPI::UnitType             ActionType::whatBuildsBWAPI()       const { return ActionTypeData::GetActionTypeData(_race, _id).whatBuildsBWAPI(); }\nActionType\t\t            ActionType::whatBuildsActionType()  const { return ActionTypes::GetActionType(_race, whatBuildsAction()); }\nActionID                    ActionType::whatBuildsAction()      const { return ActionTypeData::GetActionTypeData(_race, _id).whatBuildsAction(); }\t\n\nconst PrerequisiteSet &     ActionType::getPrerequisites()      const { return ActionTypeData::GetActionTypeData(_race, _id).getPrerequisites(); }\nconst PrerequisiteSet &     ActionType::getRecursivePrerequisites()      const { return ActionTypeData::GetActionTypeData(_race, _id).getRecursivePrerequisites(); }\nint                         ActionType::getType()               const { return ActionTypeData::GetActionTypeData(_race, _id).getType(); }\n\t\nconst std::string &         ActionType::getName()               const { return ActionTypeData::GetActionTypeData(_race, _id).getName(); }\nconst std::string &         ActionType::getShortName()          const { return ActionTypeData::GetActionTypeData(_race, _id).getShortName(); }\nconst std::string &         ActionType::getMetaName()           const { return ActionTypeData::GetActionTypeData(_race, _id).getMetaName(); }\n\t\nFrameCountType              ActionType::buildTime()             const { return ActionTypeData::GetActionTypeData(_race, _id).buildTime(); }\nResourceCountType           ActionType::mineralPrice()          const { return ActionTypeData::GetActionTypeData(_race, _id).mineralPrice(); }\nResourceCountType           ActionType::mineralPriceScaled()    const { return ActionTypeData::GetActionTypeData(_race, _id).mineralPriceScaled(); }\nResourceCountType           ActionType::gasPrice()              const { return ActionTypeData::GetActionTypeData(_race, _id).gasPrice(); }\nResourceCountType           ActionType::gasPriceScaled()        const { return ActionTypeData::GetActionTypeData(_race, _id).gasPriceScaled(); }\nSupplyCountType             ActionType::supplyRequired()        const { return ActionTypeData::GetActionTypeData(_race, _id).supplyRequired(); }\nSupplyCountType             ActionType::supplyProvided()        const { return ActionTypeData::GetActionTypeData(_race, _id).supplyProvided(); }\nUnitCountType               ActionType::numProduced()           const { return ActionTypeData::GetActionTypeData(_race, _id).numProduced(); }\n\nbool                        ActionType::isAddon()               const { return ActionTypeData::GetActionTypeData(_race, _id).isAddon(); }\nbool                        ActionType::isRefinery()            const { return ActionTypeData::GetActionTypeData(_race, _id).isRefinery(); }\nbool                        ActionType::isWorker()              const { return ActionTypeData::GetActionTypeData(_race, _id).isWorker(); }\nbool                        ActionType::isBuilding()            const { return ActionTypeData::GetActionTypeData(_race, _id).isBuilding(); }\nbool                        ActionType::isResourceDepot()       const { return ActionTypeData::GetActionTypeData(_race, _id).isResourceDepot(); }\nbool                        ActionType::isSupplyProvider()      const { return ActionTypeData::GetActionTypeData(_race, _id).isSupplyProvider(); }\nbool                        ActionType::isUnit()                const { return ActionTypeData::GetActionTypeData(_race, _id).isUnit(); }\nbool                        ActionType::isTech()                const { return ActionTypeData::GetActionTypeData(_race, _id).isTech(); }\nbool                        ActionType::isUpgrade()             const { return ActionTypeData::GetActionTypeData(_race, _id).isUpgrade(); }\nbool                        ActionType::whatBuildsIsBuilding()  const { return ActionTypeData::GetActionTypeData(_race, _id).whatBuildsIsBuilding(); }\nbool                        ActionType::whatBuildsIsLarva()     const { return ActionTypeData::GetActionTypeData(_race, _id).whatBuildsIsLarva(); }\nbool                        ActionType::canProduce()            const { return ActionTypeData::GetActionTypeData(_race, _id).canProduce(); }\nbool                        ActionType::requiresAddon()         const { return ActionTypeData::GetActionTypeData(_race, _id).requiresAddon(); }\nbool                        ActionType::isMorphed()             const { return ActionTypeData::GetActionTypeData(_race, _id).isMorphed(); }\n\nbool ActionType::canBuild(const ActionType & t) const \n{ \n    if (t.getRace() != getRace())\n    {\n        return false;\n    }\n\n    static const ActionType & Hatchery      = ActionTypes::GetActionType(\"Zerg_Hatchery\");\n    static const ActionType & Lair          = ActionTypes::GetActionType(\"Zerg_Lair\");\n    static const ActionType & Hive          = ActionTypes::GetActionType(\"Zerg_Hive\");\n    static const ActionType & Spire         = ActionTypes::GetActionType(\"Zerg_Spire\");\n    static const ActionType & GreaterSpire  = ActionTypes::GetActionType(\"Zerg_Greater_Spire\");\n\n    const ActionType & whatBuilds = t.whatBuildsActionType();\n\n    if (whatBuilds == *this)\n    {\n        return true;\n    }\n    \n    // if this is a zerg unit which is not morphed\n    // then an upgraded version of the building can construct it\n    // morphed units need the *exact* unit to morph from which is covered above\n    if ((t.getRace() == Races::Zerg) && !t.isMorphed())\n    {\n        if (whatBuilds == Hatchery)\n        {\n            return (*this == Lair || *this == Hive);\n        }\n        else if (whatBuilds == Lair)\n        {\n            return (*this == Hive);\n        }\n        else if (whatBuilds == Spire)\n        {\n            return (*this == GreaterSpire);\n        }\n    }\n    \n    return false;\n}\n\nActionType                  ActionType::requiredAddonType()     const { return ActionTypes::GetActionType(_race, ActionTypeData::GetActionTypeData(_race, _id).requiredAddonID()); }\n\nconst bool ActionType::operator == (const ActionType & rhs)     const { return _race == rhs._race && _id == rhs._id; }\nconst bool ActionType::operator != (const ActionType & rhs)     const { return _race != rhs._race || _id != rhs._id; }\nconst bool ActionType::operator <  (const ActionType & rhs)     const { return _id < rhs._id; }\n\nnamespace BOSS\n{\nnamespace ActionTypes\n{\n    std::vector< std::vector<ActionType> > allActionTypes;\n    std::map<std::string, ActionType> nameMap;\n    std::vector<ActionType>  workerActionTypes;\n    std::vector<ActionType>  refineryActionTypes;\n    std::vector<ActionType>  supplyProviderActionTypes;\n    std::vector<ActionType>  resourceDepotActionTypes;\n    size_t numActionTypes[Races::NUM_RACES] = {0, 0, 0};\n\n    void init()\n    {\n        for (RaceID r(0); r < Races::NUM_RACES; ++r)\n        {\n            allActionTypes.push_back(std::vector<ActionType>());\n            for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(r); ++a)\n            {\n                ActionType type(r, a);\n                allActionTypes[r].push_back(type);\n\n                // add the name with spaces\n                nameMap[type.getName()] = type;\n\n                // add the name with underscores\n                std::string name = type.getName();\n                for (size_t i(0); i<name.size(); ++i)\n\t            {\n\t\t            if (name[i] == ' ')\n\t\t            {\n\t\t\t            name[i] = '_';\n\t\t            }\n\t            }\n                nameMap[name] = type;\n            }\n        }\n\n        workerActionTypes.push_back(ActionTypes::GetActionType(\"Protoss_Probe\"));\n        refineryActionTypes.push_back(ActionTypes::GetActionType(\"Protoss_Assimilator\"));\n        supplyProviderActionTypes.push_back(ActionTypes::GetActionType(\"Protoss_Pylon\"));\n        resourceDepotActionTypes.push_back(ActionTypes::GetActionType(\"Protoss_Nexus\"));\n\n        workerActionTypes.push_back(ActionTypes::GetActionType(\"Terran_SCV\"));\n        refineryActionTypes.push_back(ActionTypes::GetActionType(\"Terran_Refinery\"));\n        supplyProviderActionTypes.push_back(ActionTypes::GetActionType(\"Terran_Supply_Depot\"));\n        resourceDepotActionTypes.push_back(ActionTypes::GetActionType(\"Terran_Command_Center\"));\n\n        workerActionTypes.push_back(ActionTypes::GetActionType(\"Zerg_Drone\"));\n        refineryActionTypes.push_back(ActionTypes::GetActionType(\"Zerg_Extractor\"));\n        supplyProviderActionTypes.push_back(ActionTypes::GetActionType(\"Zerg_Overlord\"));\n        resourceDepotActionTypes.push_back(ActionTypes::GetActionType(\"Zerg_Hatchery\"));\n    }\n\n    const ActionType & GetWorker(const RaceID raceID)\n    {\n        return workerActionTypes[raceID];\n    }\n\n    const ActionType & GetSupplyProvider(const RaceID raceID)\n    {\n        return supplyProviderActionTypes[raceID];\n    }\n\n    const ActionType & GetRefinery(const RaceID raceID)\n    {\n        return refineryActionTypes[raceID];\n    }\n\n    const ActionType & GetResourceDepot(const RaceID raceID)\n    {\n        return resourceDepotActionTypes[raceID];\n    }\n\n    //const ActionType & GetActionType(const std::string & name)\n    //{\n    //    std::map<\n    //    auto it = nameMap.find(name);\n\n    //    BOSS_ASSERT(it != nameMap.end(), \"ActionType::getActionType() error: ActionType name not found: %s\", name.c_str());\n\n    //    return it->second;\n    //}\n\n    const ActionType & GetActionType(const RaceID & race, const ActionID & id)\n    {\n        BOSS_ASSERT(race < Races::NUM_RACES && id < (int)ActionTypes::GetAllActionTypes(race).size(), \"Race / Action does not exist\");\n\n        return allActionTypes[race][id];\n    }\n\n    const ActionType & GetActionType(const std::string & name)\n    {\n        BOSS_ASSERT(TypeExists(name), \"ActionType name not found: %s\", name.c_str());\n\n        return nameMap[name];\n    }\n\n    const bool TypeExists(const std::string & name) \n    {\n        return nameMap.find(name) != nameMap.end();\n    }\n\n    const std::vector<ActionType> & GetAllActionTypes(const RaceID race)\n    {\n        BOSS_ASSERT(race < Races::NUM_RACES, \"Race is not valid: %d\", race);\n\n        return allActionTypes[race];\n    }\n\n    const bool TypeExists(const BWAPI::UnitType & type) \n    {\n        const RaceID raceID = ActionTypeData::GetRaceID(type.getRace());\n\n        if (raceID >= Races::NUM_RACES)\n        {\n            return false;\n        }\n\n        for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a)\n        {\n            const ActionType & data = GetActionType(raceID, a);\n            if (data.isUnit() && data.getUnitType() == type)\n            {\n                return true;\n            }\n        }\n   \n\t    return false;\n    }\n\n    const bool TypeExists(const BWAPI::UpgradeType & type) \n    {\n        const RaceID raceID = ActionTypeData::GetRaceID(type.getRace());\n\n        if (raceID >= Races::NUM_RACES)\n        {\n            return false;\n        }\n\n        for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a)\n        {\n            const ActionType & data = GetActionType(raceID, a);\n            if (data.isUpgrade() && data.getUpgradeType() == type)\n            {\n                return true;\n            }\n        }\n   \n\t    return false;\n    }\n\n    const bool TypeExists(const BWAPI::TechType & type) \n    {\n        const RaceID raceID = ActionTypeData::GetRaceID(type.getRace());\n\n        if (raceID >= Races::NUM_RACES)\n        {\n            return false;\n        }\n        \n        for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a)\n        {\n            const ActionType & data = GetActionType(raceID, a);\n            if (data.isTech() && data.getTechType() == type)\n            {\n                return true;\n            }\n        }\n   \n\t    return false;\n    }\n\n    ActionType None(Races::None, 0);\n\n //   ActionType Protoss_Probe                (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\t\t\t\n\t//ActionType Protoss_Pylon                (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\n\t//ActionType Protoss_Assimilator          (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\t\t\t\n\t//ActionType Protoss_Gateway              (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\t\n\t//ActionType Protoss_Nexus                (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\t\t\n\t//ActionType Protoss_Zealot               (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\t\n\t//ActionType Protoss_Cybernetics_Core     (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\n\t//ActionType Protoss_Dragoon              (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\t\t\n\t//ActionType Protoss_Singularity_Charge   (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\n\t//ActionType Protoss_Forge                (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\t\t\n\t//ActionType Protoss_Photon_Cannon        (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\n\t//ActionType Protoss_High_Templar         (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\t\n\t//ActionType Protoss_Citadel_of_Adun      (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\n\t//ActionType Protoss_Templar_Archives     (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\t\n\t//ActionType Protoss_Robotics_Facility    (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\n\t//ActionType Protoss_Robotics_Support_Bay (Races::Protoss, numActionTypes[Races::Protoss]++);\t\t\n\t//ActionType Protoss_Observatory          (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Stargate             (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Scout                (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Arbiter_Tribunal     (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Arbiter              (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Shield_Battery       (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Dark_Templar         (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Shuttle              (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Reaver               (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Observer             (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Corsair              (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Fleet_Beacon         (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Carrier              (Races::Protoss, numActionTypes[Races::Protoss]++);\n\t//ActionType Protoss_Leg_Enhancements     (Races::Protoss, numActionTypes[Races::Protoss]++);\n //   //ActionType Protoss_Archon(Races::Protoss, 31);\n\n //   ActionType Terran_SCV(Races::Terran, 0);\n\t//ActionType Terran_Supply_Depot(Races::Terran, 1);\n\t//ActionType Terran_Command_Center(Races::Terran, 2);\n\t//ActionType Terran_Barracks(Races::Terran, 3);\n\t//ActionType Terran_Refinery(Races::Terran, 4);\n\t//ActionType Terran_Marine(Races::Terran, 5);\n\t//ActionType Terran_Academy(Races::Terran, 6);\n\t//ActionType Terran_Stim_Packs(Races::Terran, 7);\n\t//ActionType Terran_Medic(Races::Terran, 8);\n\t//ActionType Terran_Factory(Races::Terran, 9);\n\t//ActionType Terran_Starport(Races::Terran, 10);\n\t//ActionType Terran_Wraith(Races::Terran, 11);\n //   ActionType Terran_Siege_Tank(Races::Terran, 12);\n //   ActionType Terran_Machine_Shop(Races::Terran, 13);\n //   ActionType Terran_Tank_Siege_Mode(Races::Terran, 14);\n //   ActionType Terran_Cloaking_Field(Races::Terran, 15);\n //   ActionType Terran_Control_Tower(Races::Terran, 16);\n //   ActionType Terran_Battlecruiser(Races::Terran, 17);\n //   ActionType Terran_Physics_Lab(Races::Terran, 18);\n //   ActionType Terran_Science_Facility(Races::Terran, 19);\n //   ActionType Terran_Science_Vessel(Races::Terran, 20);\n //   ActionType Terran_Vulture(Races::Terran, 21);\n //   ActionType Terran_Goliath(Races::Terran, 22);\n //   ActionType Terran_Firebat(Races::Terran, 23);\n //   ActionType Terran_Armory(Races::Terran, 24);\n //   ActionType Terran_Ghost(Races::Terran, 25);\n //   ActionType Terran_Covert_Ops(Races::Terran, 26);\n //   ActionType Terran_Comsat_Station(Races::Terran, 27);\n //   ActionType Terran_Bunker(Races::Terran, 28);\n //   ActionType Terran_Valkyrie(Races::Terran, 29);\n //   \n //   ActionType Zerg_Drone(Races::Zerg, 0);\n\t//ActionType Zerg_Overlord(Races::Zerg, 1);\n\t//ActionType Zerg_Hatchery(Races::Zerg, 2);\n\t//ActionType Zerg_Spawning_Pool(Races::Zerg, 3);\n\t//ActionType Zerg_Zergling(Races::Zerg, 4);\n\t//ActionType Zerg_Extractor(Races::Zerg, 5);\n\t//ActionType Zerg_Lair(Races::Zerg, 6);\n\t//ActionType Zerg_Hydralisk_Den(Races::Zerg, 7);\n\t//ActionType Zerg_Spire(Races::Zerg, 8);\n\t//ActionType Zerg_Hydralisk(Races::Zerg, 9);\n\t//ActionType Zerg_Mutalisk(Races::Zerg, 10);\n //   ActionType Zerg_Larva(Races::Zerg, 11);\n //   ActionType Zerg_Hive(Races::Zerg, 12);\n //   ActionType Zerg_Greater_Spire(Races::Zerg, 13);\n //   ActionType Zerg_Guardian(Races::Zerg, 14);\n //   ActionType Zerg_Defiler(Races::Zerg, 15);\n //   ActionType Zerg_Defiler_Mound(Races::Zerg, 16);\n //   ActionType Zerg_Devourer(Races::Zerg, 17);\n //   ActionType Zerg_Scourge(Races::Zerg, 18);\n //   ActionType Zerg_Queen(Races::Zerg, 19);\n //   ActionType Zerg_Queens_Nest(Races::Zerg, 20);\n //   ActionType Zerg_Ultralisk(Races::Zerg, 21);\n //   ActionType Zerg_Ultralisk_Cavern(Races::Zerg, 22);\n //   ActionType Zerg_Creep_Colony(Races::Zerg, 23);\n //   ActionType Zerg_Sunken_Colony(Races::Zerg, 24);\n //   ActionType Zerg_Spore_Colony(Races::Zerg, 25);\n //   ActionType Zerg_Evolution_Chamber(Races::Zerg, 26);\n //   ActionType Zerg_Lurker(Races::Zerg, 27);\n //   ActionType Zerg_Lurker_Aspect(Races::Zerg, 28);\n}\n}"
  },
  {
    "path": "BOSS/source/ActionType.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace BOSS\n{\n\nclass PrerequisiteSet;\n\nclass ActionType\n{\n    const ActionID\t    _id;\n    const RaceID        _race;\n\npublic:\n\t\n    ActionType();\n    ActionType(const RaceID & race, const ActionID & id);\n    ActionType(const ActionType & type);\n    ActionType(const BWAPI::UnitType & type);\n    ActionType(const BWAPI::UpgradeType & type);\n    ActionType(const BWAPI::TechType & type);\n\n    ActionType & operator = (const ActionType & rhs);\n\n    const ActionID              ID()                    const;\n    const RaceID                getRace()               const;\n\n    BWAPI::UnitType             getUnitType()           const;\n\tBWAPI::UnitType             whatBuildsBWAPI()       const;\n    ActionType                  whatBuildsActionType()  const;\n\tBWAPI::UpgradeType          getUpgradeType()        const;\n\tBWAPI::TechType             getTechType()           const;\n\t\n\tActionID                    whatBuildsAction()      const;\t\n\tconst PrerequisiteSet &     getPrerequisites()      const;\n    const PrerequisiteSet &     getRecursivePrerequisites()      const;\n\tint                         getType()               const;\n\t\n\tconst std::string &         getName()               const;\n    const std::string &         getShortName()          const;\n\tconst std::string &         getMetaName()           const;\n\t\n\tFrameCountType              buildTime()             const;\n\tResourceCountType           mineralPrice()          const;\n\tResourceCountType           mineralPriceScaled()    const;\n\tResourceCountType           gasPrice()              const;\n\tResourceCountType           gasPriceScaled()        const;\n\tSupplyCountType             supplyRequired()        const;\n\tSupplyCountType             supplyProvided()        const;\n\tUnitCountType               numProduced()           const;\n\n\tbool                        isRefinery()            const;\n\tbool                        isWorker()              const;\n\tbool                        isBuilding()            const;\n\tbool                        isResourceDepot()       const;\n\tbool                        isSupplyProvider()      const;\n\tbool                        isUnit()                const;\n\tbool                        isTech()                const;\n\tbool                        isUpgrade()             const;\n\tbool                        whatBuildsIsBuilding()  const;\n\tbool                        whatBuildsIsLarva()     const;\n\tbool                        canProduce()            const;\n\tbool                        canAttack()             const;\n    bool                        isAddon()               const;\n    bool                        requiresAddon()         const;\n    bool                        isMorphed()             const;\n    bool                        canBuild(const ActionType & t) const;\n    ActionType                  requiredAddonType()     const;\n\n    const bool operator == (const ActionType & rhs)     const;\n    const bool operator != (const ActionType & rhs)     const;\n    const bool operator <  (const ActionType & rhs)     const;\n};\n\nclass ActionSet;\n\nnamespace ActionTypes\n{\n    void init();\n    const std::vector<ActionType> &  GetAllActionTypes(const RaceID race);\n    const ActionType & GetActionType(const RaceID & race, const ActionID & id);\n    const ActionType & GetWorker(const RaceID raceID);\n    const ActionType & GetSupplyProvider(const RaceID raceID);\n    const ActionType & GetRefinery(const RaceID raceID);\n    const ActionType & GetResourceDepot(const RaceID raceID);\n    const ActionType & GetActionType(const std::string & name);\n    const bool         TypeExists(const std::string & name);\n    const bool         TypeExists(const BWAPI::UnitType & a);\n    const bool         TypeExists(const BWAPI::TechType & a);\n    const bool         TypeExists(const BWAPI::UpgradeType & a);\n\n    extern ActionType None;\n\n}\n}"
  },
  {
    "path": "BOSS/source/ActionTypeData.cpp",
    "content": "#include \"ActionTypeData.h\"\n#include \"ActionType.h\"\n\nusing namespace BOSS;\n\n// default constructor, should never be called\nActionTypeData::ActionTypeData() \n    : type(Error) \n{ \n   \n}\n\n// UnitType constructor\nActionTypeData::ActionTypeData(BWAPI::UnitType t, const ActionID id) \n\t: type                      (UnitType)\n\t, unit                      (t)\n    , raceID                    (GetRaceID(t.getRace()))\n\t, actionID                  (id)\n\t, mineralPriceVal           (t.mineralPrice() * Constants::RESOURCE_SCALE)\n\t, gasPriceVal               (t.gasPrice() * Constants::RESOURCE_SCALE)\n\t, supplyRequiredVal         (t.supplyRequired())\n\t, supplyProvidedVal         (t.supplyProvided())\n\t, buildTimeVal              (t.buildTime())\n\t, numberProduced            (1)\n\t, name                      (t.getName())\n\t, metaName                  (t.getName())\n\t, building                  (t.isBuilding())\n\t, worker                    (t.isWorker())\n\t, refinery                  (t.isRefinery())\n\t, resourceDepot             (t.isResourceDepot())\n\t, supplyProvider            (t.supplyProvided() > 0 && !t.isResourceDepot())\n\t, canProduceBool            (t.isBuilding() && t.canProduce())\n\t, canAttackBool             (t.canAttack())\n\t, whatBuildsUnitType        (t.whatBuilds().first)\n    , addon                     (t.isAddon())\n    , morphed                   (false)\n    , reqAddon                  (false)\n    , reqAddonID                (0)\n{\n\tif (t == BWAPI::UnitTypes::Zerg_Zergling || t == BWAPI::UnitTypes::Zerg_Scourge)\n\t{\n\t\tnumberProduced = 2;\n\t}\n\n    if (t == BWAPI::UnitTypes::Zerg_Lair ||\n        t == BWAPI::UnitTypes::Zerg_Hive ||\n        t == BWAPI::UnitTypes::Zerg_Greater_Spire ||\n        t == BWAPI::UnitTypes::Zerg_Lurker ||\n        t == BWAPI::UnitTypes::Zerg_Guardian ||\n        t == BWAPI::UnitTypes::Zerg_Sunken_Colony ||\n        t == BWAPI::UnitTypes::Zerg_Spore_Colony)\n    {\n        morphed = true;\n    }\n\n    setShortName();\n}\n\n// UpgradeType action\nActionTypeData::ActionTypeData(BWAPI::UpgradeType t, const ActionID id) \n\t: type(UpgradeType)\n\t, upgrade(t)\n\t, actionID(id)\n    , raceID(GetRaceID(t.getRace()))\n\t, mineralPriceVal(t.mineralPrice() * Constants::RESOURCE_SCALE)\n\t, gasPriceVal(t.gasPrice() * Constants::RESOURCE_SCALE)\n\t, supplyRequiredVal(0)\n\t, supplyProvidedVal(0)\n\t, buildTimeVal(t.upgradeTime())\n\t, numberProduced(1)\n\t, name(t.getName())\n\t, metaName(t.getName())\n\t, building(false)\n\t, worker(false)\n\t, refinery(false)\n\t, resourceDepot(false)\n\t, supplyProvider(false)\n\t, canProduceBool(false)\n\t, canAttackBool(false)\n\t, whatBuildsUnitType(t.whatUpgrades())\n    , addon(false)\n    , reqAddon(false)\n    , reqAddonID(0)\n    , morphed(false)\n{\n    setShortName();\n}\n\n// TechType action\nActionTypeData::ActionTypeData(BWAPI::TechType t, const ActionID id)\n\t: type(TechType)\n\t, tech(t)\n\t, actionID(id)\n    , raceID(GetRaceID(t.getRace()))\n\t, mineralPriceVal(t.mineralPrice() * Constants::RESOURCE_SCALE)\n\t, gasPriceVal(t.gasPrice() * Constants::RESOURCE_SCALE)\n\t, supplyRequiredVal(0)\n\t, supplyProvidedVal(0)\n\t, buildTimeVal(t.researchTime())\n\t, numberProduced(1)\n\t, name(t.getName())\n\t, metaName(t.getName())\n\t, building(false)\n\t, worker(false)\n\t, refinery(false)\n\t, resourceDepot(false)\n\t, supplyProvider(false)\n\t, canProduceBool(false)\n\t, canAttackBool(false)\n\t, whatBuildsUnitType(t.whatResearches())\n    , addon(false)\n    , reqAddon(false)\n    , reqAddonID(0)\n    , morphed(false)\n{\n    setShortName();\n}\n\nRaceID              ActionTypeData::getRaceID()             const   { return raceID; }\nActionID            ActionTypeData::getActionID()           const   { return actionID; }\n\nBWAPI::UnitType\t\tActionTypeData::getUnitType()\t\t\tconst\t{ return unit; }\nBWAPI::UnitType\t\tActionTypeData::whatBuildsBWAPI() \t\tconst\t{ return whatBuildsUnitType; }\nBWAPI::UpgradeType\tActionTypeData::getUpgradeType()\t\tconst\t{ return upgrade; }\nBWAPI::TechType\t\tActionTypeData::getTechType()\t\t\tconst\t{ return tech; }\n\t\nActionID            ActionTypeData::whatBuildsAction()\t\tconst\t{ return whatBuildsActionID; }\t\nint \t\t\t    ActionTypeData::getType() \t\t\t\tconst\t{ return type; }\n\t\nconst std::string &\tActionTypeData::getName() \t\t\t\tconst\t{ return name; }\nconst std::string &\tActionTypeData::getShortName() \t\t\tconst\t{ return shortName; }\nconst std::string &\tActionTypeData::getMetaName() \t\t\tconst\t{ return metaName; }\n\t\nFrameCountType \t\tActionTypeData::buildTime() \t\t\tconst\t{ return buildTimeVal; }\nResourceCountType\tActionTypeData::mineralPrice()\t\t\tconst\t{ return mineralPriceVal; }\nResourceCountType\tActionTypeData::mineralPriceScaled()\tconst\t{ return mineralPriceVal * 100; }\nResourceCountType\tActionTypeData::gasPrice()\t\t\t\tconst\t{ return gasPriceVal; }\nResourceCountType\tActionTypeData::gasPriceScaled()\t\tconst\t{ return gasPriceVal * 100; }\nSupplyCountType \tActionTypeData::supplyRequired() \t\tconst\t{ return supplyRequiredVal; }\nSupplyCountType\t\tActionTypeData::supplyProvided() \t\tconst\t{ return supplyProvidedVal; }\nUnitCountType \t\tActionTypeData::numProduced() \t\t\tconst\t{ return numberProduced; }\n\nbool\t\t\t\tActionTypeData::isRefinery() \t\t\tconst\t{ return refinery; }\nbool\t\t\t\tActionTypeData::isWorker() \t\t\t    const\t{ return worker;   }\nbool\t\t\t\tActionTypeData::isBuilding()\t\t\tconst\t{ return building; }\nbool\t\t\t\tActionTypeData::isResourceDepot()\t\tconst\t{ return resourceDepot; }\nbool\t\t\t\tActionTypeData::isSupplyProvider()\t\tconst\t{ return supplyProvider; }\nbool\t\t\t\tActionTypeData::isUnit()\t\t\t\tconst\t{ return type == UnitType; }\nbool\t\t\t\tActionTypeData::isTech()\t\t\t\tconst\t{ return type == TechType; }\nbool\t\t\t\tActionTypeData::isUpgrade()\t\t\t    const\t{ return type == UpgradeType; }\nbool\t\t\t\tActionTypeData::isAddon()\t\t\t    const\t{ return addon; }\nbool                ActionTypeData::isMorphed()             const   { return morphed; }\nbool                ActionTypeData::requiresAddon()         const   { return reqAddon; }\nActionID            ActionTypeData::requiredAddonID()       const   { return reqAddonID; }\n\t\nbool\t\t\t\tActionTypeData::whatBuildsIsBuilding()  const\t{ return whatBuildsIsBuildingBool; }\nbool\t\t\t\tActionTypeData::whatBuildsIsLarva() \tconst\t{ return whatBuildsIsLarvaBool; }\nbool\t\t\t\tActionTypeData::canProduce()\t\t\tconst\t{ return canProduceBool; }\nbool\t\t\t\tActionTypeData::canAttack()\t\t\t    const\t{ return canAttackBool; }\n\t\t\nvoid \t\t\t\tActionTypeData::setPrerequisites(const PrerequisiteSet & pre) \t{ prerequisites = pre; }\nvoid \t\t\t\tActionTypeData::setRecursivePrerequisites(const PrerequisiteSet & pre) \t{ recursivePrerequisites = pre; }\n\nbool                ActionTypeData::operator ==\t(const ActionTypeData & a) const { return actionID == a.actionID; }\nbool                ActionTypeData::operator <\t(const ActionTypeData & a) const { return actionID < a.actionID; }\n\nconst PrerequisiteSet & ActionTypeData::getPrerequisites() \tconst\t{ return prerequisites; }\nconst PrerequisiteSet & ActionTypeData::getRecursivePrerequisites() \tconst\t{ return recursivePrerequisites; }\n\t\nvoid ActionTypeData::setWhatBuildsActionID(const ActionID a, const bool wbib, const bool wbil)\n{\n\twhatBuildsActionID = a;\n\twhatBuildsIsBuildingBool = wbib;\n\twhatBuildsIsLarvaBool = wbil;\n}\n\nvoid ActionTypeData::setRequiredAddon(bool requiresAddon, const ActionID & id)\n{\n    reqAddon = requiresAddon;\n    reqAddonID = id;\n}\n\nvoid ActionTypeData::setShortName()\n{\n    std::string prefix = Races::GetRaceName(raceID);\n    shortName = name;\n\n    if (name.compare(0, prefix.size(), prefix) == 0)\n    {\n        shortName = name.substr(prefix.size()+1);\n    }\n}\n\n////////////////////////////////////////////////////////////\n// STATIC FUNCTIONS BELOW THIS POINT\n////////////////////////////////////////////////////////////\n\n//Vec< Vec<ActionTypeData, MAX_ACTION_TYPES>, Races::NUM_RACES> ActionTypeData::allActionTypeDataVec(Races::NUM_RACES);\n//\n//template <class ActionID> Vec< ActionID, Races::NUM_RACES >        ActionTypeData::numActionTypesVec(Races::NUM_RACES);\n//template <class ActionID>Vec< ActionTypeData, Races::NUM_RACES >  ActionTypeData::workerActionTypes(Races::NUM_RACES);\n//template <class ActionID>Vec< ActionTypeData, Races::NUM_RACES >  ActionTypeData::refineryActionTypes(Races::NUM_RACES);\n//template <class ActionID>Vec< ActionTypeData, Races::NUM_RACES >  ActionTypeData::supplyProviderActionTypes(Races::NUM_RACES);\n//template <class ActionID>Vec< ActionTypeData, Races::NUM_RACES >  ActionTypeData::resourceDepotActionTypes(Races::NUM_RACES);\n//template <class DependencyGraph>Vec< DependencyGraph, Races::NUM_RACES > ActionTypeData::dependencyGraphs(Races::NUM_RACES);\n\nstd::vector< std::vector<ActionTypeData> >  ActionTypeData::allActionTypeDataVec(Races::NUM_RACES);\n//std::vector<DependencyGraph>                ActionTypeData::dependencyGraphs(Races::NUM_RACES);\n\nvoid ActionTypeData::Init()\n{\n    // add all the legal actions\n    AddActions();\n\t\t\n\tCalculateWhatBuilds();\n\n\t// calculate the prerequisites of those actions\n\tAddPrerequisites();\n}\n\nvoid ActionTypeData::AddActions()\n{\n    std::string protoss(\"Protoss\");\n    std::string terran(\"Terran\");\n    std::string zerg(\"Zerg\");\\\n    std::vector<BWAPI::UnitType> unitTypes;\n    std::copy(BWAPI::UnitTypes::allUnitTypes().begin(), BWAPI::UnitTypes::allUnitTypes().end(), std::back_inserter(unitTypes));\n    \n    for (size_t i(0); i < unitTypes.size()-1; ++i)\n    {\n        for (size_t j(i+1); j < unitTypes.size(); ++j)\n        {\n            int costi = unitTypes[i].mineralPrice() + 2*unitTypes[i].gasPrice();\n            int costj = unitTypes[j].mineralPrice() + 2*unitTypes[j].gasPrice();\n\n            if (costi > costj)\n            {\n                std::swap(unitTypes[i], unitTypes[j]);\n            }\n        }\n    }\n\n    for (size_t i(0); i < unitTypes.size(); ++i)\n    {\n        const BWAPI::UnitType & type = unitTypes[i];\n\n        // blacklist temporary unit types which aren't buildable\n        if (type == BWAPI::UnitTypes::Zerg_Egg ||\n            type == BWAPI::UnitTypes::Zerg_Lurker_Egg ||\n            type == BWAPI::UnitTypes::Zerg_Cocoon ||\n            type == BWAPI::UnitTypes::Zerg_Infested_Terran ||\n            type == BWAPI::UnitTypes::Zerg_Infested_Command_Center ||\n            type == BWAPI::UnitTypes::Zerg_Broodling ||\n            type == BWAPI::UnitTypes::Protoss_Interceptor ||\n            type == BWAPI::UnitTypes::Protoss_Scarab ||\n            type == BWAPI::UnitTypes::Terran_Civilian ||\n            type == BWAPI::UnitTypes::Terran_Nuclear_Missile ||\n            type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine)\n        {\n            continue;\n        }\n\n        if (type.getName().compare(0, protoss.length(), protoss) == 0)\n        {\n            allActionTypeDataVec[Races::Protoss].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Protoss].size()));\n        }\n        else if (type.getName().compare(0, terran.length(), terran) == 0)\n        {\n            allActionTypeDataVec[Races::Terran].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Terran].size()));\n        }\n        else if (type.getName().compare(0, zerg.length(), zerg) == 0)\n        {\n            allActionTypeDataVec[Races::Zerg].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Zerg].size()));\n        }\n    }\n\n    for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes())\n    {\n        // blacklisted tech types we cannot create\n        if (type.whatResearches() == BWAPI::UnitTypes::None)\n        {\n            continue;\n        }\n\n        if (type.getRace() == BWAPI::Races::Protoss)\n        {\n            allActionTypeDataVec[Races::Protoss].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Protoss].size()));\n        }\n        else if (type.getRace() == BWAPI::Races::Terran)\n        {\n            allActionTypeDataVec[Races::Terran].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Terran].size()));\n        }\n        else if (type.getRace() == BWAPI::Races::Zerg)\n        {\n            allActionTypeDataVec[Races::Zerg].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Zerg].size()));\n        }\n    }\n\n    for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes())\n    {\n        // blacklisted tech types we cannot create\n        if (type.whatUpgrades() == BWAPI::UnitTypes::None)\n        {\n            continue;\n        }\n\n        if (type.getRace() == BWAPI::Races::Protoss)\n        {\n            allActionTypeDataVec[Races::Protoss].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Protoss].size()));\n        }\n        else if (type.getRace() == BWAPI::Races::Terran)\n        {\n            allActionTypeDataVec[Races::Terran].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Terran].size()));\n        }\n        else if (type.getRace() == BWAPI::Races::Zerg)\n        {\n            allActionTypeDataVec[Races::Zerg].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Zerg].size()));\n        }\n    }\n}\n\nconst RaceID ActionTypeData::GetRaceID(BWAPI::Race r)\n{\n    if (r == BWAPI::Races::Protoss)\n    {\n        return Races::Protoss;\n    }\n    else if (r == BWAPI::Races::Terran)\n    {\n        return Races::Terran;\n    }\n    else if (r == BWAPI::Races::Zerg)\n    {\n        return Races::Zerg;\n    }\n    else\n    {\n        return Races::None;\n    }\n}\n\nconst ActionID ActionTypeData::GetNumActionTypes(const RaceID race)\n{\n    return allActionTypeDataVec[race].size();\n}\n\nconst ActionTypeData & ActionTypeData::GetActionTypeData(const RaceID raceID, const ActionID & id)\n{\n    BOSS_ASSERT(raceID < Races::NUM_RACES, \"Race ID invalid: %d %d\", (int)raceID, (int)id);\n\n    return allActionTypeDataVec[raceID][id];\n}\n\nActionID ActionTypeData::GetActionID(const BWAPI::UnitType & type) \n{\n    const RaceID raceID = GetRaceID(type.getRace());\n    BOSS_ASSERT(raceID < Races::NUM_RACES, \"Race ID invalid: %d %s\", (int)raceID, type.getName().c_str());\n\n\n    for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a)\n    {\n        const ActionTypeData & data = GetActionTypeData(raceID, a);\n        if (data.isUnit() && data.getUnitType() == type)\n        {\n            return data.getActionID();\n        }\n    }\n   \n\tBOSS_ASSERT(false, \"Could not find UnitType: %d %s\", type.getID(), type.getName().c_str());\n    return 0;\n}\n\nActionID ActionTypeData::GetActionID(const BWAPI::TechType & type) \n{\n    const RaceID raceID = GetRaceID(type.getRace());\n    for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a)\n    {\n        const ActionTypeData & data = GetActionTypeData(raceID, a);\n        if (data.isTech() && data.getTechType() == type)\n        {\n            return data.getActionID();\n        }\n    }\n   \n\tBOSS_ASSERT(false, \"Could not find TechType: %d %s\", type.getID(), type.getName().c_str());\n    return 0;\n}\n\nActionID ActionTypeData::GetActionID(const BWAPI::UpgradeType & type) \n{\n    const RaceID raceID = GetRaceID(type.getRace());\n    for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a)\n    {\n        const ActionTypeData & data = GetActionTypeData(raceID, a);\n        if (data.isUpgrade() && data.getUpgradeType() == type)\n        {\n            return data.getActionID();\n        }\n    }\n   \n\tBOSS_ASSERT(false, \"Could not find TechType: %d %s\", type.getID(), type.getName().c_str());\n    return 0;\n}\n\nActionTypeData ActionTypeData::GetActionTypeData(const BWAPI::UnitType & a)\n{\n    return GetActionTypeData(GetRaceID(a.getRace()), GetActionID(a));\n}\n\nActionTypeData ActionTypeData::GetActionTypeData(const BWAPI::TechType & a)\n{\n    return GetActionTypeData(GetRaceID(a.getRace()), GetActionID(a));\n}\n\nActionTypeData ActionTypeData::GetActionTypeData(const BWAPI::UpgradeType & a)\n{\n    return GetActionTypeData(GetRaceID(a.getRace()), GetActionID(a));\n}\n\n\n// adds all prerequisites\nvoid ActionTypeData::AddPrerequisites()\n{\n    // set all prerequisites for all action types\n\tfor (RaceID r(0); r < Races::NUM_RACES; ++r)\n    {\n        for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(r); ++a)\n        {\n\t\t    allActionTypeDataVec[r][a].setPrerequisites(CalculatePrerequisites(allActionTypeDataVec[r][a]));\n        }\n    }\n\n    // set required addon data\n    for (RaceID r(0); r < Races::NUM_RACES; ++r)\n    {\n        for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(r); ++a)\n        {\n\t\t    // set the prerequisite PrerequisiteSet based on the function below\n            ActionTypeData & typeData = allActionTypeDataVec[r][a];\n\t\t    const PrerequisiteSet & pre = typeData.getPrerequisites();\n\n            for (size_t p(0); p<pre.size(); ++p)\n            {\n                const ActionType & preActionType = pre.getActionType(p);\n\n                // the addon has to be an addon of the building that construct the unit\n                if (preActionType.isAddon() && (preActionType.whatBuildsAction() == typeData.whatBuildsActionID))\n                {\n                    typeData.setRequiredAddon(true, preActionType.ID());\n                }\n            }\n        }\n    }\n\n    // set the recursive prerequisites (ie: the entire tech tree prereq for a given unit)\n    for (RaceID r(0); r < Races::NUM_RACES; ++r)\n    {\n        for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(r); ++a)\n        {\n            PrerequisiteSet recursivePre;\n            CalculateRecursivePrerequisites(recursivePre, allActionTypeDataVec[r][a]);\n\t\t    allActionTypeDataVec[r][a].setRecursivePrerequisites(recursivePre);\n        }\n    }\n}\n\t\nvoid ActionTypeData::CalculateWhatBuilds()\n{\n    for (RaceID r(0); r < Races::NUM_RACES; ++r)\n    {\n        for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(r); ++a)\n        {\n            ActionTypeData & actionTypeData = allActionTypeDataVec[r][a];\n            if (actionTypeData.whatBuildsBWAPI() == BWAPI::UnitTypes::Zerg_Larva)\n\t\t    {\n\t\t\t    actionTypeData.setWhatBuildsActionID(GetActionID(BWAPI::UnitTypes::Zerg_Larva), false, true);\n\t\t    }\n\t\t    else\n\t\t    {\n\t\t\t    ActionID actionID = GetActionID(actionTypeData.whatBuildsBWAPI());\n\t\t\t    actionTypeData.setWhatBuildsActionID(actionID, actionTypeData.whatBuildsBWAPI().isBuilding(), false);\n\t\t    }\t\n        }\n    }\n}\n\t\n// returns an PrerequisiteSet of prerequisites for a given action\nPrerequisiteSet ActionTypeData::CalculatePrerequisites(const ActionTypeData & action)\n{\n\tPrerequisiteSet pre;\n    \n\t// if it's a UnitType\n\tif (action.getType() == ActionTypeData::UnitType)\n\t{\n\t\tstd::map<BWAPI::UnitType, int> requiredUnits = action.getUnitType().requiredUnits();\n\t\tBWAPI::UnitType actionType = action.getUnitType();\n\n\t\t// if it's a protoss building that isn't a Nexus or Assimilator, we need a pylon (indirectly)\n\t\tif (actionType.getRace() == BWAPI::Races::Protoss && actionType.isBuilding() && !actionType.isResourceDepot() && \n\t\t\t!(actionType == BWAPI::UnitTypes::Protoss_Pylon) && !(actionType == BWAPI::UnitTypes::Protoss_Assimilator))\n\t\t{\n            pre.add(ActionType(Races::Protoss, GetActionID(BWAPI::UnitTypes::Protoss_Pylon)), 1);\n\t\t}\n\n\t\t// for each of the required UnitTypes\n\t\tfor (std::map<BWAPI::UnitType, int>::iterator unitIt = requiredUnits.begin(); unitIt != requiredUnits.end(); unitIt++)\n\t\t{\n\t\t\t//if (DEBUG_StarcraftData) printf(\"\\tPRE: %s\\n\", unitIt->first.getName().c_str());\n\t\n\t\t\tBWAPI::UnitType type = unitIt->first;\n            int count = unitIt->second;\n\n\t\t\t// add the action to the PrerequisiteSet if it is not a larva\n\t\t\tif (type != BWAPI::UnitTypes::Zerg_Larva)\n\t\t\t{\n\t\t\t\t//printf(\"\\t\\tAdding %s\\n\", type.getName().c_str());\n\t\t\t\tpre.add(ActionType(action.getRaceID(), GetActionID(type)), count);\n\t\t\t}\n\t\t}\n\n\t\t// if there is a TechType required\n\t\tif (action.getUnitType().requiredTech() != BWAPI::TechTypes::None)\n\t\t{\n\t\t\t//if (DEBUG_StarcraftData) printf(\"\\tPRE: %s\\n\", action.getUnitType().requiredTech().getName().c_str());\n            BWAPI::TechType required = action.getUnitType().requiredTech();\n\t\t\t// add it to the PrerequisiteSet\n\t\t\tpre.add(ActionType(action.getRaceID(), GetActionID(required)), 1);\n\t\t}\n\t}\n\n\t// if it's a TechType\n\tif (action.getType() == ActionTypeData::TechType)\n\t{\n\t\tif (action.getTechType().whatResearches() != BWAPI::UnitTypes::None)\n\t\t{\n\t\t\t//if (DEBUG_StarcraftData) printf(\"\\tPRE: %s\\n\", action.getTechType().whatResearches().getName().c_str());\n\n\t\t\t// add what researches it\n\t\t\tpre.add(ActionType(action.getRaceID(), GetActionID(action.getTechType().whatResearches())), 1);\n\t\t}\n\t}\n\n\t// if it's an UpgradeType\n\tif (action.getType() == ActionTypeData::UpgradeType)\n\t{\n\t\tif (action.getUpgradeType().whatUpgrades() != BWAPI::UnitTypes::None)\n\t\t{\n\t\t\t//if (DEBUG_StarcraftData) printf(\"\\tPRE: %s\\n\", action.getUpgradeType().whatUpgrades().getName().c_str());\n\n\t\t\t// add what upgrades it\n\t\t\tpre.add(ActionType(action.getRaceID(), GetActionID(action.getUpgradeType().whatUpgrades())), 1);\n\t\t}\n\t}\n\n\n\t//printf(\"Finish Prerequisites\\n\");\n\treturn pre;\n}\n\n// calculate the recursive prerequisites for an Action, storing them in allPre\n// assumes that prerequisites have already been calculated\nvoid ActionTypeData::CalculateRecursivePrerequisites(PrerequisiteSet & allPre, const ActionTypeData & action)\n{\n\tPrerequisiteSet pre = action.getPrerequisites();\n\n    if (action.gasPrice() > 0)\n    {\n        if (action.raceID == Races::Protoss)\n        {\n            pre.add(ActionType(Races::Protoss, GetActionID(BWAPI::UnitTypes::Protoss_Assimilator)));\n        }\n        else if (action.raceID == Races::Terran)\n        {\n            pre.add(ActionType(Races::Terran, GetActionID(BWAPI::UnitTypes::Terran_Refinery)));\n        }\n        if (action.raceID == Races::Zerg)\n        {\n            pre.add(ActionType(Races::Zerg, GetActionID(BWAPI::UnitTypes::Zerg_Extractor)));\n        }\n    }\n\n\tfor (size_t a(0); a < pre.size(); ++a)\n    {\n        const ActionType & actionType = pre.getActionType(a);\n\n        if (!allPre.contains(actionType))\n        {\n            allPre.add(actionType);\n            CalculateRecursivePrerequisites(allPre, GetActionTypeData(actionType.getRace(), actionType.ID()));\n        }\n    }\n}\n"
  },
  {
    "path": "BOSS/source/ActionTypeData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Array.hpp\"\n#include \"PrerequisiteSet.h\"\n#include <set>\n\nnamespace BOSS\n{\n    \nclass ActionTypeData\n{\npublic:\n\n    // types of actions\n    enum { UnitType,UpgradeType,TechType,Error };\n\nprivate:\n    \n    static std::vector< std::vector<ActionTypeData> > allActionTypeDataVec;\n    //static std::vector<DependencyGraph> dependencyGraphs;\n    \n    ActionID        \tactionID;\t\t\t// unique identifier to this action\n    RaceID              raceID;\n\n    int                 type;\t\t\t\t// the enum type of action this is\n    BWAPI::Race         race;\t\t\t\t// the race of this action\n    BWAPI::UnitType     unit;\t\t\t\t// holds UnitType, if it's a unit\n    BWAPI::UpgradeType  upgrade;\t\t\t// holds UpgradeType, if it's an upgrade\n    BWAPI::TechType     tech;\t\t\t\t// holds TechType, if it's a tech\n\n    ResourceCountType\tmineralPriceVal; \t// mineral price of the action\n    ResourceCountType\tgasPriceVal; \t\t// gas price of the action\n    SupplyCountType\t\tsupplyRequiredVal; \t// supply price of the action\n    SupplyCountType\t\tsupplyProvidedVal;\t// supply created by the action\n    FrameCountType\t\tbuildTimeVal;\t\t// build time of the action\n    UnitCountType\t\tnumberProduced;\t\t// the number of units produced\n\n    std::string         name;\t\t\t\t// name of the action\n    std::string         shortName;\n    std::string         metaName;\t\t\t// meta name of this action, adds 'repeat' to the string\n\n    PrerequisiteSet     prerequisites;\n    PrerequisiteSet     recursivePrerequisites;\n\n    bool                building; // is this a building\n    bool                worker; // is this a worker\n    bool                refinery; // is this a refinery\n    bool                resourceDepot; // is this a resource depot\n    bool                supplyProvider; // is this a supply provider\n    bool                canProduceBool;\n    bool                canAttackBool;\n    bool                whatBuildsIsBuildingBool; // is what builds this action a building?\n    bool                whatBuildsIsLarvaBool;\n    bool                addon;\n    bool                reqAddon;\n    bool                morphed;\n\n    ActionID            reqAddonID;\n\n    BWAPI::UnitType     whatBuildsUnitType;\t\t// the unit type that builds this\n\n    ActionID            whatBuildsActionID;\t// the action that builds this \n\n    // Private Constructors\n    ActionTypeData();\n    ActionTypeData(BWAPI::UnitType t, const ActionID id);\n    ActionTypeData(BWAPI::UpgradeType t, const ActionID id);\n    ActionTypeData(BWAPI::TechType t, const ActionID id);\n\n    static void         AddActions();\n    static void         CalculateWhatBuilds();\n    static void         AddPrerequisites();\n\n    static PrerequisiteSet CalculatePrerequisites(const ActionTypeData & action);\n    static void CalculateRecursivePrerequisites(PrerequisiteSet & allPre, const ActionTypeData & action);\n\n    static ActionTypeData   GetActionTypeData(const BWAPI::UnitType & a);\n    static ActionTypeData   GetActionTypeData(const BWAPI::TechType & a);\n    static ActionTypeData   GetActionTypeData(const BWAPI::UpgradeType & a);\n    \n    void setWhatBuildsActionID(const ActionID a,const bool wbib,const bool wbil);\n    void setShortName();\n\npublic:\n\n    static void                     Init();\n    static const ActionID           GetNumActionTypes(const RaceID race);\n    static const ActionTypeData &   GetActionTypeData(const RaceID raceID,const ActionID & id);\n    static const RaceID             GetRaceID(BWAPI::Race r);\n\n    RaceID              getRaceID()             const;\n    ActionID            getActionID()           const;\n\n    ActionType          whatBuildsActionType()  const;\n\n    BWAPI::UnitType\t\tgetUnitType()\t\t\tconst;\n    BWAPI::UnitType\t\twhatBuildsBWAPI()       const;\n    BWAPI::UpgradeType\tgetUpgradeType()\t\tconst;\n    BWAPI::TechType\t\tgetTechType()\t\t\tconst;\n\n\n    static ActionID     GetActionID(const BWAPI::UnitType & a);\n    static ActionID     GetActionID(const BWAPI::TechType & a);\n    static ActionID     GetActionID(const BWAPI::UpgradeType & a);\n\n    ActionID            whatBuildsAction()\t\tconst;\n    const PrerequisiteSet & getPrerequisites()  const;\n    const PrerequisiteSet & getRecursivePrerequisites()  const;\n    int \t\t\t    getType() \t\t\t\tconst;\n\n    const std::string & getName() \t\t\t\tconst;\n    const std::string & getShortName()          const;\n    const std::string & getMetaName() \t\t\tconst;\n\n    FrameCountType \t\tbuildTime() \t\t\tconst;\n    ResourceCountType\tmineralPrice()\t\t\tconst;\n    ResourceCountType\tmineralPriceScaled()\tconst;\n    ResourceCountType\tgasPrice()\t\t\t\tconst;\n    ResourceCountType\tgasPriceScaled()\t\tconst;\n    SupplyCountType \tsupplyRequired() \t\tconst;\n    SupplyCountType\t\tsupplyProvided() \t\tconst;\n    UnitCountType \t\tnumProduced() \t\t\tconst;\n\n    bool\t\t\t\tisRefinery() \t\t\tconst;\n    bool\t\t\t\tisWorker() \t\t\t\tconst;\n    bool\t\t\t\tisBuilding()\t\t\tconst;\n    bool\t\t\t\tisResourceDepot()\t\tconst;\n    bool\t\t\t\tisSupplyProvider()\t\tconst;\n    bool\t\t\t\tisUnit()\t\t\t\tconst;\n    bool\t\t\t\tisTech()\t\t\t\tconst;\n    bool\t\t\t\tisUpgrade()\t\t\t\tconst;\n    bool                isAddon()               const;\n    bool                isMorphed()             const;\n    bool                requiresAddon()         const;\n    ActionID            requiredAddonID()       const;\n\n    bool\t\t\t\twhatBuildsIsBuilding() \tconst;\n    bool\t\t\t\twhatBuildsIsLarva() \tconst;\n    bool\t\t\t\tcanProduce()\t\t\tconst;\n    bool\t\t\t\tcanAttack()\t\t\t\tconst;\n\n    void \t\t\t\tsetPrerequisites(const PrerequisiteSet & pre);\n    void \t\t\t\tsetRecursivePrerequisites(const PrerequisiteSet & pre);\n    void                setRequiredAddon(bool requiresAddon, const ActionID & id);\n\n    bool operator ==\t(const ActionTypeData & a) const;\n    bool operator <\t\t(const ActionTypeData & a) const;\n};\n}\n"
  },
  {
    "path": "BOSS/source/Array.hpp",
    "content": "#pragma once\n#include \"BOSSAssert.h\"\n#include \"Common.h\"\n#include <algorithm>\n\nnamespace BOSS\n{\ntemplate <class T,size_t max_capacity>\nclass Vec\n{\n    size_t\t_size;\n    size_t  _capacity;\n    T\t\t_arr[max_capacity];\n\npublic:\n\n    Vec<T,max_capacity>()\n        : _size(0)\n        ,_capacity(max_capacity)\n    {\n\t\tBOSS_ASSERT(max_capacity>0, \"Vec initializing with capacity = 0\");\n    }\n\n    Vec<T,max_capacity>(const size_t & size)\n        : _size(size)\n        ,_capacity(max_capacity)\n    {\n        BOSS_ASSERT(size <= max_capacity,\"Vec initializing with size > capacity, Size = %d, Capacity = %d\",size,_capacity);\n    }\n\n    Vec<T,max_capacity>(const size_t & size,const T & val)\n        : _size(size)\n        ,_capacity(max_capacity)\n    {\n        BOSS_ASSERT(size <= max_capacity,\"Vec initializing with size > capacity, Size = %d, Capacity = %d\",size,_capacity);\n        fill(val);\n    }\n    \n    void resize(const size_t & size)\n    {\n        BOSS_ASSERT(size <= max_capacity,\"Vec resizing with size > capacity, Size = %d, Cpacity = %d\",size,_capacity);\n        _size = size;\n    }\n\n    T & get(const size_t & index)\n    {\n        BOSS_ASSERT(index < size(),\"Vec out of bounds exception, Size = %d, Index = %d\",size(),index);\n        return _arr[index];\n    }\n\n    const T & get(const size_t & index) const\n    {\n        BOSS_ASSERT(index < size(),\"Vec out of bounds exception, Size = %d, Index = %d\",size(),index);\n        return _arr[index];\n    }\n\n    T & operator [] (const size_t & index)\n    {\n        return get(index);\n    }\n\n    const T & operator [] (const size_t & index) const\n    {\n        return get(index);\n    }\n\n    const bool contains(const T & e) const\n    {\n        for (size_t i(0); i<size(); ++i)\n        {\n            if (get(i) == e)\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void addSorted(const T & e)\n    {\n        size_t index(0);\n        while (_arr[index] < e)\n        {\n            ++index;\n        }\n        \n        addAtIndex(e, index);\n    }\n\n    void addAtIndex(const T & e, const size_t & index)\n    {\n        BOSS_ASSERT(index <= size(), \"Can't add at index: Index = %d, Size = %d\", index, size());\n        BOSS_ASSERT(_size < capacity(),\"Array over capacity: Size = %d\",capacity());\n\n        copyShiftRight(index);\n        _arr[index] = e;\n    }\n\n    void copyShiftRight(const size_t & index)\n    {\n        BOSS_ASSERT(_size < capacity(),\"Array over capacity: Size = %d\",capacity());\n        for (size_t i(_size + 1); i > index; --i)\n        {\n            _arr[i] = _arr[i-1];\n        }\n\n        _size++;\n    }\n\n    void copyShiftLeft(const size_t & index)\n    {\n        BOSS_ASSERT(size() > 0, \"Can't shift left when empty\");\n        for (size_t i(index); i < size()-1; ++i)\n        {\n            _arr[i] = _arr[i+1];\n        }\n\n        _size--;\n    }\n    \n    const size_t & capacity() const\n    {\n        return _capacity;\n    }\n\n    void push_back(const T & e)\n    {\n        BOSS_ASSERT(_size < capacity(),\"Array over capacity: Capacity = %d, Size = %d\",capacity(), _size);\n        _arr[_size] = e;\n        ++_size;\n    }\n\n    const T & back() const\n    {\n        BOSS_ASSERT(!empty(),\"Vector back() with empty array\");\n\n        return get(_size);\n    }\n\n    void remove(const size_t & index)\n    {\n        remove_by_swap(index);\n    }\n\n    void removeByShift(const size_t & index)\n    {\n        copyShiftLeft(index);\n    }\n\n    void remove_by_swap(const size_t & index)\n    {\n        BOSS_ASSERT(index < size(),\"Vector out of bounds exception, Size = %d, Index = %d\",size(),index);\n\n        std::swap(_arr[index],_arr[size()-1]);\n        pop_back();\n    }\n\n    void pop_back()\n    {\n        BOSS_ASSERT(!empty(),\"Vector pop_back() with empty array\");\n\n        _size--;\n    }\n\n    void sort()\n    {\n        std::sort(_arr, _arr + _size);\n    }\n\n    const bool empty() const\n    {\n        return size() == 0;\n    }\n\n    void clear()\n    {\n        _size = 0;\n    }\n\n    const size_t & size() const\n    {\n        return _size;\n    }\n\n    inline void fill(const T & val)\n    {\n        std::fill(_arr,_arr + _size,val);\n    }\n\n    class iterator\n    {\n        T * _ptr;\n    public:\n        iterator(T * ptr) : _ptr(ptr) { }\n        iterator    operator ++ ()                      { iterator i = *this; _ptr++; return i; }\n        iterator    operator ++ (int junk)              { _ptr++; return *this; }\n        T &         operator *  ()                      { return *_ptr; }\n        T *         operator -> ()                      { return _ptr; }\n        bool        operator == (const iterator & rhs)  { return _ptr == rhs._ptr; }\n        bool        operator != (const iterator & rhs)  { return _ptr != rhs._ptr; }\n    };\n \n    class const_iterator\n    {\n        T * _ptr;\n    public:\n        const_iterator(T * ptr) : _ptr(ptr) { }\n        const_iterator  operator ++ ()                              { const_iterator i = *this; _ptr++; return i; }\n        const_iterator  operator ++ (int junk)                      { _ptr++; return *this; }\n        const T &       operator *  ()                              { return *_ptr; }\n        const T *       operator -> ()                              { return _ptr; }\n        bool            operator == (const const_iterator & rhs)    { return _ptr == rhs._ptr; }\n        bool            operator != (const const_iterator & rhs)    { return _ptr != rhs._ptr; }\n    };\n    \n    iterator begin()\n    {\n        return iterator(_arr);\n    }\n\n    iterator end()\n    {\n        return iterator(_arr + size());\n    }\n\n};\n\n}"
  },
  {
    "path": "BOSS/source/BOSS.cpp",
    "content": "#include \"BOSS.h\"\n\nnamespace BOSS\n{\n    void init()\n    {\n        ActionTypeData::Init();\n        ActionTypes::init();\n    }\n\n    void printData()\n    {\n        for (RaceID r(0); r < Races::NUM_RACES; ++r)\n        {\n            const std::vector<ActionType> & allActions = ActionTypes::GetAllActionTypes(r);\n            for (size_t i(0); i<allActions.size(); ++i)\n            {\n                const ActionType & a = allActions[i];\n                std::cout << \"\\n\" << (int)a.getRace() << \" \" << (int)a.ID() << \" \" << a.getName() << \"\\n\\n\";\n                std::cout << \"    Built@:   \" << a.whatBuildsActionType().getName() << \"\\n\";\n                if (a.requiresAddon())\n                {\n                    std::cout << \"    Addon :   \" << a.requiredAddonType().getName() << \"\\n\";\n                }\n                \n                std::cout << a.getPrerequisites().toString();\n            }\n        }\n    }\n}"
  },
  {
    "path": "BOSS/source/BOSS.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"CombatSearch.h\"\n#include \"CombatSearch_Integral.h\"\n#include \"CombatSearch_Bucket.h\"\n#include \"CombatSearch_BestResponse.h\"\n#include \"ActionTypeData.h\"\n#include \"Timer.hpp\"\n#include \"ActionType.h\"\n#include \"Tools.h\"\n#include \"DFBB_BuildOrderSmartSearch.h\"\n#include \"Position.hpp\"\n#include \"BuildOrderSearchGoal.h\"\n#include \"BuildOrder.h\"\n#include \"NaiveBuildOrderSearch.h\"\n\nnamespace BOSS\n{\n    void init();\n    void printData();\n}"
  },
  {
    "path": "BOSS/source/BOSSAssert.cpp",
    "content": "#include \"BOSSAssert.h\"\n#include \"BOSSException.h\"\n\nusing namespace BOSS;\n\nnamespace BOSS\n{\nnamespace Assert\n{\n    const std::string currentDateTime() \n    {\n        time_t     now = time(0);\n        struct tm  tstruct;\n        char       buf[80];\n        tstruct = *localtime(&now);\n        strftime(buf, sizeof(buf), \"%Y-%m-%d_%X\", &tstruct);\n\n        for (size_t i(0); i < strlen(buf); ++i)\n        {\n            if (buf[i] == ':')\n            {\n                buf[i] = '-';\n            }\n        }\n\n        return buf;\n    }\n\n    void ReportFailure(const GameState * state, const char * condition, const char * file, int line, const char * msg, ...)\n    {\n        std::cerr << \"Assertion thrown!\\n\";\n\n        char messageBuffer[4096] = \"\";\n        if (msg != NULL)\n        {\n            va_list args;\n            va_start(args, msg);\n            vsprintf(messageBuffer, msg, args);\n            va_end(args);\n        }\n\n        std::stringstream ss;\n        ss                                      << std::endl;\n        ss << \"!Assert:   \" << condition        << std::endl;\n        ss << \"File:      \" << file             << std::endl;\n        ss << \"Message:   \" << messageBuffer    << std::endl;\n        ss << \"Line:      \" << line             << std::endl;\n        \n        #if !defined(EMSCRIPTEN)\n            std::cerr << ss.str();  \n            throw BOSSException(ss.str());\n        #else\n            printf(\"C++ AI: AI Exception Thrown:\\n %s\\n\", ss.str().c_str());\n            throw BOSSException(ss.str());\n        #endif\n    }\n}\n}\n\n"
  },
  {
    "path": "BOSS/source/BOSSAssert.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include <cstdarg>\n#include \"BOSSException.h\"\n\n#include <ctime>\n\nnamespace BOSS\n{\n\nclass GameState;\nnamespace Assert\n{\n    const std::string currentDateTime();\n    void ReportFailure(const GameState * state, const char * condition, const char * file, int line, const char * msg, ...);\n}\n}\n\n#define BOSS_ASSERT_ENABLE\n\n#ifdef BOSS_ASSERT_ENABLE\n\n    #define BOSS_ASSERT(cond, msg, ...) \\\n        do \\\n        { \\\n            if (!(cond)) \\\n            { \\\n                BOSS::Assert::ReportFailure(nullptr, #cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \\\n            } \\\n        } while(0)\n\n    #define BOSS_ASSERT_STATE(cond, state, filename, msg, ...) \\\n        do \\\n        { \\\n            if (!(cond)) \\\n            { \\\n                BOSS::Assert::ReportFailure(&state, #cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \\\n            } \\\n        } while(0)\n\n#else\n    #define SPARCRAFT_ASSERT(cond, msg, ...) \n    #define SPARCRAFT_ASSERT_STATE(cond, state, filename, msg, ...) \n#endif\n"
  },
  {
    "path": "BOSS/source/BOSSException.cpp",
    "content": "#include \"BOSSException.h\"\n\nusing namespace BOSS;\n\nBOSSException::BOSSException(std::string ss) \n    : _s(ss) \n    , _hasState(false)\n{\n}\n\n//BOSSException::BOSSException(std::string ss, const GameState * state) \n//    : _s(ss) \n//    , _hasState(false)\n//{\n//    if (state != nullptr)\n//    {\n//        _state = *state;\n//        _hasState = true;\n//    }\n//}\n\nBOSSException::~BOSSException() throw () \n{\n} \n\nconst char* BOSSException::what() const throw() \n{ \n    return _s.c_str(); \n}\n\nbool BOSSException::hasState() const \n{ \n    return _hasState; \n}\n\n//const GameState & BOSSException::getState() const \n//{ \n//    return _state; \n//}"
  },
  {
    "path": "BOSS/source/BOSSException.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace BOSS\n{\nclass BOSSException : public std::exception\n{\n    std::string _s;\n    bool _hasState;\n\npublic :\n\n    //BOSSException(std::string ss, const GameState * state);\n    BOSSException(std::string ss);\n\n    ~BOSSException() throw ();\n    const char* what() const throw();\n    bool hasState() const;\n    //const GameState & getState() const;\n}; \n}\n"
  },
  {
    "path": "BOSS/source/BOSSExperiments.cpp",
    "content": "#include \"BOSSExperiments.h\"\n\n#include \"CombatSearchExperiment.h\"\n#include \"BOSSPlotBuildOrders.h\"\n\nusing namespace BOSS;\n\nvoid Experiments::RunExperiments(const std::string & experimentFilename)\n{\n    rapidjson::Document document;\n    JSONTools::ParseJSONFile(document, experimentFilename);\n\n    BOSS_ASSERT(document.HasMember(\"Experiments\"), \"No 'Experiments' member found\");\n\n    const rapidjson::Value & experiments = document[\"Experiments\"];\n    for (rapidjson::Value::ConstMemberIterator itr = experiments.MemberBegin(); itr != experiments.MemberEnd(); ++itr)\n    {\n        const std::string &         name = itr->name.GetString();\n        const rapidjson::Value &    val  = itr->value;\n        \n        //std::cout << \"Found Experiment:   \" << name << std::endl;\n        BOSS_ASSERT(val.HasMember(\"Type\") && val[\"Type\"].IsString(), \"Experiment has no 'Type' string\");\n\n        if (val.HasMember(\"Run\") && val[\"Run\"].IsBool() && (val[\"Run\"].GetBool() == true))\n        {   \n            const std::string & type = val[\"Type\"].GetString();\n\n            if (type == \"CombatSearch\")\n            {\n                RunCombatExperiment(name, val);\n            }\n            else if (type == \"BuildOrderPlot\")\n            {\n                RunBuildOrderPlot(name, val);\n            }\n            else\n            {\n                BOSS_ASSERT(false, \"Unknown Experiment Type: %s\", type.c_str());\n            }\n        }\n    }\n\n    std::cout << \"\\n\\n\";\n}\n\nvoid Experiments::RunCombatExperiment(const std::string & name, const rapidjson::Value & val)\n{\n    CombatSearchExperiment exp(name, val);\n    exp.run();\n}\n\nvoid Experiments::RunBuildOrderPlot(const std::string & name, const rapidjson::Value & val)\n{\n    BOSSPlotBuildOrders plot(name, val);\n    plot.doPlots();\n}"
  },
  {
    "path": "BOSS/source/BOSSExperiments.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"JSONTools.h\"\n#include \"rapidjson/rapidjson.h\"\n#include \"rapidjson/document.h\"\n\nnamespace BOSS\n{\n\nnamespace Experiments\n{\n    void RunExperiments(const std::string & experimentFilename);\n\n    void RunCombatExperiment(const std::string & name, const rapidjson::Value & val);\n    void RunBuildOrderPlot(const std::string & name, const rapidjson::Value & val);\n}\n\n}"
  },
  {
    "path": "BOSS/source/BOSSLogger.cpp",
    "content": "#include \"BOSSLogger.h\"\n\nnamespace BOSS\n{\nnamespace Logger\n{\n    void LogAppendToFile(const std::string & logFile, const std::string & msg)\n    {\n        std::ofstream logStream;\n        logStream.open(logFile.c_str(), std::ofstream::app);\n        logStream << msg;\n        logStream.flush();\n        logStream.close();\n    }\n\n    void LogOverwriteToFile(const std::string & logFile, const std::string & msg)\n    {\n        std::ofstream logStream(logFile.c_str());\n        logStream << msg;\n        logStream.flush();\n        logStream.close();\n    }\n}\n}"
  },
  {
    "path": "BOSS/source/BOSSLogger.h",
    "content": "#pragma once\n\n#include <string>\n#include <iostream>\n#include <fstream>\n\nnamespace BOSS\n{\nnamespace Logger \n{\n    void LogAppendToFile(const std::string & logFile, const std::string & msg);\n    void LogOverwriteToFile(const std::string & logFile, const std::string & msg);\n};\n}"
  },
  {
    "path": "BOSS/source/BOSSParameters.cpp",
    "content": "#include \"BOSSParameters.h\"\n\nusing namespace BOSS;\n\nBOSSParameters::BOSSParameters()\n{\n\n}\n\nBOSSParameters & BOSSParameters::Instance()\n{\n    static BOSSParameters params;\n    return params;\n}\n\nvoid BOSSParameters::ParseParameters(const std::string & configFile)\n{\n    _configFile = configFile;\n\n    rapidjson::Document document;\n    JSONTools::ParseJSONFile(document, _configFile);\n\n    BOSS_ASSERT(document.HasMember(\"States\"), \"No 'States' member found\");\n    BOSS_ASSERT(document.HasMember(\"Build Orders\"), \"No 'Build Orders' member found\");\n//    BOSS_ASSERT(document.HasMember(\"Build Order Search Goals\"), \"No 'Build Order Goals' member found\");\n\n    // Parse all the States\n    const rapidjson::Value & states = document[\"States\"];\n    for (rapidjson::Value::ConstMemberIterator itr = states.MemberBegin(); itr != states.MemberEnd(); ++itr)\n    {\n        const std::string &         name = itr->name.GetString();\n        const rapidjson::Value &    val  = itr->value;\n               \n        _stateMap[name] = JSONTools::GetGameState(val);\n    }\n\n    // Parse all the Build Orders\n    const rapidjson::Value & buildOrders = document[\"Build Orders\"];\n    for (rapidjson::Value::ConstMemberIterator itr = buildOrders.MemberBegin(); itr != buildOrders.MemberEnd(); ++itr)\n    {\n        const std::string &         name = itr->name.GetString();\n        const rapidjson::Value &    val  = itr->value;\n               \n        _buildOrderMap[name] = JSONTools::GetBuildOrder(val);\n    }\n\n    // Parse all the Build Order Goals\n    if (document.HasMember(\"Build Order Search Goals\"))\n    {\n        const rapidjson::Value & buildOrderGoals = document[\"Build Order Search Goals\"];\n        for (rapidjson::Value::ConstMemberIterator itr = buildOrderGoals.MemberBegin(); itr != buildOrderGoals.MemberEnd(); ++itr)\n        {\n            const std::string &         name = itr->name.GetString();\n            const rapidjson::Value &    val  = itr->value;\n               \n            _buildOrderSearchGoalMap[name] = JSONTools::GetBuildOrderSearchGoal(val);\n        }\n    }\n}\n\nconst GameState & BOSSParameters::GetState(const std::string & key)\n{\n    BOSS_ASSERT(_stateMap.find(key) != _stateMap.end(), \"Couldn't find state: %s\", key.c_str());\n\n    return _stateMap[key];\n}\n\nconst BuildOrder & BOSSParameters::GetBuildOrder(const std::string & key)\n{\n    BOSS_ASSERT(_buildOrderMap.find(key) != _buildOrderMap.end(), \"Couldn't find build order: %s\", key.c_str());\n\n    return _buildOrderMap[key];\n}\n\nconst BuildOrderSearchGoal & BOSSParameters::GetBuildOrderSearchGoalMap(const std::string & key)\n{\n    BOSS_ASSERT(_buildOrderSearchGoalMap.find(key) != _buildOrderSearchGoalMap.end(), \"Couldn't find state: %s\", key.c_str());\n\n    return _buildOrderSearchGoalMap[key];\n}"
  },
  {
    "path": "BOSS/source/BOSSParameters.h",
    "content": "#pragma once\n\n#include \"BOSS.h\"\n#include \"JSONTools.h\"\n#include \"rapidjson/rapidjson.h\"\n#include \"rapidjson/document.h\"\n#include \"CombatSearchExperiment.h\"\n\nnamespace BOSS\n{\n\nclass BOSSParameters\n{\n    std::string                                 _configFile;\n\n    std::map<std::string, GameState>            _stateMap;\n    std::map<std::string, BuildOrder>           _buildOrderMap;\n    std::map<std::string, BuildOrderSearchGoal> _buildOrderSearchGoalMap;\n    \n    BOSSParameters();\n\npublic:\n\n    static BOSSParameters & Instance();\n    void ParseParameters(const std::string & configFile);\n\n    const GameState &               GetState(const std::string & key);\n    const BuildOrder &              GetBuildOrder(const std::string & key);\n    const BuildOrderSearchGoal &    GetBuildOrderSearchGoalMap(const std::string & key);\n};\n}\n"
  },
  {
    "path": "BOSS/source/BOSSPlotBuildOrders.cpp",
    "content": "#include \"BOSSPlotBuildOrders.h\"\n#include \"BuildOrderPlot.h\"\n#include \"BOSSParameters.h\"\n\nusing namespace BOSS;\n\nBOSSPlotBuildOrders::BOSSPlotBuildOrders(const std::string & name, const rapidjson::Value & val)\n{\n    BOSS_ASSERT(val.HasMember(\"Scenarios\") && val[\"Scenarios\"].IsArray(), \"Experiment has no Scenarios array\");\n    BOSS_ASSERT(val.HasMember(\"OutputDir\") && val[\"OutputDir\"].IsString(), \"Experiment has no OutputFile string\");\n\n    _outputDir = val[\"OutputDir\"].GetString();\n\n    const rapidjson::Value & scenarios = val[\"Scenarios\"];\n        \n    for (size_t i(0); i < scenarios.Size(); ++i)\n    {\n        const rapidjson::Value & scenario = scenarios[i];\n\n        BOSS_ASSERT(scenario.HasMember(\"State\") && scenario[\"State\"].IsString(), \"Scenario has no 'state' string\");\n        BOSS_ASSERT(scenario.HasMember(\"BuildOrder\") && scenario[\"BuildOrder\"].IsString(), \"Scenario has no 'buildOrder' string\");\n        \n        _states.push_back(BOSSParameters::Instance().GetState(scenario[\"State\"].GetString()));\n        _buildOrders.push_back(BOSSParameters::Instance().GetBuildOrder(scenario[\"BuildOrder\"].GetString()));\n        _buildOrderNames.push_back(scenario[\"BuildOrder\"].GetString());\n    }\n}\n\nvoid BOSSPlotBuildOrders::doPlots()\n{\n    for (size_t i(0); i < _buildOrders.size(); ++i)\n    {\n        BuildOrderPlot plot(_states[i], _buildOrders[i]);\n        \n        plot.writeRectanglePlot(_outputDir + _buildOrderNames[i] + \".gpl\");\n        plot.writeArmyValuePlot(_outputDir + _buildOrderNames[i] + \"_army\");\n        plot.writeResourcePlot(_outputDir + _buildOrderNames[i] + \"_resource\");\n    }\n\n    BuildOrderPlot allPlots(_states[0], _buildOrders[0]);\n    for (size_t i(1); i < _buildOrders.size(); ++i)\n    {\n        BuildOrderPlot plot(_states[i], _buildOrders[i]);\n        allPlots.addPlot(plot);\n    }\n\n    allPlots.writeRectanglePlot(_outputDir + \"BOall\");\n}"
  },
  {
    "path": "BOSS/source/BOSSPlotBuildOrders.h",
    "content": "#pragma once\n\n#include \"BOSS.h\"\n#include \"JSONTools.h\"\n#include \"rapidjson/rapidjson.h\"\n#include \"rapidjson/document.h\"\n\nnamespace BOSS\n{\n\nclass BOSSPlotBuildOrders\n{\n    std::vector<GameState>      _states;\n    std::vector<BuildOrder>     _buildOrders;\n    std::vector<std::string>    _buildOrderNames;\n    std::string                 _outputDir;\n\npublic:\n\n    BOSSPlotBuildOrders(const std::string & name, const rapidjson::Value & experimentVal);\n    \n    void doPlots();\n};\n}\n"
  },
  {
    "path": "BOSS/source/BOSS_main.cpp",
    "content": "#include \"BOSS.h\"\n#include \"BOSSParameters.h\"\n#include \"BOSSExperiments.h\"\n\n#include \"CImg/CImg.h\"\n\nusing namespace BOSS;\nusing namespace cimg_library;\n\nint main2() \n{\n    CImg<unsigned char> image(\"logo.bmp\");\n    CImg<unsigned char> visu(500,400,1,3,0);\n\n    const unsigned char red[]   = {255,0,0};\n    const unsigned char green[] = {0,255,0};\n    const unsigned char blue[]  = {0,0,255};\n\n    image.blur(2.5);\n    CImgDisplay main_disp(image,\"Click a point\");\n    CImgDisplay draw_disp(visu,\"Intensity profile\");\n\n    while (!main_disp.is_closed() && !draw_disp.is_closed()) \n    {\n        main_disp.wait();\n        if (main_disp.button() && main_disp.mouse_y()>=0) \n        {\n            const int y = main_disp.mouse_y();\n            visu.fill(0).draw_graph(image.get_crop(0,y,0,0,image.width()-1,y,0,0),red,1,1,0,255,0);\n            visu.draw_graph(image.get_crop(0,y,0,1,image.width()-1,y,0,1),green,1,1,0,255,0);\n            visu.draw_graph(image.get_crop(0,y,0,2,image.width()-1,y,0,2),blue,1,1,0,255,0).display(draw_disp);\n        }\n    }\n\n    return 0;\n}\n\nint main(int argc, char *argv[])\n{\n    // Initialize all the BOSS internal data\n    BOSS::init();\n\n    // Read in the config parameters that will be used for experiments\n    BOSS::BOSSParameters::Instance().ParseParameters(\"BOSS_Config.txt\");\n    \n    // Run the experiments\n    BOSS::Experiments::RunExperiments(\"BOSS_Config.txt\");\n    \n    return 0;\n}\n\n"
  },
  {
    "path": "BOSS/source/BaseTypes.h",
    "content": "#pragma once\n\nnamespace BOSS\n{\n    typedef\t\tint     ResourceCountType;\n    typedef \tint     SupplyCountType;\n    typedef \tint     FrameCountType;\n    typedef \tint     UnitCountType;\n    typedef     int     ActionID;\n    typedef     int     RaceID;\n}\n"
  },
  {
    "path": "BOSS/source/BuildOrder.cpp",
    "content": "#include \"BuildOrder.h\"\n\nusing namespace BOSS;\n\nBuildOrder::BuildOrder()\n    : _typeCount(128, 0)\n{\n\n}\n\nvoid BuildOrder::add(const ActionType & type)\n{\n    BOSS_ASSERT((_buildOrder.size() == 0) || (type.getRace() == _buildOrder.back().getRace()), \"Cannot have a build order with multiple races\");\n\n    _buildOrder.push_back(type);\n    _typeCount[type.ID()]++;\n}\n\nvoid BuildOrder::add(const ActionType & type, const int & amount)\n{\n    for (int i(0); i < amount; ++i)\n    {\n        add(type);\n    }\n}\n\nvoid BuildOrder::add(const BuildOrder & other)\n{\n    for (size_t i(0); i < other.size(); ++i)\n    {\n        add(other[i]);\n    }\n}\n\nvoid BuildOrder::clear()\n{\n    _buildOrder.clear();\n    _typeCount.clear();\n}\n\nconst bool BuildOrder::empty() const\n{\n    return size() == 0;\n}\n\nvoid BuildOrder::sortByPrerequisites()\n{\n    for (size_t i(0); i < _buildOrder.size()-1; ++i)\n    {\n        for (size_t j(i+1); j < _buildOrder.size(); ++j)\n        {\n            const PrerequisiteSet & recursivePre = _buildOrder[i].getRecursivePrerequisites();\n\n            if (recursivePre.contains(_buildOrder[j]))\n            {\n                std::swap(_buildOrder[i], _buildOrder[j]);\n            }\n        }\n    }\n}\n\nconst size_t BuildOrder::getTypeCount(const ActionType & type) const\n{\n    if (empty())\n    {\n        return 0;\n    }\n\n    BOSS_ASSERT(type.getRace() == _buildOrder[0].getRace(), \"Trying to get type count of a different race type\");\n\n    return _typeCount[type.ID()];\n}\n\nvoid BuildOrder::pop_back()\n{\n    _buildOrder.pop_back();\n}\n\nconst ActionType & BuildOrder::operator [] (const size_t & i) const\n{\n    return _buildOrder[i];\n}\n\nActionType & BuildOrder::operator [] (const size_t & i) \n{\n    return _buildOrder[i];\n}\n\nconst size_t BuildOrder::size() const\n{\n    return _buildOrder.size();\n}\n\nconst bool BuildOrder::isLegalFromState(const GameState & state, size_t buildOrderStartIndex) const\n{\n    GameState currentState(state);\n\n    for (size_t i(buildOrderStartIndex); i < _buildOrder.size(); ++i)\n    {\n        if (!currentState.isLegal(_buildOrder[i]))\n        {\n            return false;\n        }\n        else\n        {\n            currentState.doAction(_buildOrder[i]);\n        }\n    }\n\n    return true;\n}\n\nstd::string BuildOrder::whyIsNotLegalFromState(const GameState & state, size_t buildOrderStartIndex) const\n{\n    GameState currentState(state);\n\n    for (size_t i(buildOrderStartIndex); i < _buildOrder.size(); ++i)\n    {\n        if (!currentState.isLegal(_buildOrder[i]))\n        {\n            std::stringstream ss;\n            ss << \"Build-Order item \" << (i+1) << \" can't be built.\\n\\n\" << currentState.whyIsNotLegal(_buildOrder[i]);\n            return ss.str();\n        }\n        else\n        {\n            currentState.doAction(_buildOrder[i]);\n        }\n    }\n\n    return \"Legal\";\n}\n\nstd::string BuildOrder::getJSONString() const\n{\n    std::stringstream ss;\n\n    ss << \"\\\"Build Order\\\" : [\";\n\n    for (size_t i(0); i < _buildOrder.size(); ++i)\n    {\n        ss << \"\\\"\" << _buildOrder[i].getName() << \"\\\"\" << (i < _buildOrder.size() - 1 ? \", \" : \"\");\n    }\n\n    ss << \"]\";\n\n    return ss.str();\n}\n\nbool BuildOrder::doActions(GameState & state, const size_t buildOrderStartIndex, const size_t buildOrderEndIndex) const\n{\n    BOSS_ASSERT(buildOrderEndIndex < _buildOrder.size(), \"Can't have this end index\");\n\n    for (size_t i(buildOrderStartIndex); i < buildOrderEndIndex; ++i)\n    {\n        if(!state.isLegal(_buildOrder[i]))\n        {\n            return false;\n        }\n\n        state.doAction(_buildOrder[i]);\n    }\n\n    return true;\n}\n\n// returns whether or not all the actions were legal\nbool BuildOrder::doActions(GameState & state, size_t buildOrderStartIndex) const\n{\n    for (size_t i(buildOrderStartIndex); i < _buildOrder.size(); ++i)\n    {\n        if(!state.isLegal(_buildOrder[i]))\n        {\n            return false;\n        }\n\n        state.doAction(_buildOrder[i]);\n    }\n\n    return true;\n}\n\nconst FrameCountType BuildOrder::getCompletionTime(const GameState & state, size_t buildOrderStartIndex) const\n{\n    if (_buildOrder.size() == 0)\n    {\n        return state.getLastActionFinishTime();\n    }\n    \n    BOSS_ASSERT(buildOrderStartIndex < _buildOrder.size(), \"We can't start at an index that's past the end\");\n\n    GameState currentState(state);\n    bool isLegal = doActions(currentState, buildOrderStartIndex);\n\n    BOSS_ASSERT(isLegal, \"Build order was not legal\");\n\n    return currentState.getLastActionFinishTime();\n}\n\nstd::string BuildOrder::getNumberedString() const\n{\n    std::stringstream ss;\n\n    for (size_t i(0); i < _buildOrder.size(); ++i)\n    {\n        std::stringstream num;\n        num << i;\n        while (num.str().length() < 5)\n        {\n            num << \" \";\n        }\n\n        ss << num.str() << _buildOrder[i].getName() << std::endl;\n    }\n\n    return ss.str();\n}\n\nstd::string BuildOrder::getIDString() const\n{\n    std::stringstream ss;\n\n    for (size_t i(0); i < _buildOrder.size(); ++i)\n    {\n        ss << (int)_buildOrder[i].ID() << \" \";\n    }\n\n    return ss.str();\n}\n\nstd::string BuildOrder::getNameString(const size_t charactersPerName) const\n{\n    std::stringstream ss;\n\n    for (size_t i(0); i < _buildOrder.size(); ++i)\n    {\n        std::string name = charactersPerName == 0 ? _buildOrder[i].getShortName() : _buildOrder[i].getShortName().substr(0, charactersPerName);\n\n        ss << name << \" \";\n    }\n\n    return ss.str();\n}"
  },
  {
    "path": "BOSS/source/BuildOrder.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"ActionType.h\"\n#include \"GameState.h\"\n\nnamespace BOSS\n{\n\nclass BuildOrder\n{\n    std::vector<ActionType>     _buildOrder;\n    std::vector<size_t>         _typeCount;\n\npublic:\n\n    BuildOrder();\n\n    void                    add(const ActionType & type);\n    void                    add(const ActionType & type, const int & amount);\n    void                    add(const BuildOrder & other);\n    void                    clear();\n    void                    pop_back();\n    void                    sortByPrerequisites();\n\n    bool                    doActions(GameState & state, const size_t buildOrderStartIndex = 0) const;\n    bool                    doActions(GameState & state, const size_t buildOrderStartIndex, const size_t buildOrderEndIndex) const;\n\n    const ActionType &      operator [] (const size_t & i) const;\n    ActionType &            operator [] (const size_t & i);\n\n    const size_t            size() const;\n    const size_t            getTypeCount(const ActionType & type) const;\n    const bool              isLegalFromState(const GameState & state, const size_t buildOrderStartIndex = 0) const;\n    std::string             whyIsNotLegalFromState(const GameState & state, const size_t buildOrderStartIndex = 0) const;\n    const bool              empty() const;\n    const FrameCountType    getCompletionTime(const GameState & state, const size_t buildOrderStartIndex = 0) const;\n\n    std::string             getJSONString() const;\n    std::string             getNumberedString() const;\n    std::string             getIDString() const;\n    std::string             getNameString(const size_t charactersPerName = 0) const;\n};\n\n}"
  },
  {
    "path": "BOSS/source/BuildOrderPlot.cpp",
    "content": "#include \"BuildOrderPlot.h\"\n#include \"Eval.h\"\n\nusing namespace BOSS;\n\nBuildOrderPlot::BuildOrderPlot(const GameState & initialState, const BuildOrder & buildOrder)\n    : _initialState(initialState)\n    , _buildOrder(buildOrder)\n    , _boxHeight(20)\n    , _boxHeightBuffer(3)\n    , _maxLayer(0)\n    , _maxFinishTime(0)\n{\n    calculateStartEndTimes();\n    calculatePlot();\n}\n\nvoid BuildOrderPlot::calculateStartEndTimes()\n{\n    GameState state(_initialState);\n\n    BOSS_ASSERT(_buildOrder.isLegalFromState(state), \"Build order isn't legal!\");\n\n    for (size_t i(0); i < _buildOrder.size(); ++i)\n    {\n        const ActionType & type = _buildOrder[i];\n        state.doAction(type);\n\n        _startTimes.push_back(state.getCurrentFrame());\n\n        FrameCountType finish = state.getCurrentFrame() + type.buildTime();\n        if (type.isBuilding() && !type.isAddon() && !type.isMorphed())\n        {\n            finish += Constants::BUILDING_PLACEMENT;\n        }\n\n        _finishTimes.push_back(finish);\n\n        _maxFinishTime = std::max(_maxFinishTime, finish);\n\n        _armyValues.push_back(Eval::ArmyTotalResourceSum(state));\n\n        std::pair<int, int> mineralsBefore(state.getCurrentFrame(), state.getMinerals() + type.mineralPrice());\n        std::pair<int, int> mineralsAfter(state.getCurrentFrame(), state.getMinerals());\n\n        std::pair<int, int> gasBefore(state.getCurrentFrame(), state.getGas() + type.gasPrice());\n        std::pair<int, int> gasAfter(state.getCurrentFrame(), state.getGas());\n\n        _minerals.push_back(mineralsBefore);\n        _minerals.push_back(mineralsAfter);\n        _gas.push_back(gasBefore);\n        _gas.push_back(gasAfter);\n    }\n}\n\nvoid BuildOrderPlot::calculatePlot()\n{\n    _layers = std::vector<int>(_startTimes.size(), -1); \n\n    // determine the layers for each action\n    for (size_t i(0); i < _startTimes.size(); ++i)\n    {\n        FrameCountType start    = _startTimes[i];\n        FrameCountType finish   = _finishTimes[i];\n\n        std::vector<int> layerOverlap;\n\n        // loop through everything up to this action and see which layers it can't be in\n        for (size_t j(0); j < i; ++j)\n        {\n            if (start < _finishTimes[j])\n            {\n                layerOverlap.push_back(_layers[j]);\n            }\n        }\n\n        // find a layer we can assign to this value\n        int layerTest = 0;\n        while (true)\n        {\n            if (std::find(layerOverlap.begin(), layerOverlap.end(), layerTest) == layerOverlap.end())\n            {\n                _layers[i] = layerTest;\n                if (layerTest > _maxLayer)\n                {\n                    _maxLayer = layerTest;\n                }\n                break;\n            }\n\n            layerTest++;\n        }\n    }\n\n    for (size_t i(0); i < _buildOrder.size(); ++i)\n    {\n        Position topLeft(_startTimes[i], _layers[i] * (_boxHeight + _boxHeightBuffer));\n        Position bottomRight(_finishTimes[i], topLeft.y() + _boxHeight);\n\n        _rectangles.push_back(Rectangle(_buildOrder[i].getShortName(), topLeft, bottomRight));\n    }\n}\n\nvoid BuildOrderPlot::addPlot(const BuildOrderPlot & plot)\n{\n    _otherPlots.push_back(plot);\n}\n\nvoid BuildOrderPlot::writeResourcePlot(const std::string & filename)\n{\n    std::string noext = RemoveFileExtension(filename);\n    std::stringstream mineralss;\n\n    for (size_t i(0); i < _minerals.size(); ++i)\n    {\n        mineralss << _minerals[i].first << \" \" << _minerals[i].second/Constants::RESOURCE_SCALE << std::endl;\n    }\n\n    std::stringstream gasss;\n\n    for (size_t i(0); i < _gas.size(); ++i)\n    {\n        gasss << _gas[i].first << \" \" << _gas[i].second/Constants::RESOURCE_SCALE << std::endl;\n    }\n\n    WriteGnuPlot(noext + \"_minerals\", mineralss.str(), \" with lines \");\n    WriteGnuPlot(noext + \"_gas\", gasss.str(), \" with lines \");\n}\n\nvoid BuildOrderPlot::writeRectanglePlot(const std::string & filename)\n{\n    std::stringstream ss;\n    int maxY = (_maxLayer + 1) * (_boxHeight + _boxHeightBuffer) + 15;\n\n    for (size_t p(0); p < _otherPlots.size(); ++p)\n    {\n        maxY += (_otherPlots[p]._maxLayer + 2) * (_boxHeight + _boxHeightBuffer) + 15;\n    }\n\n    //ss << \"set title \\\"Title Goes Here\\\"\" << std::endl;\n    //ss << \"set xlabel \\\"Time (frames)\\\"\" << std::endl;\n    ss << \"set style rect fc lt -1 fs transparent solid 0.15\" << std::endl;\n    ss << \"set xrange [\" << -(_maxFinishTime*.03) << \":\" << 1.03*_maxFinishTime << \"]\" << std::endl;\n    ss << \"set yrange [-15:\" << maxY << \"]\" << std::endl;\n    ss << \"unset ytics\" << std::endl;\n    ss << \"set grid xtics\" << std::endl;\n    ss << \"set nokey\" << std::endl;\n    //ss << \"set size ratio \" << (0.05 * _maxLayer) << std::endl;\n    ss << \"set terminal wxt size 960,300\" << std::endl;\n    ss << \"plotHeight = \" << 1000 << std::endl;\n    ss << \"boxHeight = \" << _boxHeight << std::endl;\n    ss << \"boxHeightBuffer = \" << _boxHeightBuffer << std::endl;\n    ss << \"boxWidthScale = \" << 1.0 << std::endl;\n\n    for (size_t i(0); i < _buildOrder.size(); ++i)\n    {\n        const Rectangle & rect = _rectangles[i];\n        const int rectWidth = (rect.bottomRight.x() - rect.topLeft.x());\n        const int rectCenterX = rect.bottomRight.x() - (rectWidth / 2);\n        \n        std::stringstream pos;\n        pos << \"(boxWidthScale * \" << rectCenterX << \"),\";\n        pos << \"((boxHeight + boxHeightBuffer) * \" << _layers[i] << \" + boxHeight/2)\";\n\n        ss << \"set object \" << (i+1) << \" rect at \";\n        ss << pos.str();\n        ss << \" size \";\n        ss << \"(boxWidthScale * \" << (rectWidth) << \"),\";\n        ss << \"(boxHeight) \";\n        //ss << \"(boxWidthScale * \" << _finishTimes[i] << \"),\";\n        //ss << \"((boxHeight + boxHeightBuffer) * \" << _layers[i] << \" + boxHeight) \";\n        ss << \"lw 1\";\n\n        if (_buildOrder[i].isWorker())\n        {\n            ss << \" fc rgb \\\"cyan\\\"\";\n        }\n        else if (_buildOrder[i].isSupplyProvider())\n        {\n            ss << \" fc rgb \\\"gold\\\"\";\n        }\n        else if (_buildOrder[i].isRefinery())\n        {\n            ss << \" fc rgb \\\"green\\\"\";\n        }\n        else if (_buildOrder[i].isBuilding())\n        {\n            ss << \" fc rgb \\\"brown\\\"\";\n        }\n        else if (_buildOrder[i].isUpgrade())\n        {\n            ss << \" fc rgb \\\"purple\\\"\";\n        }\n        else if (_buildOrder[i].isTech())\n        {\n            ss << \" fc rgb \\\"magenta\\\"\";\n        }\n\n        ss << std::endl;\n\n        ss << \"set label \" << (i+1) << \" at \" << pos.str() << \" \\\"\" << _buildOrder[i].getShortName() << \"\\\" front center\";\n        ss << std::endl;\n    }\n\n    int currentLayer = _maxLayer + 2;\n    int currentObject = _buildOrder.size();\n\n    for (size_t p(0); p < _otherPlots.size(); ++p)\n    {\n        const BuildOrder & buildOrder = _otherPlots[p]._buildOrder;\n\n        for (size_t i(0); i < buildOrder.size(); ++i)\n        {\n            const Rectangle & rect = _otherPlots[p]._rectangles[i];\n            const int rectWidth = (rect.bottomRight.x() - rect.topLeft.x());\n            const int rectCenterX = rect.bottomRight.x() - (rectWidth / 2);\n        \n            std::stringstream pos;\n            pos << \"(boxWidthScale * \" << rectCenterX << \"),\";\n            pos << \"((boxHeight + boxHeightBuffer) * \" << (_otherPlots[p]._layers[i] + currentLayer) << \" + boxHeight/2)\";\n\n            ss << \"set object \" << (currentObject+i+1) << \" rect at \";\n            ss << pos.str();\n            ss << \" size \";\n            ss << \"(boxWidthScale * \" << (rectWidth) << \"),\";\n            ss << \"(boxHeight) \";\n            //ss << \"(boxWidthScale * \" << _finishTimes[i] << \"),\";\n            //ss << \"((boxHeight + boxHeightBuffer) * \" << _layers[i] << \" + boxHeight) \";\n            ss << \"lw 1\";\n\n            if (buildOrder[i].isWorker())\n            {\n                ss << \" fc rgb \\\"cyan\\\"\";\n            }\n            else if (buildOrder[i].isSupplyProvider())\n            {\n                ss << \" fc rgb \\\"gold\\\"\";\n            }\n            else if (buildOrder[i].isRefinery())\n            {\n                ss << \" fc rgb \\\"green\\\"\";\n            }\n            else if (buildOrder[i].isBuilding())\n            {\n                ss << \" fc rgb \\\"brown\\\"\";\n            }\n            else if (buildOrder[i].isUpgrade())\n            {\n                ss << \" fc rgb \\\"purple\\\"\";\n            }\n            else if (buildOrder[i].isTech())\n            {\n                ss << \" fc rgb \\\"magenta\\\"\";\n            }\n\n            ss << std::endl;\n\n            ss << \"set label \" << (currentObject+i+1) << \" at \" << pos.str() << \" \\\"\" << buildOrder[i].getShortName() << \"\\\" front center\";\n            ss << std::endl;\n        }\n\n        currentLayer += _otherPlots[p]._maxLayer + 2;\n        currentObject += buildOrder.size();\n    }\n\n    ss << \"plot -10000\" << std::endl;\n\n    std::ofstream out(filename);\n    out << ss.str();\n    out.close();\n}\n\nvoid BuildOrderPlot::writeArmyValuePlot(const std::string & filename)\n{\n    std::stringstream datass;\n    for (size_t i(0); i < _buildOrder.size(); ++i)\n    {\n        datass << _startTimes[i] << \" \" << _armyValues[i]/Constants::RESOURCE_SCALE << std::endl;\n    }\n \n    WriteGnuPlot(filename, datass.str(), \" with steps\");\n}\n\nvoid BuildOrderPlot::WriteGnuPlot(const std::string & filename, const std::string & data, const std::string & args)\n{\n    std::string file = RemoveFileExtension(GetFileNameFromPath(filename));\n    std::string noext = RemoveFileExtension(filename);\n\n    std::ofstream dataout(noext + \"_data.txt\");\n    dataout << data;\n    dataout.close();\n\n    std::stringstream ss;\n    ss << \"set xlabel \\\"Time (frames)\\\"\" << std::endl;\n    ss << \"set ylabel \\\"Resource Over Time\\\"\" << std::endl;\n    ss << \"plot \\\"\" << (file + \"_data.txt\") << \"\\\" \" << args << std::endl;\n\n    std::ofstream out(noext + \".gpl\");\n    out << ss.str();\n    out.close();\n}\n\nstd::string BuildOrderPlot::GetFileNameFromPath(const std::string & path)\n{\n    std::string temp(path);\n\n    const size_t last_slash_idx = temp.find_last_of(\"\\\\/\");\n    if (std::string::npos != last_slash_idx)\n    {\n        temp.erase(0, last_slash_idx + 1);\n    }\n    \n    return temp;\n}\n\nstd::string BuildOrderPlot::RemoveFileExtension(const std::string & path)\n{\n    std::string temp(path);\n\n    const size_t period_idx = temp.rfind('.');\n    if (std::string::npos != period_idx)\n    {\n        temp.erase(period_idx);\n    }\n\n    return temp;\n}"
  },
  {
    "path": "BOSS/source/BuildOrderPlot.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"ActionType.h\"\n#include \"GameState.h\"\n#include \"BuildOrder.h\"\n#include \"Position.hpp\"\n\nnamespace BOSS\n{\n\nclass Rectangle\n{\npublic:\n\n    std::string labelText;\n    Position topLeft;\n    Position bottomRight;\n    Rectangle(const std::string & label, Position & tl, const Position & br) : labelText(label), topLeft(tl), bottomRight(br) { }\n};\n\nclass BuildOrderPlot\n{\n    const GameState         _initialState;\n    const BuildOrder        _buildOrder;\n        \n    std::vector<int>        _startTimes;\n    std::vector<int>        _finishTimes;\n    std::vector<int>        _layers;\n    std::vector<double>     _armyValues;\n    std::vector< std::pair<int,int> > _minerals;\n    std::vector< std::pair<int,int> > _gas;\n    std::vector<Rectangle>  _rectangles;\n\n    std::vector<BuildOrderPlot> _otherPlots;\n\n    int                     _maxLayer;\n    int                     _maxFinishTime;\n    int                     _boxHeight;\n    int                     _boxHeightBuffer;\n\n    void calculateStartEndTimes();\n    void calculatePlot();\n\n\npublic:\n\n    BuildOrderPlot(const GameState & initialState, const BuildOrder & buildOrder);\n\n    void writeResourcePlot(const std::string & filename);\n    void writeRectanglePlot(const std::string & filename);\n    void writeArmyValuePlot(const std::string & filename);\n    void writeHybridPlot(const std::string & filename);\n\n    void addPlot(const BuildOrderPlot & plot);\n\n    static std::string GetFileNameFromPath(const std::string & path);\n    static std::string RemoveFileExtension(const std::string & path);\n    static void WriteGnuPlot(const std::string & filename, const std::string & data, const std::string & args);\n};\n\n}"
  },
  {
    "path": "BOSS/source/BuildOrderSearchGoal.cpp",
    "content": "#include \"BuildOrderSearchGoal.h\"\n\nusing namespace BOSS;\n\nBuildOrderSearchGoal::BuildOrderSearchGoal(const RaceID race)\n    : _supplyRequiredVal(0)\n    , _goalUnits(race != Races::None ? ActionTypes::GetAllActionTypes(race).size() : 0, 0)\n    , _goalUnitsMax(race != Races::None ? ActionTypes::GetAllActionTypes(race).size() : 0, 0)\n    , _race(race)\n{\n \n}\n\nvoid BuildOrderSearchGoal::calculateSupplyRequired()\n{\n    _supplyRequiredVal = 0;\n    for (ActionID a(0); a< (int)_goalUnits.size(); ++a)\n    {\n        _supplyRequiredVal += _goalUnits[a] * ActionTypes::GetActionType(_race, a).supplyRequired();\n    }\n}\n\nbool BuildOrderSearchGoal::operator == (const BuildOrderSearchGoal & g)\n{\n    for (ActionID a(0); a< (int)_goalUnits.size(); ++a)\n    {\n        if ((_goalUnits[a] != g._goalUnits[a]) || (_goalUnitsMax[a] != g._goalUnitsMax[a]))\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nvoid BuildOrderSearchGoal::setGoal(const ActionType & a, const UnitCountType num)\n{\n    BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)_goalUnits.size(), \"Action type not valid\");\n    BOSS_ASSERT(a.getRace() == _race, \"Action type race doesn't match this goal object\");\n\n    _goalUnits[a.ID()] = num;\n\n    calculateSupplyRequired();\n}\n\nbool BuildOrderSearchGoal::hasGoal() const\n{\n    for (ActionID a(0); a< (int)_goalUnits.size(); ++a)\n    {\n        if (_goalUnits[a] > 0)\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid BuildOrderSearchGoal::setGoalMax(const ActionType & a, const UnitCountType num)\n{\n    BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)_goalUnitsMax.size(), \"Action type not valid\");\n    BOSS_ASSERT(a.getRace() == _race, \"Action type race doesn't match this goal object\");\n\n    _goalUnitsMax[a.ID()] = num;\n}\n\nUnitCountType BuildOrderSearchGoal::getGoal(const ActionType & a) const\n{\n    BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)_goalUnits.size(), \"Action type not valid\");\n    BOSS_ASSERT(a.getRace() == _race, \"Action type race doesn't match this goal object\");\n\n    return _goalUnits[a.ID()];\n}\n\nUnitCountType BuildOrderSearchGoal::getGoalMax(const ActionType & a) const\n{\n    BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)_goalUnitsMax.size(), \"Action type not valid\");\n    BOSS_ASSERT(a.getRace() == _race, \"Action type race doesn't match this goal object\");\n\n    return _goalUnitsMax[a.ID()];\n}\n\nSupplyCountType BuildOrderSearchGoal::supplyRequired() const\n{\n    return _supplyRequiredVal;\n}\n\nstd::string BuildOrderSearchGoal::toString() const\n{\n    std::stringstream ss;\n    ss << \"\\nSearch Goal Information\\n\\n\";\n\n    for (ActionID a(0); a< (int)_goalUnits.size(); ++a)\n    {\n        if (_goalUnits[a] > 0)\n        {\n            ss << \"        REQ \" << _goalUnits[a] << \" \" <<  ActionTypes::GetActionType(_race, a).getName() << \"\\n\";\n        }\n    }\n\n    for (ActionID a(0); a< (int)_goalUnitsMax.size(); ++a)\n    {\n        if (_goalUnitsMax[a] > 0)\n        {\n            ss << \"        MAX \" << _goalUnitsMax[a]  << \" \" << ActionTypes::GetActionType(_race, a).getName() << \"\\n\";\n        }\n    }\n\n    return ss.str();\n}\n\nbool BuildOrderSearchGoal::isAchievedBy(const GameState & state)\n{\n    static const ActionType & Hatchery      = ActionTypes::GetActionType(\"Zerg_Hatchery\");\n    static const ActionType & Lair          = ActionTypes::GetActionType(\"Zerg_Lair\");\n    static const ActionType & Hive          = ActionTypes::GetActionType(\"Zerg_Hive\");\n    static const ActionType & Spire         = ActionTypes::GetActionType(\"Zerg_Spire\");\n    static const ActionType & GreaterSpire  = ActionTypes::GetActionType(\"Zerg_Greater_Spire\");\n\n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(state.getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(state.getRace(), a);\n\n        int have = state.getUnitData().getNumTotal(actionType);\n\n        if (state.getRace() == Races::Zerg)\n        {\n            if (actionType == Hatchery)\n            {\n                have += state.getUnitData().getNumTotal(Lair);\n                have += state.getUnitData().getNumTotal(Hive);\n            }\n            else if (actionType == Lair)\n            {\n                have += state.getUnitData().getNumTotal(Hive);\n            }\n            else if (actionType == Spire)\n            {\n                have += state.getUnitData().getNumTotal(GreaterSpire);\n            }\n        }\n\n        if (have < getGoal(actionType))\n        {\n            return false;\n        }\n    }\n\n    return true;\n}"
  },
  {
    "path": "BOSS/source/BuildOrderSearchGoal.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"ActionType.h\"\n#include \"ActionSet.h\"\n#include \"GameState.h\"\n\nnamespace BOSS\n{\nclass BuildOrderSearchGoal\n{\n\tstd::vector<UnitCountType>  _goalUnits;                 // vector of goal number of units indexed by ActionType ID\n\tstd::vector<UnitCountType>\t_goalUnitsMax;              // vector of goal max number of units indexed by ActionType ID\n\t\n\tSupplyCountType\t\t        _supplyRequiredVal;         // amount of supply required for all goal units in _goalUnits\n\n    RaceID                      _race;                      // race of the action types in the goal\n\t\n\tvoid                        calculateSupplyRequired();\n\t\npublic:\t\n\t\n\tBuildOrderSearchGoal(const RaceID race = Races::None);\n\t\n\tbool                operator == (const BuildOrderSearchGoal & g);\n\tbool                hasGoal() const;\n    bool                isAchievedBy(const GameState & state);\n\n\tSupplyCountType     supplyRequired() const;\n\tUnitCountType       operator [] (const ActionID & a) const;\n\tUnitCountType       getGoal(const ActionType & a) const;\n\tUnitCountType       getGoalMax(const ActionType & a) const;\n\t\n\tvoid                setGoal(const ActionType & a, const UnitCountType num);\n\tvoid                setGoalMax(const ActionType & a, const UnitCountType num);\n\tstd::string         toString() const;\n};\n}\n"
  },
  {
    "path": "BOSS/source/BuildOrderTester.cpp",
    "content": "#include \"BuildOrderTester.h\"\n#include \"JSONTools.h\"\n#include \"NaiveBuildOrderSearch.h\"\n\nusing namespace BOSS;\n\nBuildOrderSearchGoal BuildOrderTester::GetRandomGoal(const RaceID race)\n{\n    BuildOrderSearchGoal goal(race);\n    \n    const std::vector<ActionType> & allActionTypes = ActionTypes::GetAllActionTypes(race);\n    size_t totalActionTypes = allActionTypes.size();\n\n    size_t numUnits = 6;\n    size_t maxOfUnit = 5;\n\n    for (size_t i(0); i < numUnits; ++i)\n    {\n        const ActionType randomAction = allActionTypes[rand() % totalActionTypes];\n\n        if (randomAction.getUnitType() == BWAPI::UnitTypes::Protoss_Dark_Archon ||\n            randomAction.getUnitType() == BWAPI::UnitTypes::Protoss_Archon ||\n            randomAction.getUnitType() == BWAPI::UnitTypes::Zerg_Larva)\n        {\n            continue;\n        }\n\n        int numToAdd = rand() % maxOfUnit;\n\n        if (randomAction.isUnit() && !randomAction.isRefinery())\n        {\n            \n            goal.setGoal(randomAction, numToAdd);\n        }\n        else\n        {\n            goal.setGoal(randomAction, 1);\n        }\n    }\n\n    return goal;\n}\n\nvoid BuildOrderTester::TestRandomBuilds(const RaceID race, const size_t numTests)\n{\n    for (size_t i(0); i < numTests; ++i)\n    {\n        GameState state = GetStartState(race, 20);            \n    }\n}\n\nGameState BuildOrderTester::GetStartState(const RaceID race, int randomActions)\n{\n    GameState state(race);\n    state.setStartingState();\n    GameState copyState(state);\n    \n    BuildOrder randomBuildOrder;\n    int i = 0;\n\n    //try\n    {\n        for (i = 0; i < randomActions; ++i)\n        {\n            ActionSet legalActions;\n            state.getAllLegalActions(legalActions);\n            \n            if (legalActions.isEmpty())\n            {\n                std::cout << i << \" Legal Actions Empty!\" << std::endl;\n                std::cout << randomBuildOrder.getNumberedString() << std::endl;\n                std::cout << state.toString() << std::endl;\n               \n            }\n\n\n            ActionType randomAction = legalActions[rand() % legalActions.size()];\n\n           \n\n            if (!randomAction.isResourceDepot())\n            {\n                BOSS_ASSERT(state.isLegal(randomAction), \"Should be a legal action!\");\n\n                randomBuildOrder.add(randomAction);\n                state.doAction(randomAction);\n            }\n        }\n    }\n    /*catch (Assert::BOSSException e)\n    {\n        std::cout << std::endl << \"Random State Error @ \" << i << \": \" << randomBuildOrder[i-1].getName() << std::endl << std::endl;\n\n        std::cout << randomBuildOrder.getJSONString() << std::endl;\n\n        std::cout << randomBuildOrder.getNumberedString() << std::endl;\n\n        std::cout << state.toString() << std::endl;\n\n        for (size_t a(0); a < randomBuildOrder.size(); ++a)\n        {\n            std::cout << \"About to do: \" << randomBuildOrder[a].getName() << std::endl;\n            std::cout << copyState.toString() << std::endl;\n            copyState.doAction(randomBuildOrder[a]);\n        }\n\n        randomBuildOrder.doActions(copyState, 0, randomBuildOrder.size()-1);\n\n        std::cout << copyState.toString();\n\n        copyState.doAction(randomBuildOrder[randomBuildOrder.size()-1]);\n\n        exit(-1);\n    }*/\n\n    return state;\n}\n\nvoid BuildOrderTester::DoRandomTests(const RaceID race, const size_t numTests)\n{\n    GameState startState(race);\n    startState.setStartingState();\n    \n    srand((int)time(NULL));\n\n    for (size_t i(0); i < numTests; ++i)\n    {\n        if (i && !(i % 100000))\n        {\n            std::cout << Races::GetRaceName(race) << \" \" << i << std::endl;\n        }\n\n        //GameState startState = GetStartState(race, 20);\n        BuildOrderSearchGoal goal = GetRandomGoal(race);\n        \n        NaiveBuildOrderSearch naiveSearch(startState, goal);\n        \n        const BuildOrder & buildOrder = naiveSearch.solve();\n\n        GameState currentState(startState);\n        bool buildOrderIsLegal = buildOrder.doActions(currentState);\n\n        if (buildOrderIsLegal)\n        {\n            if (goal.isAchievedBy(currentState))\n            {\n                //std::cout << i << \"  Test Passed!\" << std::endl;\n            }\n            else\n            {\n                std::cout << goal.toString();\n                for (size_t a(0); a < buildOrder.size(); ++a)\n                {\n                    std::cout << a << \" \" << buildOrder[a].getName() << std::endl;\n                }\n                std::cout << i << \"  Found build order did not meet goal\" << std::endl;\n                std::cout << buildOrder.getJSONString() << std::endl;\n                std::cout << currentState.toString() << std::endl;\n                std::cout << goal.toString();\n            }\n        }\n        else\n        {\n            std::cout << goal.toString();\n            for (size_t a(0); a < buildOrder.size(); ++a)\n            {\n                std::cout << a << \" \" << buildOrder[a].getName() << std::endl;\n            }\n            std::cout << buildOrder.getJSONString() << std::endl;\n            std::cout << i << \"  Found build-order was not legal\" << std::endl;\n            std::cout << currentState.toString() << std::endl;\n\n        }\n    }\n}"
  },
  {
    "path": "BOSS/source/BuildOrderTester.h",
    "content": "#pragma once\n\n#include \"BOSS.h\"\n\nnamespace BOSS\n{\n\nnamespace BuildOrderTester\n{\n    GameState GetStartState(const RaceID race, int randomActions);\n    BuildOrderSearchGoal GetRandomGoal(const RaceID race);\n    void DoRandomTests(const RaceID race, const size_t numTests);\n\n    void TestRandomBuilds(const RaceID race, const size_t numTests);\n}\n}"
  },
  {
    "path": "BOSS/source/BuildingData.cpp",
    "content": "#include \"BuildingData.h\"\n\nusing namespace BOSS;\n\nBuildingStatus::BuildingStatus() \n: _type(ActionTypes::None)\n, _timeRemaining(0) \n, _isConstructing(ActionTypes::None)\n, _addon(ActionTypes::None)\n{\n\t\n}\n\t\nBuildingStatus::BuildingStatus(const ActionType & action, const ActionType & addon) \n: _type(action)\n, _timeRemaining(0) \n, _isConstructing(ActionTypes::None)\n, _addon(addon)\n{\n}\n\nBuildingStatus::BuildingStatus(const ActionType & action, FrameCountType time, const ActionType & constructing, const ActionType & addon) \n: _type(action)\n, _timeRemaining(time) \n, _isConstructing(constructing)\n, _addon(addon)\n{\n}\n\nconst bool BuildingStatus::canBuildEventually(const ActionType & action) const\n{\n    if (!_type.canBuild(action))\n    {\n        return false;\n    }\n\n    // if the type is an addon\n    if (action.isAddon())\n    {\n        // if we already have an addon we can't build it\n        if (_addon != ActionTypes::None)\n        {\n            return false;\n        }\n\n        // if we are building an addon we can't ever build it\n        if (_timeRemaining > 0 && _isConstructing.isAddon())\n        {\n            return false;\n        }\n    }\n\n    if (action.requiresAddon() && (_addon != action.requiredAddonType()))\n    {\n        if (_isConstructing != action.requiredAddonType())\n        {\n            return false;\n        }\n    }\n\n    // if the built type is morphed and we are morphing something, we won't be able to build it\n    if (action.isMorphed() && (_timeRemaining > 0) && (_isConstructing.isMorphed()))\n    {\n        return false;\n    }\n\n    return true;\n}\n\nconst bool BuildingStatus::canBuildNow(const ActionType & action) const\n{\n    if (_timeRemaining > 0)\n    {\n        return false;\n    }\n\n    if (!_type.canBuild(action))\n    {\n        return false;\n    }\n\n    if (action.isAddon() && (_addon != ActionTypes::None))\n    {\n        return false;\n    }\n\n    if (action.requiresAddon() && (_addon != action.requiredAddonType()))\n    {\n        return false;\n    }\n\n\n    return true;\n}\n\nvoid BuildingStatus::queueActionType(const ActionType & action)\n{\n    _timeRemaining = action.buildTime();\n    _isConstructing = action;\n}\n\nvoid BuildingStatus::fastForward(const FrameCountType frames)\n{\n    // if we fastforward more than the current time remaining, we will complete the action\n    bool willComplete = _timeRemaining <= frames;\n    int timeWasRemaining = _timeRemaining;\n    const std::string & name = _type.getName();\n\n    if ((_timeRemaining > 0) && willComplete)\n    {\n        BOSS_ASSERT(_isConstructing != ActionTypes::None, \"We can't be building a unit without a type %s %d\", _type.getName().c_str(), timeWasRemaining);\n\n        _timeRemaining = 0;\n\n        // if it's building an addon, add it\n        if (_isConstructing.isAddon())\n        {\n            _addon = _isConstructing;\n        }\n\n        // if we are finishing a morphed type, it becomes that type\n        if (_isConstructing.isMorphed())\n        {\n            _type = _isConstructing;\n        }\n\n        _isConstructing = ActionTypes::None;\n    }\n    else if (_timeRemaining > 0)\n    {\n        _timeRemaining -= frames;\n    }\n}\n\nBuildingData::BuildingData() \n{\n}\n\nconst size_t & BuildingData::size() const\n{\n    return _buildings.size();\n}\n\nvoid BuildingData::addBuilding(const ActionType & action, const ActionType & addon)\n{\n\tBOSS_ASSERT(action.isBuilding(), \"Trying to add a non-building to the building data\");\n\t\n    _buildings.push_back(BuildingStatus(action, addon));\n}\n\nvoid BuildingData::removeBuilding(const ActionType & action, const ActionType & addon)\n{\n\tBOSS_ASSERT(action.isBuilding(), \"Trying to remove a non-building from the building data\");\n\n\tfor (size_t i = 0; i < _buildings.size(); i++)\n\t{\n\t\tif (_buildings[i]._type == action)\n\t\t{\n\t\t\t_buildings.remove(i);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid BuildingData::addBuilding(const ActionType & action, const FrameCountType timeUntilFree, const ActionType & constructing, const ActionType & addon)\n{\n\tBOSS_ASSERT(action.isBuilding(), \"Trying to add a non-building to the building data\");\n\t\n    _buildings.push_back(BuildingStatus(action, timeUntilFree, constructing, addon));\n}\n\nconst BuildingStatus & BuildingData::getBuilding(const UnitCountType i) const\n{\n\treturn _buildings[i];\n}\n\n// how long from now until we can build the given action\nconst FrameCountType BuildingData::getTimeUntilCanBuild(const ActionType & action) const\n{\n    bool minset = false;\n\tFrameCountType min = 0;\n\t\n    for (size_t i=0; i<_buildings.size(); ++i)\n\t{\n        if (_buildings[i].canBuildEventually(action))\n        {\n            if (!minset || _buildings[i]._timeRemaining < min)\n            {\n                minset = true;\n                min = _buildings[i]._timeRemaining;\n            }\n        }\n    }\n\n\n    BOSS_ASSERT(minset, \"Min was not set\");\n    return min;\n}\n\nvoid BuildingData::queueAction(const ActionType & action)\n{\t\n\tfor (size_t i=0; i<_buildings.size(); ++i)\n\t{\n\t\tif (_buildings[i].canBuildNow(action))\n\t\t{\n\t\t\t_buildings[i].queueActionType(action);\n\t\t\treturn;\n\t\t}\n\t}\n\t\t\n\t// this method should always work since we have fast forwarded to the correct point in time\n\tBOSS_ASSERT(false, \"Didn't find a building to queue this type of unit in: %s\", action.getName().c_str());\n}\n\t\n// fast forward all the building states by amount: frames\nvoid BuildingData::fastForwardBuildings(const FrameCountType frames)\n{\n\tfor (size_t i=0; i<_buildings.size(); ++i)\n\t{\n        _buildings[i].fastForward(frames);\n\t}\n}\n\nstd::string BuildingData::toString() const\n{\n    std::stringstream ss;\n    ss << \"Buildings\\n\\n\";\n\n    for (size_t i=0; i<_buildings.size(); ++i)\n\t{\n        const BuildingStatus & b = _buildings[i];\n        ss << b._type.getName() << \"   \"; \n        ss << b._timeRemaining << \"   \"; \n        ss << (b._isConstructing != ActionTypes::None ? b._isConstructing.getName() : \"None\") << \"   \";\n        ss << (b._addon != ActionTypes::None ? b._addon.getName() : \"None\") << \"\\n\";\n    }\n\n    return ss.str();\n}\n\t\nconst bool BuildingData::canBuildNow(const ActionType & action) const\n{\n    for (size_t i=0; i<_buildings.size(); ++i)\n\t{\n        if (_buildings[i].canBuildNow(action))\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nconst bool BuildingData::canBuildEventually(const ActionType & action) const\n{\n    for (size_t i=0; i<_buildings.size(); ++i)\n\t{\n        if (_buildings[i].canBuildEventually(action))\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid BuildingData::printBuildingInformation() const\n{\n\tfor (size_t i=0; i<_buildings.size(); ++i)\n\t{\n\t\tif (_buildings[i]._timeRemaining == 0) \n\t\t{\n\t\t\tprintf(\"BUILDING INFO: %s is free to assign\\n\", _buildings[i]._type.getName().c_str());\n\t\t}\n\t\telse \n\t\t{\n\t\t\tprintf(\"BUILDING INFO: %s will be free in %d frames\\n\", _buildings[i]._type.getName().c_str(), _buildings[i]._timeRemaining);\n\t\t}\n\t}\n\t\t\n\tprintf(\"-----------------------------------------------------------\\n\\n\");\n}"
  },
  {
    "path": "BOSS/source/BuildingData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\n#include <string.h>\n#include <queue>\n#include <algorithm>\n\n#include \"PrerequisiteSet.h\"\n#include \"Array.hpp\"\n#include \"ActionType.h\"\n\nnamespace BOSS\n{\n    \nclass BuildingStatus\n{\n\npublic:\n\n\tActionType _type;               // the type of building this is\n    FrameCountType _timeRemaining;  // amount of time until the unit is finished constructing\n    ActionType _isConstructing;     // the type of unit the building is currently constructing\n    ActionType _addon;              // the type of addon that the building currently has (is set once completed)\n\t\n\t// the number of frames remaining (from currentFrame) until this building is free\n\t\n\n\tBuildingStatus();\n\t\n\tBuildingStatus(const ActionType & t, const ActionType & addon);\n\tBuildingStatus(const ActionType & t, FrameCountType time, const ActionType & constructing, const ActionType & addon);\n\n    const bool canBuildNow(const ActionType & action) const;\n    const bool canBuildEventually(const ActionType & action) const;\n    void queueActionType(const ActionType & action);\n    void fastForward(const FrameCountType frames);\n\n    const std::string toString() const;\n};\n\nclass BuildingData\n{\n\tVec<BuildingStatus, Constants::MAX_BUILDINGS> _buildings;\n\npublic:\n\n\tBuildingData();\n\n\tvoid addBuilding(const ActionType & action, const ActionType & addon);\n\tvoid removeBuilding(const ActionType & action, const ActionType & addon);\n\tvoid addBuilding(const ActionType & action, const FrameCountType timeUntilFree, const ActionType & constructing, const ActionType & addon);\n\n\tconst BuildingStatus & getBuilding(const UnitCountType i) const;\n\t\n    const FrameCountType getTimeUntilCanBuild(const ActionType & action) const;\n\n\t// queue an action\n\tvoid queueAction(const ActionType & action);\n\tvoid fastForwardBuildings(const FrameCountType frames);\n\tvoid printBuildingInformation() const;\n    const size_t & size() const;\n\n    const bool canBuildNow(const ActionType & action) const;\n    const bool canBuildEventually(const ActionType & action) const;\n\n    std::string toString() const;\n};\n}"
  },
  {
    "path": "BOSS/source/CImg/CImg.h",
    "content": "/*\n #\n #  File            : CImg.h\n #                    ( C++ header file )\n #\n #  Description     : The C++ Template Image Processing Toolkit.\n #                    This file is the main component of the CImg Library project.\n #                    ( http://cimg.eu )\n #\n #  Project manager : David Tschumperle.\n #                    ( http://tschumperle.users.greyc.fr/ )\n #\n #                    A complete list of contributors is available in file 'README.txt'\n #                    distributed within the CImg package.\n #\n #  Licenses        : This file is 'dual-licensed', you have to choose one\n #                    of the two licenses below to apply.\n #\n #                    CeCILL-C\n #                    The CeCILL-C license is close to the GNU LGPL.\n #                    ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )\n #\n #                or  CeCILL v2.0\n #                    The CeCILL license is compatible with the GNU GPL.\n #                    ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )\n #\n #  This software is governed either by the CeCILL or the CeCILL-C license\n #  under French law and abiding by the rules of distribution of free software.\n #  You can  use, modify and or redistribute the software under the terms of\n #  the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA\n #  at the following URL: \"http://www.cecill.info\".\n #\n #  As a counterpart to the access to the source code and  rights to copy,\n #  modify and redistribute granted by the license, users are provided only\n #  with a limited warranty  and the software's author,  the holder of the\n #  economic rights,  and the successive licensors  have only  limited\n #  liability.\n #\n #  In this respect, the user's attention is drawn to the risks associated\n #  with loading,  using,  modifying and/or developing or reproducing the\n #  software by the user in light of its specific status of free software,\n #  that may mean  that it is complicated to manipulate,  and  that  also\n #  therefore means  that it is reserved for developers  and  experienced\n #  professionals having in-depth computer knowledge. Users are therefore\n #  encouraged to load and test the software's suitability as regards their\n #  requirements in conditions enabling the security of their systems and/or\n #  data to be ensured and,  more generally, to use and operate it in the\n #  same conditions as regards security.\n #\n #  The fact that you are presently reading this means that you have had\n #  knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.\n #\n*/\n\n// Set version number of the library.\n#ifndef cimg_version\n#define cimg_version 171\n\n/*-----------------------------------------------------------\n #\n # Test and possibly auto-set CImg configuration variables\n # and include required headers.\n #\n # If you find that the default configuration variables are\n # not adapted to your system, you can override their values\n # before including the header file \"CImg.h\"\n # (use the #define directive).\n #\n ------------------------------------------------------------*/\n\n// Include standard C++ headers.\n// This is the minimal set of required headers to make CImg-based codes compile.\n#include <cstdio>\n#include <cstdlib>\n#include <cstdarg>\n#include <cstring>\n#include <cmath>\n#include <cfloat>\n#include <climits>\n#include <ctime>\n#include <exception>\n\n// Detect/configure OS variables.\n//\n// Define 'cimg_OS' to: '0' for an unknown OS (will try to minize library dependencies).\n//                      '1' for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).\n//                      '2' for Microsoft Windows.\n//                      (auto-detection is performed if 'cimg_OS' is not set by the user).\n#ifndef cimg_OS\n#if defined(unix)        || defined(__unix)      || defined(__unix__) \\\n || defined(linux)       || defined(__linux)     || defined(__linux__) \\\n || defined(sun)         || defined(__sun) \\\n || defined(BSD)         || defined(__OpenBSD__) || defined(__NetBSD__) \\\n || defined(__FreeBSD__) || defined (__DragonFly__) \\\n || defined(sgi)         || defined(__sgi) \\\n || defined(__MACOSX__)  || defined(__APPLE__) \\\n || defined(__CYGWIN__)\n#define cimg_OS 1\n#elif defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \\\n   || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__)\n#define cimg_OS 2\n#else\n#define cimg_OS 0\n#endif\n#elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)\n#error CImg Library: Invalid configuration variable 'cimg_OS'.\n#error (correct values are '0 = unknown OS', '1 = Unix-like OS', '2 = Microsoft Windows').\n#endif\n\n// Disable silly warnings on some Microsoft VC++ compilers.\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable:4127)\n#pragma warning(disable:4244)\n#pragma warning(disable:4311)\n#pragma warning(disable:4312)\n#pragma warning(disable:4512)\n#pragma warning(disable:4571)\n#pragma warning(disable:4640)\n#pragma warning(disable:4706)\n#pragma warning(disable:4710)\n#pragma warning(disable:4800)\n#pragma warning(disable:4804)\n#pragma warning(disable:4820)\n#pragma warning(disable:4996)\n#define _CRT_SECURE_NO_DEPRECATE 1\n#define _CRT_SECURE_NO_WARNINGS 1\n#define _CRT_NONSTDC_NO_DEPRECATE 1\n#endif\n\n// Define correct string functions for each compiler and OS.\n#if cimg_OS==2 && defined(_MSC_VER)\n#define cimg_sscanf std::sscanf\n#define cimg_sprintf std::sprintf\n#define cimg_snprintf cimg::_snprintf\n#define cimg_vsnprintf cimg::_vsnprintf\n#else\n#include <stdio.h>\n#if defined(__MACOSX__) || defined(__APPLE__)\n#define cimg_sscanf cimg::_sscanf\n#define cimg_sprintf cimg::_sprintf\n#define cimg_snprintf cimg::_snprintf\n#define cimg_vsnprintf cimg::_vsnprintf\n#else\n#define cimg_sscanf std::sscanf\n#define cimg_sprintf std::sprintf\n#define cimg_snprintf snprintf\n#define cimg_vsnprintf vsnprintf\n#endif\n#endif\n\n// Include OS-specific headers.\n#if cimg_OS==1\n#include <sys/types.h>\n#include <sys/time.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <dirent.h>\n#include <fnmatch.h>\n#elif cimg_OS==2\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#include <windows.h>\n#ifndef _WIN32_IE\n#define _WIN32_IE 0x0400\n#endif\n#include <shlobj.h>\n#include <process.h>\n#include <io.h>\n#endif\n\n// Look for C++11 features.\n#if !defined(cimg_use_cpp11) && __cplusplus>201100\n#define cimg_use_cpp11 1\n#endif\n#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0\n#include <initializer_list>\n#include <utility>\n#endif\n\n// Define own types 'cimg_long/ulong' and 'cimg_int64/uint64' to ensure portability.\n// ( constrained to 'sizeof(cimg_ulong/cimg_long) = sizeof(void*)' and 'sizeof(cimg_int64/cimg_uint64)=8' ).\n#if cimg_OS==2\n#define cimg_uint64 unsigned __int64\n#define cimg_int64 __int64\n#define cimg_ulong UINT_PTR\n#define cimg_long INT_PTR\n#else\n#if UINTPTR_MAX==0xffffffff\n#define cimg_uint64 unsigned long long\n#define cimg_int64 long long\n#else\n#define cimg_uint64 unsigned long\n#define cimg_int64 long\n#endif\n#define cimg_ulong unsigned long\n#define cimg_long long\n#endif\n\n// Configure the 'abort' signal handler (does nothing by default).\n// A typical signal handler can be defined in your own source like this:\n// Without OpenMP support: #define cimg_test_abort() if (is_abort) throw CImgAbortException(\"\")\n//\n// or\n//\n// With OpenMP support: #define cimg_test_abort() if (!omp_get_thread_num() && is_abort) throw CImgAbortException(\"\")\n//\n// where 'is_abort' is a boolean variable.\n#ifndef cimg_test_abort\n#define cimg_test_abort()\n#endif\n\n// Configure filename separator.\n//\n// Filename separator is set by default to '/', except for Windows where it is '\\'.\n#ifndef cimg_file_separator\n#if cimg_OS==2\n#define cimg_file_separator '\\\\'\n#else\n#define cimg_file_separator '/'\n#endif\n#endif\n\n// Configure verbosity of output messages.\n//\n// Define 'cimg_verbosity' to: '0' to hide library messages (quiet mode).\n//                             '1' to output library messages on the console.\n//                             '2' to output library messages on a basic dialog window (default behavior).\n//                             '3' to do as '1' + add extra warnings (may slow down the code!).\n//                             '4' to do as '2' + add extra warnings (may slow down the code!).\n//\n// Define 'cimg_strict_warnings' to replace warning messages by exception throwns.\n//\n// Define 'cimg_use_vt100' to allow output of color messages on VT100-compatible terminals.\n#ifndef cimg_verbosity\n#if cimg_OS==2\n#define cimg_verbosity 2\n#else\n#define cimg_verbosity 1\n#endif\n#elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4)\n#error CImg Library: Configuration variable 'cimg_verbosity' is badly defined.\n#error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }).\n#endif\n\n// Configure display framework.\n//\n// Define 'cimg_display' to: '0' to disable display capabilities.\n//                           '1' to use the X-Window framework (X11).\n//                           '2' to use the Microsoft GDI32 framework.\n#ifndef cimg_display\n#if cimg_OS==0\n#define cimg_display 0\n#elif cimg_OS==1\n#define cimg_display 1\n#elif cimg_OS==2\n#define cimg_display 2\n#endif\n#elif !(cimg_display==0 || cimg_display==1 || cimg_display==2)\n#error CImg Library: Configuration variable 'cimg_display' is badly defined.\n#error (should be { 0=none | 1=X-Window (X11) | 2=Microsoft GDI32 }).\n#endif\n\n// Include display-specific headers.\n#if cimg_display==1\n#include <X11/Xlib.h>\n#include <X11/Xutil.h>\n#include <X11/keysym.h>\n#include <pthread.h>\n#ifdef cimg_use_xshm\n#include <sys/ipc.h>\n#include <sys/shm.h>\n#include <X11/extensions/XShm.h>\n#endif\n#ifdef cimg_use_xrandr\n#include <X11/extensions/Xrandr.h>\n#endif\n#endif\n#ifndef cimg_appname\n#define cimg_appname \"CImg\"\n#endif\n\n// Configure OpenMP support.\n// (http://www.openmp.org)\n//\n// Define 'cimg_use_openmp' to enable OpenMP support.\n//\n// OpenMP directives may be used in a (very) few CImg functions to get\n// advantages of multi-core CPUs.\n#ifdef cimg_use_openmp\n#include <omp.h>\n#endif\n\n// Configure OpenCV support.\n// (http://opencv.willowgarage.com/wiki/)\n//\n// Define 'cimg_use_opencv' to enable OpenCV support.\n//\n// OpenCV library may be used to access images from cameras\n// (see method 'CImg<T>::load_camera()').\n#ifdef cimg_use_opencv\n#ifdef True\n#undef True\n#define _cimg_redefine_True\n#endif\n#ifdef False\n#undef False\n#define _cimg_redefine_False\n#endif\n#include <cstddef>\n#include \"cv.h\"\n#include \"highgui.h\"\n#endif\n\n// Configure LibPNG support.\n// (http://www.libpng.org)\n//\n// Define 'cimg_use_png' to enable LibPNG support.\n//\n// PNG library may be used to get a native support of '.png' files.\n// (see methods 'CImg<T>::{load,save}_png()'.\n#ifdef cimg_use_png\nextern \"C\" {\n#include \"png.h\"\n}\n#endif\n\n// Configure LibJPEG support.\n// (http://en.wikipedia.org/wiki/Libjpeg)\n//\n// Define 'cimg_use_jpeg' to enable LibJPEG support.\n//\n// JPEG library may be used to get a native support of '.jpg' files.\n// (see methods 'CImg<T>::{load,save}_jpeg()').\n#ifdef cimg_use_jpeg\nextern \"C\" {\n#include \"jpeglib.h\"\n#include \"setjmp.h\"\n}\n#endif\n\n// Configure LibTIFF support.\n// (http://www.libtiff.org)\n//\n// Define 'cimg_use_tiff' to enable LibTIFF support.\n//\n// TIFF library may be used to get a native support of '.tif' files.\n// (see methods 'CImg[List]<T>::{load,save}_tiff()').\n#ifdef cimg_use_tiff\nextern \"C\" {\n#define uint64 uint64_hack_\n#define int64 int64_hack_\n#include \"tiffio.h\"\n#undef uint64\n#undef int64\n}\n#endif\n\n// Configure LibMINC2 support.\n// (http://en.wikibooks.org/wiki/MINC/Reference/MINC2.0_File_Format_Reference)\n//\n// Define 'cimg_use_minc2' to enable LibMINC2 support.\n//\n// MINC2 library may be used to get a native support of '.mnc' files.\n// (see methods 'CImg<T>::{load,save}_minc2()').\n#ifdef cimg_use_minc2\n#include \"minc_io_simple_volume.h\"\n#include \"minc_1_simple.h\"\n#include \"minc_1_simple_rw.h\"\n#endif\n\n// Configure Zlib support.\n// (http://www.zlib.net)\n//\n// Define 'cimg_use_zlib' to enable Zlib support.\n//\n// Zlib library may be used to allow compressed data in '.cimgz' files\n// (see methods 'CImg[List]<T>::{load,save}_cimg()').\n#ifdef cimg_use_zlib\nextern \"C\" {\n#include \"zlib.h\"\n}\n#endif\n\n// Configure libcurl support.\n// (http://curl.haxx.se/libcurl/)\n//\n// Define 'cimg_use_curl' to enable libcurl support.\n//\n// Libcurl may be used to get a native support of file downloading from the network.\n// (see method 'cimg::load_network()'.)\n#ifdef cimg_use_curl\n#include \"curl/curl.h\"\n#endif\n\n// Configure Magick++ support.\n// (http://www.imagemagick.org/Magick++)\n//\n// Define 'cimg_use_magick' to enable Magick++ support.\n//\n// Magick++ library may be used to get a native support of various image file formats.\n// (see methods 'CImg<T>::{load,save}()').\n#ifdef cimg_use_magick\n#include \"Magick++.h\"\n#endif\n\n// Configure FFTW3 support.\n// (http://www.fftw.org)\n//\n// Define 'cimg_use_fftw3' to enable libFFTW3 support.\n//\n// FFTW3 library may be used to efficiently compute the Fast Fourier Transform\n// of image data, without restriction on the image size.\n// (see method 'CImg[List]<T>::FFT()').\n#ifdef cimg_use_fftw3\nextern \"C\" {\n#include \"fftw3.h\"\n}\n#endif\n\n// Configure LibBoard support.\n// (http://libboard.sourceforge.net/)\n//\n// Define 'cimg_use_board' to enable Board support.\n//\n// Board library may be used to draw 3d objects in vector-graphics canvas\n// that can be saved as '.ps' or '.svg' files afterwards.\n// (see method 'CImg<T>::draw_object3d()').\n#ifdef cimg_use_board\n#ifdef None\n#undef None\n#define _cimg_redefine_None\n#endif\n#include \"Board.h\"\n#endif\n\n// Configure OpenEXR support.\n// (http://www.openexr.com/)\n//\n// Define 'cimg_use_openexr' to enable OpenEXR support.\n//\n// OpenEXR library may be used to get a native support of '.exr' files.\n// (see methods 'CImg<T>::{load,save}_exr()').\n#ifdef cimg_use_openexr\n#include \"ImfRgbaFile.h\"\n#include \"ImfInputFile.h\"\n#include \"ImfChannelList.h\"\n#include \"ImfMatrixAttribute.h\"\n#include \"ImfArray.h\"\n#endif\n\n// Lapack configuration.\n// (http://www.netlib.org/lapack)\n//\n// Define 'cimg_use_lapack' to enable LAPACK support.\n//\n// Lapack library may be used in several CImg methods to speed up\n// matrix computations (eigenvalues, inverse, ...).\n#ifdef cimg_use_lapack\nextern \"C\" {\n  extern void sgetrf_(int*, int*, float*, int*, int*, int*);\n  extern void sgetri_(int*, float*, int*, int*, float*, int*, int*);\n  extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*);\n  extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*);\n  extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*);\n  extern void dgetrf_(int*, int*, double*, int*, int*, int*);\n  extern void dgetri_(int*, double*, int*, int*, double*, int*, int*);\n  extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*);\n  extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*,\n                      int*, double*, int*, double*, int*, int*);\n  extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*);\n  extern void dgels_(char*, int*,int*,int*,double*,int*,double*,int*,double*,int*,int*);\n  extern void sgels_(char*, int*,int*,int*,float*,int*,float*,int*,float*,int*,int*);\n}\n#endif\n\n// Check if min/max/PI macros are defined.\n//\n// CImg does not compile if macros 'min', 'max' or 'PI' are defined,\n// because it redefines functions min(), max() and const variable PI in the cimg:: namespace.\n// so it '#undef' these macros if necessary, and restore them to reasonable\n// values at the end of this file.\n#ifdef min\n#undef min\n#define _cimg_redefine_min\n#endif\n#ifdef max\n#undef max\n#define _cimg_redefine_max\n#endif\n#ifdef PI\n#undef PI\n#define _cimg_redefine_PI\n#endif\n\n// Define 'cimg_library' namespace suffix.\n//\n// You may want to add a suffix to the 'cimg_library' namespace, for instance if you need to work\n// with several versions of the library at the same time.\n#ifdef cimg_namespace_suffix\n#define __cimg_library_suffixed(s) cimg_library_##s\n#define _cimg_library_suffixed(s) __cimg_library_suffixed(s)\n#define cimg_library_suffixed _cimg_library_suffixed(cimg_namespace_suffix)\n#else\n#define cimg_library_suffixed cimg_library\n#endif\n\n/*------------------------------------------------------------------------------\n  #\n  # Define user-friendly macros.\n  #\n  # These CImg macros are prefixed by 'cimg_' and can be used safely in your own\n  # code. They are useful to parse command line options, or to write image loops.\n  #\n  ------------------------------------------------------------------------------*/\n\n// Macros to define program usage, and retrieve command line arguments.\n#define cimg_usage(usage) cimg_library_suffixed::cimg::option((char*)0,argc,argv,(char*)0,usage,false)\n#define cimg_help(str) cimg_library_suffixed::cimg::option((char*)0,argc,argv,str,(char*)0)\n#define cimg_option(name,defaut,usage) cimg_library_suffixed::cimg::option(name,argc,argv,defaut,usage)\n\n// Macros to define and manipulate local neighborhoods.\n#define CImg_2x2(I,T) T I[4]; \\\n                      T& I##cc = I[0]; T& I##nc = I[1]; \\\n                      T& I##cn = I[2]; T& I##nn = I[3]; \\\n                      I##cc = I##nc = \\\n                      I##cn = I##nn = 0\n\n#define CImg_3x3(I,T) T I[9]; \\\n                      T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \\\n                      T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \\\n                      T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \\\n                      I##pp = I##cp = I##np = \\\n                      I##pc = I##cc = I##nc = \\\n                      I##pn = I##cn = I##nn = 0\n\n#define CImg_4x4(I,T) T I[16]; \\\n                      T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \\\n                      T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \\\n                      T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \\\n                      T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \\\n                      I##pp = I##cp = I##np = I##ap = \\\n                      I##pc = I##cc = I##nc = I##ac = \\\n                      I##pn = I##cn = I##nn = I##an = \\\n                      I##pa = I##ca = I##na = I##aa = 0\n\n#define CImg_5x5(I,T) T I[25]; \\\n                      T& I##bb = I[0]; T& I##pb = I[1]; T& I##cb = I[2]; T& I##nb = I[3]; T& I##ab = I[4]; \\\n                      T& I##bp = I[5]; T& I##pp = I[6]; T& I##cp = I[7]; T& I##np = I[8]; T& I##ap = I[9]; \\\n                      T& I##bc = I[10]; T& I##pc = I[11]; T& I##cc = I[12]; T& I##nc = I[13]; T& I##ac = I[14]; \\\n                      T& I##bn = I[15]; T& I##pn = I[16]; T& I##cn = I[17]; T& I##nn = I[18]; T& I##an = I[19]; \\\n                      T& I##ba = I[20]; T& I##pa = I[21]; T& I##ca = I[22]; T& I##na = I[23]; T& I##aa = I[24]; \\\n                      I##bb = I##pb = I##cb = I##nb = I##ab = \\\n                      I##bp = I##pp = I##cp = I##np = I##ap = \\\n                      I##bc = I##pc = I##cc = I##nc = I##ac = \\\n                      I##bn = I##pn = I##cn = I##nn = I##an = \\\n                      I##ba = I##pa = I##ca = I##na = I##aa = 0\n\n#define CImg_2x2x2(I,T) T I[8]; \\\n                      T& I##ccc = I[0]; T& I##ncc = I[1]; \\\n                      T& I##cnc = I[2]; T& I##nnc = I[3]; \\\n                      T& I##ccn = I[4]; T& I##ncn = I[5]; \\\n                      T& I##cnn = I[6]; T& I##nnn = I[7]; \\\n                      I##ccc = I##ncc = \\\n                      I##cnc = I##nnc = \\\n                      I##ccn = I##ncn = \\\n                      I##cnn = I##nnn = 0\n\n#define CImg_3x3x3(I,T) T I[27]; \\\n                      T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \\\n                      T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \\\n                      T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \\\n                      T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \\\n                      T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \\\n                      T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \\\n                      T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \\\n                      T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \\\n                      T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \\\n                      I##ppp = I##cpp = I##npp = \\\n                      I##pcp = I##ccp = I##ncp = \\\n                      I##pnp = I##cnp = I##nnp = \\\n                      I##ppc = I##cpc = I##npc = \\\n                      I##pcc = I##ccc = I##ncc = \\\n                      I##pnc = I##cnc = I##nnc = \\\n                      I##ppn = I##cpn = I##npn = \\\n                      I##pcn = I##ccn = I##ncn = \\\n                      I##pnn = I##cnn = I##nnn = 0\n\n#define cimg_get2x2(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), \\\n  I[3] = (T)(img)(_n1##x,_n1##y,z,c)\n\n#define cimg_get3x3(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), \\\n  I[3] = (T)(img)(_p1##x,y,z,c), I[4] = (T)(img)(x,y,z,c), I[5] = (T)(img)(_n1##x,y,z,c), \\\n  I[6] = (T)(img)(_p1##x,_n1##y,z,c), I[7] = (T)(img)(x,_n1##y,z,c), I[8] = (T)(img)(_n1##x,_n1##y,z,c)\n\n#define cimg_get4x4(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), \\\n  I[3] = (T)(img)(_n2##x,_p1##y,z,c), I[4] = (T)(img)(_p1##x,y,z,c), I[5] = (T)(img)(x,y,z,c), \\\n  I[6] = (T)(img)(_n1##x,y,z,c), I[7] = (T)(img)(_n2##x,y,z,c), I[8] = (T)(img)(_p1##x,_n1##y,z,c), \\\n  I[9] = (T)(img)(x,_n1##y,z,c), I[10] = (T)(img)(_n1##x,_n1##y,z,c), I[11] = (T)(img)(_n2##x,_n1##y,z,c), \\\n  I[12] = (T)(img)(_p1##x,_n2##y,z,c), I[13] = (T)(img)(x,_n2##y,z,c), I[14] = (T)(img)(_n1##x,_n2##y,z,c), \\\n  I[15] = (T)(img)(_n2##x,_n2##y,z,c)\n\n#define cimg_get5x5(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), \\\n  I[3] = (T)(img)(_n1##x,_p2##y,z,c), I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_p2##x,_p1##y,z,c), \\\n  I[6] = (T)(img)(_p1##x,_p1##y,z,c), I[7] = (T)(img)(x,_p1##y,z,c), I[8] = (T)(img)(_n1##x,_p1##y,z,c), \\\n  I[9] = (T)(img)(_n2##x,_p1##y,z,c), I[10] = (T)(img)(_p2##x,y,z,c), I[11] = (T)(img)(_p1##x,y,z,c), \\\n  I[12] = (T)(img)(x,y,z,c), I[13] = (T)(img)(_n1##x,y,z,c), I[14] = (T)(img)(_n2##x,y,z,c), \\\n  I[15] = (T)(img)(_p2##x,_n1##y,z,c), I[16] = (T)(img)(_p1##x,_n1##y,z,c), I[17] = (T)(img)(x,_n1##y,z,c), \\\n  I[18] = (T)(img)(_n1##x,_n1##y,z,c), I[19] = (T)(img)(_n2##x,_n1##y,z,c), I[20] = (T)(img)(_p2##x,_n2##y,z,c), \\\n  I[21] = (T)(img)(_p1##x,_n2##y,z,c), I[22] = (T)(img)(x,_n2##y,z,c), I[23] = (T)(img)(_n1##x,_n2##y,z,c), \\\n  I[24] = (T)(img)(_n2##x,_n2##y,z,c)\n\n#define cimg_get6x6(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), \\\n  I[3] = (T)(img)(_n1##x,_p2##y,z,c), I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_n3##x,_p2##y,z,c), \\\n  I[6] = (T)(img)(_p2##x,_p1##y,z,c), I[7] = (T)(img)(_p1##x,_p1##y,z,c), I[8] = (T)(img)(x,_p1##y,z,c), \\\n  I[9] = (T)(img)(_n1##x,_p1##y,z,c), I[10] = (T)(img)(_n2##x,_p1##y,z,c), I[11] = (T)(img)(_n3##x,_p1##y,z,c), \\\n  I[12] = (T)(img)(_p2##x,y,z,c), I[13] = (T)(img)(_p1##x,y,z,c), I[14] = (T)(img)(x,y,z,c), \\\n  I[15] = (T)(img)(_n1##x,y,z,c), I[16] = (T)(img)(_n2##x,y,z,c), I[17] = (T)(img)(_n3##x,y,z,c), \\\n  I[18] = (T)(img)(_p2##x,_n1##y,z,c), I[19] = (T)(img)(_p1##x,_n1##y,z,c), I[20] = (T)(img)(x,_n1##y,z,c), \\\n  I[21] = (T)(img)(_n1##x,_n1##y,z,c), I[22] = (T)(img)(_n2##x,_n1##y,z,c), I[23] = (T)(img)(_n3##x,_n1##y,z,c), \\\n  I[24] = (T)(img)(_p2##x,_n2##y,z,c), I[25] = (T)(img)(_p1##x,_n2##y,z,c), I[26] = (T)(img)(x,_n2##y,z,c), \\\n  I[27] = (T)(img)(_n1##x,_n2##y,z,c), I[28] = (T)(img)(_n2##x,_n2##y,z,c), I[29] = (T)(img)(_n3##x,_n2##y,z,c), \\\n  I[30] = (T)(img)(_p2##x,_n3##y,z,c), I[31] = (T)(img)(_p1##x,_n3##y,z,c), I[32] = (T)(img)(x,_n3##y,z,c), \\\n  I[33] = (T)(img)(_n1##x,_n3##y,z,c), I[34] = (T)(img)(_n2##x,_n3##y,z,c), I[35] = (T)(img)(_n3##x,_n3##y,z,c)\n\n#define cimg_get7x7(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), \\\n  I[3] = (T)(img)(x,_p3##y,z,c), I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), \\\n  I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_p3##x,_p2##y,z,c), I[8] = (T)(img)(_p2##x,_p2##y,z,c), \\\n  I[9] = (T)(img)(_p1##x,_p2##y,z,c), I[10] = (T)(img)(x,_p2##y,z,c), I[11] = (T)(img)(_n1##x,_p2##y,z,c), \\\n  I[12] = (T)(img)(_n2##x,_p2##y,z,c), I[13] = (T)(img)(_n3##x,_p2##y,z,c), I[14] = (T)(img)(_p3##x,_p1##y,z,c), \\\n  I[15] = (T)(img)(_p2##x,_p1##y,z,c), I[16] = (T)(img)(_p1##x,_p1##y,z,c), I[17] = (T)(img)(x,_p1##y,z,c), \\\n  I[18] = (T)(img)(_n1##x,_p1##y,z,c), I[19] = (T)(img)(_n2##x,_p1##y,z,c), I[20] = (T)(img)(_n3##x,_p1##y,z,c), \\\n  I[21] = (T)(img)(_p3##x,y,z,c), I[22] = (T)(img)(_p2##x,y,z,c), I[23] = (T)(img)(_p1##x,y,z,c), \\\n  I[24] = (T)(img)(x,y,z,c), I[25] = (T)(img)(_n1##x,y,z,c), I[26] = (T)(img)(_n2##x,y,z,c), \\\n  I[27] = (T)(img)(_n3##x,y,z,c), I[28] = (T)(img)(_p3##x,_n1##y,z,c), I[29] = (T)(img)(_p2##x,_n1##y,z,c), \\\n  I[30] = (T)(img)(_p1##x,_n1##y,z,c), I[31] = (T)(img)(x,_n1##y,z,c), I[32] = (T)(img)(_n1##x,_n1##y,z,c), \\\n  I[33] = (T)(img)(_n2##x,_n1##y,z,c), I[34] = (T)(img)(_n3##x,_n1##y,z,c), I[35] = (T)(img)(_p3##x,_n2##y,z,c), \\\n  I[36] = (T)(img)(_p2##x,_n2##y,z,c), I[37] = (T)(img)(_p1##x,_n2##y,z,c), I[38] = (T)(img)(x,_n2##y,z,c), \\\n  I[39] = (T)(img)(_n1##x,_n2##y,z,c), I[40] = (T)(img)(_n2##x,_n2##y,z,c), I[41] = (T)(img)(_n3##x,_n2##y,z,c), \\\n  I[42] = (T)(img)(_p3##x,_n3##y,z,c), I[43] = (T)(img)(_p2##x,_n3##y,z,c), I[44] = (T)(img)(_p1##x,_n3##y,z,c), \\\n  I[45] = (T)(img)(x,_n3##y,z,c), I[46] = (T)(img)(_n1##x,_n3##y,z,c), I[47] = (T)(img)(_n2##x,_n3##y,z,c), \\\n  I[48] = (T)(img)(_n3##x,_n3##y,z,c)\n\n#define cimg_get8x8(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), \\\n  I[3] = (T)(img)(x,_p3##y,z,c), I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), \\\n  I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_n4##x,_p3##y,z,c), I[8] = (T)(img)(_p3##x,_p2##y,z,c), \\\n  I[9] = (T)(img)(_p2##x,_p2##y,z,c), I[10] = (T)(img)(_p1##x,_p2##y,z,c), I[11] = (T)(img)(x,_p2##y,z,c), \\\n  I[12] = (T)(img)(_n1##x,_p2##y,z,c), I[13] = (T)(img)(_n2##x,_p2##y,z,c), I[14] = (T)(img)(_n3##x,_p2##y,z,c), \\\n  I[15] = (T)(img)(_n4##x,_p2##y,z,c), I[16] = (T)(img)(_p3##x,_p1##y,z,c), I[17] = (T)(img)(_p2##x,_p1##y,z,c), \\\n  I[18] = (T)(img)(_p1##x,_p1##y,z,c), I[19] = (T)(img)(x,_p1##y,z,c), I[20] = (T)(img)(_n1##x,_p1##y,z,c), \\\n  I[21] = (T)(img)(_n2##x,_p1##y,z,c), I[22] = (T)(img)(_n3##x,_p1##y,z,c), I[23] = (T)(img)(_n4##x,_p1##y,z,c), \\\n  I[24] = (T)(img)(_p3##x,y,z,c), I[25] = (T)(img)(_p2##x,y,z,c), I[26] = (T)(img)(_p1##x,y,z,c), \\\n  I[27] = (T)(img)(x,y,z,c), I[28] = (T)(img)(_n1##x,y,z,c), I[29] = (T)(img)(_n2##x,y,z,c), \\\n  I[30] = (T)(img)(_n3##x,y,z,c), I[31] = (T)(img)(_n4##x,y,z,c), I[32] = (T)(img)(_p3##x,_n1##y,z,c), \\\n  I[33] = (T)(img)(_p2##x,_n1##y,z,c), I[34] = (T)(img)(_p1##x,_n1##y,z,c), I[35] = (T)(img)(x,_n1##y,z,c), \\\n  I[36] = (T)(img)(_n1##x,_n1##y,z,c), I[37] = (T)(img)(_n2##x,_n1##y,z,c), I[38] = (T)(img)(_n3##x,_n1##y,z,c), \\\n  I[39] = (T)(img)(_n4##x,_n1##y,z,c), I[40] = (T)(img)(_p3##x,_n2##y,z,c), I[41] = (T)(img)(_p2##x,_n2##y,z,c), \\\n  I[42] = (T)(img)(_p1##x,_n2##y,z,c), I[43] = (T)(img)(x,_n2##y,z,c), I[44] = (T)(img)(_n1##x,_n2##y,z,c), \\\n  I[45] = (T)(img)(_n2##x,_n2##y,z,c), I[46] = (T)(img)(_n3##x,_n2##y,z,c), I[47] = (T)(img)(_n4##x,_n2##y,z,c), \\\n  I[48] = (T)(img)(_p3##x,_n3##y,z,c), I[49] = (T)(img)(_p2##x,_n3##y,z,c), I[50] = (T)(img)(_p1##x,_n3##y,z,c), \\\n  I[51] = (T)(img)(x,_n3##y,z,c), I[52] = (T)(img)(_n1##x,_n3##y,z,c), I[53] = (T)(img)(_n2##x,_n3##y,z,c), \\\n  I[54] = (T)(img)(_n3##x,_n3##y,z,c), I[55] = (T)(img)(_n4##x,_n3##y,z,c), I[56] = (T)(img)(_p3##x,_n4##y,z,c), \\\n  I[57] = (T)(img)(_p2##x,_n4##y,z,c), I[58] = (T)(img)(_p1##x,_n4##y,z,c), I[59] = (T)(img)(x,_n4##y,z,c), \\\n  I[60] = (T)(img)(_n1##x,_n4##y,z,c), I[61] = (T)(img)(_n2##x,_n4##y,z,c), I[62] = (T)(img)(_n3##x,_n4##y,z,c), \\\n  I[63] = (T)(img)(_n4##x,_n4##y,z,c);\n\n#define cimg_get9x9(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(_p4##x,_p4##y,z,c), I[1] = (T)(img)(_p3##x,_p4##y,z,c), I[2] = (T)(img)(_p2##x,_p4##y,z,c), \\\n  I[3] = (T)(img)(_p1##x,_p4##y,z,c), I[4] = (T)(img)(x,_p4##y,z,c), I[5] = (T)(img)(_n1##x,_p4##y,z,c), \\\n  I[6] = (T)(img)(_n2##x,_p4##y,z,c), I[7] = (T)(img)(_n3##x,_p4##y,z,c), I[8] = (T)(img)(_n4##x,_p4##y,z,c), \\\n  I[9] = (T)(img)(_p4##x,_p3##y,z,c), I[10] = (T)(img)(_p3##x,_p3##y,z,c), I[11] = (T)(img)(_p2##x,_p3##y,z,c), \\\n  I[12] = (T)(img)(_p1##x,_p3##y,z,c), I[13] = (T)(img)(x,_p3##y,z,c), I[14] = (T)(img)(_n1##x,_p3##y,z,c), \\\n  I[15] = (T)(img)(_n2##x,_p3##y,z,c), I[16] = (T)(img)(_n3##x,_p3##y,z,c), I[17] = (T)(img)(_n4##x,_p3##y,z,c), \\\n  I[18] = (T)(img)(_p4##x,_p2##y,z,c), I[19] = (T)(img)(_p3##x,_p2##y,z,c), I[20] = (T)(img)(_p2##x,_p2##y,z,c), \\\n  I[21] = (T)(img)(_p1##x,_p2##y,z,c), I[22] = (T)(img)(x,_p2##y,z,c), I[23] = (T)(img)(_n1##x,_p2##y,z,c), \\\n  I[24] = (T)(img)(_n2##x,_p2##y,z,c), I[25] = (T)(img)(_n3##x,_p2##y,z,c), I[26] = (T)(img)(_n4##x,_p2##y,z,c), \\\n  I[27] = (T)(img)(_p4##x,_p1##y,z,c), I[28] = (T)(img)(_p3##x,_p1##y,z,c), I[29] = (T)(img)(_p2##x,_p1##y,z,c), \\\n  I[30] = (T)(img)(_p1##x,_p1##y,z,c), I[31] = (T)(img)(x,_p1##y,z,c), I[32] = (T)(img)(_n1##x,_p1##y,z,c), \\\n  I[33] = (T)(img)(_n2##x,_p1##y,z,c), I[34] = (T)(img)(_n3##x,_p1##y,z,c), I[35] = (T)(img)(_n4##x,_p1##y,z,c), \\\n  I[36] = (T)(img)(_p4##x,y,z,c), I[37] = (T)(img)(_p3##x,y,z,c), I[38] = (T)(img)(_p2##x,y,z,c), \\\n  I[39] = (T)(img)(_p1##x,y,z,c), I[40] = (T)(img)(x,y,z,c), I[41] = (T)(img)(_n1##x,y,z,c), \\\n  I[42] = (T)(img)(_n2##x,y,z,c), I[43] = (T)(img)(_n3##x,y,z,c), I[44] = (T)(img)(_n4##x,y,z,c), \\\n  I[45] = (T)(img)(_p4##x,_n1##y,z,c), I[46] = (T)(img)(_p3##x,_n1##y,z,c), I[47] = (T)(img)(_p2##x,_n1##y,z,c), \\\n  I[48] = (T)(img)(_p1##x,_n1##y,z,c), I[49] = (T)(img)(x,_n1##y,z,c), I[50] = (T)(img)(_n1##x,_n1##y,z,c), \\\n  I[51] = (T)(img)(_n2##x,_n1##y,z,c), I[52] = (T)(img)(_n3##x,_n1##y,z,c), I[53] = (T)(img)(_n4##x,_n1##y,z,c), \\\n  I[54] = (T)(img)(_p4##x,_n2##y,z,c), I[55] = (T)(img)(_p3##x,_n2##y,z,c), I[56] = (T)(img)(_p2##x,_n2##y,z,c), \\\n  I[57] = (T)(img)(_p1##x,_n2##y,z,c), I[58] = (T)(img)(x,_n2##y,z,c), I[59] = (T)(img)(_n1##x,_n2##y,z,c), \\\n  I[60] = (T)(img)(_n2##x,_n2##y,z,c), I[61] = (T)(img)(_n3##x,_n2##y,z,c), I[62] = (T)(img)(_n4##x,_n2##y,z,c), \\\n  I[63] = (T)(img)(_p4##x,_n3##y,z,c), I[64] = (T)(img)(_p3##x,_n3##y,z,c), I[65] = (T)(img)(_p2##x,_n3##y,z,c), \\\n  I[66] = (T)(img)(_p1##x,_n3##y,z,c), I[67] = (T)(img)(x,_n3##y,z,c), I[68] = (T)(img)(_n1##x,_n3##y,z,c), \\\n  I[69] = (T)(img)(_n2##x,_n3##y,z,c), I[70] = (T)(img)(_n3##x,_n3##y,z,c), I[71] = (T)(img)(_n4##x,_n3##y,z,c), \\\n  I[72] = (T)(img)(_p4##x,_n4##y,z,c), I[73] = (T)(img)(_p3##x,_n4##y,z,c), I[74] = (T)(img)(_p2##x,_n4##y,z,c), \\\n  I[75] = (T)(img)(_p1##x,_n4##y,z,c), I[76] = (T)(img)(x,_n4##y,z,c), I[77] = (T)(img)(_n1##x,_n4##y,z,c), \\\n  I[78] = (T)(img)(_n2##x,_n4##y,z,c), I[79] = (T)(img)(_n3##x,_n4##y,z,c), I[80] = (T)(img)(_n4##x,_n4##y,z,c)\n\n#define cimg_get2x2x2(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), \\\n  I[3] = (T)(img)(_n1##x,_n1##y,z,c), I[4] = (T)(img)(x,y,_n1##z,c), I[5] = (T)(img)(_n1##x,y,_n1##z,c), \\\n  I[6] = (T)(img)(x,_n1##y,_n1##z,c), I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)\n\n#define cimg_get3x3x3(img,x,y,z,c,I,T) \\\n  I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c), I[1] = (T)(img)(x,_p1##y,_p1##z,c), \\\n  I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c), I[3] = (T)(img)(_p1##x,y,_p1##z,c), I[4] = (T)(img)(x,y,_p1##z,c), \\\n  I[5] = (T)(img)(_n1##x,y,_p1##z,c), I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c), I[7] = (T)(img)(x,_n1##y,_p1##z,c), \\\n  I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c), I[9] = (T)(img)(_p1##x,_p1##y,z,c), I[10] = (T)(img)(x,_p1##y,z,c), \\\n  I[11] = (T)(img)(_n1##x,_p1##y,z,c), I[12] = (T)(img)(_p1##x,y,z,c), I[13] = (T)(img)(x,y,z,c), \\\n  I[14] = (T)(img)(_n1##x,y,z,c), I[15] = (T)(img)(_p1##x,_n1##y,z,c), I[16] = (T)(img)(x,_n1##y,z,c), \\\n  I[17] = (T)(img)(_n1##x,_n1##y,z,c), I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c), I[19] = (T)(img)(x,_p1##y,_n1##z,c), \\\n  I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c), I[21] = (T)(img)(_p1##x,y,_n1##z,c), I[22] = (T)(img)(x,y,_n1##z,c), \\\n  I[23] = (T)(img)(_n1##x,y,_n1##z,c), I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c), I[25] = (T)(img)(x,_n1##y,_n1##z,c), \\\n  I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)\n\n// Macros to perform various image loops.\n//\n// These macros are simpler to use than loops with C++ iterators.\n#define cimg_for(img,ptrs,T_ptrs) \\\n  for (T_ptrs *ptrs = (img)._data, *_max##ptrs = (img)._data + (img).size(); ptrs<_max##ptrs; ++ptrs)\n#define cimg_rof(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size() - 1; ptrs>=(img)._data; --ptrs)\n#define cimg_foroff(img,off) for (cimg_ulong off = 0, _max##off = (img).size(); off<_max##off; ++off)\n\n#define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)\n#define cimg_forX(img,x) cimg_for1((img)._width,x)\n#define cimg_forY(img,y) cimg_for1((img)._height,y)\n#define cimg_forZ(img,z) cimg_for1((img)._depth,z)\n#define cimg_forC(img,c) cimg_for1((img)._spectrum,c)\n#define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)\n#define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)\n#define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)\n#define cimg_forXC(img,x,c) cimg_forC(img,c) cimg_forX(img,x)\n#define cimg_forYC(img,y,c) cimg_forC(img,c) cimg_forY(img,y)\n#define cimg_forZC(img,z,c) cimg_forC(img,c) cimg_forZ(img,z)\n#define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)\n#define cimg_forXYC(img,x,y,c) cimg_forC(img,c) cimg_forXY(img,x,y)\n#define cimg_forXZC(img,x,z,c) cimg_forC(img,c) cimg_forXZ(img,x,z)\n#define cimg_forYZC(img,y,z,c) cimg_forC(img,c) cimg_forYZ(img,y,z)\n#define cimg_forXYZC(img,x,y,z,c) cimg_forC(img,c) cimg_forXYZ(img,x,y,z)\n\n#define cimg_rof1(bound,i) for (int i = (int)(bound) - 1; i>=0; --i)\n#define cimg_rofX(img,x) cimg_rof1((img)._width,x)\n#define cimg_rofY(img,y) cimg_rof1((img)._height,y)\n#define cimg_rofZ(img,z) cimg_rof1((img)._depth,z)\n#define cimg_rofC(img,c) cimg_rof1((img)._spectrum,c)\n#define cimg_rofXY(img,x,y) cimg_rofY(img,y) cimg_rofX(img,x)\n#define cimg_rofXZ(img,x,z) cimg_rofZ(img,z) cimg_rofX(img,x)\n#define cimg_rofYZ(img,y,z) cimg_rofZ(img,z) cimg_rofY(img,y)\n#define cimg_rofXC(img,x,c) cimg_rofC(img,c) cimg_rofX(img,x)\n#define cimg_rofYC(img,y,c) cimg_rofC(img,c) cimg_rofY(img,y)\n#define cimg_rofZC(img,z,c) cimg_rofC(img,c) cimg_rofZ(img,z)\n#define cimg_rofXYZ(img,x,y,z) cimg_rofZ(img,z) cimg_rofXY(img,x,y)\n#define cimg_rofXYC(img,x,y,c) cimg_rofC(img,c) cimg_rofXY(img,x,y)\n#define cimg_rofXZC(img,x,z,c) cimg_rofC(img,c) cimg_rofXZ(img,x,z)\n#define cimg_rofYZC(img,y,z,c) cimg_rofC(img,c) cimg_rofYZ(img,y,z)\n#define cimg_rofXYZC(img,x,y,z,c) cimg_rofC(img,c) cimg_rofXYZ(img,x,y,z)\n\n#define cimg_for_in1(bound,i0,i1,i) \\\n for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound) - 1; i<=_max##i; ++i)\n#define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img)._width,x0,x1,x)\n#define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img)._height,y0,y1,y)\n#define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img)._depth,z0,z1,z)\n#define cimg_for_inC(img,c0,c1,c) cimg_for_in1((img)._spectrum,c0,c1,c)\n#define cimg_for_inXY(img,x0,y0,x1,y1,x,y) cimg_for_inY(img,y0,y1,y) cimg_for_inX(img,x0,x1,x)\n#define cimg_for_inXZ(img,x0,z0,x1,z1,x,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inX(img,x0,x1,x)\n#define cimg_for_inXC(img,x0,c0,x1,c1,x,c) cimg_for_inC(img,c0,c1,c) cimg_for_inX(img,x0,x1,x)\n#define cimg_for_inYZ(img,y0,z0,y1,z1,y,z) cimg_for_inZ(img,x0,z1,z) cimg_for_inY(img,y0,y1,y)\n#define cimg_for_inYC(img,y0,c0,y1,c1,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inY(img,y0,y1,y)\n#define cimg_for_inZC(img,z0,c0,z1,c1,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inZ(img,z0,z1,z)\n#define cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inXY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_inXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_inXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXZ(img,x0,z0,x1,z1,x,z)\n#define cimg_for_inYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inYZ(img,y0,z0,y1,z1,y,z)\n#define cimg_for_inXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n  cimg_for_inC(img,c0,c1,c) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n#define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img)._width - 1 - (n),x)\n#define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img)._height - 1 - (n),y)\n#define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img)._depth  - 1 - (n),z)\n#define cimg_for_insideC(img,c,n) cimg_for_inC(img,n,(img)._spectrum - 1 - (n),c)\n#define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y)\n#define cimg_for_insideXYZ(img,x,y,z,n) \\\n  cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z)\n#define cimg_for_insideXYZC(img,x,y,z,c,n) \\\n  cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z)\n\n#define cimg_for_out1(boundi,i0,i1,i) \\\n for (int i = (int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1) + 1:i)\n#define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \\\n for (int j = 0; j<(int)(boundj); ++j) \\\n for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \\\n  ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1) + 1:i))\n#define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \\\n for (int k = 0; k<(int)(boundk); ++k) \\\n for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \\\n for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \\\n  ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1) + 1:i))\n#define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \\\n for (int l = 0; l<(int)(boundl); ++l) \\\n for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \\\n for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \\\n for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1) + 1; \\\n  i<(int)(boundi); ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1) + 1:i))\n#define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img)._width,x0,x1,x)\n#define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img)._height,y0,y1,y)\n#define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img)._depth,z0,z1,z)\n#define cimg_for_outC(img,c0,c1,c) cimg_for_out1((img)._spectrum,c0,c1,c)\n#define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img)._width,(img)._height,x0,y0,x1,y1,x,y)\n#define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img)._width,(img)._depth,x0,z0,x1,z1,x,z)\n#define cimg_for_outXC(img,x0,c0,x1,c1,x,c) cimg_for_out2((img)._width,(img)._spectrum,x0,c0,x1,c1,x,c)\n#define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img)._height,(img)._depth,y0,z0,y1,z1,y,z)\n#define cimg_for_outYC(img,y0,c0,y1,c1,y,c) cimg_for_out2((img)._height,(img)._spectrum,y0,c0,y1,c1,y,c)\n#define cimg_for_outZC(img,z0,c0,z1,c1,z,c) cimg_for_out2((img)._depth,(img)._spectrum,z0,c0,z1,c1,z,c)\n#define cimg_for_outXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) \\\n  cimg_for_out3((img)._width,(img)._height,(img)._depth,x0,y0,z0,x1,y1,z1,x,y,z)\n#define cimg_for_outXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) \\\n  cimg_for_out3((img)._width,(img)._height,(img)._spectrum,x0,y0,c0,x1,y1,c1,x,y,c)\n#define cimg_for_outXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) \\\n  cimg_for_out3((img)._width,(img)._depth,(img)._spectrum,x0,z0,c0,x1,z1,c1,x,z,c)\n#define cimg_for_outYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) \\\n  cimg_for_out3((img)._height,(img)._depth,(img)._spectrum,y0,z0,c0,y1,z1,c1,y,z,c)\n#define cimg_for_outXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n cimg_for_out4((img)._width,(img)._height,(img)._depth,(img)._spectrum,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c)\n#define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img)._width - 1 - (n),x)\n#define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img)._height - 1 - (n),y)\n#define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img)._depth - 1 - (n),z)\n#define cimg_for_borderC(img,c,n) cimg_for_outC(img,n,(img)._spectrum - 1 - (n),c)\n#define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y)\n#define cimg_for_borderXYZ(img,x,y,z,n) \\\n  cimg_for_outXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z)\n#define cimg_for_borderXYZC(img,x,y,z,c,n) \\\n cimg_for_outXYZC(img,n,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n), \\\n                  (img)._depth - 1 - (n),(img)._spectrum - 1 - (n),x,y,z,c)\n\n#define cimg_for_spiralXY(img,x,y) \\\n for (int x = 0, y = 0, _n1##x = 1, _n1##y = (img).width()*(img).height(); _n1##y; \\\n      --_n1##y, _n1##x+=(_n1##x>>2) - ((!(_n1##x&3)?--y:((_n1##x&3)==1?(img)._width - 1 - ++x:\\\n      ((_n1##x&3)==2?(img)._height - 1 - ++y:--x))))?0:1)\n\n#define cimg_for_lineXY(x,y,x0,y0,x1,y1) \\\n for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \\\n      _dx=(x1)>(x0)?(int)(x1) - (int)(x0):(_sx=-1,(int)(x0) - (int)(x1)), \\\n      _dy=(y1)>(y0)?(int)(y1) - (int)(y0):(_sy=-1,(int)(y0) - (int)(y1)), \\\n      _counter = _dx, \\\n      _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \\\n      _counter>=0; \\\n      --_counter, x+=_steep? \\\n      (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \\\n      (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))\n\n#define cimg_for2(bound,i) \\\n for (int i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1; \\\n      _n1##i<(int)(bound) || i==--_n1##i; \\\n      ++i, ++_n1##i)\n#define cimg_for2X(img,x) cimg_for2((img)._width,x)\n#define cimg_for2Y(img,y) cimg_for2((img)._height,y)\n#define cimg_for2Z(img,z) cimg_for2((img)._depth,z)\n#define cimg_for2C(img,c) cimg_for2((img)._spectrum,c)\n#define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)\n#define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)\n#define cimg_for2XC(img,x,c) cimg_for2C(img,c) cimg_for2X(img,x)\n#define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)\n#define cimg_for2YC(img,y,c) cimg_for2C(img,c) cimg_for2Y(img,y)\n#define cimg_for2ZC(img,z,c) cimg_for2C(img,c) cimg_for2Z(img,z)\n#define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)\n#define cimg_for2XZC(img,x,z,c) cimg_for2C(img,c) cimg_for2XZ(img,x,z)\n#define cimg_for2YZC(img,y,z,c) cimg_for2C(img,c) cimg_for2YZ(img,y,z)\n#define cimg_for2XYZC(img,x,y,z,c) cimg_for2C(img,c) cimg_for2XYZ(img,x,y,z)\n\n#define cimg_for_in2(bound,i0,i1,i) \\\n for (int i = (int)(i0)<0?0:(int)(i0), \\\n      _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \\\n      i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \\\n      ++i, ++_n1##i)\n#define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img)._width,x0,x1,x)\n#define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img)._height,y0,y1,y)\n#define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img)._depth,z0,z1,z)\n#define cimg_for_in2C(img,c0,c1,c) cimg_for_in2((img)._spectrum,c0,c1,c)\n#define cimg_for_in2XY(img,x0,y0,x1,y1,x,y) cimg_for_in2Y(img,y0,y1,y) cimg_for_in2X(img,x0,x1,x)\n#define cimg_for_in2XZ(img,x0,z0,x1,z1,x,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2X(img,x0,x1,x)\n#define cimg_for_in2XC(img,x0,c0,x1,c1,x,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2X(img,x0,x1,x)\n#define cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2Y(img,y0,y1,y)\n#define cimg_for_in2YC(img,y0,c0,y1,c1,y,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Y(img,y0,y1,y)\n#define cimg_for_in2ZC(img,z0,c0,z1,c1,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Z(img,z0,z1,z)\n#define cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2XY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_in2XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2XZ(img,x0,y0,x1,y1,x,z)\n#define cimg_for_in2YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2YZ(img,y0,z0,y1,z1,y,z)\n#define cimg_for_in2XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n  cimg_for_in2C(img,c0,c1,c) cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n\n#define cimg_for3(bound,i) \\\n for (int i = 0, _p1##i = 0, \\\n      _n1##i = 1>=(bound)?(int)(bound) - 1:1; \\\n      _n1##i<(int)(bound) || i==--_n1##i; \\\n      _p1##i = i++, ++_n1##i)\n#define cimg_for3X(img,x) cimg_for3((img)._width,x)\n#define cimg_for3Y(img,y) cimg_for3((img)._height,y)\n#define cimg_for3Z(img,z) cimg_for3((img)._depth,z)\n#define cimg_for3C(img,c) cimg_for3((img)._spectrum,c)\n#define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)\n#define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)\n#define cimg_for3XC(img,x,c) cimg_for3C(img,c) cimg_for3X(img,x)\n#define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)\n#define cimg_for3YC(img,y,c) cimg_for3C(img,c) cimg_for3Y(img,y)\n#define cimg_for3ZC(img,z,c) cimg_for3C(img,c) cimg_for3Z(img,z)\n#define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)\n#define cimg_for3XZC(img,x,z,c) cimg_for3C(img,c) cimg_for3XZ(img,x,z)\n#define cimg_for3YZC(img,y,z,c) cimg_for3C(img,c) cimg_for3YZ(img,y,z)\n#define cimg_for3XYZC(img,x,y,z,c) cimg_for3C(img,c) cimg_for3XYZ(img,x,y,z)\n\n#define cimg_for_in3(bound,i0,i1,i) \\\n for (int i = (int)(i0)<0?0:(int)(i0), \\\n      _p1##i = i - 1<0?0:i - 1, \\\n      _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \\\n      i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \\\n      _p1##i = i++, ++_n1##i)\n#define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img)._width,x0,x1,x)\n#define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img)._height,y0,y1,y)\n#define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img)._depth,z0,z1,z)\n#define cimg_for_in3C(img,c0,c1,c) cimg_for_in3((img)._spectrum,c0,c1,c)\n#define cimg_for_in3XY(img,x0,y0,x1,y1,x,y) cimg_for_in3Y(img,y0,y1,y) cimg_for_in3X(img,x0,x1,x)\n#define cimg_for_in3XZ(img,x0,z0,x1,z1,x,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3X(img,x0,x1,x)\n#define cimg_for_in3XC(img,x0,c0,x1,c1,x,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3X(img,x0,x1,x)\n#define cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3Y(img,y0,y1,y)\n#define cimg_for_in3YC(img,y0,c0,y1,c1,y,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Y(img,y0,y1,y)\n#define cimg_for_in3ZC(img,z0,c0,z1,c1,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Z(img,z0,z1,z)\n#define cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3XY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_in3XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3XZ(img,x0,y0,x1,y1,x,z)\n#define cimg_for_in3YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3YZ(img,y0,z0,y1,z1,y,z)\n#define cimg_for_in3XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n  cimg_for_in3C(img,c0,c1,c) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n\n#define cimg_for4(bound,i) \\\n for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1, \\\n      _n2##i = 2>=(bound)?(int)(bound) - 1:2; \\\n      _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \\\n      _p1##i = i++, ++_n1##i, ++_n2##i)\n#define cimg_for4X(img,x) cimg_for4((img)._width,x)\n#define cimg_for4Y(img,y) cimg_for4((img)._height,y)\n#define cimg_for4Z(img,z) cimg_for4((img)._depth,z)\n#define cimg_for4C(img,c) cimg_for4((img)._spectrum,c)\n#define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)\n#define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)\n#define cimg_for4XC(img,x,c) cimg_for4C(img,c) cimg_for4X(img,x)\n#define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)\n#define cimg_for4YC(img,y,c) cimg_for4C(img,c) cimg_for4Y(img,y)\n#define cimg_for4ZC(img,z,c) cimg_for4C(img,c) cimg_for4Z(img,z)\n#define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)\n#define cimg_for4XZC(img,x,z,c) cimg_for4C(img,c) cimg_for4XZ(img,x,z)\n#define cimg_for4YZC(img,y,z,c) cimg_for4C(img,c) cimg_for4YZ(img,y,z)\n#define cimg_for4XYZC(img,x,y,z,c) cimg_for4C(img,c) cimg_for4XYZ(img,x,y,z)\n\n#define cimg_for_in4(bound,i0,i1,i) \\\n for (int i = (int)(i0)<0?0:(int)(i0), \\\n      _p1##i = i - 1<0?0:i - 1, \\\n      _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \\\n      _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \\\n      i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \\\n      _p1##i = i++, ++_n1##i, ++_n2##i)\n#define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img)._width,x0,x1,x)\n#define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img)._height,y0,y1,y)\n#define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img)._depth,z0,z1,z)\n#define cimg_for_in4C(img,c0,c1,c) cimg_for_in4((img)._spectrum,c0,c1,c)\n#define cimg_for_in4XY(img,x0,y0,x1,y1,x,y) cimg_for_in4Y(img,y0,y1,y) cimg_for_in4X(img,x0,x1,x)\n#define cimg_for_in4XZ(img,x0,z0,x1,z1,x,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4X(img,x0,x1,x)\n#define cimg_for_in4XC(img,x0,c0,x1,c1,x,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4X(img,x0,x1,x)\n#define cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4Y(img,y0,y1,y)\n#define cimg_for_in4YC(img,y0,c0,y1,c1,y,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Y(img,y0,y1,y)\n#define cimg_for_in4ZC(img,z0,c0,z1,c1,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Z(img,z0,z1,z)\n#define cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4XY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_in4XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4XZ(img,x0,y0,x1,y1,x,z)\n#define cimg_for_in4YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4YZ(img,y0,z0,y1,z1,y,z)\n#define cimg_for_in4XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n  cimg_for_in4C(img,c0,c1,c) cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n\n#define cimg_for5(bound,i) \\\n for (int i = 0, _p2##i = 0, _p1##i = 0, \\\n      _n1##i = 1>=(bound)?(int)(bound) - 1:1, \\\n      _n2##i = 2>=(bound)?(int)(bound) - 1:2; \\\n      _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \\\n      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)\n#define cimg_for5X(img,x) cimg_for5((img)._width,x)\n#define cimg_for5Y(img,y) cimg_for5((img)._height,y)\n#define cimg_for5Z(img,z) cimg_for5((img)._depth,z)\n#define cimg_for5C(img,c) cimg_for5((img)._spectrum,c)\n#define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)\n#define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)\n#define cimg_for5XC(img,x,c) cimg_for5C(img,c) cimg_for5X(img,x)\n#define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)\n#define cimg_for5YC(img,y,c) cimg_for5C(img,c) cimg_for5Y(img,y)\n#define cimg_for5ZC(img,z,c) cimg_for5C(img,c) cimg_for5Z(img,z)\n#define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)\n#define cimg_for5XZC(img,x,z,c) cimg_for5C(img,c) cimg_for5XZ(img,x,z)\n#define cimg_for5YZC(img,y,z,c) cimg_for5C(img,c) cimg_for5YZ(img,y,z)\n#define cimg_for5XYZC(img,x,y,z,c) cimg_for5C(img,c) cimg_for5XYZ(img,x,y,z)\n\n#define cimg_for_in5(bound,i0,i1,i) \\\n for (int i = (int)(i0)<0?0:(int)(i0), \\\n      _p2##i = i - 2<0?0:i - 2, \\\n      _p1##i = i - 1<0?0:i - 1, \\\n      _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \\\n      _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \\\n      i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \\\n      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)\n#define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img)._width,x0,x1,x)\n#define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img)._height,y0,y1,y)\n#define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img)._depth,z0,z1,z)\n#define cimg_for_in5C(img,c0,c1,c) cimg_for_in5((img)._spectrum,c0,c1,c)\n#define cimg_for_in5XY(img,x0,y0,x1,y1,x,y) cimg_for_in5Y(img,y0,y1,y) cimg_for_in5X(img,x0,x1,x)\n#define cimg_for_in5XZ(img,x0,z0,x1,z1,x,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5X(img,x0,x1,x)\n#define cimg_for_in5XC(img,x0,c0,x1,c1,x,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5X(img,x0,x1,x)\n#define cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5Y(img,y0,y1,y)\n#define cimg_for_in5YC(img,y0,c0,y1,c1,y,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Y(img,y0,y1,y)\n#define cimg_for_in5ZC(img,z0,c0,z1,c1,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Z(img,z0,z1,z)\n#define cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5XY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_in5XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5XZ(img,x0,y0,x1,y1,x,z)\n#define cimg_for_in5YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5YZ(img,y0,z0,y1,z1,y,z)\n#define cimg_for_in5XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n  cimg_for_in5C(img,c0,c1,c) cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n\n#define cimg_for6(bound,i) \\\n for (int i = 0, _p2##i = 0, _p1##i = 0, \\\n      _n1##i = 1>=(bound)?(int)(bound) - 1:1, \\\n      _n2##i = 2>=(bound)?(int)(bound) - 1:2, \\\n      _n3##i = 3>=(bound)?(int)(bound) - 1:3; \\\n      _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \\\n      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)\n#define cimg_for6X(img,x) cimg_for6((img)._width,x)\n#define cimg_for6Y(img,y) cimg_for6((img)._height,y)\n#define cimg_for6Z(img,z) cimg_for6((img)._depth,z)\n#define cimg_for6C(img,c) cimg_for6((img)._spectrum,c)\n#define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)\n#define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)\n#define cimg_for6XC(img,x,c) cimg_for6C(img,c) cimg_for6X(img,x)\n#define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)\n#define cimg_for6YC(img,y,c) cimg_for6C(img,c) cimg_for6Y(img,y)\n#define cimg_for6ZC(img,z,c) cimg_for6C(img,c) cimg_for6Z(img,z)\n#define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)\n#define cimg_for6XZC(img,x,z,c) cimg_for6C(img,c) cimg_for6XZ(img,x,z)\n#define cimg_for6YZC(img,y,z,c) cimg_for6C(img,c) cimg_for6YZ(img,y,z)\n#define cimg_for6XYZC(img,x,y,z,c) cimg_for6C(img,c) cimg_for6XYZ(img,x,y,z)\n\n#define cimg_for_in6(bound,i0,i1,i) \\\n for (int i = (int)(i0)<0?0:(int)(i0), \\\n      _p2##i = i - 2<0?0:i - 2, \\\n      _p1##i = i - 1<0?0:i - 1, \\\n      _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \\\n      _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \\\n      _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \\\n      i<=(int)(i1) && \\\n      (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \\\n      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)\n#define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img)._width,x0,x1,x)\n#define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img)._height,y0,y1,y)\n#define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img)._depth,z0,z1,z)\n#define cimg_for_in6C(img,c0,c1,c) cimg_for_in6((img)._spectrum,c0,c1,c)\n#define cimg_for_in6XY(img,x0,y0,x1,y1,x,y) cimg_for_in6Y(img,y0,y1,y) cimg_for_in6X(img,x0,x1,x)\n#define cimg_for_in6XZ(img,x0,z0,x1,z1,x,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6X(img,x0,x1,x)\n#define cimg_for_in6XC(img,x0,c0,x1,c1,x,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6X(img,x0,x1,x)\n#define cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6Y(img,y0,y1,y)\n#define cimg_for_in6YC(img,y0,c0,y1,c1,y,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Y(img,y0,y1,y)\n#define cimg_for_in6ZC(img,z0,c0,z1,c1,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Z(img,z0,z1,z)\n#define cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6XY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_in6XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6XZ(img,x0,y0,x1,y1,x,z)\n#define cimg_for_in6YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6YZ(img,y0,z0,y1,z1,y,z)\n#define cimg_for_in6XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n  cimg_for_in6C(img,c0,c1,c) cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n\n#define cimg_for7(bound,i) \\\n for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \\\n      _n1##i = 1>=(bound)?(int)(bound) - 1:1, \\\n      _n2##i = 2>=(bound)?(int)(bound) - 1:2, \\\n      _n3##i = 3>=(bound)?(int)(bound) - 1:3; \\\n      _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \\\n      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)\n#define cimg_for7X(img,x) cimg_for7((img)._width,x)\n#define cimg_for7Y(img,y) cimg_for7((img)._height,y)\n#define cimg_for7Z(img,z) cimg_for7((img)._depth,z)\n#define cimg_for7C(img,c) cimg_for7((img)._spectrum,c)\n#define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)\n#define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)\n#define cimg_for7XC(img,x,c) cimg_for7C(img,c) cimg_for7X(img,x)\n#define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)\n#define cimg_for7YC(img,y,c) cimg_for7C(img,c) cimg_for7Y(img,y)\n#define cimg_for7ZC(img,z,c) cimg_for7C(img,c) cimg_for7Z(img,z)\n#define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)\n#define cimg_for7XZC(img,x,z,c) cimg_for7C(img,c) cimg_for7XZ(img,x,z)\n#define cimg_for7YZC(img,y,z,c) cimg_for7C(img,c) cimg_for7YZ(img,y,z)\n#define cimg_for7XYZC(img,x,y,z,c) cimg_for7C(img,c) cimg_for7XYZ(img,x,y,z)\n\n#define cimg_for_in7(bound,i0,i1,i) \\\n for (int i = (int)(i0)<0?0:(int)(i0), \\\n      _p3##i = i - 3<0?0:i - 3, \\\n      _p2##i = i - 2<0?0:i - 2, \\\n      _p1##i = i - 1<0?0:i - 1, \\\n      _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \\\n      _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \\\n      _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \\\n      i<=(int)(i1) && \\\n      (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \\\n      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)\n#define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img)._width,x0,x1,x)\n#define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img)._height,y0,y1,y)\n#define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img)._depth,z0,z1,z)\n#define cimg_for_in7C(img,c0,c1,c) cimg_for_in7((img)._spectrum,c0,c1,c)\n#define cimg_for_in7XY(img,x0,y0,x1,y1,x,y) cimg_for_in7Y(img,y0,y1,y) cimg_for_in7X(img,x0,x1,x)\n#define cimg_for_in7XZ(img,x0,z0,x1,z1,x,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7X(img,x0,x1,x)\n#define cimg_for_in7XC(img,x0,c0,x1,c1,x,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7X(img,x0,x1,x)\n#define cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7Y(img,y0,y1,y)\n#define cimg_for_in7YC(img,y0,c0,y1,c1,y,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Y(img,y0,y1,y)\n#define cimg_for_in7ZC(img,z0,c0,z1,c1,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Z(img,z0,z1,z)\n#define cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7XY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_in7XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7XZ(img,x0,y0,x1,y1,x,z)\n#define cimg_for_in7YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7YZ(img,y0,z0,y1,z1,y,z)\n#define cimg_for_in7XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n  cimg_for_in7C(img,c0,c1,c) cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n\n#define cimg_for8(bound,i) \\\n for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \\\n      _n1##i = 1>=(bound)?(int)(bound) - 1:1, \\\n      _n2##i = 2>=(bound)?(int)(bound) - 1:2, \\\n      _n3##i = 3>=(bound)?(int)(bound) - 1:3, \\\n      _n4##i = 4>=(bound)?(int)(bound) - 1:4; \\\n      _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \\\n      i==(_n4##i = _n3##i = _n2##i = --_n1##i); \\\n      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)\n#define cimg_for8X(img,x) cimg_for8((img)._width,x)\n#define cimg_for8Y(img,y) cimg_for8((img)._height,y)\n#define cimg_for8Z(img,z) cimg_for8((img)._depth,z)\n#define cimg_for8C(img,c) cimg_for8((img)._spectrum,c)\n#define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)\n#define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)\n#define cimg_for8XC(img,x,c) cimg_for8C(img,c) cimg_for8X(img,x)\n#define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)\n#define cimg_for8YC(img,y,c) cimg_for8C(img,c) cimg_for8Y(img,y)\n#define cimg_for8ZC(img,z,c) cimg_for8C(img,c) cimg_for8Z(img,z)\n#define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)\n#define cimg_for8XZC(img,x,z,c) cimg_for8C(img,c) cimg_for8XZ(img,x,z)\n#define cimg_for8YZC(img,y,z,c) cimg_for8C(img,c) cimg_for8YZ(img,y,z)\n#define cimg_for8XYZC(img,x,y,z,c) cimg_for8C(img,c) cimg_for8XYZ(img,x,y,z)\n\n#define cimg_for_in8(bound,i0,i1,i) \\\n for (int i = (int)(i0)<0?0:(int)(i0), \\\n      _p3##i = i - 3<0?0:i - 3, \\\n      _p2##i = i - 2<0?0:i - 2, \\\n      _p1##i = i - 1<0?0:i - 1, \\\n      _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \\\n      _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \\\n      _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \\\n      _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \\\n      i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \\\n      i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \\\n      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)\n#define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img)._width,x0,x1,x)\n#define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img)._height,y0,y1,y)\n#define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img)._depth,z0,z1,z)\n#define cimg_for_in8C(img,c0,c1,c) cimg_for_in8((img)._spectrum,c0,c1,c)\n#define cimg_for_in8XY(img,x0,y0,x1,y1,x,y) cimg_for_in8Y(img,y0,y1,y) cimg_for_in8X(img,x0,x1,x)\n#define cimg_for_in8XZ(img,x0,z0,x1,z1,x,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8X(img,x0,x1,x)\n#define cimg_for_in8XC(img,x0,c0,x1,c1,x,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8X(img,x0,x1,x)\n#define cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8Y(img,y0,y1,y)\n#define cimg_for_in8YC(img,y0,c0,y1,c1,y,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Y(img,y0,y1,y)\n#define cimg_for_in8ZC(img,z0,c0,z1,c1,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Z(img,z0,z1,z)\n#define cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8XY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_in8XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8XZ(img,x0,y0,x1,y1,x,z)\n#define cimg_for_in8YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8YZ(img,y0,z0,y1,z1,y,z)\n#define cimg_for_in8XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n  cimg_for_in8C(img,c0,c1,c) cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n\n#define cimg_for9(bound,i) \\\n  for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \\\n       _n1##i = 1>=(int)(bound)?(int)(bound) - 1:1, \\\n       _n2##i = 2>=(int)(bound)?(int)(bound) - 1:2, \\\n       _n3##i = 3>=(int)(bound)?(int)(bound) - 1:3, \\\n       _n4##i = 4>=(int)(bound)?(int)(bound) - 1:4; \\\n       _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \\\n       i==(_n4##i = _n3##i = _n2##i = --_n1##i); \\\n       _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)\n#define cimg_for9X(img,x) cimg_for9((img)._width,x)\n#define cimg_for9Y(img,y) cimg_for9((img)._height,y)\n#define cimg_for9Z(img,z) cimg_for9((img)._depth,z)\n#define cimg_for9C(img,c) cimg_for9((img)._spectrum,c)\n#define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)\n#define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)\n#define cimg_for9XC(img,x,c) cimg_for9C(img,c) cimg_for9X(img,x)\n#define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)\n#define cimg_for9YC(img,y,c) cimg_for9C(img,c) cimg_for9Y(img,y)\n#define cimg_for9ZC(img,z,c) cimg_for9C(img,c) cimg_for9Z(img,z)\n#define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)\n#define cimg_for9XZC(img,x,z,c) cimg_for9C(img,c) cimg_for9XZ(img,x,z)\n#define cimg_for9YZC(img,y,z,c) cimg_for9C(img,c) cimg_for9YZ(img,y,z)\n#define cimg_for9XYZC(img,x,y,z,c) cimg_for9C(img,c) cimg_for9XYZ(img,x,y,z)\n\n#define cimg_for_in9(bound,i0,i1,i) \\\n  for (int i = (int)(i0)<0?0:(int)(i0), \\\n       _p4##i = i - 4<0?0:i - 4, \\\n       _p3##i = i - 3<0?0:i - 3, \\\n       _p2##i = i - 2<0?0:i - 2, \\\n       _p1##i = i - 1<0?0:i - 1, \\\n       _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \\\n       _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \\\n       _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \\\n       _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \\\n       i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \\\n       i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \\\n       _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)\n#define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img)._width,x0,x1,x)\n#define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img)._height,y0,y1,y)\n#define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img)._depth,z0,z1,z)\n#define cimg_for_in9C(img,c0,c1,c) cimg_for_in9((img)._spectrum,c0,c1,c)\n#define cimg_for_in9XY(img,x0,y0,x1,y1,x,y) cimg_for_in9Y(img,y0,y1,y) cimg_for_in9X(img,x0,x1,x)\n#define cimg_for_in9XZ(img,x0,z0,x1,z1,x,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9X(img,x0,x1,x)\n#define cimg_for_in9XC(img,x0,c0,x1,c1,x,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9X(img,x0,x1,x)\n#define cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9Y(img,y0,y1,y)\n#define cimg_for_in9YC(img,y0,c0,y1,c1,y,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Y(img,y0,y1,y)\n#define cimg_for_in9ZC(img,z0,c0,z1,c1,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Z(img,z0,z1,z)\n#define cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9XY(img,x0,y0,x1,y1,x,y)\n#define cimg_for_in9XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9XZ(img,x0,y0,x1,y1,x,z)\n#define cimg_for_in9YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9YZ(img,y0,z0,y1,z1,y,z)\n#define cimg_for_in9XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \\\n  cimg_for_in9C(img,c0,c1,c) cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n\n#define cimg_for2x2(img,x,y,z,c,I,T) \\\n  cimg_for2((img)._height,y) for (int x = 0, \\\n   _n1##x = (int)( \\\n   (I[0] = (T)(img)(0,y,z,c)), \\\n   (I[2] = (T)(img)(0,_n1##y,z,c)), \\\n   1>=(img)._width?(img).width() - 1:1);  \\\n   (_n1##x<(img).width() && ( \\\n   (I[1] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \\\n   x==--_n1##x; \\\n   I[0] = I[1], \\\n   I[2] = I[3], \\\n   ++x, ++_n1##x)\n\n#define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,c,I,T) \\\n  cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \\\n   _n1##x = (int)( \\\n   (I[0] = (T)(img)(x,y,z,c)), \\\n   (I[2] = (T)(img)(x,_n1##y,z,c)), \\\n   x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \\\n   x<=(int)(x1) && ((_n1##x<(img).width() && (  \\\n   (I[1] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \\\n   x==--_n1##x); \\\n   I[0] = I[1], \\\n   I[2] = I[3], \\\n   ++x, ++_n1##x)\n\n#define cimg_for3x3(img,x,y,z,c,I,T) \\\n  cimg_for3((img)._height,y) for (int x = 0, \\\n   _p1##x = 0, \\\n   _n1##x = (int)( \\\n   (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[3] = I[4] = (T)(img)(0,y,z,c)), \\\n   (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \\\n   1>=(img)._width?(img).width() - 1:1); \\\n   (_n1##x<(img).width() && ( \\\n   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[5] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \\\n   x==--_n1##x; \\\n   I[0] = I[1], I[1] = I[2], \\\n   I[3] = I[4], I[4] = I[5], \\\n   I[6] = I[7], I[7] = I[8], \\\n   _p1##x = x++, ++_n1##x)\n\n#define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,c,I,T) \\\n  cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \\\n   _p1##x = x - 1<0?0:x - 1, \\\n   _n1##x = (int)( \\\n   (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[3] = (T)(img)(_p1##x,y,z,c)), \\\n   (I[6] = (T)(img)(_p1##x,_n1##y,z,c)), \\\n   (I[1] = (T)(img)(x,_p1##y,z,c)), \\\n   (I[4] = (T)(img)(x,y,z,c)), \\\n   (I[7] = (T)(img)(x,_n1##y,z,c)), \\\n   x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \\\n   x<=(int)(x1) && ((_n1##x<(img).width() && ( \\\n   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[5] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \\\n   x==--_n1##x);            \\\n   I[0] = I[1], I[1] = I[2], \\\n   I[3] = I[4], I[4] = I[5], \\\n   I[6] = I[7], I[7] = I[8], \\\n   _p1##x = x++, ++_n1##x)\n\n#define cimg_for4x4(img,x,y,z,c,I,T) \\\n  cimg_for4((img)._height,y) for (int x = 0, \\\n   _p1##x = 0, \\\n   _n1##x = 1>=(img)._width?(img).width() - 1:1, \\\n   _n2##x = (int)( \\\n   (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[4] = I[5] = (T)(img)(0,y,z,c)), \\\n   (I[8] = I[9] = (T)(img)(0,_n1##y,z,c)), \\\n   (I[12] = I[13] = (T)(img)(0,_n2##y,z,c)), \\\n   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[6] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   2>=(img)._width?(img).width() - 1:2); \\\n   (_n2##x<(img).width() && ( \\\n   (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[7] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \\\n   _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], \\\n   I[4] = I[5], I[5] = I[6], I[6] = I[7], \\\n   I[8] = I[9], I[9] = I[10], I[10] = I[11], \\\n   I[12] = I[13], I[13] = I[14], I[14] = I[15], \\\n   _p1##x = x++, ++_n1##x, ++_n2##x)\n\n#define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,c,I,T) \\\n  cimg_for_in4((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \\\n   _p1##x = x - 1<0?0:x - 1, \\\n   _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \\\n   _n2##x = (int)( \\\n   (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[4] = (T)(img)(_p1##x,y,z,c)), \\\n   (I[8] = (T)(img)(_p1##x,_n1##y,z,c)), \\\n   (I[12] = (T)(img)(_p1##x,_n2##y,z,c)), \\\n   (I[1] = (T)(img)(x,_p1##y,z,c)), \\\n   (I[5] = (T)(img)(x,y,z,c)), \\\n   (I[9] = (T)(img)(x,_n1##y,z,c)), \\\n   (I[13] = (T)(img)(x,_n2##y,z,c)), \\\n   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[6] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \\\n   x<=(int)(x1) && ((_n2##x<(img).width() && ( \\\n   (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[7] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \\\n   _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], \\\n   I[4] = I[5], I[5] = I[6], I[6] = I[7], \\\n   I[8] = I[9], I[9] = I[10], I[10] = I[11], \\\n   I[12] = I[13], I[13] = I[14], I[14] = I[15], \\\n   _p1##x = x++, ++_n1##x, ++_n2##x)\n\n#define cimg_for5x5(img,x,y,z,c,I,T) \\\n cimg_for5((img)._height,y) for (int x = 0, \\\n   _p2##x = 0, _p1##x = 0, \\\n   _n1##x = 1>=(img)._width?(img).width() - 1:1, \\\n   _n2##x = (int)( \\\n   (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \\\n   (I[5] = I[6] = I[7] = (T)(img)(0,_p1##y,z,c)), \\\n   (I[10] = I[11] = I[12] = (T)(img)(0,y,z,c)), \\\n   (I[15] = I[16] = I[17] = (T)(img)(0,_n1##y,z,c)), \\\n   (I[20] = I[21] = I[22] = (T)(img)(0,_n2##y,z,c)), \\\n   (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[13] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[23] = (T)(img)(_n1##x,_n2##y,z,c)),  \\\n   2>=(img)._width?(img).width() - 1:2); \\\n   (_n2##x<(img).width() && ( \\\n   (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[14] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \\\n   _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \\\n   I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \\\n   I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \\\n   I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \\\n   I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \\\n   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)\n\n#define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,c,I,T) \\\n cimg_for_in5((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \\\n   _p2##x = x - 2<0?0:x - 2, \\\n   _p1##x = x - 1<0?0:x - 1, \\\n   _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \\\n   _n2##x = (int)( \\\n   (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \\\n   (I[5] = (T)(img)(_p2##x,_p1##y,z,c)), \\\n   (I[10] = (T)(img)(_p2##x,y,z,c)), \\\n   (I[15] = (T)(img)(_p2##x,_n1##y,z,c)), \\\n   (I[20] = (T)(img)(_p2##x,_n2##y,z,c)), \\\n   (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \\\n   (I[6] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[11] = (T)(img)(_p1##x,y,z,c)), \\\n   (I[16] = (T)(img)(_p1##x,_n1##y,z,c)), \\\n   (I[21] = (T)(img)(_p1##x,_n2##y,z,c)), \\\n   (I[2] = (T)(img)(x,_p2##y,z,c)), \\\n   (I[7] = (T)(img)(x,_p1##y,z,c)), \\\n   (I[12] = (T)(img)(x,y,z,c)), \\\n   (I[17] = (T)(img)(x,_n1##y,z,c)), \\\n   (I[22] = (T)(img)(x,_n2##y,z,c)), \\\n   (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[13] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \\\n   x<=(int)(x1) && ((_n2##x<(img).width() && ( \\\n   (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[14] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \\\n   _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \\\n   I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \\\n   I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \\\n   I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \\\n   I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \\\n   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)\n\n#define cimg_for6x6(img,x,y,z,c,I,T) \\\n cimg_for6((img)._height,y) for (int x = 0, \\\n   _p2##x = 0, _p1##x = 0, \\\n   _n1##x = 1>=(img)._width?(img).width() - 1:1, \\\n   _n2##x = 2>=(img)._width?(img).width() - 1:2, \\\n   _n3##x = (int)( \\\n   (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \\\n   (I[6] = I[7] = I[8] = (T)(img)(0,_p1##y,z,c)), \\\n   (I[12] = I[13] = I[14] = (T)(img)(0,y,z,c)), \\\n   (I[18] = I[19] = I[20] = (T)(img)(0,_n1##y,z,c)), \\\n   (I[24] = I[25] = I[26] = (T)(img)(0,_n2##y,z,c)), \\\n   (I[30] = I[31] = I[32] = (T)(img)(0,_n3##y,z,c)), \\\n   (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[15] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \\\n   (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[16] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \\\n   (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \\\n   3>=(img)._width?(img).width() - 1:3); \\\n   (_n3##x<(img).width() && ( \\\n   (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \\\n   (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \\\n   (I[17] = (T)(img)(_n3##x,y,z,c)), \\\n   (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \\\n   (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \\\n   (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \\\n   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \\\n   I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \\\n   I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \\\n   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \\\n   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \\\n   I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \\\n   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)\n\n#define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,c,I,T) \\\n  cimg_for_in6((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \\\n   _p2##x = x - 2<0?0:x - 2, \\\n   _p1##x = x - 1<0?0:x - 1, \\\n   _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \\\n   _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \\\n   _n3##x = (int)( \\\n   (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \\\n   (I[6] = (T)(img)(_p2##x,_p1##y,z,c)), \\\n   (I[12] = (T)(img)(_p2##x,y,z,c)), \\\n   (I[18] = (T)(img)(_p2##x,_n1##y,z,c)), \\\n   (I[24] = (T)(img)(_p2##x,_n2##y,z,c)), \\\n   (I[30] = (T)(img)(_p2##x,_n3##y,z,c)), \\\n   (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \\\n   (I[7] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[13] = (T)(img)(_p1##x,y,z,c)), \\\n   (I[19] = (T)(img)(_p1##x,_n1##y,z,c)), \\\n   (I[25] = (T)(img)(_p1##x,_n2##y,z,c)), \\\n   (I[31] = (T)(img)(_p1##x,_n3##y,z,c)), \\\n   (I[2] = (T)(img)(x,_p2##y,z,c)), \\\n   (I[8] = (T)(img)(x,_p1##y,z,c)), \\\n   (I[14] = (T)(img)(x,y,z,c)), \\\n   (I[20] = (T)(img)(x,_n1##y,z,c)), \\\n   (I[26] = (T)(img)(x,_n2##y,z,c)), \\\n   (I[32] = (T)(img)(x,_n3##y,z,c)), \\\n   (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[15] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \\\n   (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[16] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \\\n   (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \\\n   x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \\\n   x<=(int)(x1) && ((_n3##x<(img).width() && ( \\\n   (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \\\n   (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \\\n   (I[17] = (T)(img)(_n3##x,y,z,c)), \\\n   (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \\\n   (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \\\n   (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \\\n   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \\\n   I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \\\n   I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \\\n   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \\\n   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \\\n   I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \\\n   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)\n\n#define cimg_for7x7(img,x,y,z,c,I,T) \\\n  cimg_for7((img)._height,y) for (int x = 0, \\\n   _p3##x = 0, _p2##x = 0, _p1##x = 0, \\\n   _n1##x = 1>=(img)._width?(img).width() - 1:1, \\\n   _n2##x = 2>=(img)._width?(img).width() - 1:2, \\\n   _n3##x = (int)( \\\n   (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \\\n   (I[7] = I[8] = I[9] = I[10] = (T)(img)(0,_p2##y,z,c)), \\\n   (I[14] = I[15] = I[16] = I[17] = (T)(img)(0,_p1##y,z,c)), \\\n   (I[21] = I[22] = I[23] = I[24] = (T)(img)(0,y,z,c)), \\\n   (I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_n1##y,z,c)), \\\n   (I[35] = I[36] = I[37] = I[38] = (T)(img)(0,_n2##y,z,c)), \\\n   (I[42] = I[43] = I[44] = I[45] = (T)(img)(0,_n3##y,z,c)), \\\n   (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \\\n   (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[25] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \\\n   (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \\\n   (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[26] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \\\n   (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \\\n   3>=(img)._width?(img).width() - 1:3); \\\n   (_n3##x<(img).width() && ( \\\n   (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \\\n   (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \\\n   (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \\\n   (I[27] = (T)(img)(_n3##x,y,z,c)), \\\n   (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \\\n   (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \\\n   (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \\\n   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \\\n   I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \\\n   I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \\\n   I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \\\n   I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \\\n   I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \\\n   I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \\\n   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)\n\n#define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,c,I,T) \\\n  cimg_for_in7((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \\\n   _p3##x = x - 3<0?0:x - 3, \\\n   _p2##x = x - 2<0?0:x - 2, \\\n   _p1##x = x - 1<0?0:x - 1, \\\n   _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \\\n   _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \\\n   _n3##x = (int)( \\\n   (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \\\n   (I[7] = (T)(img)(_p3##x,_p2##y,z,c)), \\\n   (I[14] = (T)(img)(_p3##x,_p1##y,z,c)), \\\n   (I[21] = (T)(img)(_p3##x,y,z,c)), \\\n   (I[28] = (T)(img)(_p3##x,_n1##y,z,c)), \\\n   (I[35] = (T)(img)(_p3##x,_n2##y,z,c)), \\\n   (I[42] = (T)(img)(_p3##x,_n3##y,z,c)), \\\n   (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \\\n   (I[8] = (T)(img)(_p2##x,_p2##y,z,c)), \\\n   (I[15] = (T)(img)(_p2##x,_p1##y,z,c)), \\\n   (I[22] = (T)(img)(_p2##x,y,z,c)), \\\n   (I[29] = (T)(img)(_p2##x,_n1##y,z,c)), \\\n   (I[36] = (T)(img)(_p2##x,_n2##y,z,c)), \\\n   (I[43] = (T)(img)(_p2##x,_n3##y,z,c)), \\\n   (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \\\n   (I[9] = (T)(img)(_p1##x,_p2##y,z,c)), \\\n   (I[16] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[23] = (T)(img)(_p1##x,y,z,c)), \\\n   (I[30] = (T)(img)(_p1##x,_n1##y,z,c)), \\\n   (I[37] = (T)(img)(_p1##x,_n2##y,z,c)), \\\n   (I[44] = (T)(img)(_p1##x,_n3##y,z,c)), \\\n   (I[3] = (T)(img)(x,_p3##y,z,c)), \\\n   (I[10] = (T)(img)(x,_p2##y,z,c)), \\\n   (I[17] = (T)(img)(x,_p1##y,z,c)), \\\n   (I[24] = (T)(img)(x,y,z,c)), \\\n   (I[31] = (T)(img)(x,_n1##y,z,c)), \\\n   (I[38] = (T)(img)(x,_n2##y,z,c)), \\\n   (I[45] = (T)(img)(x,_n3##y,z,c)), \\\n   (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \\\n   (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[25] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \\\n   (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \\\n   (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[26] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \\\n   (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \\\n   x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \\\n   x<=(int)(x1) && ((_n3##x<(img).width() && ( \\\n   (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \\\n   (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \\\n   (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \\\n   (I[27] = (T)(img)(_n3##x,y,z,c)), \\\n   (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \\\n   (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \\\n   (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \\\n   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \\\n   I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \\\n   I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \\\n   I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \\\n   I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \\\n   I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \\\n   I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \\\n   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)\n\n#define cimg_for8x8(img,x,y,z,c,I,T) \\\n  cimg_for8((img)._height,y) for (int x = 0, \\\n   _p3##x = 0, _p2##x = 0, _p1##x = 0, \\\n   _n1##x = 1>=((img)._width)?(img).width() - 1:1, \\\n   _n2##x = 2>=((img)._width)?(img).width() - 1:2, \\\n   _n3##x = 3>=((img)._width)?(img).width() - 1:3, \\\n   _n4##x = (int)( \\\n   (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \\\n   (I[8] = I[9] = I[10] = I[11] = (T)(img)(0,_p2##y,z,c)), \\\n   (I[16] = I[17] = I[18] = I[19] = (T)(img)(0,_p1##y,z,c)), \\\n   (I[24] = I[25] = I[26] = I[27] = (T)(img)(0,y,z,c)), \\\n   (I[32] = I[33] = I[34] = I[35] = (T)(img)(0,_n1##y,z,c)), \\\n   (I[40] = I[41] = I[42] = I[43] = (T)(img)(0,_n2##y,z,c)), \\\n   (I[48] = I[49] = I[50] = I[51] = (T)(img)(0,_n3##y,z,c)), \\\n   (I[56] = I[57] = I[58] = I[59] = (T)(img)(0,_n4##y,z,c)), \\\n   (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \\\n   (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[28] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \\\n   (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \\\n   (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \\\n   (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[29] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \\\n   (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \\\n   (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \\\n   (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \\\n   (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \\\n   (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \\\n   (I[30] = (T)(img)(_n3##x,y,z,c)), \\\n   (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \\\n   (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \\\n   (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \\\n   (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \\\n   4>=((img)._width)?(img).width() - 1:4); \\\n   (_n4##x<(img).width() && ( \\\n   (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \\\n   (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \\\n   (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \\\n   (I[31] = (T)(img)(_n4##x,y,z,c)), \\\n   (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \\\n   (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \\\n   (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \\\n   (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \\\n   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \\\n   I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \\\n   I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \\\n   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \\\n   I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \\\n   I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \\\n   I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \\\n   I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \\\n   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)\n\n#define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,c,I,T) \\\n  cimg_for_in8((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \\\n   _p3##x = x - 3<0?0:x - 3, \\\n   _p2##x = x - 2<0?0:x - 2, \\\n   _p1##x = x - 1<0?0:x - 1, \\\n   _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \\\n   _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \\\n   _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \\\n   _n4##x = (int)( \\\n   (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \\\n   (I[8] = (T)(img)(_p3##x,_p2##y,z,c)), \\\n   (I[16] = (T)(img)(_p3##x,_p1##y,z,c)), \\\n   (I[24] = (T)(img)(_p3##x,y,z,c)), \\\n   (I[32] = (T)(img)(_p3##x,_n1##y,z,c)), \\\n   (I[40] = (T)(img)(_p3##x,_n2##y,z,c)), \\\n   (I[48] = (T)(img)(_p3##x,_n3##y,z,c)), \\\n   (I[56] = (T)(img)(_p3##x,_n4##y,z,c)), \\\n   (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \\\n   (I[9] = (T)(img)(_p2##x,_p2##y,z,c)), \\\n   (I[17] = (T)(img)(_p2##x,_p1##y,z,c)), \\\n   (I[25] = (T)(img)(_p2##x,y,z,c)), \\\n   (I[33] = (T)(img)(_p2##x,_n1##y,z,c)), \\\n   (I[41] = (T)(img)(_p2##x,_n2##y,z,c)), \\\n   (I[49] = (T)(img)(_p2##x,_n3##y,z,c)), \\\n   (I[57] = (T)(img)(_p2##x,_n4##y,z,c)), \\\n   (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \\\n   (I[10] = (T)(img)(_p1##x,_p2##y,z,c)), \\\n   (I[18] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[26] = (T)(img)(_p1##x,y,z,c)), \\\n   (I[34] = (T)(img)(_p1##x,_n1##y,z,c)), \\\n   (I[42] = (T)(img)(_p1##x,_n2##y,z,c)), \\\n   (I[50] = (T)(img)(_p1##x,_n3##y,z,c)), \\\n   (I[58] = (T)(img)(_p1##x,_n4##y,z,c)), \\\n   (I[3] = (T)(img)(x,_p3##y,z,c)), \\\n   (I[11] = (T)(img)(x,_p2##y,z,c)), \\\n   (I[19] = (T)(img)(x,_p1##y,z,c)), \\\n   (I[27] = (T)(img)(x,y,z,c)), \\\n   (I[35] = (T)(img)(x,_n1##y,z,c)), \\\n   (I[43] = (T)(img)(x,_n2##y,z,c)), \\\n   (I[51] = (T)(img)(x,_n3##y,z,c)), \\\n   (I[59] = (T)(img)(x,_n4##y,z,c)), \\\n   (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \\\n   (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[28] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \\\n   (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \\\n   (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \\\n   (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[29] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \\\n   (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \\\n   (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \\\n   (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \\\n   (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \\\n   (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \\\n   (I[30] = (T)(img)(_n3##x,y,z,c)), \\\n   (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \\\n   (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \\\n   (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \\\n   (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \\\n   x + 4>=(img).width()?(img).width() - 1:x + 4); \\\n   x<=(int)(x1) && ((_n4##x<(img).width() && ( \\\n   (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \\\n   (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \\\n   (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \\\n   (I[31] = (T)(img)(_n4##x,y,z,c)), \\\n   (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \\\n   (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \\\n   (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \\\n   (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \\\n   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \\\n   I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \\\n   I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \\\n   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \\\n   I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \\\n   I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \\\n   I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \\\n   I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \\\n   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)\n\n#define cimg_for9x9(img,x,y,z,c,I,T) \\\n  cimg_for9((img)._height,y) for (int x = 0, \\\n   _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \\\n   _n1##x = 1>=((img)._width)?(img).width() - 1:1, \\\n   _n2##x = 2>=((img)._width)?(img).width() - 1:2, \\\n   _n3##x = 3>=((img)._width)?(img).width() - 1:3, \\\n   _n4##x = (int)( \\\n   (I[0] = I[1] = I[2] = I[3] = I[4] = (T)(img)(_p4##x,_p4##y,z,c)), \\\n   (I[9] = I[10] = I[11] = I[12] = I[13] = (T)(img)(0,_p3##y,z,c)), \\\n   (I[18] = I[19] = I[20] = I[21] = I[22] = (T)(img)(0,_p2##y,z,c)), \\\n   (I[27] = I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_p1##y,z,c)), \\\n   (I[36] = I[37] = I[38] = I[39] = I[40] = (T)(img)(0,y,z,c)), \\\n   (I[45] = I[46] = I[47] = I[48] = I[49] = (T)(img)(0,_n1##y,z,c)), \\\n   (I[54] = I[55] = I[56] = I[57] = I[58] = (T)(img)(0,_n2##y,z,c)), \\\n   (I[63] = I[64] = I[65] = I[66] = I[67] = (T)(img)(0,_n3##y,z,c)), \\\n   (I[72] = I[73] = I[74] = I[75] = I[76] = (T)(img)(0,_n4##y,z,c)), \\\n   (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \\\n   (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \\\n   (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[41] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \\\n   (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \\\n   (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \\\n   (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \\\n   (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[42] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \\\n   (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \\\n   (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \\\n   (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \\\n   (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \\\n   (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \\\n   (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \\\n   (I[43] = (T)(img)(_n3##x,y,z,c)), \\\n   (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \\\n   (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \\\n   (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \\\n   (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \\\n   4>=((img)._width)?(img).width() - 1:4); \\\n   (_n4##x<(img).width() && ( \\\n   (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \\\n   (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \\\n   (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \\\n   (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \\\n   (I[44] = (T)(img)(_n4##x,y,z,c)), \\\n   (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \\\n   (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \\\n   (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \\\n   (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \\\n   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \\\n   I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], \\\n   I[16] = I[17], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \\\n   I[24] = I[25], I[25] = I[26], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], \\\n   I[32] = I[33], I[33] = I[34], I[34] = I[35], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], \\\n   I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[45] = I[46], I[46] = I[47], I[47] = I[48], \\\n   I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[54] = I[55], I[55] = I[56], \\\n   I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[63] = I[64], \\\n   I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \\\n   I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], \\\n   I[79] = I[80], \\\n   _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)\n\n#define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,c,I,T) \\\n  cimg_for_in9((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \\\n   _p4##x = x - 4<0?0:x - 4, \\\n   _p3##x = x - 3<0?0:x - 3, \\\n   _p2##x = x - 2<0?0:x - 2, \\\n   _p1##x = x - 1<0?0:x - 1, \\\n   _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \\\n   _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \\\n   _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \\\n   _n4##x = (int)( \\\n   (I[0] = (T)(img)(_p4##x,_p4##y,z,c)), \\\n   (I[9] = (T)(img)(_p4##x,_p3##y,z,c)), \\\n   (I[18] = (T)(img)(_p4##x,_p2##y,z,c)), \\\n   (I[27] = (T)(img)(_p4##x,_p1##y,z,c)), \\\n   (I[36] = (T)(img)(_p4##x,y,z,c)), \\\n   (I[45] = (T)(img)(_p4##x,_n1##y,z,c)), \\\n   (I[54] = (T)(img)(_p4##x,_n2##y,z,c)), \\\n   (I[63] = (T)(img)(_p4##x,_n3##y,z,c)), \\\n   (I[72] = (T)(img)(_p4##x,_n4##y,z,c)), \\\n   (I[1] = (T)(img)(_p3##x,_p4##y,z,c)), \\\n   (I[10] = (T)(img)(_p3##x,_p3##y,z,c)), \\\n   (I[19] = (T)(img)(_p3##x,_p2##y,z,c)), \\\n   (I[28] = (T)(img)(_p3##x,_p1##y,z,c)), \\\n   (I[37] = (T)(img)(_p3##x,y,z,c)), \\\n   (I[46] = (T)(img)(_p3##x,_n1##y,z,c)), \\\n   (I[55] = (T)(img)(_p3##x,_n2##y,z,c)), \\\n   (I[64] = (T)(img)(_p3##x,_n3##y,z,c)), \\\n   (I[73] = (T)(img)(_p3##x,_n4##y,z,c)), \\\n   (I[2] = (T)(img)(_p2##x,_p4##y,z,c)), \\\n   (I[11] = (T)(img)(_p2##x,_p3##y,z,c)), \\\n   (I[20] = (T)(img)(_p2##x,_p2##y,z,c)), \\\n   (I[29] = (T)(img)(_p2##x,_p1##y,z,c)), \\\n   (I[38] = (T)(img)(_p2##x,y,z,c)), \\\n   (I[47] = (T)(img)(_p2##x,_n1##y,z,c)), \\\n   (I[56] = (T)(img)(_p2##x,_n2##y,z,c)), \\\n   (I[65] = (T)(img)(_p2##x,_n3##y,z,c)), \\\n   (I[74] = (T)(img)(_p2##x,_n4##y,z,c)), \\\n   (I[3] = (T)(img)(_p1##x,_p4##y,z,c)), \\\n   (I[12] = (T)(img)(_p1##x,_p3##y,z,c)), \\\n   (I[21] = (T)(img)(_p1##x,_p2##y,z,c)), \\\n   (I[30] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[39] = (T)(img)(_p1##x,y,z,c)), \\\n   (I[48] = (T)(img)(_p1##x,_n1##y,z,c)), \\\n   (I[57] = (T)(img)(_p1##x,_n2##y,z,c)), \\\n   (I[66] = (T)(img)(_p1##x,_n3##y,z,c)), \\\n   (I[75] = (T)(img)(_p1##x,_n4##y,z,c)), \\\n   (I[4] = (T)(img)(x,_p4##y,z,c)), \\\n   (I[13] = (T)(img)(x,_p3##y,z,c)), \\\n   (I[22] = (T)(img)(x,_p2##y,z,c)), \\\n   (I[31] = (T)(img)(x,_p1##y,z,c)), \\\n   (I[40] = (T)(img)(x,y,z,c)), \\\n   (I[49] = (T)(img)(x,_n1##y,z,c)), \\\n   (I[58] = (T)(img)(x,_n2##y,z,c)), \\\n   (I[67] = (T)(img)(x,_n3##y,z,c)), \\\n   (I[76] = (T)(img)(x,_n4##y,z,c)), \\\n   (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \\\n   (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \\\n   (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \\\n   (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[41] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \\\n   (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \\\n   (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \\\n   (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \\\n   (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \\\n   (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \\\n   (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \\\n   (I[42] = (T)(img)(_n2##x,y,z,c)), \\\n   (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \\\n   (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \\\n   (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \\\n   (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \\\n   (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \\\n   (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \\\n   (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \\\n   (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \\\n   (I[43] = (T)(img)(_n3##x,y,z,c)), \\\n   (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \\\n   (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \\\n   (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \\\n   (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \\\n   x + 4>=(img).width()?(img).width() - 1:x + 4); \\\n   x<=(int)(x1) && ((_n4##x<(img).width() && ( \\\n   (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \\\n   (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \\\n   (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \\\n   (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \\\n   (I[44] = (T)(img)(_n4##x,y,z,c)), \\\n   (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \\\n   (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \\\n   (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \\\n   (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \\\n   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \\\n   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \\\n   I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], \\\n   I[16] = I[17], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \\\n   I[24] = I[25], I[25] = I[26], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], \\\n   I[32] = I[33], I[33] = I[34], I[34] = I[35], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], \\\n   I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[45] = I[46], I[46] = I[47], I[47] = I[48], \\\n   I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[54] = I[55], I[55] = I[56], \\\n   I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[63] = I[64], \\\n   I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \\\n   I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], \\\n   I[79] = I[80], \\\n   _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)\n\n#define cimg_for2x2x2(img,x,y,z,c,I,T) \\\n cimg_for2((img)._depth,z) cimg_for2((img)._height,y) for (int x = 0, \\\n   _n1##x = (int)( \\\n   (I[0] = (T)(img)(0,y,z,c)), \\\n   (I[2] = (T)(img)(0,_n1##y,z,c)), \\\n   (I[4] = (T)(img)(0,y,_n1##z,c)), \\\n   (I[6] = (T)(img)(0,_n1##y,_n1##z,c)), \\\n   1>=(img)._width?(img).width() - 1:1); \\\n   (_n1##x<(img).width() && ( \\\n   (I[1] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \\\n   (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \\\n   x==--_n1##x; \\\n   I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \\\n   ++x, ++_n1##x)\n\n#define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \\\n cimg_for_in2((img)._depth,z0,z1,z) cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \\\n   _n1##x = (int)( \\\n   (I[0] = (T)(img)(x,y,z,c)), \\\n   (I[2] = (T)(img)(x,_n1##y,z,c)), \\\n   (I[4] = (T)(img)(x,y,_n1##z,c)), \\\n   (I[6] = (T)(img)(x,_n1##y,_n1##z,c)), \\\n   x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \\\n   x<=(int)(x1) && ((_n1##x<(img).width() && ( \\\n   (I[1] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \\\n   (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \\\n   x==--_n1##x); \\\n   I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \\\n   ++x, ++_n1##x)\n\n#define cimg_for3x3x3(img,x,y,z,c,I,T) \\\n cimg_for3((img)._depth,z) cimg_for3((img)._height,y) for (int x = 0, \\\n   _p1##x = 0, \\\n   _n1##x = (int)( \\\n   (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \\\n   (I[3] = I[4] = (T)(img)(0,y,_p1##z,c)),  \\\n   (I[6] = I[7] = (T)(img)(0,_n1##y,_p1##z,c)), \\\n   (I[9] = I[10] = (T)(img)(0,_p1##y,z,c)), \\\n   (I[12] = I[13] = (T)(img)(0,y,z,c)), \\\n   (I[15] = I[16] = (T)(img)(0,_n1##y,z,c)), \\\n   (I[18] = I[19] = (T)(img)(0,_p1##y,_n1##z,c)), \\\n   (I[21] = I[22] = (T)(img)(0,y,_n1##z,c)), \\\n   (I[24] = I[25] = (T)(img)(0,_n1##y,_n1##z,c)), \\\n   1>=(img)._width?(img).width() - 1:1); \\\n   (_n1##x<(img).width() && ( \\\n   (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \\\n   (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \\\n   (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \\\n   (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[14] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \\\n   (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \\\n   (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \\\n   x==--_n1##x; \\\n   I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \\\n   I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \\\n   I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \\\n   _p1##x = x++, ++_n1##x)\n\n#define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \\\n cimg_for_in3((img)._depth,z0,z1,z) cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \\\n   _p1##x = x - 1<0?0:x - 1, \\\n   _n1##x = (int)( \\\n   (I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \\\n   (I[3] = (T)(img)(_p1##x,y,_p1##z,c)),  \\\n   (I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c)), \\\n   (I[9] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[12] = (T)(img)(_p1##x,y,z,c)), \\\n   (I[15] = (T)(img)(_p1##x,_n1##y,z,c)), \\\n   (I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c)), \\\n   (I[21] = (T)(img)(_p1##x,y,_n1##z,c)), \\\n   (I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c)), \\\n   (I[1] = (T)(img)(x,_p1##y,_p1##z,c)), \\\n   (I[4] = (T)(img)(x,y,_p1##z,c)),  \\\n   (I[7] = (T)(img)(x,_n1##y,_p1##z,c)), \\\n   (I[10] = (T)(img)(x,_p1##y,z,c)), \\\n   (I[13] = (T)(img)(x,y,z,c)), \\\n   (I[16] = (T)(img)(x,_n1##y,z,c)), \\\n   (I[19] = (T)(img)(x,_p1##y,_n1##z,c)), \\\n   (I[22] = (T)(img)(x,y,_n1##z,c)), \\\n   (I[25] = (T)(img)(x,_n1##y,_n1##z,c)), \\\n   x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \\\n   x<=(int)(x1) && ((_n1##x<(img).width() && ( \\\n   (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \\\n   (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \\\n   (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \\\n   (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[14] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \\\n   (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \\\n   (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \\\n   (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \\\n   x==--_n1##x); \\\n   I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \\\n   I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \\\n   I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \\\n   _p1##x = x++, ++_n1##x)\n\n#define cimglist_for(list,l) for (int l = 0; l<(int)(list)._width; ++l)\n#define cimglist_for_in(list,l0,l1,l) \\\n  for (int l = (int)(l0)<0?0:(int)(l0), _max##l = (unsigned int)l1<(list)._width?(int)(l1):(int)(list)._width - 1; \\\n  l<=_max##l; ++l)\n\n#define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn\n\n// Macros used to display error messages when exceptions are thrown.\n// You should not use these macros is your own code.\n#define _cimgdisplay_instance \"[instance(%u,%u,%u,%c%s%c)] CImgDisplay::\"\n#define cimgdisplay_instance _width,_height,_normalization,_title?'\\\"':'[',_title?_title:\"untitled\",_title?'\\\"':']'\n#define _cimg_instance \"[instance(%u,%u,%u,%u,%p,%sshared)] CImg<%s>::\"\n#define cimg_instance _width,_height,_depth,_spectrum,_data,_is_shared?\"\":\"non-\",pixel_type()\n#define _cimglist_instance \"[instance(%u,%u,%p)] CImgList<%s>::\"\n#define cimglist_instance _width,_allocated_width,_data,pixel_type()\n\n/*------------------------------------------------\n #\n #\n #  Define cimg_library:: namespace\n #\n #\n -------------------------------------------------*/\n//! Contains <i>all classes and functions</i> of the \\CImg library.\n/**\n   This namespace is defined to avoid functions and class names collisions\n   that could happen with the inclusion of other C++ header files.\n   Anyway, it should not happen often and you should reasonnably start most of your\n   \\CImg-based programs with\n   \\code\n   #include \"CImg.h\"\n   using namespace cimg_library;\n   \\endcode\n   to simplify the declaration of \\CImg Library objects afterwards.\n**/\nnamespace cimg_library_suffixed {\n\n  // Declare the four classes of the CImg Library.\n  template<typename T=float> struct CImg;\n  template<typename T=float> struct CImgList;\n  struct CImgDisplay;\n  struct CImgException;\n\n  // Declare cimg:: namespace.\n  // This is an uncomplete namespace definition here. It only contains some\n  // necessary stuff to ensure a correct declaration order of the classes and functions\n  // defined afterwards.\n  namespace cimg {\n\n    // Define ascii sequences for colored terminal output.\n#ifdef cimg_use_vt100\n    static const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 };\n    static const char t_black[] = { 0x1b, '[', '0', ';', '3', '0', ';', '5', '9', 'm', 0 };\n    static const char t_red[] = { 0x1b, '[', '0', ';', '3', '1', ';', '5', '9', 'm', 0 };\n    static const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 };\n    static const char t_yellow[] = { 0x1b, '[', '0', ';', '3', '3', ';', '5', '9', 'm', 0 };\n    static const char t_blue[] = { 0x1b, '[', '0', ';', '3', '4', ';', '5', '9', 'm', 0 };\n    static const char t_magenta[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 };\n    static const char t_cyan[] = { 0x1b, '[', '0', ';', '3', '6', ';', '5', '9', 'm', 0 };\n    static const char t_white[] = { 0x1b, '[', '0', ';', '3', '7', ';', '5', '9', 'm', 0 };\n    static const char t_bold[] = { 0x1b, '[', '1', 'm', 0 };\n    static const char t_underscore[] = { 0x1b, '[', '4', 'm', 0 };\n#else\n    static const char t_normal[] = { 0 };\n    static const char *const t_black = cimg::t_normal,\n      *const t_red = cimg::t_normal,\n      *const t_green = cimg::t_normal,\n      *const t_yellow = cimg::t_normal,\n      *const t_blue = cimg::t_normal,\n      *const t_magenta = cimg::t_normal,\n      *const t_cyan = cimg::t_normal,\n      *const t_white = cimg::t_normal,\n      *const t_bold = cimg::t_normal,\n      *const t_underscore = cimg::t_normal;\n#endif\n\n    inline std::FILE* output(std::FILE *file=0);\n    inline void info();\n\n    //! Avoid warning messages due to unused parameters. Do nothing actually.\n    template<typename T>\n    inline void unused(const T&, ...) {}\n\n    // [internal] Lock/unlock a mutex for managing concurrent threads.\n    // 'lock_mode' can be { 0=unlock | 1=lock | 2=trylock }.\n    // 'n' can be in [0,31] but mutex range [0,15] is reserved by CImg.\n    inline int mutex(const unsigned int n, const int lock_mode=1);\n\n    inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) {\n      static unsigned int mode = cimg_verbosity;\n      if (is_set) { cimg::mutex(0); mode = value<4?value:4; cimg::mutex(0,0); }\n      return mode;\n    }\n\n    // Mandatory because Microsoft's _snprintf() and _vsnprintf() do not add the '\\0' character\n    // at the end of the string.\n#if cimg_OS==2 && defined(_MSC_VER)\n    inline int _snprintf(char *const s, const size_t size, const char *const format, ...) {\n      va_list ap;\n      va_start(ap,format);\n      const int result = _vsnprintf(s,size,format,ap);\n      va_end(ap);\n      return result;\n    }\n\n    inline int _vsnprintf(char *const s, const size_t size, const char *const format, va_list ap) {\n      int result = -1;\n      cimg::mutex(6);\n      if (size) result = _vsnprintf_s(s,size,_TRUNCATE,format,ap);\n      if (result==-1) result = _vscprintf(format,ap);\n      cimg::mutex(6,0);\n      return result;\n    }\n\n    // Mutex-protected version of sscanf, sprintf and snprintf.\n    // Used only MacOSX, as it seems those functions are not re-entrant on MacOSX.\n#elif defined(__MACOSX__) || defined(__APPLE__)\n    inline int _sscanf(const char *const s, const char *const format, ...) {\n      cimg::mutex(6);\n      va_list args;\n      va_start(args,format);\n      const int result = std::vsscanf(s,format,args);\n      va_end(args);\n      cimg::mutex(6,0);\n      return result;\n    }\n\n    inline int _sprintf(char *const s, const char *const format, ...) {\n      cimg::mutex(6);\n      va_list args;\n      va_start(args,format);\n      const int result = std::vsprintf(s,format,args);\n      va_end(args);\n      cimg::mutex(6,0);\n      return result;\n    }\n\n    inline int _snprintf(char *const s, const size_t n, const char *const format, ...) {\n      cimg::mutex(6);\n      va_list args;\n      va_start(args,format);\n      const int result = std::vsnprintf(s,n,format,args);\n      va_end(args);\n      cimg::mutex(6,0);\n      return result;\n    }\n\n    inline int _vsnprintf(char *const s, const size_t size, const char* format, va_list ap) {\n      cimg::mutex(6);\n      const int result = std::vsnprintf(s,size,format,ap);\n      cimg::mutex(6,0);\n      return result;\n    }\n#endif\n\n    //! Set current \\CImg exception mode.\n    /**\n       The way error messages are handled by \\CImg can be changed dynamically, using this function.\n       \\param mode Desired exception mode. Possible values are:\n       - \\c 0: Hide library messages (quiet mode).\n       - \\c 1: Print library messages on the console.\n       - \\c 2: Display library messages on a dialog window (default behavior).\n       - \\c 3: Do as \\c 1 + add extra debug warnings (slow down the code!).\n       - \\c 4: Do as \\c 2 + add extra debug warnings (slow down the code!).\n     **/\n    inline unsigned int& exception_mode(const unsigned int mode) {\n      return _exception_mode(mode,true);\n    }\n\n    //! Return current \\CImg exception mode.\n    /**\n       \\note By default, return the value of configuration macro \\c cimg_verbosity\n    **/\n    inline unsigned int& exception_mode() {\n      return _exception_mode(0,false);\n    }\n\n    //! Set current \\CImg openmp mode.\n    /**\n       The way openmp-based methods are handled by \\CImg can be changed dynamically, using this function.\n       \\param mode Desired openmp mode. Possible values are:\n       - \\c 0: Never parallelize (quiet mode).\n       - \\c 1: Always parallelize.\n       - \\c 2: Adaptive parallelization mode (default behavior).\n     **/\n    inline unsigned int& _openmp_mode(const unsigned int value, const bool is_set) {\n      static unsigned int mode = 2;\n      if (is_set)  { cimg::mutex(0); mode = value<2?value:2; cimg::mutex(0,0); }\n      return mode;\n    }\n\n    inline unsigned int& openmp_mode(const unsigned int mode) {\n      return _openmp_mode(mode,true);\n    }\n\n    //! Return current \\CImg openmp mode.\n    inline unsigned int& openmp_mode() {\n      return _openmp_mode(0,false);\n    }\n\n#define cimg_openmp_if(cond) if (cimg::openmp_mode()==1 || (cimg::openmp_mode()>1 && (cond)))\n\n    // Display a simple dialog box, and wait for the user's response.\n    inline int dialog(const char *const title, const char *const msg, const char *const button1_label=\"OK\",\n                      const char *const button2_label=0, const char *const button3_label=0,\n                      const char *const button4_label=0, const char *const button5_label=0,\n                      const char *const button6_label=0, const bool centering=false);\n\n    // Evaluate math expression.\n    inline double eval(const char *const expression,\n                       const double x=0, const double y=0, const double z=0, const double c=0);\n\n  }\n\n  /*---------------------------------------\n    #\n    # Define the CImgException structures\n    #\n    --------------------------------------*/\n  //! Instances of \\c CImgException are thrown when errors are encountered in a \\CImg function call.\n  /**\n     \\par Overview\n\n      CImgException is the base class of all exceptions thrown by \\CImg (except \\b CImgAbortException).\n      CImgException is never thrown itself. Derived classes that specify the type of errord are thrown instead.\n      These classes can be:\n\n      - \\b CImgAbortException: Thrown when a computationally-intensive function is aborted by an external signal.\n        This is the only \\c non-derived exception class.\n\n      - \\b CImgArgumentException: Thrown when one argument of a called \\CImg function is invalid.\n      This is probably one of the most thrown exception by \\CImg.\n      For instance, the following example throws a \\c CImgArgumentException:\n      \\code\n      CImg<float> img(100,100,1,3); // Define a 100x100 color image with float-valued pixels.\n      img.mirror('e');              // Try to mirror image along the (non-existing) 'e'-axis.\n      \\endcode\n\n      - \\b CImgDisplayException: Thrown when something went wrong during the display of images in CImgDisplay instances.\n\n      - \\b CImgInstanceException: Thrown when an instance associated to a called \\CImg method does not fit\n      the function requirements. For instance, the following example throws a \\c CImgInstanceException:\n      \\code\n      const CImg<float> img;           // Define an empty image.\n      const float value = img.at(0);   // Try to read first pixel value (does not exist).\n      \\endcode\n\n      - \\b CImgIOException: Thrown when an error occured when trying to load or save image files.\n      This happens when trying to read files that do not exist or with invalid formats.\n      For instance, the following example throws a \\c CImgIOException:\n      \\code\n      const CImg<float> img(\"missing_file.jpg\");  // Try to load a file that does not exist.\n      \\endcode\n\n      - \\b CImgWarningException: Thrown only if configuration macro \\c cimg_strict_warnings is set, and\n      when a \\CImg function has to display a warning message (see cimg::warn()).\n\n      It is not recommended to throw CImgException instances by yourself,\n      since they are expected to be thrown only by \\CImg.\n      When an error occurs in a library function call, \\CImg may display error messages on the screen or on the\n      standard output, depending on the current \\CImg exception mode.\n      The \\CImg exception mode can be get and set by functions cimg::exception_mode() and\n      cimg::exception_mode(unsigned int).\n\n      \\par Exceptions handling\n\n      In all cases, when an error occurs in \\CImg, an instance of the corresponding exception class is thrown.\n      This may lead the program to break (this is the default behavior), but you can bypass this behavior by\n      handling the exceptions by yourself,\n      using a usual <tt>try { ... } catch () { ... }</tt> bloc, as in the following example:\n      \\code\n      #define \"CImg.h\"\n      using namespace cimg_library;\n      int main() {\n        cimg::exception_mode(0);                                    // Enable quiet exception mode.\n        try {\n          ...                                                       // Here, do what you want to stress CImg.\n        } catch (CImgException &e) {                                // You succeeded: something went wrong!\n          std::fprintf(stderr,\"CImg Library Error: %s\",e.what());   // Display your custom error message.\n          ...                                                       // Do what you want now to save the ship!\n          }\n        }\n      \\endcode\n  **/\n  struct CImgException : public std::exception {\n#define _cimg_exception_err(etype,disp_flag) \\\n  std::va_list ap, ap2; \\\n  va_start(ap,format); va_start(ap2,format); \\\n  int size = cimg_vsnprintf(0,0,format,ap2); \\\n  if (size++>=0) { \\\n    delete[] _message; \\\n    _message = new char[size]; \\\n    cimg_vsnprintf(_message,size,format,ap); \\\n    if (cimg::exception_mode()) { \\\n      std::fprintf(cimg::output(),\"\\n%s[CImg] *** %s ***%s %s\\n\",cimg::t_red,etype,cimg::t_normal,_message); \\\n      if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,\"Abort\"); } \\\n      catch (CImgException&) {} \\\n      if (cimg::exception_mode()>=3) cimg_library_suffixed::cimg::info(); \\\n    } \\\n  } \\\n  va_end(ap); va_end(ap2); \\\n\n    char *_message;\n    CImgException() { _message = new char[1]; *_message = 0; }\n    CImgException(const char *const format, ...):_message(0) { _cimg_exception_err(\"CImgException\",true); }\n    CImgException(const CImgException& e):std::exception(e) {\n      const size_t size = std::strlen(e._message);\n      _message = new char[size + 1];\n      std::strncpy(_message,e._message,size);\n      _message[size] = 0;\n    }\n    ~CImgException() throw() { delete[] _message; }\n    CImgException& operator=(const CImgException& e) {\n      const size_t size = std::strlen(e._message);\n      _message = new char[size + 1];\n      std::strncpy(_message,e._message,size);\n      _message[size] = 0;\n      return *this;\n    }\n    //! Return a C-string containing the error message associated to the thrown exception.\n    const char *what() const throw() { return _message; }\n  };\n\n  // The CImgAbortException class is used to throw an exception when\n  // a computationally-intensive function has been aborted by an external signal.\n  struct CImgAbortException : public std::exception {\n    char *_message;\n    CImgAbortException() { _message = new char[1]; *_message = 0; }\n    CImgAbortException(const char *const format, ...):_message(0) { _cimg_exception_err(\"CImgAbortException\",true); }\n    CImgAbortException(const CImgAbortException& e):std::exception(e) {\n      const size_t size = std::strlen(e._message);\n      _message = new char[size + 1];\n      std::strncpy(_message,e._message,size);\n      _message[size] = 0;\n    }\n    ~CImgAbortException() throw() { delete[] _message; }\n    CImgAbortException& operator=(const CImgAbortException& e) {\n      const size_t size = std::strlen(e._message);\n      _message = new char[size + 1];\n      std::strncpy(_message,e._message,size);\n      _message[size] = 0;\n      return *this;\n    }\n    //! Return a C-string containing the error message associated to the thrown exception.\n    const char *what() const throw() { return _message; }\n  };\n\n  // The CImgArgumentException class is used to throw an exception related\n  // to invalid arguments encountered in a library function call.\n  struct CImgArgumentException : public CImgException {\n    CImgArgumentException(const char *const format, ...) { _cimg_exception_err(\"CImgArgumentException\",true); }\n  };\n\n  // The CImgDisplayException class is used to throw an exception related\n  // to display problems encountered in a library function call.\n  struct CImgDisplayException : public CImgException {\n    CImgDisplayException(const char *const format, ...) { _cimg_exception_err(\"CImgDisplayException\",false); }\n  };\n\n  // The CImgInstanceException class is used to throw an exception related\n  // to an invalid instance encountered in a library function call.\n  struct CImgInstanceException : public CImgException {\n    CImgInstanceException(const char *const format, ...) { _cimg_exception_err(\"CImgInstanceException\",true); }\n  };\n\n  // The CImgIOException class is used to throw an exception related\n  // to input/output file problems encountered in a library function call.\n  struct CImgIOException : public CImgException {\n    CImgIOException(const char *const format, ...) { _cimg_exception_err(\"CImgIOException\",true); }\n  };\n\n  // The CImgWarningException class is used to throw an exception for warnings\n  // encountered in a library function call.\n  struct CImgWarningException : public CImgException {\n    CImgWarningException(const char *const format, ...) { _cimg_exception_err(\"CImgWarningException\",false); }\n  };\n\n  /*-------------------------------------\n    #\n    # Define cimg:: namespace\n    #\n    -----------------------------------*/\n  //! Contains \\a low-level functions and variables of the \\CImg Library.\n  /**\n     Most of the functions and variables within this namespace are used by the \\CImg library for low-level operations.\n     You may use them to access specific const values or environment variables internally used by \\CImg.\n     \\warning Never write <tt>using namespace cimg_library::cimg;</tt> in your source code. Lot of functions in the\n     <tt>cimg:: namespace</tt> have the same names as standard C functions that may be defined in the global\n     namespace <tt>::</tt>.\n  **/\n  namespace cimg {\n\n    // Define traits that will be used to determine the best data type to work in CImg functions.\n    //\n    template<typename T> struct type {\n      static const char* string() {\n        static const char* s[] = { \"unknown\",   \"unknown8\",   \"unknown16\",  \"unknown24\",\n                                   \"unknown32\", \"unknown40\",  \"unknown48\",  \"unknown56\",\n                                   \"unknown64\", \"unknown72\",  \"unknown80\",  \"unknown88\",\n                                   \"unknown96\", \"unknown104\", \"unknown112\", \"unknown120\",\n                                   \"unknown128\" };\n        return s[(sizeof(T)<17)?sizeof(T):0];\n      }\n      static bool is_float() { return false; }\n      static bool is_inf(const T) { return false; }\n      static bool is_nan(const T) { return false; }\n      static T min() { return ~max(); }\n      static T max() { return (T)1<<(8*sizeof(T) - 1); }\n      static T inf() { return max(); }\n      static T cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(T)val; }\n      static const char* format() { return \"%s\"; }\n      static const char* format(const T& val) { static const char *const s = \"unknown\"; cimg::unused(val); return s; }\n    };\n\n    template<> struct type<bool> {\n      static const char* string() { static const char *const s = \"bool\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const bool) { return false; }\n      static bool is_nan(const bool) { return false; }\n      static bool min() { return false; }\n      static bool max() { return true; }\n      static bool inf() { return max(); }\n      static bool is_inf() { return false; }\n      static bool cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(bool)val; }\n      static const char* format() { return \"%s\"; }\n      static const char* format(const bool val) { static const char* s[] = { \"false\", \"true\" }; return s[val?1:0]; }\n    };\n\n    template<> struct type<unsigned char> {\n      static const char* string() { static const char *const s = \"unsigned char\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const unsigned char) { return false; }\n      static bool is_nan(const unsigned char) { return false; }\n      static unsigned char min() { return 0; }\n      static unsigned char max() { return (unsigned char)-1; }\n      static unsigned char inf() { return max(); }\n      static unsigned char cut(const double val) {\n        return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; }\n      static const char* format() { return \"%u\"; }\n      static unsigned int format(const unsigned char val) { return (unsigned int)val; }\n    };\n\n#if defined(CHAR_MAX) && CHAR_MAX==255\n    template<> struct type<char> {\n      static const char* string() { static const char *const s = \"char\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const char) { return false; }\n      static bool is_nan(const char) { return false; }\n      static char min() { return 0; }\n      static char max() { return (char)-1; }\n      static char inf() { return max(); }\n      static char cut(const double val) {\n        return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; }\n      static const char* format() { return \"%u\"; }\n      static unsigned int format(const char val) { return (unsigned int)val; }\n    };\n#else\n    template<> struct type<char> {\n      static const char* string() { static const char *const s = \"char\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const char) { return false; }\n      static bool is_nan(const char) { return false; }\n      static char min() { return ~max(); }\n      static char max() { return (char)((unsigned char)-1>>1); }\n      static char inf() { return max(); }\n      static char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(char)val; }\n      static const char* format() { return \"%d\"; }\n      static int format(const char val) { return (int)val; }\n    };\n#endif\n\n    template<> struct type<signed char> {\n      static const char* string() { static const char *const s = \"signed char\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const signed char) { return false; }\n      static bool is_nan(const signed char) { return false; }\n      static signed char min() { return ~max(); }\n      static signed char max() { return (signed char)((unsigned char)-1>>1); }\n      static signed char inf() { return max(); }\n      static signed char cut(const double val) {\n        return val<(double)min()?min():val>(double)max()?max():(signed char)val; }\n      static const char* format() { return \"%d\"; }\n      static int format(const signed char val) { return (int)val; }\n    };\n\n    template<> struct type<unsigned short> {\n      static const char* string() { static const char *const s = \"unsigned short\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const unsigned short) { return false; }\n      static bool is_nan(const unsigned short) { return false; }\n      static unsigned short min() { return 0; }\n      static unsigned short max() { return (unsigned short)-1; }\n      static unsigned short inf() { return max(); }\n      static unsigned short cut(const double val) {\n        return val<(double)min()?min():val>(double)max()?max():(unsigned short)val; }\n      static const char* format() { return \"%u\"; }\n      static unsigned int format(const unsigned short val) { return (unsigned int)val; }\n    };\n\n    template<> struct type<short> {\n      static const char* string() { static const char *const s = \"short\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const short) { return false; }\n      static bool is_nan(const short) { return false; }\n      static short min() { return ~max(); }\n      static short max() { return (short)((unsigned short)-1>>1); }\n      static short inf() { return max(); }\n      static short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(short)val; }\n      static const char* format() { return \"%d\"; }\n      static int format(const short val) { return (int)val; }\n    };\n\n    template<> struct type<unsigned int> {\n      static const char* string() { static const char *const s = \"unsigned int\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const unsigned int) { return false; }\n      static bool is_nan(const unsigned int) { return false; }\n      static unsigned int min() { return 0; }\n      static unsigned int max() { return (unsigned int)-1; }\n      static unsigned int inf() { return max(); }\n      static unsigned int cut(const double val) {\n        return val<(double)min()?min():val>(double)max()?max():(unsigned int)val; }\n      static const char* format() { return \"%u\"; }\n      static unsigned int format(const unsigned int val) { return val; }\n    };\n\n    template<> struct type<int> {\n      static const char* string() { static const char *const s = \"int\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const int) { return false; }\n      static bool is_nan(const int) { return false; }\n      static int min() { return ~max(); }\n      static int max() { return (int)((unsigned int)-1>>1); }\n      static int inf() { return max(); }\n      static int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(int)val; }\n      static const char* format() { return \"%d\"; }\n      static int format(const int val) { return val; }\n    };\n\n    template<> struct type<cimg_uint64> {\n      static const char* string() { static const char *const s = \"unsigned int64\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const cimg_uint64) { return false; }\n      static bool is_nan(const cimg_uint64) { return false; }\n      static cimg_uint64 min() { return 0; }\n      static cimg_uint64 max() { return (cimg_uint64)-1; }\n      static cimg_uint64 inf() { return max(); }\n      static cimg_uint64 cut(const double val) {\n        return val<(double)min()?min():val>(double)max()?max():(cimg_uint64)val; }\n      static const char* format() { return \"%lu\"; }\n      static unsigned long format(const cimg_uint64 val) { return (unsigned long)val; }\n    };\n\n    template<> struct type<cimg_int64> {\n      static const char* string() { static const char *const s = \"int64\"; return s; }\n      static bool is_float() { return false; }\n      static bool is_inf(const cimg_int64) { return false; }\n      static bool is_nan(const cimg_int64) { return false; }\n      static cimg_int64 min() { return ~max(); }\n      static cimg_int64 max() { return (cimg_int64)((cimg_uint64)-1>>1); }\n      static cimg_int64 inf() { return max(); }\n      static cimg_int64 cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(cimg_int64)val; }\n      static const char* format() { return \"%ld\"; }\n      static long format(const long val) { return (long)val; }\n    };\n\n    template<> struct type<double> {\n      static const char* string() { static const char *const s = \"double\"; return s; }\n      static bool is_float() { return true; }\n      static bool is_inf(const double val) {\n#ifdef isinf\n        return (bool)isinf(val);\n#else\n        return !is_nan(val) && (val<cimg::type<double>::min() || val>cimg::type<double>::max());\n#endif\n      }\n      static bool is_nan(const double val) {\n#ifdef isnan\n        return (bool)isnan(val);\n#else\n        return !(val==val);\n#endif\n      }\n      static double min() { return -DBL_MAX; }\n      static double max() { return DBL_MAX; }\n      static double inf() {\n#ifdef INFINITY\n        return (double)INFINITY;\n#else\n        return max()*max();\n#endif\n      }\n      static double nan() {\n#ifdef NAN\n        return (double)NAN;\n#else\n        const double val_nan = -std::sqrt(-1.0); return val_nan;\n#endif\n      }\n      static double cut(const double val) { return val<min()?min():val>max()?max():val; }\n      static const char* format() { return \"%.16g\"; }\n      static double format(const double val) { return val; }\n    };\n\n    template<> struct type<float> {\n      static const char* string() { static const char *const s = \"float\"; return s; }\n      static bool is_float() { return true; }\n      static bool is_inf(const float val) {\n#ifdef isinf\n        return (bool)isinf(val);\n#else\n        return !is_nan(val) && (val<cimg::type<float>::min() || val>cimg::type<float>::max());\n#endif\n      }\n      static bool is_nan(const float val) {\n#ifdef isnan\n        return (bool)isnan(val);\n#else\n        return !(val==val);\n#endif\n      }\n      static float min() { return -FLT_MAX; }\n      static float max() { return FLT_MAX; }\n      static float inf() { return (float)cimg::type<double>::inf(); }\n      static float nan() { return (float)cimg::type<double>::nan(); }\n      static float cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(float)val; }\n      static const char* format() { return \"%.16g\"; }\n      static double format(const float val) { return (double)val; }\n    };\n\n    template<> struct type<long double> {\n      static const char* string() { static const char *const s = \"long double\"; return s; }\n      static bool is_float() { return true; }\n      static bool is_inf(const long double val) {\n#ifdef isinf\n        return (bool)isinf(val);\n#else\n        return !is_nan(val) && (val<cimg::type<long double>::min() || val>cimg::type<long double>::max());\n#endif\n      }\n      static bool is_nan(const long double val) {\n#ifdef isnan\n        return (bool)isnan(val);\n#else\n        return !(val==val);\n#endif\n      }\n      static long double min() { return -LDBL_MAX; }\n      static long double max() { return LDBL_MAX; }\n      static long double inf() { return max()*max(); }\n      static long double nan() { const long double val_nan = -std::sqrt(-1.0L); return val_nan; }\n      static long double cut(const long double val) { return val<min()?min():val>max()?max():val; }\n      static const char* format() { return \"%.16g\"; }\n      static double format(const long double val) { return (double)val; }\n    };\n\n    template<typename T, typename t> struct superset { typedef T type; };\n    template<> struct superset<bool,unsigned char> { typedef unsigned char type; };\n    template<> struct superset<bool,char> { typedef char type; };\n    template<> struct superset<bool,signed char> { typedef signed char type; };\n    template<> struct superset<bool,unsigned short> { typedef unsigned short type; };\n    template<> struct superset<bool,short> { typedef short type; };\n    template<> struct superset<bool,unsigned int> { typedef unsigned int type; };\n    template<> struct superset<bool,int> { typedef int type; };\n    template<> struct superset<bool,cimg_uint64> { typedef cimg_uint64 type; };\n    template<> struct superset<bool,cimg_int64> { typedef cimg_int64 type; };\n    template<> struct superset<bool,float> { typedef float type; };\n    template<> struct superset<bool,double> { typedef double type; };\n    template<> struct superset<unsigned char,char> { typedef short type; };\n    template<> struct superset<unsigned char,signed char> { typedef short type; };\n    template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };\n    template<> struct superset<unsigned char,short> { typedef short type; };\n    template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };\n    template<> struct superset<unsigned char,int> { typedef int type; };\n    template<> struct superset<unsigned char,cimg_uint64> { typedef cimg_uint64 type; };\n    template<> struct superset<unsigned char,cimg_int64> { typedef cimg_int64 type; };\n    template<> struct superset<unsigned char,float> { typedef float type; };\n    template<> struct superset<unsigned char,double> { typedef double type; };\n    template<> struct superset<signed char,unsigned char> { typedef short type; };\n    template<> struct superset<signed char,char> { typedef short type; };\n    template<> struct superset<signed char,unsigned short> { typedef int type; };\n    template<> struct superset<signed char,short> { typedef short type; };\n    template<> struct superset<signed char,unsigned int> { typedef cimg_int64 type; };\n    template<> struct superset<signed char,int> { typedef int type; };\n    template<> struct superset<signed char,cimg_uint64> { typedef cimg_int64 type; };\n    template<> struct superset<signed char,cimg_int64> { typedef cimg_int64 type; };\n    template<> struct superset<signed char,float> { typedef float type; };\n    template<> struct superset<signed char,double> { typedef double type; };\n    template<> struct superset<char,unsigned char> { typedef short type; };\n    template<> struct superset<char,signed char> { typedef short type; };\n    template<> struct superset<char,unsigned short> { typedef int type; };\n    template<> struct superset<char,short> { typedef short type; };\n    template<> struct superset<char,unsigned int> { typedef cimg_int64 type; };\n    template<> struct superset<char,int> { typedef int type; };\n    template<> struct superset<char,cimg_uint64> { typedef cimg_int64 type; };\n    template<> struct superset<char,cimg_int64> { typedef cimg_int64 type; };\n    template<> struct superset<char,float> { typedef float type; };\n    template<> struct superset<char,double> { typedef double type; };\n    template<> struct superset<unsigned short,char> { typedef int type; };\n    template<> struct superset<unsigned short,signed char> { typedef int type; };\n    template<> struct superset<unsigned short,short> { typedef int type; };\n    template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };\n    template<> struct superset<unsigned short,int> { typedef int type; };\n    template<> struct superset<unsigned short,cimg_uint64> { typedef cimg_uint64 type; };\n    template<> struct superset<unsigned short,cimg_int64> { typedef cimg_int64 type; };\n    template<> struct superset<unsigned short,float> { typedef float type; };\n    template<> struct superset<unsigned short,double> { typedef double type; };\n    template<> struct superset<short,unsigned short> { typedef int type; };\n    template<> struct superset<short,unsigned int> { typedef cimg_int64 type; };\n    template<> struct superset<short,int> { typedef int type; };\n    template<> struct superset<short,cimg_uint64> { typedef cimg_int64 type; };\n    template<> struct superset<short,cimg_int64> { typedef cimg_int64 type; };\n    template<> struct superset<short,float> { typedef float type; };\n    template<> struct superset<short,double> { typedef double type; };\n    template<> struct superset<unsigned int,char> { typedef cimg_int64 type; };\n    template<> struct superset<unsigned int,signed char> { typedef cimg_int64 type; };\n    template<> struct superset<unsigned int,short> { typedef cimg_int64 type; };\n    template<> struct superset<unsigned int,int> { typedef cimg_int64 type; };\n    template<> struct superset<unsigned int,cimg_uint64> { typedef cimg_uint64 type; };\n    template<> struct superset<unsigned int,cimg_int64> { typedef cimg_int64 type; };\n    template<> struct superset<unsigned int,float> { typedef float type; };\n    template<> struct superset<unsigned int,double> { typedef double type; };\n    template<> struct superset<int,unsigned int> { typedef cimg_int64 type; };\n    template<> struct superset<int,cimg_uint64> { typedef cimg_int64 type; };\n    template<> struct superset<int,cimg_int64> { typedef cimg_int64 type; };\n    template<> struct superset<int,float> { typedef float type; };\n    template<> struct superset<int,double> { typedef double type; };\n    template<> struct superset<cimg_uint64,char> { typedef cimg_int64 type; };\n    template<> struct superset<cimg_uint64,signed char> { typedef cimg_int64 type; };\n    template<> struct superset<cimg_uint64,short> { typedef cimg_int64 type; };\n    template<> struct superset<cimg_uint64,int> { typedef cimg_int64 type; };\n    template<> struct superset<cimg_uint64,cimg_int64> { typedef cimg_int64 type; };\n    template<> struct superset<cimg_uint64,float> { typedef double type; };\n    template<> struct superset<cimg_uint64,double> { typedef double type; };\n    template<> struct superset<cimg_int64,float> { typedef double type; };\n    template<> struct superset<cimg_int64,double> { typedef double type; };\n    template<> struct superset<float,double> { typedef double type; };\n\n    template<typename t1, typename t2, typename t3> struct superset2 {\n      typedef typename superset<t1, typename superset<t2,t3>::type>::type type;\n    };\n\n    template<typename t1, typename t2, typename t3, typename t4> struct superset3 {\n      typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type;\n    };\n\n    template<typename t1, typename t2> struct last { typedef t2 type; };\n\n#define _cimg_Tt typename cimg::superset<T,t>::type\n#define _cimg_Tfloat typename cimg::superset<T,float>::type\n#define _cimg_Ttfloat typename cimg::superset2<T,t,float>::type\n#define _cimg_Ttdouble typename cimg::superset2<T,t,double>::type\n\n    // Define variables used internally by CImg.\n#if cimg_display==1\n    struct X11_info {\n      unsigned int nb_wins;\n      pthread_t *events_thread;\n      pthread_cond_t wait_event;\n      pthread_mutex_t wait_event_mutex;\n      CImgDisplay **wins;\n      Display *display;\n      unsigned int nb_bits;\n      bool is_blue_first;\n      bool is_shm_enabled;\n      bool byte_order;\n#ifdef cimg_use_xrandr\n      XRRScreenSize *resolutions;\n      Rotation curr_rotation;\n      unsigned int curr_resolution;\n      unsigned int nb_resolutions;\n#endif\n      X11_info():nb_wins(0),events_thread(0),display(0),\n                 nb_bits(0),is_blue_first(false),is_shm_enabled(false),byte_order(false) {\n#ifdef __FreeBSD__\n        XInitThreads();\n#endif\n        wins = new CImgDisplay*[1024];\n        pthread_mutex_init(&wait_event_mutex,0);\n        pthread_cond_init(&wait_event,0);\n#ifdef cimg_use_xrandr\n        resolutions = 0;\n        curr_rotation = 0;\n        curr_resolution = nb_resolutions = 0;\n#endif\n      }\n\n      ~X11_info() {\n        delete[] wins;\n        /*\n          if (events_thread) {\n          pthread_cancel(*events_thread);\n          delete events_thread;\n          }\n          if (display) { } // XCloseDisplay(display); }\n          pthread_cond_destroy(&wait_event);\n          pthread_mutex_unlock(&wait_event_mutex);\n          pthread_mutex_destroy(&wait_event_mutex);\n        */\n      }\n    };\n#if defined(cimg_module)\n    X11_info& X11_attr();\n#elif defined(cimg_main)\n    X11_info& X11_attr() { static X11_info val; return val; }\n#else\n    inline X11_info& X11_attr() { static X11_info val; return val; }\n#endif\n#define cimg_lock_display() cimg::mutex(15)\n#define cimg_unlock_display() cimg::mutex(15,0)\n\n#elif cimg_display==2\n    struct Win32_info {\n      HANDLE wait_event;\n      Win32_info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }\n    };\n#if defined(cimg_module)\n    Win32_info& Win32_attr();\n#elif defined(cimg_main)\n    Win32_info& Win32_attr() { static Win32_info val; return val; }\n#else\n    inline Win32_info& Win32_attr() { static Win32_info val; return val; }\n#endif\n#endif\n\n    struct Mutex_info {\n#if cimg_OS==2\n      HANDLE mutex[32];\n      Mutex_info() { for (unsigned int i = 0; i<32; ++i) mutex[i] = CreateMutex(0,FALSE,0); }\n      void lock(const unsigned int n) { WaitForSingleObject(mutex[n],INFINITE); }\n      void unlock(const unsigned int n) { ReleaseMutex(mutex[n]); }\n      int trylock(const unsigned int) { return 0; }\n#elif defined(_PTHREAD_H)\n      pthread_mutex_t mutex[32];\n      Mutex_info() { for (unsigned int i = 0; i<32; ++i) pthread_mutex_init(&mutex[i],0); }\n      void lock(const unsigned int n) { pthread_mutex_lock(&mutex[n]); }\n      void unlock(const unsigned int n) { pthread_mutex_unlock(&mutex[n]); }\n      int trylock(const unsigned int n) { return pthread_mutex_trylock(&mutex[n]); }\n#else\n      Mutex_info() {}\n      void lock(const unsigned int) {}\n      void unlock(const unsigned int) {}\n      int trylock(const unsigned int) { return 0; }\n#endif\n    };\n#if defined(cimg_module)\n    Mutex_info& Mutex_attr();\n#elif defined(cimg_main)\n    Mutex_info& Mutex_attr() { static Mutex_info val; return val; }\n#else\n    inline Mutex_info& Mutex_attr() { static Mutex_info val; return val; }\n#endif\n\n#if defined(cimg_use_magick)\n    static struct Magick_info {\n      Magick_info() {\n        Magick::InitializeMagick(\"\");\n      }\n    } _Magick_info;\n#endif\n\n#if cimg_display==1\n    // Define keycodes for X11-based graphical systems.\n    const unsigned int keyESC        = XK_Escape;\n    const unsigned int keyF1         = XK_F1;\n    const unsigned int keyF2         = XK_F2;\n    const unsigned int keyF3         = XK_F3;\n    const unsigned int keyF4         = XK_F4;\n    const unsigned int keyF5         = XK_F5;\n    const unsigned int keyF6         = XK_F6;\n    const unsigned int keyF7         = XK_F7;\n    const unsigned int keyF8         = XK_F8;\n    const unsigned int keyF9         = XK_F9;\n    const unsigned int keyF10        = XK_F10;\n    const unsigned int keyF11        = XK_F11;\n    const unsigned int keyF12        = XK_F12;\n    const unsigned int keyPAUSE      = XK_Pause;\n    const unsigned int key1          = XK_1;\n    const unsigned int key2          = XK_2;\n    const unsigned int key3          = XK_3;\n    const unsigned int key4          = XK_4;\n    const unsigned int key5          = XK_5;\n    const unsigned int key6          = XK_6;\n    const unsigned int key7          = XK_7;\n    const unsigned int key8          = XK_8;\n    const unsigned int key9          = XK_9;\n    const unsigned int key0          = XK_0;\n    const unsigned int keyBACKSPACE  = XK_BackSpace;\n    const unsigned int keyINSERT     = XK_Insert;\n    const unsigned int keyHOME       = XK_Home;\n    const unsigned int keyPAGEUP     = XK_Page_Up;\n    const unsigned int keyTAB        = XK_Tab;\n    const unsigned int keyQ          = XK_q;\n    const unsigned int keyW          = XK_w;\n    const unsigned int keyE          = XK_e;\n    const unsigned int keyR          = XK_r;\n    const unsigned int keyT          = XK_t;\n    const unsigned int keyY          = XK_y;\n    const unsigned int keyU          = XK_u;\n    const unsigned int keyI          = XK_i;\n    const unsigned int keyO          = XK_o;\n    const unsigned int keyP          = XK_p;\n    const unsigned int keyDELETE     = XK_Delete;\n    const unsigned int keyEND        = XK_End;\n    const unsigned int keyPAGEDOWN   = XK_Page_Down;\n    const unsigned int keyCAPSLOCK   = XK_Caps_Lock;\n    const unsigned int keyA          = XK_a;\n    const unsigned int keyS          = XK_s;\n    const unsigned int keyD          = XK_d;\n    const unsigned int keyF          = XK_f;\n    const unsigned int keyG          = XK_g;\n    const unsigned int keyH          = XK_h;\n    const unsigned int keyJ          = XK_j;\n    const unsigned int keyK          = XK_k;\n    const unsigned int keyL          = XK_l;\n    const unsigned int keyENTER      = XK_Return;\n    const unsigned int keySHIFTLEFT  = XK_Shift_L;\n    const unsigned int keyZ          = XK_z;\n    const unsigned int keyX          = XK_x;\n    const unsigned int keyC          = XK_c;\n    const unsigned int keyV          = XK_v;\n    const unsigned int keyB          = XK_b;\n    const unsigned int keyN          = XK_n;\n    const unsigned int keyM          = XK_m;\n    const unsigned int keySHIFTRIGHT = XK_Shift_R;\n    const unsigned int keyARROWUP    = XK_Up;\n    const unsigned int keyCTRLLEFT   = XK_Control_L;\n    const unsigned int keyAPPLEFT    = XK_Super_L;\n    const unsigned int keyALT        = XK_Alt_L;\n    const unsigned int keySPACE      = XK_space;\n    const unsigned int keyALTGR      = XK_Alt_R;\n    const unsigned int keyAPPRIGHT   = XK_Super_R;\n    const unsigned int keyMENU       = XK_Menu;\n    const unsigned int keyCTRLRIGHT  = XK_Control_R;\n    const unsigned int keyARROWLEFT  = XK_Left;\n    const unsigned int keyARROWDOWN  = XK_Down;\n    const unsigned int keyARROWRIGHT = XK_Right;\n    const unsigned int keyPAD0       = XK_KP_0;\n    const unsigned int keyPAD1       = XK_KP_1;\n    const unsigned int keyPAD2       = XK_KP_2;\n    const unsigned int keyPAD3       = XK_KP_3;\n    const unsigned int keyPAD4       = XK_KP_4;\n    const unsigned int keyPAD5       = XK_KP_5;\n    const unsigned int keyPAD6       = XK_KP_6;\n    const unsigned int keyPAD7       = XK_KP_7;\n    const unsigned int keyPAD8       = XK_KP_8;\n    const unsigned int keyPAD9       = XK_KP_9;\n    const unsigned int keyPADADD     = XK_KP_Add;\n    const unsigned int keyPADSUB     = XK_KP_Subtract;\n    const unsigned int keyPADMUL     = XK_KP_Multiply;\n    const unsigned int keyPADDIV     = XK_KP_Divide;\n\n#elif cimg_display==2\n    // Define keycodes for Windows.\n    const unsigned int keyESC        = VK_ESCAPE;\n    const unsigned int keyF1         = VK_F1;\n    const unsigned int keyF2         = VK_F2;\n    const unsigned int keyF3         = VK_F3;\n    const unsigned int keyF4         = VK_F4;\n    const unsigned int keyF5         = VK_F5;\n    const unsigned int keyF6         = VK_F6;\n    const unsigned int keyF7         = VK_F7;\n    const unsigned int keyF8         = VK_F8;\n    const unsigned int keyF9         = VK_F9;\n    const unsigned int keyF10        = VK_F10;\n    const unsigned int keyF11        = VK_F11;\n    const unsigned int keyF12        = VK_F12;\n    const unsigned int keyPAUSE      = VK_PAUSE;\n    const unsigned int key1          = '1';\n    const unsigned int key2          = '2';\n    const unsigned int key3          = '3';\n    const unsigned int key4          = '4';\n    const unsigned int key5          = '5';\n    const unsigned int key6          = '6';\n    const unsigned int key7          = '7';\n    const unsigned int key8          = '8';\n    const unsigned int key9          = '9';\n    const unsigned int key0          = '0';\n    const unsigned int keyBACKSPACE  = VK_BACK;\n    const unsigned int keyINSERT     = VK_INSERT;\n    const unsigned int keyHOME       = VK_HOME;\n    const unsigned int keyPAGEUP     = VK_PRIOR;\n    const unsigned int keyTAB        = VK_TAB;\n    const unsigned int keyQ          = 'Q';\n    const unsigned int keyW          = 'W';\n    const unsigned int keyE          = 'E';\n    const unsigned int keyR          = 'R';\n    const unsigned int keyT          = 'T';\n    const unsigned int keyY          = 'Y';\n    const unsigned int keyU          = 'U';\n    const unsigned int keyI          = 'I';\n    const unsigned int keyO          = 'O';\n    const unsigned int keyP          = 'P';\n    const unsigned int keyDELETE     = VK_DELETE;\n    const unsigned int keyEND        = VK_END;\n    const unsigned int keyPAGEDOWN   = VK_NEXT;\n    const unsigned int keyCAPSLOCK   = VK_CAPITAL;\n    const unsigned int keyA          = 'A';\n    const unsigned int keyS          = 'S';\n    const unsigned int keyD          = 'D';\n    const unsigned int keyF          = 'F';\n    const unsigned int keyG          = 'G';\n    const unsigned int keyH          = 'H';\n    const unsigned int keyJ          = 'J';\n    const unsigned int keyK          = 'K';\n    const unsigned int keyL          = 'L';\n    const unsigned int keyENTER      = VK_RETURN;\n    const unsigned int keySHIFTLEFT  = VK_SHIFT;\n    const unsigned int keyZ          = 'Z';\n    const unsigned int keyX          = 'X';\n    const unsigned int keyC          = 'C';\n    const unsigned int keyV          = 'V';\n    const unsigned int keyB          = 'B';\n    const unsigned int keyN          = 'N';\n    const unsigned int keyM          = 'M';\n    const unsigned int keySHIFTRIGHT = VK_SHIFT;\n    const unsigned int keyARROWUP    = VK_UP;\n    const unsigned int keyCTRLLEFT   = VK_CONTROL;\n    const unsigned int keyAPPLEFT    = VK_LWIN;\n    const unsigned int keyALT        = VK_LMENU;\n    const unsigned int keySPACE      = VK_SPACE;\n    const unsigned int keyALTGR      = VK_CONTROL;\n    const unsigned int keyAPPRIGHT   = VK_RWIN;\n    const unsigned int keyMENU       = VK_APPS;\n    const unsigned int keyCTRLRIGHT  = VK_CONTROL;\n    const unsigned int keyARROWLEFT  = VK_LEFT;\n    const unsigned int keyARROWDOWN  = VK_DOWN;\n    const unsigned int keyARROWRIGHT = VK_RIGHT;\n    const unsigned int keyPAD0       = 0x60;\n    const unsigned int keyPAD1       = 0x61;\n    const unsigned int keyPAD2       = 0x62;\n    const unsigned int keyPAD3       = 0x63;\n    const unsigned int keyPAD4       = 0x64;\n    const unsigned int keyPAD5       = 0x65;\n    const unsigned int keyPAD6       = 0x66;\n    const unsigned int keyPAD7       = 0x67;\n    const unsigned int keyPAD8       = 0x68;\n    const unsigned int keyPAD9       = 0x69;\n    const unsigned int keyPADADD     = VK_ADD;\n    const unsigned int keyPADSUB     = VK_SUBTRACT;\n    const unsigned int keyPADMUL     = VK_MULTIPLY;\n    const unsigned int keyPADDIV     = VK_DIVIDE;\n\n#else\n    // Define random keycodes when no display is available.\n    // (should rarely be used then!).\n    const unsigned int keyESC        = 1U;   //!< Keycode for the \\c ESC key (architecture-dependent).\n    const unsigned int keyF1         = 2U;   //!< Keycode for the \\c F1 key (architecture-dependent).\n    const unsigned int keyF2         = 3U;   //!< Keycode for the \\c F2 key (architecture-dependent).\n    const unsigned int keyF3         = 4U;   //!< Keycode for the \\c F3 key (architecture-dependent).\n    const unsigned int keyF4         = 5U;   //!< Keycode for the \\c F4 key (architecture-dependent).\n    const unsigned int keyF5         = 6U;   //!< Keycode for the \\c F5 key (architecture-dependent).\n    const unsigned int keyF6         = 7U;   //!< Keycode for the \\c F6 key (architecture-dependent).\n    const unsigned int keyF7         = 8U;   //!< Keycode for the \\c F7 key (architecture-dependent).\n    const unsigned int keyF8         = 9U;   //!< Keycode for the \\c F8 key (architecture-dependent).\n    const unsigned int keyF9         = 10U;  //!< Keycode for the \\c F9 key (architecture-dependent).\n    const unsigned int keyF10        = 11U;  //!< Keycode for the \\c F10 key (architecture-dependent).\n    const unsigned int keyF11        = 12U;  //!< Keycode for the \\c F11 key (architecture-dependent).\n    const unsigned int keyF12        = 13U;  //!< Keycode for the \\c F12 key (architecture-dependent).\n    const unsigned int keyPAUSE      = 14U;  //!< Keycode for the \\c PAUSE key (architecture-dependent).\n    const unsigned int key1          = 15U;  //!< Keycode for the \\c 1 key (architecture-dependent).\n    const unsigned int key2          = 16U;  //!< Keycode for the \\c 2 key (architecture-dependent).\n    const unsigned int key3          = 17U;  //!< Keycode for the \\c 3 key (architecture-dependent).\n    const unsigned int key4          = 18U;  //!< Keycode for the \\c 4 key (architecture-dependent).\n    const unsigned int key5          = 19U;  //!< Keycode for the \\c 5 key (architecture-dependent).\n    const unsigned int key6          = 20U;  //!< Keycode for the \\c 6 key (architecture-dependent).\n    const unsigned int key7          = 21U;  //!< Keycode for the \\c 7 key (architecture-dependent).\n    const unsigned int key8          = 22U;  //!< Keycode for the \\c 8 key (architecture-dependent).\n    const unsigned int key9          = 23U;  //!< Keycode for the \\c 9 key (architecture-dependent).\n    const unsigned int key0          = 24U;  //!< Keycode for the \\c 0 key (architecture-dependent).\n    const unsigned int keyBACKSPACE  = 25U;  //!< Keycode for the \\c BACKSPACE key (architecture-dependent).\n    const unsigned int keyINSERT     = 26U;  //!< Keycode for the \\c INSERT key (architecture-dependent).\n    const unsigned int keyHOME       = 27U;  //!< Keycode for the \\c HOME key (architecture-dependent).\n    const unsigned int keyPAGEUP     = 28U;  //!< Keycode for the \\c PAGEUP key (architecture-dependent).\n    const unsigned int keyTAB        = 29U;  //!< Keycode for the \\c TAB key (architecture-dependent).\n    const unsigned int keyQ          = 30U;  //!< Keycode for the \\c Q key (architecture-dependent).\n    const unsigned int keyW          = 31U;  //!< Keycode for the \\c W key (architecture-dependent).\n    const unsigned int keyE          = 32U;  //!< Keycode for the \\c E key (architecture-dependent).\n    const unsigned int keyR          = 33U;  //!< Keycode for the \\c R key (architecture-dependent).\n    const unsigned int keyT          = 34U;  //!< Keycode for the \\c T key (architecture-dependent).\n    const unsigned int keyY          = 35U;  //!< Keycode for the \\c Y key (architecture-dependent).\n    const unsigned int keyU          = 36U;  //!< Keycode for the \\c U key (architecture-dependent).\n    const unsigned int keyI          = 37U;  //!< Keycode for the \\c I key (architecture-dependent).\n    const unsigned int keyO          = 38U;  //!< Keycode for the \\c O key (architecture-dependent).\n    const unsigned int keyP          = 39U;  //!< Keycode for the \\c P key (architecture-dependent).\n    const unsigned int keyDELETE     = 40U;  //!< Keycode for the \\c DELETE key (architecture-dependent).\n    const unsigned int keyEND        = 41U;  //!< Keycode for the \\c END key (architecture-dependent).\n    const unsigned int keyPAGEDOWN   = 42U;  //!< Keycode for the \\c PAGEDOWN key (architecture-dependent).\n    const unsigned int keyCAPSLOCK   = 43U;  //!< Keycode for the \\c CAPSLOCK key (architecture-dependent).\n    const unsigned int keyA          = 44U;  //!< Keycode for the \\c A key (architecture-dependent).\n    const unsigned int keyS          = 45U;  //!< Keycode for the \\c S key (architecture-dependent).\n    const unsigned int keyD          = 46U;  //!< Keycode for the \\c D key (architecture-dependent).\n    const unsigned int keyF          = 47U;  //!< Keycode for the \\c F key (architecture-dependent).\n    const unsigned int keyG          = 48U;  //!< Keycode for the \\c G key (architecture-dependent).\n    const unsigned int keyH          = 49U;  //!< Keycode for the \\c H key (architecture-dependent).\n    const unsigned int keyJ          = 50U;  //!< Keycode for the \\c J key (architecture-dependent).\n    const unsigned int keyK          = 51U;  //!< Keycode for the \\c K key (architecture-dependent).\n    const unsigned int keyL          = 52U;  //!< Keycode for the \\c L key (architecture-dependent).\n    const unsigned int keyENTER      = 53U;  //!< Keycode for the \\c ENTER key (architecture-dependent).\n    const unsigned int keySHIFTLEFT  = 54U;  //!< Keycode for the \\c SHIFTLEFT key (architecture-dependent).\n    const unsigned int keyZ          = 55U;  //!< Keycode for the \\c Z key (architecture-dependent).\n    const unsigned int keyX          = 56U;  //!< Keycode for the \\c X key (architecture-dependent).\n    const unsigned int keyC          = 57U;  //!< Keycode for the \\c C key (architecture-dependent).\n    const unsigned int keyV          = 58U;  //!< Keycode for the \\c V key (architecture-dependent).\n    const unsigned int keyB          = 59U;  //!< Keycode for the \\c B key (architecture-dependent).\n    const unsigned int keyN          = 60U;  //!< Keycode for the \\c N key (architecture-dependent).\n    const unsigned int keyM          = 61U;  //!< Keycode for the \\c M key (architecture-dependent).\n    const unsigned int keySHIFTRIGHT = 62U;  //!< Keycode for the \\c SHIFTRIGHT key (architecture-dependent).\n    const unsigned int keyARROWUP    = 63U;  //!< Keycode for the \\c ARROWUP key (architecture-dependent).\n    const unsigned int keyCTRLLEFT   = 64U;  //!< Keycode for the \\c CTRLLEFT key (architecture-dependent).\n    const unsigned int keyAPPLEFT    = 65U;  //!< Keycode for the \\c APPLEFT key (architecture-dependent).\n    const unsigned int keyALT        = 66U;  //!< Keycode for the \\c ALT key (architecture-dependent).\n    const unsigned int keySPACE      = 67U;  //!< Keycode for the \\c SPACE key (architecture-dependent).\n    const unsigned int keyALTGR      = 68U;  //!< Keycode for the \\c ALTGR key (architecture-dependent).\n    const unsigned int keyAPPRIGHT   = 69U;  //!< Keycode for the \\c APPRIGHT key (architecture-dependent).\n    const unsigned int keyMENU       = 70U;  //!< Keycode for the \\c MENU key (architecture-dependent).\n    const unsigned int keyCTRLRIGHT  = 71U;  //!< Keycode for the \\c CTRLRIGHT key (architecture-dependent).\n    const unsigned int keyARROWLEFT  = 72U;  //!< Keycode for the \\c ARROWLEFT key (architecture-dependent).\n    const unsigned int keyARROWDOWN  = 73U;  //!< Keycode for the \\c ARROWDOWN key (architecture-dependent).\n    const unsigned int keyARROWRIGHT = 74U;  //!< Keycode for the \\c ARROWRIGHT key (architecture-dependent).\n    const unsigned int keyPAD0       = 75U;  //!< Keycode for the \\c PAD0 key (architecture-dependent).\n    const unsigned int keyPAD1       = 76U;  //!< Keycode for the \\c PAD1 key (architecture-dependent).\n    const unsigned int keyPAD2       = 77U;  //!< Keycode for the \\c PAD2 key (architecture-dependent).\n    const unsigned int keyPAD3       = 78U;  //!< Keycode for the \\c PAD3 key (architecture-dependent).\n    const unsigned int keyPAD4       = 79U;  //!< Keycode for the \\c PAD4 key (architecture-dependent).\n    const unsigned int keyPAD5       = 80U;  //!< Keycode for the \\c PAD5 key (architecture-dependent).\n    const unsigned int keyPAD6       = 81U;  //!< Keycode for the \\c PAD6 key (architecture-dependent).\n    const unsigned int keyPAD7       = 82U;  //!< Keycode for the \\c PAD7 key (architecture-dependent).\n    const unsigned int keyPAD8       = 83U;  //!< Keycode for the \\c PAD8 key (architecture-dependent).\n    const unsigned int keyPAD9       = 84U;  //!< Keycode for the \\c PAD9 key (architecture-dependent).\n    const unsigned int keyPADADD     = 85U;  //!< Keycode for the \\c PADADD key (architecture-dependent).\n    const unsigned int keyPADSUB     = 86U;  //!< Keycode for the \\c PADSUB key (architecture-dependent).\n    const unsigned int keyPADMUL     = 87U;  //!< Keycode for the \\c PADMUL key (architecture-dependent).\n    const unsigned int keyPADDIV     = 88U;  //!< Keycode for the \\c PADDDIV key (architecture-dependent).\n#endif\n\n    const double PI = 3.14159265358979323846;   //!< Value of the mathematical constant PI\n\n    // Define a 12x13 font (small size).\n    static const char *const data_font12x13 =\n\"                          .wjwlwmyuw>wjwkwbwjwkwRxuwmwjwkwmyuwJwjwlx`w      Fw                         mwlwlwuwnwuynwuwmyTwlwkwuwmwuwnwlwkwuwmwuw_wuxl\"\n\"wlwkwuwnwuynwuwTwlwlwtwnwtwnw my     Qw   +wlw   b{ \\\\w  Wx`xTw_w[wbxawSwkw  nynwky<x1w `y    ,w  Xwuw   CxlwiwlwmyuwbwuwUwiwlwbwiwrwqw^wuwmxuwnwiwlwmy\"\n\"uwJwiwlw^wnwEymymymymy1w^wkxnxtxnw<| gybwkwuwjwtwowmxswnxnwkxlxkw:wlymxlymykwn{myo{nymy2ykwqwqwm{myozn{o{mzpwrwpwkwkwswowkwqwqxswnyozlyozmzp}pwrwqwqwq\"\n\"wswswsxsxqwqwp}qwlwiwjybw`w[wcw_wkwkwkwkw mw\\\"wlwiw=wtw`xIw awuwlwm{o{mylwn|pwtwtwoy`w_w_wbwiwkxcwqwpwkznwuwjzpyGzqymyaxlylw_zWxkxaxrwqxrwqyswowkwkwkwk\"\n\"wkwkwk}qyo{o{o{o{owkwkwkwkznxswnymymymymyayuwqwrwpwrwpwrwpwrwqwqwpwkwtwlwkwlwuwnwuynwuwmyTwkwlwuwmwuwnwkwlwuwmwuwkxlwuxmwkwlwuwnwuynwuwTwkwlwuwmwuwlwm\"\n\"wkwtwUwuwuwowswowswowswowsw;wqwtw_ymzp~py>w bwswcwkwuwjwuwozpwtwuwnwtwowkwjwmwuwuwkwIxmxuxowuwmwswowswmxnwjwhwowswowsw0wmwowswuwnwrwowswpwswowkwjwrwqw\"\n\"rwpwkwkwtwnwkxsxqxswowswpwswnwswpwswowrwnwmwrwqwqwqwswswrwswowswjwpwlxjwkxuxLw[wcw_wSwkw mw\\\"wlwiw=wtwmxlwFw cwswnwuwnwkwjwswo{pwrwpwtwtwpwswby`w`yUwlw\"\n\"twpwqwpwswowlw\\\\wrwrxuwHwrwfwuwjwlwlwTyuwVwlwtwawswowswowswcwuwmwuwmwuwmwuwmwuwlwkwuwnwswpwkwkwkwkwkwkwkwkwswoxswowswowswowswowswowswowrwpwswpwrwpwrwpw\"\n\"rwpwrwpwswoznwtw  Ww (wGwtwtwqwqwqwuwuwuwqwswuwqwqw=wqxtw`{nzp~q{ozowrwnxmwtwow bzawkwuwl}rwuwnwtwuwnwtwowkwjwlyjwIwlwswmwiwkwnwuwnwkwhwnwswowswowkwew\"\n\"ewixnwsytwswuwnwrwpwkwrwpwkwkwkwrwpwkwkwuwmwkxsxqwuwtwpwqwqwswowqwqwswowiwmwrwpwswowtwtwpwuwmwuwjwowkwjwlxsxXynzmymznyozlzoznwkwkwtwnwkzuyrzmynzmzowux\"\n\"myozmwswpwrwowtwtwrwrwpwrwp{mwlwiwHyuwpwtwkwmxlynzoxswmwmwswnwswowtxq|owtwtwpym{p{owswnwuwmwlwkwqwqxuwuxqwrwpwtwtwqwqwowlwuwuwkwmwlwtwowuwuwdwjznwl{nw\"\n\"uwnwkx_wtxtwswtwlwtwWwuytwgyjwmwjwawswoyuwVwlwtwnwtwmwtwnwtwmwuwmwlwuwmwuwmwuwmwuwmwuwmwuwmxuwowkwkwkwkwkwkwkwkwkwrwpwuwtwpwqwqwqwqwqwqwqwqwqwowtwpwsw\"\n\"uwqwrwpwrwpwrwpwrwowuwnwswowuwlymymymymymymyuyqymymymymynwkwkwkwjynzmymymymymykwmzowswowswowswowswpwrwozowrwW}q}qwtwtwqwtwtwqwtwtwA}rwuw_{p~r~r}pwtwow\"\n\"rwnxmwtwow aw_w]wtwpwuwmxuwmybwjwlyjwIwlwswmwiwnynwtwnznzkwmynwswTyp}pylwmwtwtwtwswuwn{owkwrwp{o{owk|pwkwkxlwkwuwuwuwqwuwtwpwqwqwswowqwqwswoykwmwrwpws\"\n\"wowuwuwuwowkwjwnwkwjwDwowswowkwswowswowkwswowswowkwkwuwmwkwswswswswowswowswowswoxlwswowkwswpwrwowtwtwqwtwowrwlwoxkwhxVxuxpwtypwuwjwnwtwnwkwswowtxnxmws\"\n\"wowqwqwtwuxqwtwnwtwtwqwswowswmwm{nwuwlxnwkwqwqwtwtwqwrwpwtwtwqwuyuwpwiwhwnwmwrwnwbwkwuwlwlwswoxuxowlwtw`wuwrwszmwtwo}dwuwtwuw[}qymx`wswoyuwow_ylxlwtwo\"\n\"yuwoyuwoyuwmwlwuwmwuwmwuwmwuwmwuwmwuwmwt{swk{o{o{o{owkwkwkwlztwpwuwtwpwqwqwqwqwqwqwqwqwqwnxowtwtwqwrwpwrwpwrwpwrwnwmwswowuwiwkwkwkwkwkwkwswswkwswowswo\"\n\"wswowswowkwkwkwkwswowswowswowswowswowswowswcwtxowswowswowswowswpwrwowswpwrwWwtwtwqwqwqwuwuwuwqwuwswqwqw>wowuw`}q~q|q}qwrwpwrwowtwnwtwo~ izaw]wtwoykwux\"\n\"qwtwswfwjwmwuwuwn}eyaxlwswmwjwjwpwswjwowswmwmwswnzWy]ypwlwtwtwuwswswowrwpwkwrwpwkwkwsyqwrwpwkwkwuwmwkwuwuwuwqwtwuwpwqwqznwqwqzkynwmwrwowuwnwuwuwuwowkw\"\n\"jwnwkxkwGzowswowkwswo{owkwswowswowkwkxlwkwswswswswowswowswowswowjxmwkwswowtwnwuwuwuwpxmwtwlwlwlwiwlytwewtwtwqwswowtxoznwswnxmwswnwuwmwuwnwswowtwtwqwtw\"\n\"twqwtwnwtwtwqwswowswmwmwswowswmwmwkwqwqwtwtwqwrwowuwuwpwuyuwq~own~own~owbwkwuwmznwswmwbwswawuwrwgwtwhwdwuytwXwJwswnxuw=wtwmwswowtxowswqxmwswowswowswow\"\n\"swowswowswnwtwowkwkwkwkwkwkwkwkwkwrwpwtwuwpwqwqwqwqwqwqwqwqwqwnxowtwtwqwrwpwrwpwrwpwrwnwmwswowtwmznznznznznzn~swk{o{o{o{owkwkwkwkwswowswowswowswowswow\"\n\"swowswo}qwuwuwowswowswowswowswowtwnwswowtwUwuwuwowswowswowswowsw@}qx`}q~pzo{pwrwpwrwowtwnwtwow aw_w_}owuwmwuwtwrwswuwewjwkwiwJwkwswmwkwiwp|kwowswmwmws\"\n\"wkwWym}mypwlwszr{owrwpwkwrwpwkwkwqwqwrwpwkwkwtwnwkwtwtwqwtwuwpwqwqwkwqwqwtwiwnwmwrwowuwnwuwuwuwpwuwlwkwmwjwkwHwswowswowkwswowkwkwswowswowkwkwuwmwkwsws\"\n\"wswswowswowswowswowhwnwkwswowtwnwuwuwuwpxmwtwmwkwlwiwmwtydwtwtwqwswowswowtwnwswowkwswnwuwnwtwnwswowtwtwqwtwtwqwtwnwtwtwqwswowswmwmwswowswnwlwkwqwqxuwu\"\n\"xqwrwnyowqwpwiwhwpwuwuwowrwpwuwuwdwkwuwlwlwswo{owkxuwawtxtwszmwtwiwdwuwtwuwXwJwswmwuwKzmwtwlwtxowrwpwtxrxl{o{o{o{o{o{o{owkwkwkwkwkwkwkwkwkwrwpwtwuwpwq\"\n\"wqwqwqwqwqwqwqwqwowtwpwuwswqwrwpwrwpwrwpwrwnwmznwswowswowswowswowswowswowswowswowkwkwkwkwkwkwkwkwkwswowswowswowswowswowswowswcwuwuwowswowswowswowswowt\"\n\"wnwswowtwTymymymymy=wmw^wuwuwmxlxmyowrwowtwnwtwmxmw bwswIwuwmwuwmwuwtwrxswdwjw]wJwkxuxmwlwlwswlwjwowswmwmwswlwSycyawlwswowrwowswpwswowkwjwrwqwrwpwkwkw\"\n\"swowkwqwqwsxowswpwjwswpwswowrwnwmxtxnwlwswpwswmwlwlwjwkwHwswowswowkwswowswowkwswowswowkwkwtwnwkwswswswswowswowswowswowkwswowkwswnxlwswpwtwmxmwjwlwiwTx\"\n\"uxpwtxowswowtwnwswowkwswnynwtwnwswowtwtwqxuwuxqwtwnwtwtwqwswowswmwlwuwnwswowkwjwswo{pwrwmwmwswnwjwiwnymwtwnycwkwuwlwl{mwmwiw_wrwdwtwVwrw*wswmwuw?wtwlw\"\n\"tzqwrwpwtzswkwswowswowswowswowswowswowswnwswpwkwkwkwkwkwkwkwkwswowsxowswowswowswowswowswowrwpwswpxtxpxtxpxtxpxtxnwmwkwswowswowswowswowswowswowswowtxow\"\n\"kwswowswowswowswowkwkwkwkwswowswowswowswowswowswowswlwnxtwowswowswowswowswnxmwswnx >wlw\\\\wkx`wnwrwoznwtwmxl| gybw^wtwozmwsxpzuxfxlx]wnw_wlxjyn{o{nykwnz\"\n\"mymwkynymwkwewewjwjwrwswqwp{myozn{owizpwrwpwkwkwrwp{owqwqwsxnyowiyowrwozmwlzmwlwswqxsxnwm}qwjxlwGzozmymznynwjzowswowkwkwswowkwswswswswnynzmzowjymxlznx\"\n\"lwswqwrwnwm{mwlwiwHxuxpzmxlymynwswmwnwrwozmxuxo{pwtxn{pzmykwmyo}p{owkyuynwnwrwmwly`w_w_wbwjzo{pwqwnwmwhw_z>zY}M|nwuw2wqwqwryrwqwqyowqwqwqwqwqwqwqwqwqw\"\n\"qwqwqwr{qyo{o{o{o{owkwkwkwkznwsxnymymymymycwuynznznznzmwmwkwuynznznznznznznyuzrymymymymynwkwkwkwjynwswnymymymymybzmznznznznwlzmw     hwHwlwSwTw <w8z ]\"\n\"x tx Zxjwmx RwWw/wgw pw_ynwky=wCwmwaw\\\\w_wnw  1wIwlz 'wiwuwaw  mw    Pw   swlwjw     hw        f| pyWx/wgw rxSw/wCwmwaw\\\\w_wnw  1w  AwRx  nw    Pw   txk\"\n\"wlxm\";\n\n    // Define a 20x23 font (normal size).\n    static const char *const data_font20x23 =\n\"                                                9q\\\\q^r_rnp`qnq`plp7q\\\\q^q_qmqbq\\\\q^q_qmqHqmp_q\\\\q^r_rnp`qnq7q\\\\q^q_qmq_q \\\"r                               \"\n\"                        Mq^q^qnq`pnr`qnq`plp6q^q^pmp`qmqaq^q^pmp`qmqIpmq]q^q^qnq`pnr`qnq6q^q^pmp`qmq`q \\\"plp         'q     5qmq               Vq      \"\n\"               Xq    [plp      3qYq_p^rnpLplp8qYq_qNqYq_q4rmpaqYq_q_rmp%qYq^pGq  Irc|!pKp]raqjq`p   HtNq_qmq\\\\plqbp_shpdscq[q^q[p [q]s_r`uau]rbv`tcxbua\"\n\"t LsZucrav_udwcxdw`udqiqeq]q]qjreq]sksgrjqbtcv_tcvaud{eqiqgqfqgqjsjqlrjrhrirfzfs`q[sZqMqJqCqNsLq]q]q]q]q   .scq]s \\\\sKt%r  [s^raxdxat_qazgqlqlqctJqIqIq\"\n\"LqHsOqiqOtaqmq\\\\uft nufu`sLs`t\\\\qKv<r\\\\rLrepirepitgpeq]r^r^r^r^r^r^{gudxdxdxdxdq]q]q]q]wcrjqbt`t`t`t`tLtlpgqiqeqiqeqiqeqiqgrireq[s_q[q_pnp_pnr`qnq`plp7q[\"\n\"q_s`qmqcq[q_s`qmq]pkpbpmr`q[q_s`pmraqmq8q[q^pnp_qnq^qaq\\\\qnq !pnqd{!pJp^tdunucr _y  dvOq_qmq\\\\plpap_pmpipdudq[p\\\\p_plplp _q^ubtawcw^rbvavdxcwcw Ou]yerawb\"\n\"xeyexdwbxeqiqeq]q]qkrdq]sksgrjqdxewbxewcwe{eqiqfqhqfqjsjqkqjqfqiqezfs`q[s[sMpJqCqOtLq]q]q]q]q  q 1tcq]t ^vaq_w&r  \\\\u_raxdxcxcuczgqlqlqexMsJqJsMq[p^uPq\"\n\"iqdq]uaqmq]qkqcq!qkqguaqmqNpkp\\\\p]pKtmp:p]plpKpfpfpfpcpipdq]r^r^r^r^r^r^{ixexdxdxdxdq]q]q]q]yerjqdxdxdxdxdxPwnpfqiqeqiqeqiqeqiqfqiqdq\\\\u_p[p^pnpKqnq_r5p\"\n\"[p^pmp`qmqbp[p^pmp`qmq]tKp[p^pmpLqmq7p[p]pnp_qnq^p`q\\\\qnq5uauauauaucq`qhq4p]pKr_ueunucr `q  \\\\rkpOq_qmq\\\\plpctbqmqkqerlpdq\\\\q\\\\q_qnpnq\\\\q%q^qkqcqnqapjrdpjr`\"\n\"sbq]rkp^qcrkrerkq Oplr`sirgtbqkrdripeqjsfq]q]ripeqiqeq]q]qlrcq]sksgskqerjrfqkrdrjrfqkrerjp`q`qiqfqhqeqkskqiqlqdqkq\\\\qeq]qZq\\\\qmqNqKqCqOqIq5q]q  q 1q`qZq\"\n\" _rlqbtaqjp$q  ^qkqatbr^q]rjrewdqhqgqlqlqfrjrOuKqKu8p_rlpOqkqcq]qFpgpcp\\\"pgpTpkp\\\\q^p\\\\p^qLump:p^pjpLpgpepgpbpjpPt`t`t`t`t`qnq_qnqcripeq]q]q]q]q]q]q]q]qj\"\n\"sfskqerjrfrjrfrjrfrjrfrjrRrjrfqiqeqiqeqiqeqiqeqkqcvbrlq`q]q_plp Iq]q_qmqNq]q_qmqKtIq]q_qmq ^q]q^plpKq`q mqkqcqkqcqkqcqkqcqkqdq`qhq5q^qLt`ueunudtasbqip\"\n\"`q`pipcq  [qIq_qmq`{gvcqmqkpdq_q\\\\q\\\\q]rZq%q_rkraqZq]qaqnqbq]qXqcqiqeqiq1pSpXq`qfrhqnqbqjqdq]qhqfq]q]q]qiqeq]q]qmrbq]qnqmqnqgskqeqhqfqjqdqhqfqjqeqYq`qiq\"\n\"frjreqkskqirnrdrmr]qdq]qZq]qkq)qCqOqIq5q]q  q 1q`qZq _qkq_qaq mq  ^qkqaqnqar_q]qhqfrnqnreqhqgqlqlqfqhqPwLqLw9p_q_phqdqkqcq]qGplslpiu#pmtlpUpkp\\\\q_q_r8u\"\n\"mp:p^pjpLpgpepgperipcq^qnq`qnq`qnq`qnq`qnq`qnq`qmqcq]q]q]q]q]q]q]q]q]qhqfskqeqhqfqhqfqhqfqhqfqhqdphpfqirfqiqeqiqeqiqeqiqermrcwcqkq    [q 3qZp Oq nqmqm\"\n\"qeqiqeqiqeqiqeqiqeq_piq4q^pLvatd|evdvcqipasaqkqdq  [qHq_qmq`{hrnpmpcqmqlpcq_q\\\\pZp]rZq%q_qiqaqZq]qapmqbq^qWqcqiqeqiqdq]qUsSs[qaqdqhqnqbqjqeq\\\\qgqgq]q^q\\\\\"\n\"qiqeq]q]qnraq]qnqmqnqgqnqlqfqfqgqjqeqfqgqjqeqYq`qiqeqjqdqlqmqlqhqnqbqmq]rdq]qZq^pgp=taqns`s`snqatdv_snqcqnsbq]q]qkqcq]qnsmshqns`saqnsasnqcqnr`tbvaqjqe\"\n\"qiqdqkqkqjrkreqiqdw`q`qZq#tnreqkq^qatauaqnsdqiq`raqjqdqiqdpmrcxdqmqmqatbxfyeqiqbqnq`r`q^qfqhrmqmrfqhqgqlqlqgqfqep[pnqnp[p`q`pipbpnqnpNq]taq^qnqnqbqmqb\"\n\"q\\\\qIqmpkpmqkqkp$qmpkpmqVqmq\\\\q`q[pLqjqeump:p^pjpLphpdphpapkpbq^qnq`qnq`qnq`qnq`qnq`qnq`qmqdq\\\\q]q]q]q]q]q]q]q]qgqgqnqlqfqfqhqfqhqfqhqfqhqfqfrjrhqiqnqgqi\"\n\"qeqiqeqiqeqiqdqmqbqkrdqmsbt`t`t`t`t`t`tlsfs_t`t`t`tbq]q]q]q[tbqns`s_s_s_s_s\\\\q`smpdqjqdqjqdqjqdqjqeqiqdqnscqiq;qlqlqgqgqgqnqmqnqgqjqnqgqgqfq_qjq<{fpjpL\"\n\"vatd|fxeqkqdqipasaqkqdp  \\\\yNqGplqeqmp`qmqmqcrLqZq`qnpnq\\\\q%q_qiqaqZq^rbqmqbubqms^qaqkqdqiqdq]qXuf{fu_q`qlrnqlqjqlqcqkreq\\\\qgqgq]q^q\\\\qiqeq]q]t`q]qnqmqnqg\"\n\"qnqlqfqfqgqkreqfqgqkres[q`qiqeqjqdqlqmqlqhs`s]rcq]qZq#vbwcvbwcwev`wcwcq]q]qlqbq]vnthwcwcwcwcubwcvaqjqdqkqcqkqkqiqkqdqiqdw`q`qZq7smsfxdqlr^qavdvawdqkq_\"\n\"raqjqdpgpeqntdxdqmqmqcwdyfyeqiqcqlq`raq^qfqhqlqlqfqhqgqlqlqgqfqfrZqZraqarkraqLq^vbq^wbqmqbq]tKpmpfpkpjp_plp9plpkplpUs[qaqZpLqjqeump:p^pjpaplp_piqdpiqa\"\n\"plqbq_qlqbqlqbqlqbqlqbqlqbqlqbrmqdq\\\\q]q]q]q]q]q]q]q]qgqgqnqlqfqfqhqfqhqfqhqfqhqfqerlrgqjqmqgqiqeqiqeqiqeqiqcsaqjqdqnq`vbvbvbvbvbvbvnuivbwcwcwcwcq]q]q]\"\n\"q]wcwcwcwcwcwcwOwcqjqdqjqdqjqdqjqeqiqdwdqiq;pkqkpgpepgpmumpgpjrmpgpepfq_qkq;{hrkpLxdxf|fxepipdqipas`pkpcp  ZqHqGplpdt_pmplpmshsMqZqaplplp]q&q^qiqaq[qa\"\n\"t`plqbvcx_q`ucrkr:uc{cucq`qlvlqjqlqcwdq\\\\qgqgxdvcqjtfyeq]q]s_q]qmsmqgqmqmqfqfqgwdqfqgwcv_q`qiqdqlqbqmqmqmqfr`s]qbq\\\\q[q#pjqcrlrdqkpcrlrcqkrdq^rlrcrlrdq]\"\n\"q]qmqaq]rlrlqirlrdqkqcrlrerlrcr_qjpbq]qjqdqkqcqlslqhqmqbqkq^q_q`qZq_tjpSqmsmpgrlsdqnsaqmqbqkqdq\\\\rlrdqlq_raqjqeqgqgrnqnrdqlqcqmqmqcqkqerkq`qaycqlq_rbq^\"\n\"qfqhqlqlqfqhqgqlqlqgqnvnqgrYqYrbqbrirbqLq_rnpmpdwaqmqcydq^qlqLpmpfpkpkq`plpa{RpltkpB{gpXpLqjqdtmpcqHp]plp_plp`pipjpipipmsfplpjphr_qlqbqlqbqlqbqlqbqlqb\"\n\"qlqbqlxkq\\\\xdxdxdxdq]q]q]q_vjqgqmqmqfqfqhqfqhqfqhqfqhqfqdrnrfqkqlqgqiqeqiqeqiqeqiqcsaqjqdqnq`pjqcpjqcpjqcpjqcpjqcpjqcpjrlrjqkpbqkrdqkrdqkrdqkrdq]q]q]q]\"\n\"qkrdrlrdqkqcqkqcqkqcqkqcqkqOqkqcqjqdqjqdqjqdqjqdqkqcrlrdqkq:pnwnpgpnwnpgplslpgpkrlpgpkqkpfq^qlq6qaqlpMzfzfzfzgqipdqipbqmp`qmqc|  fqHqHqlpcuasmplpmpiul\"\n\"qSqZq]p^{+q^qiqaq\\\\q`ubqlqbpkrdrkrarawcx<tEteq`qlqlqlqjqlqcwdq\\\\qgqgxdvcqjtfyeq]q]t`q]qmsmqgqmqmqfqfqgvcqfqgv_t`q`qiqdqlqbqmqmqmqgs_q]qaq\\\\q[q\\\"vcqjqeq]qj\"\n\"qdqiqdq^qjqcqjqdq]q]qnq`q]qkqkqiqjqeqiqdqjqeqjqcq^s^q]qjqdqkqbqmsmqgqmqbqkq_qas_qYsc{Spkqkphqkrcqntcvcqiqeq\\\\qjqdqmr`tbqjqeqgqgqmqmqdqlqcqmqmqdqiqfqiqa\"\n\"qaycqlq_qaq^qfqhqlqlqfqhqfqmqmqfqnvnqh}cqc}cqc}cqLq_qmpawbqkqasaq^qkqMpmpfpjsnpaplp`{RplpmqkpB{huatKqjqbrmpcqJt^r]plpctlpjqktlpmpkpltlpjqhq^qlqbqlqbql\"\n\"qbqlqbqlqcrlrcqlxkq\\\\xdxdxdxdq]q]q]q_vjqgqmqmqfqfqhqfqhqfqhqfqhqfqcteqlqkqgqiqeqiqeqiqeqiqbq`qkrdqmravbvbvbvbvbvbvjqkq]qiqeqiqeqiqeqiqdq]q]q]q^qiqdqjqe\"\n\"qiqeqiqeqiqeqiqeqiqd{hqkpnqdqjqdqjqdqjqdqjqdqkqcqjqdqkq:pnwnpgpnwnpgplslpgplrkpgpkqkpfq^qlq6qaqmqMzg|fxdxfqipdqipbqmqaqmqcp  \\\\wLqK{dt]qmqmqkrmrnrSqZqK\"\n\"{TtKq^qiqaq]r\\\\rdqkq\\\\qdqiqaqarkrcsmq<tEtfq_qlqlqlqkqjqdqjqeq\\\\qgqgq]q^qgqfqiqeq]q]qnraq]qmsmqgqlqnqfqfqgq^qfqgqkq]raq`qiqdqlqbqnqkqnqgt`q^raq\\\\q[q#wcqjqe\"\n\"q]qjqdydq^qjqcqjqdq]q]s_q]qkqkqiqjqeqiqdqjqeqjqcq]uaq]qjqcqmqaqmpmpmqfs`qmq_ras_qYscpjtRpkqkphqkrcqkreqlrcqiqcr_qjqdqmq_qnqbqjqeqlqlqgqmqmqdqlqcqmqmqd\"\n\"qiqfqiqaqaqiqdqjqaq`q^qfqhqlqlqfqhqfrnqnrfqfqh}cqc}cqc}cqLq_qmp_q^qkq`qMrlqMpmpfpWplpUqRplplqlp=q&qjq`pmp _plp]qkpnpdqhpeqkpnpiq^qjqdqjqdqjqdqjqdqjqdq\"\n\"jqdqkqdq\\\\q]q]q]q]q]q]q]q]qgqgqlqnqfqfqhqfqhqfqhqfqhqfqbrdqmqjqgqiqeqiqeqiqeqiqbq`wcqlrcwcwcwcwcwcwc~kq]yeyeyeydq]q]q]q^qiqdqjqeqiqeqiqeqiqeqiqeqiqd{hq\"\n\"lpmqdqjqdqjqdqjqdqjqcqmqbqjqcqmq9pkqkpgpepgpmumpgpmrjpgpepfq]pmq:{epmpLzg|evbveqipdqipbqmqaqmpbq  [qHqK{cpmq^plqmqkqktRqZqFqOtKq^qiqaq^rZqdy^qdqiqaqaq\"\n\"iq]q:uc{cudq_qlqlqmqjxdqiqfq\\\\qgqgq]q^qgqfqiqeq]q]qmrbq]qlqlqgqlqnqfqfqgq^qfqgqkr]qaq`qiqcqnqaqnqkqnqhrnq`q_r`q\\\\q[q$qjqcqjqeq]qjqdydq^qjqcqjqdq]q]s_q]q\"\n\"kqkqiqjqeqiqdqjqeqjqcqZsbq]qjqcqmqaqnqmqnqfs`qmq`r^r`qZr9pkqkphqkrcqjqeqkqcqiqet_qjqcqnq`rnqbqjqeqlqlqgqmqmqdqlqcqmqmqdqiqfqiqaqaqiqdqjqbr`q]qhqgrmqmr\"\n\"fqhqeweqfqgrYqYrdpnqnpdrirdpnqnpNq_qmp_q]qmqcyPrmqMqmpkpmqkvaplpVqRqmpkpmq=q&qjq`pmp(v_plp\\\\pkpmpdphqepkpmpjq]xdxdxdxdxdxdwdq\\\\q]q]q]q]q]q]q]q]qgqgqlqnq\"\n\"fqfqhqfqhqfqhqfqhqfqcteqnqiqgqiqeqiqeqiqeqiqbq`vbqjqeqjqdqjqdqjqdqjqdqjqdqjqdqjxkq]yeyeyeydq]q]q]q^qiqdqjqeqiqeqiqeqiqeqiqeqiqQqmplqdqjqdqjqdqjqdqjqcq\"\n\"mqbqjqcqmq9qlqlqgqgqgqnqmqnqgqnqjqgqgqfq]qnq:{eqnpLzg|dt`tdqipcpipbpkp`sbq  Zq plq`pmq_pkqmqkqjrQqZqFq'q]rkraq_rYqdy^qdqiqbq`qiq^q6uf{fuaq_qlyjzeqiqeq\"\n\"]qhqfq]q]qhqfqiqeq]q]qlrcq]qlqlqgqkseqhqfq]qhqfqjq]qaq`qiqcqnq`skshrmraq_q_q[q\\\\q$qjqcqjqeq]qjqdq\\\\q^qjqcqjqdq]q]qnq`q]qkqkqiqjqeqiqdqjqeqjqcqXqbq]qjqcq\"\n\"mqaqnqmqnqgqmq`s_q\\\\q`qZq7pmpnqmpgqkrcqjqeqkpbqiqeq\\\\qjqcs_qlqcqjqeqlqlqgqmqmqdqlqcqmqmqdqiqfqiqaq`qkqdrjrdr_q]riqfrnqnreqhqducqhqerZqZrdwdrkrdwOq_qmp_q\"\n\"^w`q`q[sKplslpTplpWqQpmpkqnp<q&qjq`pmp aplp\\\\pkplpephqepkplpjq^zfzfzfzfzfzfxcq]q]q]q]q]q]q]q]q]qhqfqkseqhqfqhqfqhqfqhqfqhqcrnreriqfqiqeqiqeqiqeqiqbq`q]\"\n\"qjqeqjqdqjqdqjqdqjqdqjqdqjqdqjqdq]q]q]q]q\\\\q]q]q]q^qiqdqjqeqiqeqiqeqiqeqiqeqiqQqnpkqdqjqdqjqdqjqdqjqbsaqjqbs7qmqmqeqiqeqiqeqiqeqiqeq]qnp7q]rJrnpnresnpn\"\n\"sct_rcqipcqkqcqkqasaq  [rkp&plpcplpnr`qkqmqkrltRqZqFq'q\\\\qkq`q`r_pjr^qcpjrcqkrbq`rkrdpkr3sSsLrlrnrhqhqeqjreripeqjsfq]q]riqfqiqeq]q]qkrdq]qgqgqkserjrfq]\"\n\"rjrfqjrfpiraq_qkqbt`skshqkqaq`q^q[q\\\\q$qkrcrlrdqkpcrlrcqipdq^rlrcqjqdq]q]qmqaq]qkqkqiqjqdqkqcrlrerlrcq^pjqbq]rlrbs_rkrfqmq`s`r\\\\q`qZq6qlrfrmscrlrepkqbrk\"\n\"qdqkpaqjqcs`rlqcrlrernsnrgrnqnrdqlqcrnqnrdrkqdqkraq`qkqdqhqer^q\\\\rkqdwdqhqbqarjrdpYqYpbubpipbuNq_rnpmpbq^qnqnq`q`qZqIpgpRplp7pgp;q&rlr`pmp bplp[pkufpiq\"\n\"dpkukrlpcqhqfqhqfqhqfqhqfqhqfqhqfqjqcripeq]q]q]q]q]q]q]q]qjsfqkserjrfrjrfrjrfrjrfrjrdrlrfrjreqkqcqkqcqkqcqkqaq`q]qnplqeqkrdqkrdqkrdqkrdqkrdqkrdqksjpjq\"\n\"kpbqipdqipdqipdqipdq]q]q]q]qkqcqjqdqkqcqkqcqkqcqkqcqkq^qbqkqcrlrdrlrdrlrdrlrbsarlrbs6qkqcqkqcqkqcqkqcqkqdq\\\\r7q\\\\qFp\\\\p]r^rcqipcvbqkqas`r  \\\\vOqIqlpcw_pip\"\n\"mpivnrRpZpEqbqIq^q[ubwdxdw]qcwbwaq_wcvbq]qRpSp[q^q^qhqexcxeyexdq\\\\xeqiqeq]q]qjrexdqgqgqjrdxeq\\\\xeqiqfx`q_war_ririqiqbqazfq[q\\\\q$xcwcvbwcxdq]wcqjqdq]q]qlq\"\n\"bq]qkqkqiqjqdwcwcwcq^wbu`wbs_rkrgqkq`q`w`q`qZq$yewdqmq`wdvaqjqbr`qkqcyeyewcqlsdwcxdw`sauczexdq^umteucqhqbq`xLqJsKsMq^vdxdpgpaq`qYqIqkq bqkq?{+yapmp Jp\"\n\"fpfpipcpfpiucqhqfqhqfqhqfqhqfqhqfqhqfqjxixexdxdxdxdq]q]q]q]yeqjrdxdxdxdxdxdrjrgpnwdwcwcwcwaq`q]qnuexdxdxdxdxdxdvnwjvbxdxdxdxdq]q]q]q]wcqjqdwcwcwcwcw^q\"\n\"bwbwcwcwcwaq`w`q4uauauauaucq\\\\r7p[qFp\\\\p\\\\p\\\\pbqipasapip`q^y  ctNqIqmqbu_phsgslrSq\\\\qEqbqIq^qZsawdxcu\\\\qbt^taq]uataq]q q]qgpiqfqfw`udwcxdqZudqiqeq]q]qirfxdq\"\n\"gqgqjrbtcqZtcqirfv_q]s_r_rirjrircqazfq[q\\\\q#tnqcqns`s`snqaucq\\\\snqcqjqdq]q]qkqcq]qkqkqiqjqbsaqnsasnqcq]t_t_snqaq^rkrhrkraq`w`q`qZq#smrevbs^t`s`qjqbq`qiq\"\n\"dqnrmqdrmrcubqkrcubqntat^r`sc|fxdq^umtcqaqhqbq^tJqIqIqLq]tcxLq`qYqHu `u>{+qnrmqapmp Kpepgpiuhpephscqfqhqfqhqfqhqfqhqfqhqfqhqixgudxdxdxdxdq]q]q]q]wcqjr\"\n\"bt`t`t`t`taphpgplt`s_s_s_s_q`q]qmsctnqctnqctnqctnqctnqctnqbsktgs_uauauaucq]q]q]q[saqjqbs_s_s_s_sNpms_snqbsnqbsnqbsnqaq`qns_q !p Zp      jp#q\\\\q6q7q   l\"\n\"q [sjq  Qq -q  OqZq]q  Cq;q HqWq $rIq`qZq _q iqbqKqFqIq`q     hp$q]u   JqYpmpLp   .p        jp    ]p Xr`q[r !p       Tp\\\"p\\\\p6q6q   mq Yx  Qr -r  Ps\\\\q_s\"\n\"  Ipkq:q HqWq $qHq`qZq _q iqbqKqFqIq`q     hp$q]t   IqYpmpLq   /q        kq     Fq_q[q #s       Tp\\\"q^q6p   1p Vu  Rs    YsJsMy &v<s HqWq &sHtcq]t _q i\"\n\"qbqKqFqIq`q     hp$q   2q2q   /q        kq     Hs_q]s \\\"q                (r     Xy %t;r GqWq &rFscq]s ^q iqbqKqFqIq`q         ,q4r   0r        lr     G\"\n\"r^q                               *q                                                                                   kr               i\";\n\n    // Define a 47x53 font (extra-large size).\n    static const char *const data_font47x53 =\n\"                                                                                                                                                      \"\n\"        9])]2_2]T\\\\8^U^3]  E])]2`4^U^>])]2_4^U^ 6^T\\\\5])]1_2]T\\\\8^U^  K])]2`4^V^3]                                                                       \"\n\"                                                                                                                    U]*\\\\2a4`V\\\\8^U^5a  F]*\\\\1\\\\X\\\\4^U^=]*\\\\\"\n\"2a5^U^ 7aV\\\\4]*\\\\1a4`V\\\\8^U^  J]*\\\\1\\\\X\\\\4^V^3\\\\                                                                                                             \"\n\"                                                                              S],\\\\1\\\\W\\\\5g8^U^6c  F],\\\\1\\\\V\\\\5^U^<],\\\\2]W]6^U^ 8h3],\\\\0\\\\W\\\\5g8^U^  I],\\\\1\\\\V\\\\5^V\"\n\"^4\\\\      ;]                                                                                                                                           \"\n\"                                         :\\\\-]2\\\\U\\\\6\\\\V`7^U^7]U]  F\\\\-]2\\\\T\\\\6^U^;\\\\-]3]U]7^U^ 8\\\\Va1\\\\-]1\\\\U\\\\6\\\\V`7^U^  H\\\\-]2\\\\T\\\\6^V^5]      =a                  \"\n\"              J]                                                                                                                                      \"\n\"              N\\\\/]2\\\\S\\\\7\\\\T]6^U^7\\\\S\\\\  E\\\\/]2\\\\R\\\\7^U^:\\\\/]3]S]8^U^ 8\\\\T^/\\\\/]1\\\\S\\\\7\\\\T]6^U^  G\\\\/]2\\\\R\\\\7^V^6]      =c                                L^           \"\n\"                                                         *^                            U`                                         O^             )\\\\S\\\\ \"\n\"                    !^$^3\\\\  E]U\\\\  K^$^4^ G^$^4]   J^$^3\\\\   #^$^3\\\\ 4^            B[                                                                    \"\n\"&^                            Xe                                         S^             (\\\\S\\\\               )Z      Q^&^3^2]S\\\\ A\\\\S\\\\  K^&^3^ F^&^4_  >]S\"\n\"\\\\9^&^3^2]S\\\\   W^&^3^ 6^        Q]    M[               ?`   ![1^H]?` =]4](\\\\    %` >b4c  Bb ?`2a    .a   Ib   Pb      Aa <a @b      Fb =b  F^ :] '] Da A\"\n\"].].].].]            <_:]._    Xh ?c   W^       @`   La   Pa        Sa   Va5^U^ @`   \\\"f4_ >`0`*^   $^.` <^F]F^F]G`G]     F\\\\S\\\\ ;b        %a2a2a2a2a <bR\"\n\"\\\\     D`4^(^3`4`U\\\\8^V^6\\\\S\\\\  J^(^3`4^U^@^(^3_4^U^/^/`U\\\\8^(^3`4`U\\\\8^V^  K^(^3`4^V^1^9]+^V^      ?`    O\\\\  D\\\\6]M]            We D]1]T] 9[3bJ\\\\@e<])]2])\\\\  \"\n\"  T]0d3_7h9i/_;k5f?n:f7e    3g :_8i3h@h9n?l5iB]H]C].].]J^B].`I`H_J]<g?g1g?g4hAuB]H]G]C]F]K_K]S^J^F^G^CrBb7]*b'_ D] :] '] Fc A].].].].]            >a:]\"\n\".a   !^T_ Bg   `       Dd2_8n?m7g3]:rD]P]P]@g <] 8] 8] B] 3e J^K^ If7^U^+b@d   Fb@f5a Ad4e-] :f  Ra0d AaF\\\\HaF\\\\HeJ\\\\?]._0_0_0_0_2\\\\U\\\\0tHh@n?n?n?n?].].].]\"\n\"-h:_J]<g8g8g8g8g BhV]G]H]C]H]C]H]C]H]G^G^B]*d5](]2\\\\X\\\\4aW]8^V^6\\\\S\\\\  I](]3]X]5^U^?](]3\\\\W\\\\5^U^.^R[9aW]7](]2\\\\X\\\\4aW]8^V^  J](]2\\\\X\\\\4^V^1]8]+^V^      ?a>w   \"\n\"P[ 9[/a:aQa7[    Wl      \\\"h E]1]T]+\\\\R\\\\;[4dL]Ag=])]2])\\\\    U^1f8c8k;j1`;k7h?n;h9g    5i*b:_8k6kBl=n?l7mD]H]C].].]L_A].`I`H`K]>kAj6kAj9kBuB]H]F]E]E^L_L^\"\n\"R^L^D^I^BrBb7^+b(a D] ;] '] Gd A].].].].]      ;]     (b:].b   #^Q] Dj  !a       Ff3_8n?m8i4]:rD]P]P]Bk ?_ 9] 9_ C]&[0f I]K]=]0g7^U^-fC\\\\S]   IfBf6c B[\"\n\"S]5[S].] <i  R\\\\W\\\\1]T] B\\\\W\\\\G]H\\\\W\\\\G]H[S]K]?]._0_0_0_0_2c1uIkBn?n?n?n?].].].]-l>`K]>k<k<k<k<k EoF]H]C]H]C]H]C]H]F^I^A],h6]*]2\\\\V\\\\6]Wa7^V^6\\\\S\\\\  H]*]2\\\\V]6^U\"\n\"^>]*]3]W]6^U^._V_;]Wa5]*]2\\\\V\\\\6]Wa7^V^  I]*]2\\\\V\\\\5^V^2]7]+^V^      @]W\\\\=v   P[ 9\\\\1c<cSd:]   \\\"o      #_S^ F]1]T],]S];[5^V^N]A_T]=]*]0]*\\\\    U]1^T^;e8`S_<\"\n\"^R_2`;k8^R]?n<_T_;^S^    6^S_.i>_8m:`R`Cn?n?l9`QaE]H]C].].]M_@].aKaH`K]?`S`Bk8`S`Bk;_R_BuB]H]F]E]D]MaM]P]L]B^K^ArB]1]&])c D] <] '] G] :].].].].]      \"\n\";]     (^6]*^   #]P^ E^P\\\\   V^       H^T^4_8n?m:`S`6]:rD]P]P]C`S` Aa :] :a D]&[1^S\\\\ I^M^=]0^R[7^U^/^R^EZO\\\\   L^R^ N]U] :],\\\\0] <j  M\\\\2]R] >\\\\H]B\\\\H]=\\\\M]>\"\n\"]._0_0_0_0_0_/uK`R`Cn?n?n?n?].].].]-n@`K]?`S`>`S`>`S`>`S`>`S` H`ScE]H]C]H]C]H]C]H]E^K^@],^T^5],]1\\\\V\\\\6\\\\U`7^V^6]U\\\\  F],]2\\\\T\\\\6^U^=],]2\\\\U\\\\6^U^-e9\\\\U`4],]1\\\\\"\n\"V\\\\6\\\\U`7^V^  H],]1\\\\V\\\\5^V^3]6]+^V^  B`1`1`1`1`6]W]>u   P[ 9]2e>eUf;^   %q      $^O\\\\ F]1]T],]S];[5]T]N\\\\@]P[=]*]0]2ZR\\\\RZ   $]2]P]<_W]8]N]<ZL^4a;]+]MZ/]<^P\"\n\"^=^Q^    7\\\\O]1nAa9]N_<_M]C]NaA].]+_L^E]H]C].].]N_?].aKaHaL]@^M^C]P_:^M^C]P_=^M\\\\6]6]H]F^G^D]MaM]P^N^B^K^-^B]1]&]*e D] =] '] H] 9].].].].]      ;]     )\"\n\"^5])^   %^O]8^3]LZ   U]       I^R^6a9_0]+^M^7]:]H]D]P]P]D^M^ Cc ;] ;c E]&[2^PZ H]M]<]1^-^U^1]L];[   N]L] Q]S] :\\\\,\\\\1] <dU\\\\  M\\\\2\\\\P\\\\ >\\\\H\\\\A\\\\H\\\\<\\\\M\\\\=]/a2a2a\"\n\"2a2a1_/]V];_M]C].].].].].].].]-]ObBaL]@^M^@^M^@^M^@^M^@^M^ J^N`D]H]C]H]C]H]C]H]E^K^@]-^Q]5].]1\\\\T\\\\7\\\\S]6^V^5c  E].]2]S\\\\7^U^<].]2\\\\S\\\\7^U^,a6\\\\S]2].]1\\\\T\\\\7\\\\S\"\n\"]6^V^  G].]1\\\\T\\\\6^V^4]5]+^V^  De6e6e6e6e9\\\\U\\\\>u   P[ :_3f@gVf<_   &r      $]M[ F]1]T],\\\\R]>d<^T^P]A^OZ=]+].]4]T\\\\T]   &^3^P^=[S]8[K].]4\\\\X];],]!]<]N]>^O^  \"\n\"  8ZM^3`P`Ba9]M^=^J\\\\C]K_B].],^H\\\\E]H]C].].]O_>].aKaHaL]A^K^D]N^<^K^D]N^>]JZ6]6]H]E]G]C]MaM]O^P^@^M^-^A]1]&]+_W_ D] >] '] H] 9]  B].]      ;]     )]4](]\"\n\"   %]N]:c6]   G]       J^P^7a8_1],^K^;c=]H]D]P]P]E^K^ Ee <] <e F]&[2] =^O^<]1] 0\\\\H\\\\<\\\\   P\\\\H\\\\ R\\\\Q\\\\+]3\\\\,\\\\2] <eU\\\\  M\\\\3]P\\\\ >\\\\I]A\\\\I]<\\\\N]=]/a2a2a2a2a2a1]U]<\"\n\"^J\\\\C].].].].].].].]-]K_CaL]A^K^B^K^B^K^B^K^B^K^ K]K^D]H]C]H]C]H]C]H]D^M^?]-]P]4]0]1\\\\R\\\\  Ha  C]0]2]R] E]0]2\\\\Q\\\\ 9c 9]0]1\\\\R\\\\   !]0]1\\\\R\\\\ ?]4]   Di:i:i:i:i\"\n\";\\\\6]G]   P\\\\ :`5g@gWh>a   (_       J]KZ F]1]T],\\\\R\\\\?h>]R]P\\\\@]1]+].]3^V\\\\V^.]   T]2]N]5]8ZJ]-]6]X];]-]!^=]L]?]M]    *]5_J_Ec:]L^>]H[C]I^C].],]F[E]H]C].].]\"\n\"P_=].]X]M]X]HbM]A]I]D]M]<]I]D]M]?]%]6]H]E]G]C^NaN^N]Q^>^O^-^@]0]'],_U_  &] '] H] 9]  B].]      ;]     )]4](]   %]N]:d7]   F]       K]N]8c8^1],]I]>i@]H\"\n\"]D]P]P]E]I] Fg =] =g G]&[2] <]O];]1] 1\\\\F\\\\=\\\\   Q\\\\F\\\\ S\\\\Q\\\\+]3\\\\.]  IeU\\\\  M\\\\3\\\\N\\\\ ?\\\\I\\\\@\\\\I\\\\=]M\\\\<]0c4c4c4c4c3a1]U]<]H[C].].].].].].].]-]J_DbM]A]I]B]I]B]I]B]I]\"\n\"B]I] L]J_E]H]C]H]C]H]C]H]C^O^>].]N]    .]        '`X_           I]   FbWa=bWa=bWa=bWa=bWa<\\\\6^I^  ?Z2[ :a5gAiXh?c   *^       H] 7]1]T]-]S]Aj>]R]Q]@]1],\"\n\"],\\\\1^X\\\\X^,]   T]3]L]6]'].]7]W];]-]!]<]L]?]M^    +]6^F^F]W]:]K]?]FZC]H^D].]-]DZE]H]C].].]Q_<].]X]M]X]H]X]M]B]G]E]M^>]G]E]M^@]%]6]H]E^I^B]O^X]O]M^R^=]O^\"\n\"-^@]0]']-_S_  '] '] H] 9]  B].]      ;]     )]4](]   %]N]:e8_   H]       L]M]8]W]7^2]-]G]AmB]H]D]P]P]F]G] Hi >] >i  J[3] ;^Q^;]1] 2\\\\RbT\\\\Ge   R\\\\VdR\\\\ T\\\\\"\n\"Q\\\\+]4\\\\2a  IfU\\\\  M\\\\3\\\\N\\\\ ?\\\\J\\\\?\\\\J\\\\AaM\\\\ G]W]4]W]4]W]4]W]4]W]4c3^U]=]FZC].].].].].].].]-]H]D]X]M]B]G]D]G]D]G]D]G]D]G]A[H[B]J`E]H]C]H]C]H]C]H]B]O^>g8]N]    \"\n\"         1]T_      3[    9]   G_O^?_O^?_O^?_O^?_O^=\\\\5]I^  @\\\\3[ ;c6gAy?d7`8]L]7^7]L]>^       H] 6]1]T]-]S]B_W[U]>]R]R]?]1],],]0d*]   T]3]L]6]'].]7\\\\V];]\"\n\".] ]<]L]@]K]  7Z PZ X]7^D^G]W]:]K]?]/]G]D].]-]/]H]C].].]R_;].]X^O^X]H]X^N]B]G]E]L]>]G]E]L]@]%]6]H]D]I]A]O]W]O]L^T^<^Q^-^?]0]'].^O^  Sb7]U`2b4`U]8a8])`\"\n\"7]T_  M].]%_O_@_2`0`3`/_3c9]     )]4](]   N_6]N]3^7a/c0_ <^  D[U^  Ga  N]L]9]W]6^3]-]G]B`W]W`C]H]D]P]P]F]G] I_X]X_ ?] ?_X]X_  Nb7]2ZFZ=]Q]:]0] 3[SfU[I\"\n\"g   R[UfS[ T\\\\Q\\\\+]5]2a  IfU\\\\  M\\\\3\\\\N\\\\ ?\\\\K]?\\\\K]AaN] G]W]4]W]4]W]4]W]4]W]4]W]3]T]=]/].].].].].].].]-]G]E]X^N]B]G]D]G]D]G]D]G]D]G]B]J]C]KbF]H]C]H]C]H]C]H]B\"\n\"^Q^=j;]P_9b3b3b3b3b3b3bN`Bb3a2a2a2a    V_2_2`1`1`1`1` ;aU]    :]U`   S^T]U^A^L^A^L^A^L^A^L^?]5]I]  @^5\\\\ <e7gAy@f;e:]L]8`8^N^?^       G] 6]1]T]-\\\\R\\\\A]U[\"\n\"RZ>]R]R\\\\>]1],],].`(]   U^3]L]6]'].]8]V];].]!^<]L]@]K]  :] P]#^8^A]I^W^;]K]@].]G^E].].].]H]C].].]S_:].]W]O]W]H]W]N]C]E]F]L]?]E]F]L]@]%]6]H]D]J^A]O]W]O]\"\n\"L^U^:^S^-^>]0^(]/^M^  Wh:]Wd6f8dW]:e>h2dW]?]Vd<].].]O_>].]WdScK]Vd8f;]Wd7dW]?]Wa6h>h6]L]B]I]A]P`P]K^L^B^K^@l4]4](]   PdU]A]N]2^8e5g;]Vd?^J^8]6]L] E]V`\"\n\">pA]S]S]:e6kDo>]L]:^W^6^4].]E]D_U]U_D]H]D]P]P]G]E] K_W]W_ @] @_W]W_  Qf9]3\\\\H\\\\>^S^:]0_ 6[ThT[K]Q\\\\   S[T\\\\R]S[ U]S]+]6],] ?]L]@fU\\\\  M\\\\3\\\\N\\\\ ?\\\\K\\\\>\\\\K\\\\;]O\\\\ G\"\n\"^W^6^W^6^W^6^W^6^W^5]W]4^T]>].].].].].].].].]-]G^F]W]N]C]E]F]E]F]E]F]E]F]E]D_L_E]K]W]F]H]C]H]C]H]C]H]A^S^<k<]Ra<h9h9h9h9h9h9hTeFf7e6e6e6e;].].].]\\\"^;]V\"\n\"d8f7f7f7f7f/^6eX]@]L]?]L]?]L]?]L]B^K^?]Wd>^K^  O]S]S]B]I]B]I]B]I]B]I]@]5^K^  @]4[ ;f8gAyAg<h<]L]8`7]N]>]       F] 6]1]T]-\\\\R\\\\B]T[6]R]S]>^2]-]*\\\\.`(]   U\"\n\"]2]L]6]'].]9]U];].]!];]L]@]K]  =` P`'^7]?\\\\I]U];]K]@].]F]E].].].]H]C].].]T_9].]W]O]W]H]W^O]C]E]F]L]?]E]F]L]@]%]6]H]C]K]@^P]W]P^K^V^9]S]-^=]/](]0^K^  Xi\"\n\";]Xf9h9fX]<h?h3fX]?]Xg=].].]P_=].]XfVfL]Xg:h<]Xf9fX]?]Xb7i>h6]L]A]K]@^Q`Q^J^N^@]K]?l4]4](]   QfW^A]O^1]6f9h;]Xg@_K]7]6]L]=]G]C^Wc@pA]S]S]<h9mDo>]L]:]U\"\n\"]5^5].]E]E^S]S^E]H]D]P]P]G]E]@Z+]V]V^-Z4]5ZKZ:]V]V^  Sh9]4^J^>]S]9]._ 8[U_Q[T[L]P\\\\   S[T\\\\Q]T[ T]U]*]7]*] @]L]@fU\\\\  M\\\\3\\\\N\\\\ ?\\\\L]>\\\\L]:]Q]:]1]U]6]U]6]U]6]\"\n\"U]6]U]6^W^5]S]>].].].].].].].].]-]F]F]W^O]C]E]F]E]F]E]F]E]F]E]C_N_D]L^W]F]H]C]H]C]H]C]H]@]S];]P_=]S^8i:i:i:i:i:i:iVgIh9h9h9h9h<].].].]'d<]Xg:h9h9h9h9h\"\n\"0^8k?]L]?]L]?]L]?]L]A]K]>]Xf>]K]  O]R]R]D]G]D]VZOZV]D]KZV]D]G]A]4]K]  @]3[ <g7fAyBi>j=]L]8`7]N]?]       F^ 6]1]T]5uI]T[6]R]S\\\\<^3]-]*]1d*]   U]3]J]7]']\"\n\".]9\\\\T];].\\\\Ua-^;]L]@]K^?].] Uc Pc+_8]>]J]U];]K]@].]F]E].].].]H]C].].]U_8].]W^Q^W]H]V]O]C]E]F]L]?]E]F]L]@^&]6]H]C]K]?]Q^V]Q]I^X^8^U^.^<]/](]1^I^  ]R_<aT\"\n\"_;_R\\\\:^Tb=_S^@h4_Ub?bT^=].].]Q_<].aT_X]T^LbT^;_T_=aT_;^Tb?aTZ8_R]>h6]L]A]K]?]Q`Q]H^P^?]K]?l4]4](]   R^U^W]@]O]0^7g;_S];bT^@`L]8_7]L]>]E]E^W]V]@pA]S]S]\"\n\"=_T_<oDo?]K^;]U]5_6].\\\\D]E]R]R]E]H]D]P]P]G]E]A\\\\+[U]U\\\\,\\\\6]6\\\\L\\\\;[U]U\\\\  S_W[V\\\\9]3^V`V^=^U^9]/a :[T]G[M\\\\O\\\\1ZQZ  M[S\\\\P\\\\S[ Ud)]8](\\\\ @]L]@fU\\\\  M\\\\3\\\\N\\\\9ZQZ0\\\\L\\\\=\"\n\"\\\\L\\\\8\\\\Q\\\\9]1]U]6]U]6]U]6]U]6]U]6]U]5]S]>].].].].].].].].]-]F]F]V]O]C]E]F]E]F]E]F]E]F]E]B_P_C]L]V^G]H]C]H]C]H]C]H]@^U^;]N^>]T]6]R_;]R_;]R_;]R_;]R_;]R_;]R\"\n\"_X_T^K_R\\\\:_S^;_S^;_S^;_S^=].].].]*h=bT^;_T_;_T_;_T_;_T_;_T_1^9_T`>]L]?]L]?]L]?]L]A]K]>aT_?]K]  P]Q]R]E]F]E]V\\\\Q\\\\W]E]K\\\\W]E]F]A]4^L]  A^@ZN\\\\ =i8e@yCk?^R^\"\n\"=]L]9b8]O^?]       Im B]1]T]5uI]T[6]S^T]<^3]-]*]3^X\\\\X^,]   V^3]J]7](^/]9]T];e7]We/]9]N]?]K^?].] Wd Nd._8]O`U\\\\T\\\\K]S]<]L^A]-]F^F].]/]-]H]C].].]V_7].]V]Q\"\n\"]V]H]V^P]D]C]G]L]@]C]G]L]?^']6]H]C^M^?]Q]U]Q]Ic6^W^._<]/^)]2^G^ !ZM^=`Q^=^NZ;^Q`>^P^=].^Q`?`Q^>].].]R_;].`R^X\\\\R^M`Q^=^P^>`Q^=^Q`?`1]MZ;].]L]A^M^?]Q`Q]\"\n\"G^R^>^M^1^4]4](]  D]P^A]R^X]@]P^/]9^Vb=^NZ;`Q^AaN^8_7]L]>]E]F^V]U]>]P]>]S]S]>^P^>`T`7]6]J]<]S]5^6]/]C]G]Q]Q]F]H]D]P]P]H]C]C^&]TZ,^7]7^N^6]TZ H]/^U[TZ9\"\n\"]2n;]U]8]0d <[U]F[M\\\\P]2[R[  M[S\\\\P\\\\S[ Tb(]9]'\\\\ @]L]@fU\\\\  M\\\\3]P]9[R[1\\\\M\\\\<\\\\M\\\\7\\\\R\\\\8]2]S]8]S]8]S]8]S]8]S]7]U]6]R]?]-].].].].].].].]-]F]F]V^P]D]C]H]C]H]C]H]\"\n\"C]H]C]B_R_C]L]T]G]H]C]H]C]H]C]H]?^W^:]M]>]U^6ZM^<ZM^<ZM^<ZM^<ZM^<ZM^<ZMbP]M^NZ;^P^=^P^=^P^=^P^>].].].]+i=`Q^=^P^=^P^=^P^=^P^=^P^2^:^P^>]L]?]L]?]L]?]L]\"\n\"A^M^>`Q^@^M^  P]Q]Q]F]E]F]W^S^W]F]L^W]F]E]B]3]M^  B^B^O[ =k8d?xClA^P^>]L]9]X]8^P]>\\\\       Hl A] 9uI]T[5]T]T]:^ =]*]5^V\\\\V^.]   V]2]J]7](]/^:]S];h:]Xg0]\"\n\"9^P^?]K^?].]!e Je2_7\\\\PdW\\\\S\\\\L]S]<]M^@]-]E]F].]/]-]H]C].].]X_5].]V]Q]V]H]U^Q]D]C]G]L]@]C]G]M^?`)]6]H]B]M]>]Q]U]Q]Hb5c-^;].])]   B]=_O]=].]O_>]N^>].]O_?_\"\n\"O]>].].]S_:]._P`P]M_O]=]N]>_O]=]O_?_1]-].]L]@]M]>]RbR]G^R^=]M]1^3]4](]  FaSaD^Qa?]R_.]9]R`>]._O]>^N]8`7]L]>]E]G^U]U^?]P]>]S]S]>]N]>^P^7]6]J]<]S]4^7]/]\"\n\"C]G]Q]Q]F]H]D]P]P]H]C]D_&]&_8]8_N_7] B]/]T[3]1l:^W^8]1]W` >\\\\U\\\\E\\\\N\\\\P]3\\\\S\\\\  N\\\\S\\\\P\\\\S\\\\ S_']:]&\\\\ @]L]@fU\\\\  M\\\\2\\\\P\\\\8\\\\S\\\\2\\\\N]<\\\\N]7\\\\S]8]2]S]8]S]8]S]8]S]8]S]8]S]\"\n\"7]R]?]-].].].].].].].]-]E]G]U^Q]D]C]H]C]H]C]H]C]H]C]A_T_B]M]S]G]H]C]H]C]H]C]H]>c9]M^?]U]'].].].].].].`O^N].]N^>]N^>]N^>]N^?].].].],_R^>_O]=]N]=]N]=]N]\"\n\"=]N]=]N]2^:]O_?]L]?]L]?]L]?]L]@]M]=_O]?]M]  O\\\\P]Q]F\\\\D]F\\\\U^U^V]F\\\\L^V]F\\\\D]B]3]M]  RuJ`O[ >m9c>wCmA]N]>]L]9]X]7]P]?]       Im A] 2\\\\R\\\\A]T[5^V^T\\\\:` ?](\\\\6]T\"\n\"\\\\T]/]   V]2]J]7])^1_9]S];i;bS^2^8^S_>]K^?].]$e@u@e6_7]QfX\\\\S\\\\M^S^=]N^?]-]E]F].]/]-]H]C].].c4].]U]S]U]H]T]Q]D]C]G]M^@]C]G]M]=c-]6]H]B]M]>^R]U]R^G`4c.^:]\"\n\".])]   B]=^M]?^/]M^?]L]>]/]M^?^N^?].].]T_9].^O_O^N^N^?]M^?^M]?]M^?^0]-].]L]@]M]>^S]X]S^F^T^<^O^2_3]4](]  GcUcE]Pa?]Vb-]:]O_?].^N^>]O^8a8]L]?]C]H]T]T]?\"\n\"]P]>]S]S]?]L]@^N^8]6]J]=^S^4^8]/]C]H^Q]Q^G]H]D]P]P]H]C]E_%]%_9]9_L_8] B]0^T[3]0_T_>cWc=]1]U_ ?[U\\\\C[N]R^4]T]  N[R\\\\Q]R[ 'uG]&] @]L]?eU\\\\  M\\\\2]R]8]T]3\\\\N\\\\;\"\n\"\\\\N\\\\7]S\\\\7]3^S^:^S^:^S^:^S^:^S^9]S]8^R]?]-].].].].].].].]-]E]G]T]Q]D]C]H]C]H]C]H]C]H]C]@_V_A]N]R]G]H]C]H]C]H]C]H]>c9]L]?]U]'].].].].].]._M]O^/]L]?]L]?]L\"\n\"]?]L]?].].].]-^O]>^N^?]M^?]M^?]M^?]M^?]M^ I]O`?]L]?]L]?]L]?]L]@^O^=^M]@^O^  P]P]P\\\\G]C\\\\G]T^W^T\\\\G]M^T\\\\G]C\\\\B]3^O^  RuJ[X]P[ >o=\\\\XaX]BwDoC]L\\\\>]L]:^X^8]P]?\"\n\"]       E] 5] 3]S]A^U[4dT];b @](]6ZR\\\\RZ.]   V]2]J]7]*^7d8]R];]R_<aQ^3]5f<^M_?].]'e=u=e:_6\\\\Q^S`S]N]Q]=l>]-]E]Fm>k=]-rC].].b3].]U]S]U]H]T^R]D]C]G]M]?]C]\"\n\"G]N^<f1]6]H]B^O^=]S^U^S]F_2a.^9].])]   A]>^M]?].]M^?]L]>]/]M^?^M]?].].]U_8].^N^N]N^M]?]L]?^M]?]M^?^0]-].]L]@^O^=]S]X]S]D^V^:]O]2_2]4](]  H\\\\U^W]U\\\\E]Pa?\"\n\"]Vb-];]M^?].^M]>^P]7a8]L]?]C]H]T]T]?]P]>]S]S]?]L]@]L]8]6p=]Q]3^9]/]C]H]P]P]G]H]C]Q]Q]G]ViV]F_$]$_:]:_J_9] B]0]S[3]0]P]>o=]2]S_ @[U\\\\C[M]T_5^U^;u O[R\\\\R]\"\n\"Q[ 'uH]/ZQ] ?]L]?eU\\\\  M\\\\1]T]7^U^4\\\\O]O]I\\\\O]T`MZQ]S]O]E]3]Q]:]Q]:]Q]:]Q]:]Q]:^S^9]QmO]-m>m>m>m>].].].]1hL]G]T^R]D]C]H]C]H]C]H]C]H]C]?_X_@]O]Q]G]H]C]H]C]\"\n\"H]C]H]=a8]L]?]U]&].].].].].].^M]O].]L]?]L]?]L]?]L]?].].].].^M]?^M]?]L]?]L]?]L]?]L]?]L] I]Pa?]L]?]L]?]L]?]L]?]O]<^M]?]O]  O]P]P\\\\G]C\\\\G]ScS\\\\G]N^S\\\\G]P]P\\\\B\"\n\"]2]O]  QuF]Q[ >oAqDuDqD]L]?]L]:^X^8^R^?\\\\       D] 5] 3]S]@`X[3bS\\\\R^G]W^N] P](].\\\\&]   W]1]J]7]*^7c8]Q];ZM^=`O^4]4d:]M_?].])d:u:d=_5\\\\R]O^R\\\\N]Q]=j<]-]E]F\"\n\"m>k=]-rC].].a2].]U^U^U]H]S]R]D]C]G]N^?]C]G]P_:g3]6]H]A]O]<]S]S]S]E^1_.^8]-]*]   A]>^M]?]/^M^?]K]?]0^M^?]L]?].].]V_7].]M]M]N]L]@^L]?^M]@^M^?]/]-].]L]?]\"\n\"O]<]S]X]S]C^X^9]O]2^1]4](]0_IZ O[R\\\\X]S\\\\G^O_>]Vd9_U];]L]?].]L]=]P]8]X^9]L]?]C]I^T]S]@]P]>]S]S]?]L]@]L^9]6p=]Q]3^9]/]C]H]P]P]G]H]C]Q]Q]G]ViV]G_#]#_;];_H\"\n\"_:] B]0]S[3]0\\\\N\\\\>o=]2]Q^ A[U\\\\C[LcX\\\\6]T]9u O[RfP[ 'uIf7e >]L]>dU\\\\<] :f5d4]T]:fT\\\\O^NfT\\\\UdOeR\\\\O^F^3]Q]:]Q]:]Q]:]Q]:]Q]:]Q]:^QmO]-m>m>m>m>].].].]1hL]G]S]R\"\n\"]D]C]H]C]H]C]H]C]H]C]>d?]P^Q]G]H]C]H]C]H]C]H]<_7]L]?]U^'].].].].].].^L]P].]K]@]K]@]K]@]K]@].].].].]L]?]L]@^L]@^L]@^L]@^L]@^L] I]Q]X^@]L]?]L]?]L]?]L]?]\"\n\"O]<^M]?]O]  O\\\\WmX]H\\\\WmX]H\\\\QaR]H\\\\N^R]H\\\\O]P]C]2]O]  QuF]R\\\\ ?qCsDtDrE]L]?]L]:]V]7]R]>x      '] 5] 3\\\\R\\\\?e3^R\\\\SbJ^V^O] P](].\\\\&]   W]1]J]7]+^6e:]Q]-^>_M]5^6\"\n\"h<^O`  Qe8u8e@^5]R\\\\M]R\\\\O^Q^>m?]-]E]Fm>k=]KdFrC].].b3].]T]U]T]H]S^S]D]C]G]P_>]C]Gk6f5]6]H]A^Q^<]S]S]S]F_1_/_8]-]*]   A]>]K]A].]K]@]J]?]0]K]?]L]?].].]W_\"\n\"6].]M]M]N]L]@]J]@]K]A]K]?]/^.].]L]?]O]<]T^W]T]C^X^9^Q^3^1]3]']3dN\\\\ P\\\\R`Q[G]N_>]Q`;bW];\\\\K^?]/]L]=]Q^8]W]9]L]?]C]I]S]S]@]P]>]S]S]@]J]B^L^9]6p>^Q^4^9]/]C\"\n\"]H]P]P]G]H]C]Q]Q]G]ViV]H_\\\"]\\\"_<]<_F_;] B]1]R[3]1]N]8a6]2]P^ B[U\\\\C[K`V\\\\7]T]8u O[RdN[ 'uIf5a <]L]=cU\\\\<] :f3`1]T];fU\\\\N^NfU\\\\T[S]NaQ\\\\N^G^3^Q^<^Q^<^Q^<^Q^<^Q\"\n\"^;]Q]:]PmO]-m>m>m>m>].].].]1hL]G]S^S]D]C]H]C]H]C]H]C]H]C]=b>]P]P]G]H]C]H]C]H]C]H]<_7]L]?]U_(].].].].].].]K]Q].]J]A]J]A]J]A]J]@].].].].]L]?]L]@]J]A]J]A\"\n\"]J]A]J]A]J] K]P\\\\V]@]L]?]L]?]L]?]L]?^Q^<]K]@^Q^  O\\\\WmX]H\\\\WmX]H\\\\P_Q]H\\\\O^Q]H\\\\O]P]C]2^Q^  D^<]R[ >qDuEsCqD]L]?]L]:]V]7]R]>x      '] 5] 3\\\\R\\\\=f+]TdL^T^P] P]\"\n\"(].\\\\2u  *]1]J]7],^-_=]P],]>_M]5]7_R^<^Qa  Sd .dC^4\\\\R]M]R\\\\O]O]>]N_@]-]E]F].]/]KdF]H]C].].]X^4].]T]U]T]H]R]S]D]C]Gk=]C]Gj1c6]6]H]@]Q];^T]S]T^Ga1].^7]-]*\"\n\"]   Lh>]K]A].]K]@]J]?]0]K]?]L]?].].]X_5].]M]M]N]L]@]J]@]K]A]K]?]._0].]L]>]Q];^U]V]U^Bb7]Q]3^1^3]'^6iS^ P[P^P[G]N_>]N^=dX]<]J]>^1]L]=^R]8^W]9]L]@]A]J]S\"\n\"]S]@]P]>]S]S]@]J]B]J]9]6]J]>]O]5^8]/]C]H]P]P]G]H]B]R]R]F]C]Iz<]<z=]=z<] B]1]R[7j:\\\\L\\\\7_5]2]P^ B[U\\\\C[ V]T]7u O[R\\\\U^O[  T]   ]L];aU\\\\<]   I]T],]O[X\\\\>]K]@]\"\n\"O[X\\\\I`3]O]<]O]<]O]<]O]<]O]<]O];]P]?]-].].].].].].].]-]E]G]R]S]D]C]H]C]H]C]H]C]H]C]<`=]Q]O]G]H]C]H]C]H]C]H];]6]L]?]T_4h9h9h9h9h9h9hK]Q].]J]A]J]A]J]A]J]\"\n\"@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]Q\\\\U]@]L]?]L]?]L]?]L]>]Q];]K]?]Q]  N\\\\WmX]H\\\\WmX]H\\\\P_Q]H\\\\P^P]H\\\\O]P]C]1]Q]  C]:]S[ ?sEvEqAoC]L]?]L];^V^8^T^>x     \"\n\" '] 5] 4]S]<g-\\\\T^V^M]S_Q\\\\ O](].\\\\2u Se =^1]J]7]-^*^?]O],^?^K]7^7]N]<^Sb  Sa (aC]3\\\\R\\\\K\\\\R\\\\P^O^?]L^A]-]E]F].]/]KdF]H]C].].]W^5].]T^W^T]H]R^T]D]C]Gj<]C]Gj-\"\n\"`7]6]H]@]Q]:]U^S^U]Fb2]/^6]-^+]   Nj>]K]A].]K]@p?]0]K]?]L]?].].b3].]M]M]N]L]@]J]@]K]A]K]?].c4].]L]>]Q]:]U]V]U]@`6^S^4^5b2]&b<u P[O]P\\\\H]N^=]M]>^Ua<]J]=\"\n\"c7]L]<]S^8]V^:]L]@]A]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]?^O^7^7]/]C]H]P]P]G]H]B]R]R]F]C]Iz<]<z=]=z<] B]1]R[7j:\\\\L\\\\7_ C^P] B[U\\\\C[ W]T] W] O[R\\\\T^P[  T]   ]L]7\"\n\"]U\\\\<]   H]T]-\\\\O\\\\X\\\\>\\\\I\\\\@\\\\O\\\\X\\\\J`3^O^>^O^>^O^>^O^>^O^=]O]<^P]?]-].].].].].].].]-]E]G]R^T]D]C]H]C]H]C]H]C]H]C];^<]R]N]G]H]C]H]C]H]C]H];]6]L]?]S`8j;j;j;j;j\"\n\";j;|Q].pApApAp@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]R]U]@]L]?]L]?]L]?]L]>^S^;]K]?^S^  N\\\\WmX]H\\\\WmX]H\\\\QaR]H\\\\Q^O]H\\\\O]P]C]1^S^  D]9]T\\\\ ?sFwDo?nC]L]?]L];\"\n\"]T]7]T]=]       Hj ?] 4]S]8d/]T]T]N^R_R\\\\ O](] =u Se =]0]J]7].^(]?]O]+]?^K]7]7]L]<gX]  Sa (aC]3\\\\R\\\\K\\\\R\\\\P]M]?]K]A]-]E]F].]/]D]F]H]C].].]V^6].]S]W]S]H]Q]T\"\n\"]D]C]Gg9]C]G]Q_,^7]6]H]@^S^:]U]Q]U]G^X]2]0^5],]+]   Pl>]K]A].]K]@p?]0]K]?]L]?].].a2].]M]M]N]L]@]J]@]K]A]K]?]-f8].]L]>^S^:]U]V]U]?^4]S]4^4`0]$`<^Si O[O\"\n\"\\\\O\\\\H]N^=]M^@^S`<]J]=c7]L]<]S]8^U]:]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]?]M]7]6]/^E^H]P]P]G]H]A]S]S]E]C]Iz<]<z=]=z<] B]1]R[7j:\\\\L\\\\6] A^Q] B[U\\\\C[Ni:]T]\"\n\" V] O[R\\\\S]P[  T]   ]L]6\\\\U\\\\<]  Dh2]T]/]P\\\\W\\\\?]I\\\\A]P\\\\W\\\\K`2]M]>]M]>]M]>]M]>]M]>^O^=]O]?]-].].].].].].].]-]E]G]Q]T]D]C]H]C]H]C]H]C]H]C]<`=]S]M]G]H]C]H]C]H]\"\n\"C]H];]6]M^?]R`;l=l=l=l=l=l=~Q].pApApAp@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]S]T]@]L]?]L]?]L]?]L]=]S]:]K]>]S]  M]P]P\\\\G]C\\\\G]ScS\\\\G]S^N\\\\G]P]P\\\\B]0]S]  D]\"\n\"7\\\\T[ >sFwCn?mB]L]?]L];]T]7]T]=]       Hi >] 4]S]7[Xa1]T^T^O]P_T] O](] =u Se =]0]J]7]/^'^A]N]+]?^K]7]8^L^<eW]  Sd .dC]3\\\\R\\\\K\\\\R\\\\P]M]?]K]A]-]E]F].]/]D]F]H\"\n\"]C].].]U^7].]ScS]H]Q^U]D]C]G]/]C]G]O^,^8]6]H]?]S]9]U]Q]U]H^W^3]1^4],]+]   Q`P]>]K]A].]K]@p?]0]K]?]L]?].].b3].]M]M]N]L]@]J]@]K]A]K]?]+e9].]L]=]S]9]V]T]\"\n\"V]@_4]S]5_4b2]&b<\\\\Nd M[O]P\\\\H]N^=]L]@]Q_<]J]?e7]L];]T]8]T]:]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]?]M]8^6].]E]G]P]Q^G]H]A^T]T^E]C]Iz<]<z=]=z<] B]1]R[3]\"\n\"1\\\\L\\\\6] A_R] B\\\\U\\\\E\\\\Ni:]T] V] O\\\\S\\\\R]R\\\\  T]   ]L]6\\\\U\\\\<]  Dh2]T]/\\\\O[V\\\\?\\\\H\\\\A\\\\O[V\\\\L`1]M]>]M]>]M]>]M]>]M]>]M]>^O]?]-].].].].].].].]-]E]G]Q^U]D]C]H]C]H]C]H]C]\"\n\"H]C]=b>]T]L]G]H]C]H]C]H]C]H];]6]M]>]Qa>`P]>`P]>`P]>`P]>`P]>`P]>`PoQ].pApApAp@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]T]S]@]L]?]L]?]L]?]L]=]S]:]K]>]S]  \"\n\"L\\\\P]P\\\\F\\\\C\\\\F\\\\T^W^T\\\\F\\\\T^M\\\\F\\\\C\\\\B]0]S]  E^7]U[ >sFwBl=kA]L]?]L]<^T^8^V^=]       Ij >] <u=[U^1\\\\S]R]O]O_U\\\\ N](] 1] Ge =]0]J]7]0_&]A]N]+]?^K]8^8]J]:aU\\\\  Pe 4\"\n\"eA]3\\\\R\\\\K\\\\R\\\\Qo@]J]A].]F^F].].]E]F]H]C].].]T^8].]RaR]H]P]U]C]E]F].]E]F]N^,]8]6]H]?]S]9^V]Q]V^H^V^4]2_4],]+]   Q]M]>]K]A].]K]@],]0]K]?]L]?].].c4].]M]M]N]\"\n\"L]@]J]@]K]A]K]?](d;].]L]=]S]9^W]T]W^@`5^U^5^/_3]'_8ZJ` K[O]P\\\\H]N^=]L]@]P];]J]@_0]L];]U^9^T^;]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]@^M^:^5].]E]F]Q]Q]F\"\n\"]H]@^U]U^C]E]G_\\\"]\\\"_BZT]TZB_F_;] B]1]R[3]1\\\\L\\\\?o I_S] A[U]F[ V]T] W] N[S\\\\R]R[  S]   ]L]6\\\\U\\\\   ']T]/\\\\O\\\\V\\\\@\\\\H\\\\A\\\\O\\\\V\\\\M_0o@o@o@o@o?m>l>].].].].].].].].]-]F^\"\n\"G]P]U]C]E]F]E]F]E]F]E]F]E]=d?^V]L]F]H]C]H]C]H]C]H];]6]N^>]O`?]M]>]M]>]M]>]M]>]M]>]M]>]M]?].].].].]-].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J] K]U]R]@]L]?]L]?\"\n\"]L]?]L]=^U^:]K]>^U^  L\\\\P]Q]F\\\\D]F\\\\U^U^V]F\\\\U^M]F\\\\D]B\\\\/^U^  OuD]V[ =sFwBk;i@]L]?]L]<]R]7]V];]       F^   Nu=[T^3]S]R]O]N_V\\\\ N](] 1]   ].]L]6]1_%]Aq0]>]K]\"\n\"8]7]J]/]  Md:u:d>]3\\\\R\\\\K\\\\S\\\\Po@]J]A].]F]E].].]E]F]H]C].].]S^9].]RaR]H]P^V]C]E]F].]E]F]M],]8]6]H]>]U^8]W^Q^W]H^U^4]2^3]+],]   R^M]>]K]A].]K]@],]0]K]?]L]?\"\n\"].].]X_5].]M]M]N]L]@]J]@]K]A]K]?]$`;].]L]=^U^8]W]T]W]@b5]U]5^,]3]']  J\\\\Q_Q[G]N^=]L]A]O];]J]@].]L];]U]8]R];]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]5]L]?]K];\"\n\"^4].^G^F]Q]Q]F]H]?_W]W_B]E]F_#]#_B\\\\U]U\\\\B_H_A\\\\U]U[ H]1]R[3]1]N]?o H`V] @[T]G[ U]T] X] N[S\\\\Q]S[  S]   ]L]6\\\\U\\\\   (]T]/]P\\\\U\\\\A]I]B]P\\\\U\\\\M^/o@o@o@o@o@o@m>].]\"\n\".].].].].].].]-]F]F]P^V]C]E]F]E]F]E]F]E]F]E]>_X_?]W^L]F]H]C]H]C]H]C]H];]6]P_=]M^@^M]?^M]?^M]?^M]?^M]?^M]?^M]?].].].].]-].].].]/]J]@]L]@]J]A]J]A]J]A]J]\"\n\"A]J] K]U\\\\Q]@]L]?]L]?]L]?]L]<]U]9]K]=]U]  K]Q]Q]F]E]F]W^S^W]F]W^L]F]E]B\\\\.]U]  NuC\\\\V[ =eXZXdFgXhAi9h@]L]?]L]<]R]7]V];]       E]   Nu=[S]3\\\\R]R]O]M_X\\\\ M](\"\n\"] 1]   ].]L]6]2_$]Aq0]>]K]8]7]J]/]  Ke=u=e<]3\\\\R\\\\K\\\\S\\\\Po@]J]A].]F]E].].]E]F]H]C].].]R^:].]RaR]H]O^W]C]E]F].]E]F]M^-]8]6]H]>]U]7]W]O]W]I^S^5]3^2]+],]   R\"\n\"]L]>]K]A].]K]@],]0]K]?]L]?].].]W_6].]M]M]N]L]@]J]@]K]A]K]?]\\\"_<].]L]<]U]7]W]T]W]Ac5^W^6^+^4](]  H[R\\\\X]S\\\\G]N^=]L]A]O];]J]A^.]L]:]W^9^R];]L]@]O]O]J]S]S]@\"\n\"]P]>]S]S]@]J]B]J]9]5]L]?]K];^4]-]G]D]R]R]E]H]>kA]E]E_$]$_B^V]V^B_J_A^V]V] I]1]R[3]0\\\\N\\\\>o G`X] ?\\\\U_Q[T\\\\ T]T] ] N\\\\T\\\\Q]T\\\\  S]   ]L]6\\\\U\\\\   )]T].\\\\P\\\\T\\\\A\\\\I]A\"\n\"\\\\P\\\\T\\\\N^.o@o@o@o@o@o@m>].].].].].].].].]-]F]F]O^W]C]E]F]E]F]E]F]E]F]E]?_V_@]W]K]F]H]C]H]C]H]C]H];]6k<]L^A]L]?]L]?]L]?]L]?]L]?]L]?]L]?].].].].]-].].].]/\"\n\"]J]@]L]@]J]A]J]A]J]A]J]A]J] K]V\\\\P]@]L]?]L]?]L]?]L]<^W^9]K]=^W^  J]R]R]D]G]D]W\\\\Q\\\\W]D]W\\\\L]D]G]A\\\\.^V]  NuC]W[ <cWZXdEfXh@g8g?]L]?]L]=^R^8^X^:]       F]  \"\n\" G\\\\R\\\\5[S]4]R]R]O]Lb M](\\\\ 0]   ].]L]6]3_#]Aq0]>]K]9]6]J]/]  He@u@e H\\\\R]M]T]Q^J]A]J]@]/]G^E].]-]F]F]H]C].].]Q^;].]Q_Q]H]N]W]B]G]E]-]G^F]L]-]8]6]I^>^W^7]\"\n\"W]O]W]I^R^6]4^1]+],]   R]M^>^M^@]/^M^?]-]0^M^?]L]?].].]V_7].]M]M]N]L]@^L]?^M^A^M^?] ]<].]L]<]U]7]X]R]X]B^W^5]W]6^)]4](]  H\\\\T]W]U\\\\F]O_=]L]A]P^;^L^A]-]L\"\n\"]:]W]8]P]<]L]@]O]O]J^T]T]?]P]>]S]S]@^L]A^L]8]5]L]@^J]=^3]-^I^D^S]S^E]H]<g>]G]C_%]%_A_W]W_A_L_@_W]W_ J]0]S[3]0]P]5]4],b =[ThT[ R]T]!] M[T\\\\P]U[  R]   ]L\"\n\"]6\\\\U\\\\   *]T].]P[S\\\\B]J]A]P[S\\\\N].^J]B^J]B^J]B^J]B^J]B^K^A]M]=]/].].].].].].].]-]G^F]N]W]B]G]D]G]D]G]D]G]D]G]?_T_AbK]E]I^C]I^C]I^C]I^;]6j;]K]A]M^?]M^?]M^\"\n\"?]M^?]M^?]M^?]M_?].].].].].].].].]/]J]@]L]@^L]@^L]@^L]@^L]@^L] J^X]Q]?]L]?]L]?]L]?]L];]W]8^M^<]W]  I]R]S]C]H]C]VZOZW]C]VZL]C]H]@\\\\-]W]  MuC]X[ ;cWZWbDe\"\n\"WZXe>e6e>]L]?]L]=]P]8^X^:]       F^   H\\\\R\\\\5[S]5]Q]R]O^L` K]*] 0]  !^.]L]6]4_\\\"]2],^>^M]8]6]J]0]  DeCuCe E]R\\\\M]T\\\\P]I]A]J]@]/]G]D].]-]F]F]H]C].].]P^<].]Q\"\n\"_Q]H]N^X]B]G]E]-]G]E]L^.]8]5]J]<]W]6^X]O]X^J^Q^6]5^0]+^-]   R]M^>^M]?].]M^?]-]/]M^?]L]?].].]U_8].]M]M]N]L]?]L]?^M]?]M^?] ]<].]M^<^W^6aRbB^V^6]W]7^(]4]\"\n\"(]  GcUcE]P_=]L]A]P]9]L]@]-]L]:^X]9^P]<]M^@]P^O]I]T]T]?]P]>]S]S]@^L]@]L]8]5]M]?]I]>^2],]I]B_U]U_D]H]:c<]G]B_&]&_?_X]X_?_N_>_X]X_ I]0]S[3]0_T_5]4]+` ;[\"\n\"SfU[ P^U^#] L[U\\\\P]V[  Q]   ]M^6\\\\U\\\\   ,^U^-\\\\P\\\\S\\\\B\\\\J]@\\\\P\\\\S\\\\N].]I]B]I]B]I]B]I]B]I]B]I]B^M]=]/].].].].].].].]-]G]E]N^X]B]G]D]G]D]G]D]G]D]G]@_R_A`J]D]J]A]J\"\n\"]A]J]A]J]:]6g8]K]A]M^?]M^?]M^?]M^?]M^?]M^?]M_?].].].].].].].].].]L]?]L]?]L]?]L]?]L]?]L]?]L]3^;aP]?]M^?]M^?]M^?]M^;]W]8^M];]W]  H]S]T^B]J^B]J^B]J^B]J^@\"\n\"\\\\-]W]  G^1_ :aW[V`BcW[Wc<d5c=]L]>]N]<]P]7]X]8]       F]KZ   X]S]5[S]5\\\\P]R]N]K_ K]*] 0]  !],]N]5]5_\\\"]1],]<]M]9^6^L^0]  Ad Nd A\\\\R]O^U\\\\P^I^B]K^?]H[C]H^D]\"\n\".],]G]F]H]C].].]O^=].]P^Q]H]M]X]A]I]D],]I^E]K]AZH^8]5]J]<]W]5bObJ^O^7]6_0]*]-]   R]M^>^M]?^/]M^?^.]/]M^?]L]?].].]T_9].]M]M]N]L]?]L]?^M]?]M^?] ]<].]M^;\"\n\"]W]5aRaB^U^6c8_(]4](]  FaSaD]P_=]M]@]P]9]L]@]-]L]9b9]O^=^N^?\\\\P_Q]H]T]T]?]P]=]T]T]?^L]@]L]8]4]N]@^I^?]1],^K^A`W]W`C]H]7]8]I]@^&]&^=i=^N^<i H]0^T[3]1l6]\"\n\"4])_ <\\\\RbT\\\\ O]T]#] L\\\\V\\\\O]X\\\\     M^N^6\\\\U\\\\   ,]T]-\\\\OhF\\\\J]@\\\\OhQ]/^I^D^I^D^I^D^I^D^I^C]I]B]L]<]H[C].].].].].].].]-]H]D]M]X]A]I]B]I]B]I]B]I]B]I]@_P_B_J]C]J\"\n\"]A]J]A]J]A]J]:]6].]K]A]M^?]M^?]M^?]M^?]M^?]M^?]M_?^/^/^/^/^/].].].].]L]?]L]?]L]?]L]?]L]?]L]?]L]3^;`O]?]M^?]M^?]M^?]M^;c8^M];c  G^U]U^@^M^@^M^@^M^@^M^?\"\n\"\\\\-c  H^0_ 9^U[U^@aV[Va:b3a<]L]>^P^=^P]7]X]8_       H^M[ F] 6]S]>ZQ[T^6]P]S^N^K^ K]*] 0]:] 8]0],]O^5]6_2ZI]1]-^<^O^9]4]L]0]<].] Uc Pc1]2\\\\Q^S`W^P]G]B]K]\"\n\">^J\\\\C]I^C].],^H]F]H]C].].]N^>].]C]H]MbA^K^D],^K^D]K^B[I]7]5^L^<c5aMaJ^N]7]6^/]*]-]   R^O_>_O]=].]O_>].].]O_?]L]?].].]S_:].]M]M]N]L]>]N]>_O]=]O_?] ]<]-\"\n\"]O_;]X^5aRaC^S^6a8_']4](]  D]P^B^Ra>^N]@]Q]7]N]?^.]L]9a8]N]=^N^?]Q_Q]G]U]U]>]P]=]T]T]?_N]>]N]7]4^P^@]G]@^1]+^M^?mB]H]7]8^K^?\\\\%]%\\\\;g;\\\\L\\\\:g G]/]T[3]2n7]\"\n\"4]'^ <\\\\F\\\\ M\\\\S\\\\  J\\\\F\\\\     L^N^6\\\\U\\\\   ,\\\\S\\\\-]OhG]K]@]OhQ]LZ=]G]D]G]D]G]D]G]D]G]D]G]D^L]<^J\\\\C].].].].].].].]-]J_D]MbA^K^B^K^B^K^B^K^B^K^A_N_B^K]B^L^A^L^A^\"\n\"L^A^L^:]6].]K]A^O_?^O_?^O_?^O_?^O_?^O_?^Oa?].].].].]/].].].]-]N]>]L]>]N]=]N]=]N]=]N]=]N]2^;_O]=]O_>]O_>]O_>]O_:a7_O]9a  E^P_>^P_>^P_>^P_>^P_>\\\\,a  H^.]\"\n\" /[5]T[S\\\\8a1`<]L]=^R^<]O^8b7_       H^O\\\\ F] 6\\\\R\\\\=[R[U^5\\\\N]T]L^M` L]*] 0]:] 8]1^+]P]4]7_1[L_1]<ZL^:^Q^8]4^N^>ZM];].] R` P`.]2]QfXaN]G]B]L^=^L]C]K_B].]+\"\n\"_J]F]H]C].].]M^?].]C]H]La@^M^C]+^M^C]J]B]L^7]4^N^:a4aMaK^M^8]7^.]*^.]   Q]P`>`Q^=^NZ;^Q`>_LZ>].^Q`?]L]?].].]Q^;].]M]M]N]L]>^P^>`Q^=^Q`?]/ZL];]-^Q`:a4`\"\n\"P`D^Q^7a8^&]4](]   S]Sb>_P^@]R^7^P^>^MZ<]L]9a9]M]=_P`XZB]Q_Q]G^V]V^>]P]=^U]U^?`P^>^P^6]4]Q^?]G]A^0]*^O^<i@]H]7]7^M^=Z$]%Z8e9ZKZ7e F]/^U[TZ9]3^V`V^8]4]\"\n\"&^ <\\\\H\\\\ K[R[  I\\\\H\\\\     K_P`XZ9\\\\U\\\\   ,[R[,\\\\E\\\\D\\\\K]?\\\\E\\\\M]O\\\\=]G]D]G]D]G]D]G]D]G]D]G]D]K];^L]C].].].].].].].]-]K_C]La@^M^@^M^@^M^@^M^@^M^A_L_C`N^A^N^?^N^?^\"\n\"N^?^N^9]6].]L]?]P`>]P`>]P`>]P`>]P`>]P`>]P]X^LZN^NZ;_LZ>_LZ>_LZ>_LZ?].].].]-^P^>]L]>^P^=^P^=^P^=^P^=^P^2^:^P^=^Q`>^Q`>^Q`>^Q`:a7`Q^9a  Dk<k<k<k<k>],a  \"\n\"H]-] /[,[._0_;]L]=j<]N]7`5a       J_S^ F] 6\\\\R\\\\=^U[W_5]N^V^K_Rd L],] /]:] 8]1])^T^3]8_0^Q`0]<]Q_8^S^8^3_R_=]R^:].] O] P]+]1\\\\PdW`N^G^C]N_;`R`C]NaA].]*`O\"\n\"`F]H]C].].]L^@].]C]H]La?`S`B]*`S`B]J]B`Q_6]3_R_9a4aMaL^K^9]8^-])].]   Q_Tb>aS^;_R\\\\:^Sa=`Q]>]-^Sa?]L]?].].]P^<].]M]M]N]L]=_T_=aS^;^Sa?]/^R_:]-^Sa:a3_P_\"\n\"C^P^7_8^%]4](]   S_V^X^?aS^>]T^5_T_=`R]<]L]8_8]M^>`SdA]SaS]E^W]W^=]P^=_W]W_>]X]T_<_T_5^4^T^?^G^C^/])^Q^8c=]H]7]6`S` ?] ;c >c E]._W[V\\\\9]4^J^9]4]%] ;]L]\"\n\" IZQZ  H]L] !u  ,`Sd9\\\\U\\\\   ,ZQZ,]E\\\\E]L]?]E\\\\M_S^>^G^F^G^F^G^F^G^F^G^F^G^F^K]:`R`C].].].].].].].]-]ObB]La?`S`>`S`>`S`>`S`>`S`?]J]CcS`?_R_=_R_=_R_=_R_8]6\"\n\"].]V[R^?_Tb>_Tb>_Tb>_Tb>_Tb>_Tb>_T^V_Q]M_R\\\\:`Q]=`Q]=`Q]=`Q]?].].].],_T_=]L]=_T_;_T_;_T_;_T_;_T_1^:`T_;^Sa=^Sa=^Sa=^Sa9_6aS^7_  Bi:i:i:i:i=]+`  I],] /[\"\n\",[-].]:]L]<h;]N]7`3q      \\\"h E] 7]S]=k5]LdIjW^ M],] /]:] 8]1](f9k?n?l/]<j6g7]1j<h9].] LZ PZ(]1]O`U]K]E]Cm8kBn?n?](nE]H]C].].]K^Am>]C]H]K`>kA])kA]J^Cm5\"\n\"]2j7_2`M`K^J]9]8tC])].]   PgX]>]Xf9h9fX]<k>],fX]?]L]?].].]O^=].]M]M]N]L]<h<]Xf9fX]?]/j9d4gX]:a3_P_D^O^7_8m4]4](]   RfXaBk=^V^3h;j<]L]8_9^L]>qA^U]W]U^D\"\n\"i<]O`?k=]Xg:h3a7f>uCn?]/eSe;]:]H]7]5k >] :a <a D]-h>n?\\\\H\\\\8]4]%] 9^R^   *^R^  Xu  ,q9\\\\U\\\\    /]D\\\\F]LfH]D\\\\Li>]E]F]E]F]E]F]E]F]E]F]E]F]JnIkBn?n?n?n?].].].\"\n\"]-n@]K`>k<k<k<k<k=[H[Co<j;j;j;j7]6].]Vf=gX]=gX]=gX]=gX]=gX]=gX]=gTjLh9k<k<k<k?].].].]+h<]L]<h9h9h9h9h Fk:gX]=gX]=gX]=gX]9_6]Xf6_  @e6e6e6e6e;]+_  G\\\\+[\"\n\" /].]-[,[9]L];e:^N^8`2p       e D] 7]S]<i4\\\\JbGgT^ M\\\\,\\\\ .]:] 8]1]'d8k?n>i-]<i4e6]0h;g8].]   I]0]3]E]Cl6h@l=n?]&jC]H]C].].]J^Bm>]C]H]K`<g?]'g?]I]Bj3]1h6\"\n\"_2_K_L^I^:]8tC])].]   OdV]>]Wd6f8dW]:i>]+dW]?]L]?].].]N^>].]M]M]N]L];f;]Wd7dW]?]/i7c3dV]9_2_P_E^M^8_8m4]4](]   QdV`B]Xe;d1f8h<]L]8_9]K]>]XdW_@eWeBg;]O\"\n\"`=g;]Vd8f1`6d=uCn?]/eSe;]:]H]7]3g <] 9_ :_ C]+f>n>ZFZ7]4]%] 7f   &f  Vu  ,]XdW_9\\\\U\\\\    /\\\\C\\\\F\\\\KfH\\\\C\\\\Kg=]E]F]E]F]E]F]E]F]E]F]E]F]JnHh@n?n?n?n?].].].]-l>\"\n\"]K`<g8g8g8g8g J]Vh:h9h9h9h6]6].]Ve;dV]<dV]<dV]<dV]<dV]<dV]<eRiJf7i:i:i:i?].].].]*f;]L];f7f7f7f7f F]Xe7dV]<dV]<dV]<dV]9_6]Wd5_  <\\\\-\\\\-\\\\-\\\\-\\\\6]+_  FZ*[ /]\"\n\".],Z+Z9]L]8`8]L]7^.m       W` A] 7\\\\R\\\\7b2]H^BaP_ O].] .]:\\\\ 7]2^%`6k?n:b*]9c/a5],b6b5].\\\\   H]/\\\\4]C]Di0b=h9n?]#c?]H]C].].]I_Dm>]C]H]J_9a<]$d?]I^?c0].b3_2\"\n\"_K_M^G^;]8tC](]/]   M`T]>]U`2b4`U]7c;])`U]?]L]?].].]M^?].]M]M]N]L]8`8]U`3`U]?],c2a0_T]9_2^N^F^K^8]7m4]4](]   O`R^B]Va8b-`3d:]L]7]9^J]?]V`T]>cUc?c9]N_:\"\n\"a8]T`3`-_4`<wDn?]/eSe;]:]H]7]0a 9] 8] 8] B])b<n @]4]&^ 5b   \\\"b  Tu  ,]V`T]8\\\\U\\\\    0].].]0b;]C]H]C]H]C]H]C]H]C]H^E^H^JnEb=n?n?n?n?].].].]-h:]J_9a2a2a2a\"\n\"2a G\\\\Rb4b3b3b3b3]6].]Vc7`T]:`T]:`T]:`T]:`T]:`T]:aMcEb2c4c4c4c<].].].]'`8]L]8`1`1`1`1` D]Ua2_T]9_T]9_T]9_T]8]5]U`2]      =]                       &[   \"\n\"O].]  E]  E]         ']    S]        R]      ^       (](]/]        C]  S]    '] V]      F^ 7]4](]   %])[  4]7] @])_Q_:] 9]6]                6[   S]0[R\"\n\"^           H]%\\\\U\\\\ A\\\\            @\\\\             /Z            <\\\\             ,[    M^5](^      =]                       &[   N]0]  D\\\\  D]         '\\\\  \"\n\"  Q^DZ       1]      _       )](]/]        D^  S]    '] V]      F] 6]4](]   %]   ;]7] @] /] 9]6]                6[   S]0g           H]%\\\\U\\\\ @\\\\         \"\n\"   @\\\\                          J\\\\                  X]4](]      <]                       &[   N]0]  D\\\\  E^         '\\\\    P^G]       2]      X^       )]\"\n\"(^0]        D]  R]    '] V]      G^ 6]4](]   %]   ;]7] @] /] 9]6]                6[   S]0e           F]%\\\\U\\\\ ?[            ?[                          \"\n\"I[                  ^4])^      @ZV]                       &[   M]2]  D]  E]         ']    O_K_       3]      V^       *b,]5b        E^  R]    '] V]   \"\n\"   G^ 6^5])^   %]   ;]7] @] /] 9]6]                6[   S].a           D]%\\\\U\\\\ ?\\\\            @\\\\                          J\\\\                 !^4])^     \"\n\" B\\\\V]                       &[   M]2]  D\\\\            G\\\\    L`P`       2]      U^       +b =b        RZN^  R^    '] V]      H^ 4^6]*^   $]   ;]7] @] /]\"\n\" 9]6]                6[   S]            J]  :\\\\            @\\\\                          J\\\\                 \\\"^3]*^      A\\\\V\\\\                       %[   L\"\n\"]4]                   Vm       2^      S^       ,b =b        R\\\\Q_  R]    &] V]      I^ 3b:].b   $]   ;]7] @] /] 9]6]                6[   S]           \"\n\" J]  @ZU]            FZU]                          PZU]                 #^2]+^      @b                       %[                       Si       4b     \"\n\"                  %i  Ua    &] V]      Mb 2a:].a   #]   ;]7] @] /] 9]6]                   .]            J]  @b            Fb                          \"\n\"Pb                 'b2]       E`                                               Qb       1a                       $g  S`    %] V]      Ma /_:]._   !]  \"\n\" ;]7] @] /] 9]6]                   .]            J]  @a            Ea                          Oa                 &a1]       D^                       \"\n\"                                X^                 Ip      Fc  Q^    #] V]      M_  A]    )]   ;]7] @] /] 9]6]                                T]  @`  \"\n\"          D`                          N`                 %_/]       BZ                                                                        Ap      \"\n\"                 6]                                                                                                                                   \"\n\"                                                        p                       6]                                                                    \"\n\"                                                                                                                                                      \"\n\"                                                F]']2]    +]']2^ D]']3_   E]']1]   \\\"]']2^ 8]                             H\";\n\n    // Define a 90x103 font (huge size).\n    static const char *const _data_font90x103[] = {  // Defined as an array to avoid MS compiler limit about constant string (65Kb).\n      // Start of first string.\n\"                                                                                                                                                      \"\n\"                                                                                                                                                      \"\n\"                                                                        HX     4V         >X       IX           *W             FW                     \"\n\"                                                                                                                                                      \"\n\"                                                                                                                                                      \"\n\"                                                                                                                     HX  W 4Z 3VCT   <Z     >X  W 4Z  \"\n\" HX  W 4Z     'VCT ;X  W 3Y 2UCT       KX  W 3Y   0W                                                                                                  \"\n\"                                                                                                                                                      \"\n\"                                                                                                                                                      \"\n\"                                    @W !W 4\\\\ 5YET ?XHX 8]     >W !W 4\\\\ 7XGX KW !W 4\\\\ 7XHX   +YET :W !W 3[ 5ZFT ?XGX     EW !W 3[ 7XGX 5W              \"\n\"                                                                                                                                                      \"\n\"                                                                                                                                                      \"\n\"                                                                                                                        >W \\\"V 3\\\\ 7]HU ?XHX 9`     ?W \\\"\"\n\"V 3\\\\ 7XGX JW \\\"V 3\\\\ 7XHX   -]HU 9W \\\"V 3] 7]HT ?XGX     DW \\\"V 3] 8XGX 5V                                                                                \"\n\"                                                                                                                                                      \"\n\"                                                                                                                                                      \"\n\"                                                      <W $V 3VNV 8_KV ?XHX 9`     >W $V 3VNV 8XGX IW $V 3VNV 8XHX   -_KV 8W $V 2] 7_KU ?XGX     CW $V \"\n\"2] 8XGX 6V                                                                                                                                            \"\n\"                                                                                                                                                      \"\n\"                                                                                                                                                :W &W \"\n\"4VLV :j >XHX :VJV     >W &W 4VLV 9XGX HW &W 4VLV 9XHX   .j 6W &W 3VMV 9i >XGX     BW &W 3VMV 9XGX 7W               MW                                 \"\n\"                                                                                                                                                      \"\n\"                                                                                                                                                      \"\n\"                                                                                      CV 'W 4VJV ;j >XHX ;UGV     >V 'W 4VJV :XGX GV 'W 4VJV :XHX   .j\"\n\" 5V 'W 3VKV :i >XGX     AV 'W 3VKV :XGX 8W               N[                                                                                           \"\n\"                                                                                                                                                      \"\n\"                                                                                                                                                      \"\n\"                            DV )W 4VHU <VK_ =XHX ;TEU     =V )W 4VHU :XGX FV )W 4VHU :XHX   /VK_ 3V )W 3VIV <UK_ =XGX     @V )W 3VIV ;XGX 9W          \"\n\"     N]                                                                                                                                               \"\n\"                                                                                                                                                      \"\n\"                                                                                                                              DV *V 3UFU =UH\\\\ <XHX <UD\"\n\"T     <V *V 3UFU ;XGX EV *V 3UFU ;XHX   /UH\\\\ 1V *V 2UGU <TH] =XGX     ?V *V 2UGU ;XGX 9V               a                                              \"\n\"                                                                                                                                                      \"\n\"                                                                                                                                                      \"\n\"                                                                         EV ,V 3UDU >TEY ;XHX <TBT     <V ,V 3UDU <XGX DV ,V 3UDU <XHX   /TEY /V ,V 2U\"\n\"EU =TFZ <XGX     >V ,V 2UEU <XGX :V               Na                                                                                                  \"\n\"                                                                                                                                                      \"\n\"                                                                                                                                                      \"\n\"                     DU -V 3VDV ?TCV :XHX <TBT     ;U -V 3VDV =XGX CU -V 3VDV =XHX   /TCV -U -V 2UCU >TCU :XGX     =U -V 2UCU =XGX ;V               NV\"\n\"IV                                                                          \\\"W                                                                        \"\n\"                                                                                                                                                      \"\n\"                                                                                                                          JU /V 3VBV     ETBT     :U /\"\n\"V 3VBV   FU /V 3VBV       (U /V 2UAU         DU /V 2UAU   @V               NVGV                                                                       \"\n\"   $X                                                                                                                                                 \"\n\"              *X                                                                                                                                      \"\n\"                           JX                                GTBT                                                   MX  GX 7V     :UEU     DX  GX 7V  \"\n\" JX  GX 7W       4X  GX 6V         GX  GX 5V   (X                            &X                                                                       \"\n\"                                                                                        )X                                                     8V     \"\n\"                                                                                                      ;X                                FTBT          \"\n\"                                         LX  IX 7X     <UCU     DX  IX 7X   JX  IX 6W       3X  IX 6X         GX  IX 5X   *X                          \"\n\"  &Y                                                                                                                                                  \"\n\"             (X                                                     9V                                                                                \"\n\"                           <X                                ETBT                                                   KX  KX 6X 1TBT   BTAT     CX  KX 6\"\n\"Y   JX  KX 6Y     (TBT BX  KX 5X 1TBT       LX  KX 4X   +X                            %T                                                    #W 9W     \"\n\"                                                                                          3a   :a     <W   2W    >W   E\\\\   AW ,W ,W ,W ,W             \"\n\"                HY GV +Y         4Z           NX                 @X                                                                  %W               \"\n\"                 DUDU                                                 =Y 7W  KW 6Z 4XDT   BTAT     BW  KW 6Z   IW  KW 6[   ,Y )XDT AW  KW 5Z 4XDT     \"\n\"  KW  KW 4Z   ,W BW                 8V         (S                                             <S       9V 7V                                          \"\n\"                                                     3a   :a     ;W   3W    >W   H_   AW ,W ,W ,W ,W                             L] GV +]         ;a  \"\n\"        #[                 F^                                           8XGX                      +W                                BTEU              \"\n\"                      *R            9a :W  MW 6\\\\ 6ZET ?XHX <TAT     AW  MW 6\\\\ 7XGX LW  MW 5[ 7XGX .Y +ZET @W  MW 5\\\\ 6ZET ?XHX     DW  MW 4\\\\ 7XHX 0W AW\"\n\" &XHX               MZ         +T                                   $Y         BS 1W,V MY   8W 7W  T           9X   5Z /[     0Z   8Z /Y           GY \"\n\"      .\\\\       <\\\\               [   4[   :\\\\              -a   :a     :W   4W    >W   Ja   AW ,W ,W ,W ,W                             N_ GV +_         \"\n\"?e   8]       J]                 Jb       8[       <[                  $Y       FY 7XGX   =Z         Di 5W   8Z .Y !W         FW *Y   4W)V*W)V-Y(V    \"\n\"        <UFU   3\\\\                    +[ 0[ 0[ 0[ 0[   4[=T            <e ;W  W 5\\\\ 7\\\\FT ?XHX <TAT     @W  W 6^ 8XGX KW  W 5] 8XGX .Z@R ?\\\\FT ?W  W 4\\\\ 7\\\\\"\n\"FT ?XHX     CW  W 3\\\\ 7XHX 1W @W &XHX               N\\\\         ,T     :U :U5U                            `   EX 2VFV   .S 4]0W\\\"b DV  V 5V  T         7W\"\n\" .` 3[ 7c 8d )Z Dq 8b Hy Bb 7`           Na   /Z @k .d Kj ?x Mt 7f MX/X'X -X -X2Z&X -]0]0[3X Dc Ii -c Ij 4f N~W$X/X.X&X.X4Y4XDY/Y/Y,Y'~S%a >W $a  MY  \"\n\" EW   5W    >W   Kb   AW ,W ,W ,W ,W                            !a GV +a         Ch   =f       ^                 Mf 2Z @x Mx <c 3X C~Q)X?X?X Kc   2T  \"\n\" .V   .T   CX   $a  !W.W   N` ;XGX ![ Lb       &Z Mi 7[   >a 5a &W   0g    #\\\\ -_   <\\\\*V.\\\\*V0a-V\\\"X )Z /Z /Z /Z /Z 4WJV 1~U+d Kx Mx Mx Mx MX -X -X -X ,j\"\n\" @[3X Dc 8c 8c 8c 8c   <cBV.X/X'X/X'X/X'X/X/Y,Y$X &h ;W \\\"W 5VNV 8]HU ?XHX <TAT     ?W \\\"W 5VNV 8XGX JW \\\"W 5VMV 9XGX -ZDV @]HU >W \\\"W 4VNV 8]HU ?XHX     \"\n\"BW \\\"W 3VNV 8XHX 2W ?W &XHX               ^ K~\\\\       >S   3Q +[ @[;[ ;Q                          ;e   HX 2VFV #VBV FS 6`1V#g GV !V 3V !T         7W 0d\"\n\" :` ;j ?k -[ Dq :g Ky Df ;d          $f   1Z @o 5j Np Ex Mt :m\\\"X/X'X -X -X3Z%X -]0]0\\\\4X Gi Lm 4i Ln ;m#~W$X/X-X(X-X4Y4XCY1Y-Y.Y&~S%a >W $a  N[   EV   \"\n\"5W    >W   Lc   AW ,W ,W ,W ,W                            \\\"b GV +a         Dk   Aj      \\\"_                 h 3Z @x Mx ?i 6X C~Q)X?X?X Ni   6V   /V   /\"\n\"V   DX   &f  #W0W   e >XGX %c#e       +b\\\"i 9_   Be 9d 'V   3k    %^ /c   @^*V0^*V2d.V\\\"X )Z /Z /Z /Z /Z 3b 1~U.j Nx Mx Mx Mx MX -X -X -X ,p F\\\\4X Gi >i \"\n\">i >i >i   BiEV.X/X'X/X'X/X'X/X.Y.Y#X 'j ;V \\\"V 5VLV :_IT >XHX <TAT     >V \\\"V 5VLV 9XGX IV \\\"V 4VMV 9XGX ,ZHY A_IT <V \\\"V 4VLV :_IT >XHX     AV \\\"V 3VLV 9\"\n\"XHX 2V >W &XHX              !_ K~[       >T   4R -_ D_?_ >S         =t                Fh   IX 2VFV #VBV FS 7c4V#i HV \\\"W 3V !T         7V 0f @e >o Co 0\"\n\"\\\\ Dq <j Ly Fj ?h          (i  \\\\ ?Z @r :o\\\"s Hx Mt <q$X/X'X -X -X4Z$X -]0]0\\\\4X Im Np 9m Np ?q%~W$X/X-X(X,W5[6XAX1X+X.X%~S%a =V $a  ]   EV   6W    >W   M\"\n\"d   AW ,W ,W ,W ,W               HW             1b GV +b         Fm   Dm      #`                \\\"j 4Z @x Mx Am 8X C~Q)X?X?X!m   9X   0V   0X   EX   'h\"\n\"  $W0W  \\\"h ?XGX 'g%g       0h%i :a   Cf :f *V   4m    %^ 0e   A^+V/^+V1f1V!X )Z /Z /Z /Z /Z 2` 1~V0o\\\"x Mx Mx Mx MX -X -X -X ,t J\\\\4X Im Bm Bm Bm Bm   F\"\n\"mHV-X/X'X/X'X/X'X/X-X.X\\\"X (l ;V $V 4UJU :ULXLU >XHX <UCU     =V $V 5VJV :XGX HV $V 4VKV :XGX +ZL\\\\ AULXLU ;V $V 3UJU :ULXLU >XHX     @V $V 2UJU 9XHX 3V\"\n\" =W &XHX              !` K~Z       >T   4S /a FaAa @T         @w                Hl   KX 2VFV $WCV ES 8e5V$j HV \\\"V 1V \\\"T         7V 2j Eh ?q Dp 1\\\\ Dq >\"\n\"l Ly Hn Bj          +l %e E\\\\ At >s$v Kx Mt >u&X/X'X -X -X5Z#X -^2^0]5X Jo q ;o r Br%~W$X/X-X(X,X6[6XAY3Y+Y0Y%~S%W 3V  IW !_   FW   7W    >W   Md   AW \"\n\",W ,W ,W ,W               HW             2[ ?V #[         Hn   En      #`                #l 6\\\\ Ax Mx Cp 9X C~Q)X?X?X\\\"o   ;Z   1V   1Z   FX  KS 0i  #W2\"\n\"W LV ,i ?XGX *l'h       3l'i ;c   Dg ;g ,W   6o    %^ 1g   B^,V.^,V0g3V X *\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 2^ 0~V2s$x Mx Mx Mx MX -X -X -X ,v L]5X Jo Do Do Do Do   HpKW\"\n\"-X/X'X/X'X/X'X/X-Y0Y\\\"X )n <W &W 5VJV ;TI_ >XHX ;UEU     <W &W 5VIV ;XGX HW &W 5VIV ;XGX *g ?TI_ ;W &W 4VJV ;TI_ >XHX     @W &W 3VJV :XHX 4W =W &XHX   \"\n\"  1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ =XMV K~Y       =S   4U 1c IdCc AU         Dz                In   LX 2VFV $VBV ES 9g7V$k HV #W 1W #T         8W 3l Fh ?r Eq 3] Dq ?m L\"\n\"y Ip Em          -n )k H\\\\ Au Av%x Mx Mt ?x(X/X'X -X -X6Z\\\"X -^2^0]5X Ls\\\"s ?s\\\"s Et%~W$X/X,X*X+X6[6X@Y5Y)Y2Y$~S%W 3W  JW \\\"a   FW   8W    >W   NZ   6W ,W \"\n\",W ,W ,W               HW             2X <V  X         H[G[   Go       KZ                %[H[ 7\\\\ Ax Mx Ds ;X C~Q)X?X?X$s   >\\\\   2V   2\\\\   GX  KS 1j  #\"\n\"W2W LV -j ?XGX +ZEZ)VGY       5ZDZ)i <e   EUFY <UFX -W   7q    %VMU 2YIY   CVMU,V.VMU,V0UFX3V X *\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 1\\\\ 0~W4v%x Mx Mx Mx MX -X -X -X ,x N]5X\"\n\" Ls Hs Hs Hs Hs   LsMW,X/X'X/X'X/X'X/X,Y2Y!X *\\\\G[ <W (W 4UHU <UH] =XHX ;VGV     ;W (W 5VHV ;XGX GW (W 4UGU ;XGX )c =UH] 9W (W 3UHU <UH] =XHX     ?W (W\"\n\" 2UHU :XHX 5W <W &XHX     5c 8c 8c 8c 8c @WKU J~X       >T   5V 2e KfEe CW         G|                Jp   MX 2VFV $VBV ES 9XIX8V$l HV #V /V #T        \"\n\" 8V 3n Gh ?s Fr 5^ Dq @n Lx Ir Go          .o -q L^ Bv Cx&z x Mt A{)X/X'X -X -X7Z!X -^2^0^6X Mu#t Au#t Gu%~W$X/X,X*X+X6[6X?X5X'X2X#~S%W 2V  JW #c   FW\"\n\"   9W    >W   NX   4W ,W ,W ,W ,W               HW             2W ;V  NW         IZCY   Hp       JY                &ZDZ 9^ Bx Mx Eu <X C~Q)X?X?X%u   @\"\n\"^   3V   3^   HX  KS 2k  \\\"W4W KV -ZGW ?XGX -X=X+R@W       8X<X  .XIX   FQ@W <Q@W /W   7dGU    %QHU 3XEX   DQHU-V-QHU-V/Q@W5V NX +^ 3^ 3^ 3^ 3^ 2\\\\ 0~W5\"\n\"x&x Mx Mx Mx MX -X -X -X ,z!^6X Mu Ju Ju Ju Ju   N}+X/X'X/X'X/X'X/X+X2X X +ZBY ;W *W 4UFU =TF\\\\ =XHX :VIV     9W *W 5VFV <XGX FW *W 4VGV <XGX (_ :TF\\\\ 8\"\n\"W *W 3UFU =TF\\\\ =XHX     >W *W 2UFU ;XHX 6W ;W &XHX     7h =h =h =h =h DWJV K~X       >T   5W 4g MgFg EY         J~                K]FZ   MX 2VFV $VBV \"\n\"ES :XGX9V%\\\\GX HV $W /W 3PATAP         GV 3[H[ Gh ?]F] GZE^ 6^ Dq A]FX Lx I\\\\F\\\\ G\\\\G[          /[H] 0u N^ Bw E_D^&{!x Mt B`C_)X/X'X -X -X8Z X -_4_0_7X N^\"\n\"E^$u C^E^$u H^E\\\\%~W$X/X,Y,Y*W7]8X>Y7Y'Y4Y#~S%W 2V  JW $e   FV   9W    >W   NW   3W ,W ,W ,W ,W               HW             2W ;V  NW         IY@X >X \"\n\"4[AV       IX                &X@X 9^ Bx Mx F^E^ =X C~Q)X?X?X&^E^   B`   4V   4`   IX  KS 3\\\\GW  \\\"W4W KV .YBT ?XGX .V7V,P=W       :W8W  /VEV   3V +V /V \"\n\"  7eGU     KU 3WCW   ;U-V$U-V LV5V NX +^ 3^ 3^ 3^ 3^ 3^ 1~W6_D^&x Mx Mx Mx MX -X -X -X ,{\\\"_7X N^E^ L^E^ L^E^ L^E^ L^E^  !^Ed*X/X'X/X'X/X'X/X+Y4Y X +Y?\"\n\"X ;V *V 4UDU >TEZ <XHX 9a     7V *V 4UDV =XGX EV *V 4VEV =XGX )] 7TEZ 6V *V 3UDU >TEZ <XHX     =V *V 2UDU <XHX 6V :W &XHX     9k @k @k @k @k EWJV K~W \"\n\"      >T   5Y 5g MhHi G[         M~Q                L\\\\AW   MX 2VFV $VCV DS :WEW:V%ZAU HV $V -V 3RCTCR         HW 4ZDZ H\\\\LX ?Y?[ HV>\\\\ 8_ DX )[?T -Y J[B\"\n\"[ I[CZ          0WAZ 2x ^ BX>^ G]=Z&X=b#X -X '];[)X/X'X -X -X:[ NX -_4_0_7X \\\\?\\\\%X@^ E\\\\?\\\\%X?] J[=X =X <X/X+X,X)X8]8X=Y9Y%Y6Y )Y$W 2W  KW %ZMZ   FV   :W\"\n\"    >W   X   3W     4W ,W               HW             3X ;V  NX         KY?X Ca 9Y:R       HX                (X>X :VNV BZ /X '\\\\?\\\\ A^ FX0X)X?X?X'\\\\?\\\\  \"\n\" Db   5V   5b   JX  KS 3ZBT  !W6W JV .X?R   4V4U HV       ;V4V  1VCV   4V *U 0V   7fGU     KU 4WAW   <U.V#U.V JU6V MX +^ 3^ 3^ 3^ 3^ 3^ 2XIX F]=Z&X -X\"\n\" -X -X -X -X -X -X ,X=b$_7X \\\\?\\\\ N\\\\?\\\\ N\\\\?\\\\ N\\\\?\\\\ N\\\\?\\\\  #\\\\?`)X/X'X/X'X/X'X/X*Y6Y NX ,Y=W :V ,V 3UDU >TDX   ;a     6V ,V 4UBU   GV ,V 3UCU   0` 6TDX 4V ,V\"\n\" 2UDU >TDX       >V ,V 1UDU   :V 9W       (o Do Do Do Do GWIU J~V       >T   6Z 6i jIj I\\\\         N~R                M[=U   MX 2VFV %VBV H] AWCW;V%Y=R\"\n\" HV %W -V 4UETEU         IV 4ZBZ IWGX ?V;[ IS9Z 9VNX DX *Z;R -X JZ>Y JZ?Y          1U>Z 5`C_#` CX;[ H[7W&X9_$X -X (\\\\6X)X/X'X -X -X;[ MX -_4_0`8X![;[&X\"\n\"=[ F[;[&X<[ LZ8U =X <X/X+X,X)X8]8X<X9X#X6X )Z$W 1V  KW &ZKZ   FV   ;W    >W   W   2W     4W ,W               HW             3W :V  MW         KX=W Cc \"\n\";X7P       HX                (W<W ;WNW BY /X ([;[ Gg JX0X)X?X?X([;[   Fd   6V   6d   KX  KS 4Y>R  !X8X JV /X<P   6V1U IV       <U0U  2UAU   3U *U 1V  \"\n\" 6fGU     KU 4V?V   <U/V\\\"U/V IU7V LX ,` 5` 5` 5` 5` 5` 3XIX G[7W&X -X -X -X -X -X -X -X ,X9_%`8X![;[![;[![;[![;[![;[  %[;](X/X'X/X'X/X'X/X)X6X MX ,X;W\"\n\" :V .V 3UBU ?TBT   7]     3V .V 4VAU   GV .V 3UAU   4d 7TBT 1V .V 2UBU ?TBT       ;V .V 1UBU   <V 8W       )r Gr Gr Gr Gr IVHR GX+W       =S   5[ 7i!k\"\n\"Jk I]        !^                )Y:T   MX 2VFV %VBV Le EVAV<V$X:P HV %W -W 6WFTFV         IV 4X?Y IRBX ?T7Y IP5Z :VNX DX +Z8P .Y JY<Y KY=X          1S;\"\n\"Y 6];\\\\$WNW CX9Z J[4U&X6]%X -X )[2V)X/X'X -X -X<[ LX -XNV6VNX0`8X\\\"Z7Z'X;Z HZ7Z'X;Z LY4R =X <X/X*X.X(X8]8X<Y;Y#Y8Y *Z#W 1V  KW 'ZIZ   FV   <W    >W   W \"\n\"  2W     4W ,W               HW             3W :V  MW         KW<X Dd <W       -W                )W;X <WNW AY 0X )Z7Z Jl MX0X)X?X?X)Z7Z   Hf   7V   7f\"\n\"   LX  KS 4X;P   W8W IV /W   \\\"V.U JV       >U.U  4VAV &V 5U *U 2V   6gGU     KU 5W?W   =U/V\\\"U/V IU7V LX ,WNW 5WNW 5WNW 5WNW 5WNW 5WNW 4XHX H[4U&X -X -\"\n\"X -X -X -X -X -X ,X6]&`8X\\\"Z7Z#Z7Z#Z7Z#Z7Z#Z7Z  'Z8['X/X'X/X'X/X'X/X)Y8Y MX ,W:W 9V 0V 3U@U     ?[     1V 0V 3U@V   GV 0V 3U?U   8h   1V 0V 2U@U       \"\n\"  CV 0V 1U@U   >V 7W       *`L` I`L` I`L` I`L` I`L` JV =X,X       >T   6] 9k\\\"lKl K_        #\\\\                'Y8S   MX 2VFV %VBV Nk IVAV=V$X 1V %V +V \"\n\"6YHTHY -V       EW 5Y>Y :X ?R5Z .Y ;VMX DX +Y  DX IY<Y LY;X          2Q8Y 8[5[&WNW CX8Y KZ1T&X4\\\\&X -X *Z.T)X/X'X -X -X=[ KX -XNV6VNX0a9X#Z5Z(X:Y IZ5Z(\"\n\"X:Z NY1P =X <X/X*X.X'W9WNV:X:Y=Y!Y:Y *Z\\\"W 1W  LW (ZGZ      -W    >W   W   2W     4W ,W               HW             3W :V  MW         KW;W De =W      \"\n\" -X                *W:W <VLV @Y 1X *Z5Z Mp X0X)X?X?X*Z5Z   Jh   8V   8h   MX  KS 5Y   :X:X IV /W   #U+T JV       ?U+T  5U?U &V 5U +V     AgGU     KU 5\"\n\"V=V   =U0V!U0V IV8V KX ,WNW 5WNW 5WNW 5WNW 5WNW 5WNW 4XHX IZ1T&X -X -X -X -X -X -X -X ,X4\\\\'a9X#Z5Z%Z5Z%Z5Z%Z5Z%Z5Z  )Z5Z(X/X'X/X'X/X'X/X(Y:Y LX -X:W  \"\n\"        !W                    2\\\\LZ                          EW       +[@[ K[@[ K[@[ K[@[ K[@[ KV <X-X     /P 0T   7^ 9k\\\"lLm La        %Z              \"\n\"  %Z6Q   MX 2VFV %VCV n KWAW>V$X 1V &W +W 5XITIX +V       EV 4X<X :X ?P2Y -X <WMX DX ,Y  CX JY:Y MX9W          2P7Y :Z0Z(WLW DX7X KY.R&X2Z&X -X *Y+R)X\"\n\"/X'X -X -X>[ JX -XNW8WNX0a9X#Y3Y(X9Y JY3Y(X9Y NX  LX <X/X*X.X'X:VMV:X9X=X NX:X *Z!W 0V  LW )ZEZ      .W    >W   W   2W     4W ,W               HW     \"\n\"        3W :V  MW         LX;W Df >W       ,W                +W8W >WLW @Y 2X +Z3Z!t\\\"X0X)X?X?X*Y3Y   Kj   9V   9j     AS 5X   8W:W HV /W   #T)T KV     \"\n\"  @T(T  6U?U &V 5T +V     AhGU     KU 5V=V   =U0V!U0V JV7V   WLW 7WLW 7WLW 7WLW 7WLW 7XNX 6XGX IY.R&X -X -X -X -X -X -X -X ,X2Z'a9X#Y3Y%Y3Y%Y3Y%Y3Y%Y3\"\n\"Y  )Y3Z)X/X'X/X'X/X'X/X'X:X Ki >W8V                               *XHZ                          FW       ,Z<Z MZ<Z MZ<Z MZ<Z MZ<Z LV <X.X     .R 2S   \"\n\"7` :k#nMm Mb        &Z                $Y4P   MX 2VFV &VBV!o KV?V?V#W 0V &V )V 3XKTKX )V       EV 5X:X ;X  X -Y =VLX DX -Y  CY JY:Y NY9X           HX ;\"\n\"Z-Y)WLW DX7Y MY,Q&X1Z'X -X +Y)Q)X/X'X -X -X?[ IX -XMV8VMX0XNX:X$Y1Y)X9Y KY1Y)X8X NX  LX <X/X)X0X&X:VMV:X9Y?Y NY<Y *Y W 0V  LW *ZCZ      /W    >W   W  \"\n\" 2W     4W ,W               HW             3W :V  MW         LW:W Dg ?W       ,X                ,W8W >WLW ?Y 3X +Y1Y\\\"v#X0X)X?X?X+Y1Y   MYNVNY   :V   :\"\n\"YNVNY     BS 5X   8X<X HV /W   $T?ZBT*c       AT&T  7U?U &V 6U -W     @hGU     KU 6V;V   >U1V U1V KW7V   NWLW 7WLW 7WLW 7WLW 7WLW 7WLW 6XGX JY,Q&X -X \"\n\"-X -X -X -X -X -X ,X1Z(XNX:X$Y1Y'Y1Y'Y1Y'Y1Y'Y1Y P)P$Y3[)X/X'X/X'X/X'X/X'Y<Y Km BW8W                               +UDZ               7P          1W  \"\n\"     -Y8Y Y8Y Y8Y Y8Y Y8Y MV ;W.X     /T 4T   7a ;k#nMn Nc 6P :W4W ?Z ?X6X KY                #Y   0X 2VFV &VBV\\\"p KV?V?V#W 0V 'W )W 2XMTMX 'V       FW \"\n\"5X:X ;X  Y -X >VKX DX -X  BX IX8X NX7W      KP  1P  =X <Y)X+XLX EX6X NY*P&X0Z(X -X ,Y'P)X/X'X -X -X@Z GX -XMV8VMX0XNX:X%Y/Y*X8X LY/Y*X8Y!X  KX <X/X)X0\"\n\"X&X:VMV:X8YAY LY>Y *Z W 0W  MW +ZAZ      0W    >W   W   2W     4W ,W               HW             3W :V  MW         LW:W DSF[ @X       -X             \"\n\"   -X8W ?WJW ?Y 4X ,Y/Y%z%X0X)X?X?X,Y/Y   YMVMY   ;V   ;YMVMY     CS 5X 5P*Q JW<W GV /W   %TBbET/g       BTGb?T  8U?U &V 7U 5_     ?hGU     KU 6V;V   \"\n\">U2V NU2V$_7V   NXLX 9XLX 9XLX 9XLX 9XLX 8WLW 6XGX KY*P&X -X -X -X -X -X -X -X ,X0Z)XNX:X%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y\\\"R+R&Y3]*X/X'X/X'X/X'X/X&Y>Y Jp EW:Y     \"\n\"                          +R@Y               7Q          2W       .XEVFY\\\"X5Y\\\"X5Y\\\"X5Y\\\"X5Y NV ;X/X     0V 5T   8c <k#nNo e >^ AW4W ?Z >W6W KY           \"\n\"     \\\"Y   0X 2VFV &VCW#[LSKZ KV?V@V\\\"W 0V 'W )W 1XNTNX &V       FW 6Y:Y <X  NX -X ?WKX DX .Y  CY IX8X NX7W      NS  1S  @X =X&X,WJW EX6X NY /X/Y(X -X ,\"\n\"Y /X/X'X -X -XAZ FX -XMW:WMX0XMX;X%Y/Y*X8Y MY/Y*X8Y!X  KX <X/X)Y1X%W;WMW;W6XAX JX>X *Z NW 0W  MW ,Z?Z      1W    >W   W   2W     4W ,W               H\"\n\"W             3W :V  MW         LW:W DPAY ?Y       .W                -W6W @WJW >Y 5X ,X-X&_MXM_&X0X)X?X?X,Y/Y  !YLVLY   <V   <YLVLY     DS 6Y 6R,R JX>\"\n\"W FV /X   'TCfFT2i       CUGfBT  9U?U &V 7U 5]     >iGU     KU 6V;V   >U2V NU2V$]5V   NWJW 9WJW 9WJW 9WJW 9WJW 9WJW 8XFX KY /X -X -X -X -X -X -X -X ,X\"\n\"/Y)XMX;X%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y#T-T'Y3]*X/X'X/X'X/X'X/X%X>X Ir GW=\\\\                                GY               9S          3W       /XDVDX$X2X$X2X$X\"\n\"2X$X2X V ;X0X     0X 7T   8d <k#~`!g Bd DW4W ?[ ?X7W LY                !X   /X 2VFV &VCV#ZJSGV KV?VAV!W 0V 'V 'V /d $V       FV 5X8X <X  NX -X ?VJX DX\"\n\" .X  BX HX8X Y7X     #V  1V  CX >X$X-WJW EX6X Y .X.Y)X -X -Y .X/X'X -X -XBZ EX -XLV:VLX0XMX;X&Y-Y+X7X NY-Y+X7X!X  KX <X/X(X2X$X<VKV<X6YCY JY@Y +Z MW /\"\n\"V  MW -Y;Y    \\\"Z ;WDX 0Z 2XDW >Z <W !X :WDY     IW ,W  HX8X MY 3Z *X 3X &X 7] <W             3W :V  MW       ;X :W:W 4Y @[ )\\\\ (Y   6X     8QEV     :[ \"\n\"    JW6W @VIW =Y 6X -Y-Y(]JXJ]'X0X)X?X?X-Y-Y  #YKVKY   =V   =YKVKY     IZ 9X 6T.T JW>W FV .X   (TDgFT3j       CTFhDT  9U?U &V 8U 4\\\\     =iGU     KU 6V\"\n\";V   >U3V MU3V#\\\\5V   MWJW 9WJW 9WJW 9WJW 9WJW 9WJW 8XFX LY .X -X -X -X -X -X -X -X ,X.Y*XMX;X&Y-Y+Y-Y+Y-Y+Y-Y+Y-Y%V/V)Y3_+X/X'X/X'X/X'X/X%Y@Y Is HW?^ \"\n\"?Z /Z /Z /Z /Z /Z /Z6Y NZ 0Z /Z /Z /Z         8Y 1Y 3Z /Z /Z /Z /Z   3ZCV          5WDX       DXCVCW%X0W%X0W%X0W%X0W V :X1X     0X 7T   9f =k#~`\\\"h Cf \"\n\"EW4W @\\\\ ?X8X LX                !Y   /X 2VFV 'VBV#XHSET KV?VAV!W 0V (W 'W .` \\\"V       GW 5X8X <X  NX -X @VIX DX .X  BX HX8X X5W     &Y  1Y  FX >W\\\"W.XJX\"\n\" FX6X X -X.Y)X -X -X -X/X'X -X -XCZ DX -XLV:VLX0XLX<X&X+X+X7X NX+X+X7X!X  KX <X/X(X2X$X<VKV<X5YEY HYBY +Z LW /W  NW .Y9Y    'b ?WG^ 7b 9^GW A` Gl 2_GW\"\n\" MWG_ DW ,W ,W8Y MW ,WG^>^4WG_ 9` @WG^ 9^GW MWG\\\\ ;f Gm <W6W#X2X#W;X;W5Y7Y#W1X\\\"u 6W :V  MW       >^BV\\\"W:W 3X ?^ 0e AWG_ KV.X ?X <W6W   HTG[ K}!WCWCW Ca\"\n\" 7p&{ NW6W AWHW >Z 7X -X+X)\\\\HXH\\\\(X0X)X?X?X-X+X  $YJVJY   >V   >YJVJY     Ma =X 7V0V JW@W EV .Y   *TEiET5k       DTEiDT  :VAV &V 9U 3_   ;W6W NiGU     \"\n\"KU 6V;V   >U3V MU3V#_8V   NXJX ;XJX ;XJX ;XJX ;XJX ;XJX :XEX LX -X -X -X -X -X -X -X -X ,X.Y*XLX<X&X+X+X+X+X+X+X+X+X+X&X1X*X3`+X/X'X/X'X/X'X/X$YBY Ht \"\n\"IW@_ Cb 7b 7b 7b 7b 7b 7b>a'b 7` 5` 5` 5` AW ,W ,W ,W  DY EWG_ 9` 5` 5` 5` 5` (Z <`GV W6W MW6W MW6W MW6W#W1X NWG^ HW1X     NWBVBW&W.W&WJP:PJW&W4PJW&W.\"\n\"W!V :X2X     0X 6S   8g >k#~`#j Fj GW4W @\\\\ >W8W LX                 X   .X 2VFV 'VBV$XGSCR KV?VBV X 1V (W 'W ,\\\\  V       GW 5X8X <X  NX -X AWIX DX /X  \"\n\"BY HX8X X5W     ([  1[  HX ?W W/WHW FX6X!Y -X-Y*X -X .Y -X/X'X -X -XDZ CX -XLW<WLX0XKW<X'Y+X+X7X Y+X+X7X!X  KX <X/X'X4X#X<VKV<X4XFY FXBX *Y KW /W  NW \"\n\"/Y7Y    +g AWIb ;f =bIW De Il 3bIW MWIc FW ,W ,W9Y LW ,WIbBb6WIc >f CWIb =bIW MWI^ =j Im <W6W\\\"W2W\\\"W<Z<W4X7X!W2W!u 6W :V  MW       @bEW\\\"W:W 2X @c 8j CW\"\n\"Ic MX0W =W <W6W IW/W\\\"VI^ L}!WCWCW Ee =t&{ W4W BWHW =Y 7X .X*Y*ZFXFZ(X0X)X?X?X.Y+X  #WIVIW   =V   =WIVIW     f ?X 8X2X KW@W EV .Z   +SE[GVDS6ZDV       \"\n\"DSDVDXDS  9UAU %V :U 2`   <W6W NiGU     KU 6V;V   >U4V LU4V\\\"`:V GX /WHW ;WHW ;WHW ;WHW ;WHW ;WHW :XEX MY -X -X -X -X -X -X -X -X ,X-Y+XKW<X'Y+X,Y+X,Y+\"\n\"X,Y+X,Y+X'Z3Z,Y4WNY,X/X'X/X'X/X'X/X#XBX Gu JWB\\\\ Ag <g <g <g <g <g <gBe+f <e :e :e :e CW ,W ,W ,W  Mc FWIc >f ;f ;f ;f ;f +Z >eJU NW6W MW6W MW6W MW6W\\\"W\"\n\"2W MWIb IW2W     NWAVAW(W,W(WJR<RJW(W4RJW(W,W\\\"V 9W2X     1X 6T   9i ?k#~`#k Hl HW4W @] ?X9W LW                 NX   .X 2VFV 'VCW$WFSAP KV?VBV NW 1V (V\"\n\" &W *X  MV       GV 5X6X =X  NX -X AVHX DX /X  BX GX8X X5X     ,^  1^  LX ?W MW0WHW FX6X!X ,X-Y*X -X .X ,X/X'X -X -XEZ BX -XKV<VKX0XKX=X'Y+Y,X7X Y+Y,X\"\n\"7X!X  KX <X/X'X4X\\\"W=WKV<W3YGY FYDY +Z KW .V  NW 0Y5Y    /l CWJe ?j AeJW Eh Kl 5eJW MWJe GW ,W ,W:Y KW ,WJdDd7WJe @h DWJe AeJW MWJ_ ?l Im <W6W\\\"W2W!W=Z=\"\n\"W2X9X W2W!u 6W :V  MW       BeFV!W;X 1W ?f =k CWJe NY2X =X =W6W JW-W$WI` N}!WCWCW Gi Av&{ W4W BVGW <Y 8X .X)X+ZEXEZ)X0X)X?X?X.Y+Y  #UHVHU   <V   <UHVH\"\n\"U    !j AX 9Z4Z KWBW DV -Z   -TFY@RDT8XAV       ETDVBWET  :VCV %V ;V )X   =W6W NiGU     KU 6V;V   >U5V KU5V GX<V FX /WHW ;WHW ;WHW ;WHW ;WHW ;WHW :WDX\"\n\" MX ,X -X -X -X -X -X -X -X ,X-Y+XKX=X'Y+Y-Y+Y-Y+Y-Y+Y-Y+Y'Z5Z+Y5WMY,X/X'X/X'X/X'X/X#YDY GX@^ KWCZ Al Al Al Al Al Al AlFh.j ?h =h =h =h EW ,W ,W ,W !g\"\n\" GWJe @h =h =h =h =h ,Z @hLV NW6W MW6W MW6W MW6W\\\"W2W MWJe KW2W     W@VAW)W+W)WJT>TKW)W4TKW)W+W\\\"V 9X3X     2X 5T   :k ?i\\\"~`$m Jn IW4W A^ ?X:X MW       \"\n\"          NY   .X 2VFV 7~X2XFS <V?VCV MX 2V )W %W +X  MV       GV 5X6X =X  NX -X BVGX DX /X  BX GX8X X5X LX -X  7a  1a  X @W KW2XHX GX6X!X ,X,X*X -X .\"\n\"X ,X/X'X -X -XFZ AX -XKV<VKX0XJW=X'X)X,X7X X)X,X7X!X  KX <X/X'X4X\\\"X>VIV>X2YIY DYFY +Z JW .V  NW 1Y3Y    1n DWLh Bm ChLW Gk Ll 6hLW MWKg HW ,W ,W;Y JW \"\n\",WKfGg8WKg Cl FWLh ChLW MWK` @m Im <W6W\\\"X4X!W=Z=W1X;X NW3X!u 6W :V  MW       CgGV!W;W 0X ?g Am CWKg [4X >Y =W6W JW-W&YJb }!WCWCW Hk Dx&{ W4W CWFW <Y 9\"\n\"X /Y)X,ZDXDZ*X0X)X?X?X.X)X P #SGVGS %P 7V 9P0P CSGVGS    !l BX 8ZGWFZ JWCX DV ,Z   .SEW<PCS8V?V .P>P     JSCVAVDS  :WEV $V <V &W   >W6W NiGU     KU 6V\"\n\";V BP>P /U5V KU5V EW=V FX 0XHX =XHX =XHX =XHX =XHX =XHX <XDX MX ,X -X -X -X -X -X -X -X ,X,X+XJW=X'X)X-X)X-X)X-X)X-X)X&Z7Z*X5WKX,X/X'X/X'X/X'X/X\\\"YFY F\"\n\"X=[ KWDY @n Cn Cn Cn Cn Cn CnHj1m Bk @k @k @k FW ,W ,W ,W $j GWKg Cl Al Al Al Al .Z Bs MW6W MW6W MW6W MW6W\\\"W3X MWLh LW3X     V?V@W*V)W*VJV@VKW*V4VKW*V\"\n\")W#V 9X4X     2X 4S   :l ?i\\\"~`%o Lp JW4W A^ >W:X MW                 NX   -X 2VFV 7~X2WES <V?VDV LX 2V )W %W -\\\\  V       HW 5X6X =X  NX .X BWGX DX 0X  \"\n\"BY FX:X NX5X LX -X  :d  1d $Y @V IV2WFW GX6X\\\"Y ,X,Y+X -X /Y ,X/X'X -X -XH[ @X -XKW>WKX0XJX>X(Y)X,X7X!Y)X,X7X!Y  LX <X/X&X6X!X>VIV>X1YKY BXFX +Z IW .W \"\n\" W 2Y1Y    2o EWMj Dn DjMW Hn Nl 7jMW MWLi IW ,W ,W<Y IW ,WLhIi9WLi En GWMj EjMW MWLa An Im <W6W!W4W W=Z=W1Y=Y MW4W u 6W :V  MW       DiIV W;W /W =g C\"\n\"m CWLi![4W =Y =W6W KW+W(ZKd!}!WCWCW Im Fy&{ W4W CWFW ;Y :X /X'X-YCXCY*X0X)X?X?X/Y)X!R #QFVFQ $R 9V :R1R DQFVFQ    \\\"n BX 7ZJ\\\\JZ HWDW CV +[   1TFW.T:W?V\"\n\" /Q?Q     KTCVAWET  :XIX $V =V #U   >W6W NiGU     KU 6V;V BQ?Q 0U6V JU6V BU>V EX 0WFW =WFW =WFW =WFW =WFW =WFW <XDX NY ,X -X -X -X -X -X -X -X ,X,Y,XJ\"\n\"X>X(Y)X.Y)X.Y)X.Y)X.Y)X%Z9Z*Y6WJX,X/X'X/X'X/X'X/X!XFX EX;Z LWDX ?o Do Do Do Do Do DoKn4n Cn Cn Cn Cn HW ,W ,W ,W %l HWLi En Cn Cn Cn Cn /Z Cs LW6W MW6\"\n\"W MW6W MW6W!W4W LWMj LW4W     W?V?V+W(V+WKXBXKV+W5XKV+W(V$W 8W4X     2X 5T   ;n ?g!~_%p LZDZ JW4W A^ >W:W MW                 MX   -X 2VFV 7~X2WES <WAW\"\n\"DV KX 3V )W %W /` \\\"V       HV 4X6X =X  Y .X BVFX DX 0X  BX EX:X NX5X LX -X  <e  /e 'Y @V GV4XFX HX7X!X +X+X+X -X /X +X/X'X -X -XI[ ?X -XJV>VJX0XIW>X(X\"\n\"'X-X7X!X'X-X7X!Y  LX <X/X&X6X!X>VIV>X1YKY AXHX +Z HW -V  W 3Y/Y    3p FWMk Fo EkMW Io Nl 8kMW MWMk JW ,W ,W=Y HW ,WMjJj:WMk Gp HWMk GkMW MWMb Bo Im <W\"\n\"6W!W4W W>\\\\>W0X=X LW5X u 6W :V  MW       EkJV W<X /W >j Fn CWMk\\\"\\\\6X =Z >W6W KW+W)[Ke\\\"}!WCWCW Jo Hz&{ W4W DWDW ;Y ;X /X'X.YBXBY+X0X)X?X?X/X'X#T  HV  IT \"\n\":V ;T3T :V   CV +o BX 6ZM`MZ GXFX CV *\\\\   3SFW,S:V>V 0R@R     KSBV@VDS  9e #V ?W \\\"V   ?W6W NiGU     KU 6V;V BR@R 1U6V JU6V BV?V EX 1XFX ?XFX ?XFX ?XFX\"\n\" ?XFX ?XFW =XCX NX +X -X -X -X -X -X -X -X ,X+X,XIW>X(X'X/X'X/X'X/X'X/X'X%Z;Z)X5VHX-X/X'X/X'X/X'X/X XHX DX:Y LWEX >p Ep Ep Ep Ep Ep EpMp6o Do Do Do Do\"\n\" HW ,W ,W ,W 'o IWMk Gp Ep Ep Ep Ep 0Z Ds KW6W MW6W MW6W MW6W!W5X LWMk MW5X     V>V?W,V'W,VKZDYKW,V5YKW,V'W%W 8X5W     2X 4T   ;o @g ~^%q NY@Y KW4W B`\"\n\" ?X<X MV                 LX   -X 2VFV 7~X2WES ;VAVDV JY 4V )V $W 1d $V       HV 4X6X =X  X .Y CWFX DXLY =XEX 'Y EY<X MX5X LX -X  ?e  )e +Y ?V:X6V4WDW \"\n\"HX7X!X +X+X+X -X /X +X/X'X -X -XJ[ >X -XJW@WJX0XIX?X(X'X-X7X!X'X-X8Y Y  MX <X/X%W6X W?WIV>W/YMY @YJY +Y GW -V  W 4X+X    4YE\\\\ FWNXG\\\\ H]EX F\\\\GXNW J\\\\F[ \"\n\"GW ,\\\\GXNW MWNXG[ JW ,W ,W?Z GW ,WNXH[KXH[:WNXG[ H]H] IWNXG\\\\ I\\\\GXNW MWNXFQ C\\\\CW CW ,W6W!X6X NW?\\\\?W.X?X JW6W 1X 6W :V  MW     9X=X\\\"[IZKW W=Y /W @m H]DV \"\n\"CWNXG[\\\"\\\\6W =[ >W6W LW)W*ZJWKY\\\"}!WCWCW K\\\\H] J{&{ V3W DWDW :Y <X /X'X.XAXAX+X0X)X?X?X/X'X$V  IV  JV ;V <V5V ;V   CV ,^MSKW BX 5x EWFW BV ,_   5TFW,S:V?W\"\n\" 1SAS     LTBV@VDS  9d \\\"V @W  U   ?W6W NiGU     KU 5V=V ASAS 2U7V IU7V @U@V DX 1WDW ?WDW ?WDW ?WDW ?WDW ?XFX >XCX NX +X -X -X -X -X -X -X -X ,X+X,XIX?\"\n\"X(X'X/X'X/X'X/X'X/X'X$Z=Z(X6WHX-X/X'X/X'X/X'X/X YJY DX9Y MWEW =YE\\\\ EYE\\\\ EYE\\\\ EYE\\\\ EYE\\\\ EYE\\\\ EYE]N\\\\G[7]EX E\\\\F[ F\\\\F[ F\\\\F[ F\\\\F[ IW ,W ,W ,W (p IWNXG[ H]H\"\n\"] G]H] G]H] G]H] G]H] 1Z E]H^ JW6W MW6W MW6W MW6W W6W KWNXG\\\\ MW6W     NV>V>V,V&V,VJZFYIV,V6YIV,V&V%W 7W6X     3X LR:T   ;q @e N~^&s!Y>Y LW4W B` >W<X N\"\n\"W                $x   FX 2VFV 7~X2WES ;VAVEW IY 5V *W #W 4XNTNX &V       IW 5X5X =X  X .X CWEX Di AXH_ +X CX<X MX5X LX -X  Be  #e /Z @V<^IUDV5WDW HX8Y\"\n\"!X +X+X+X -X /X +X/X'X -X -XK[ =X -XIV@VIX0XHW?X(X'X-X7X!X'X-X8X NZ  NX <X/X%X8X NX@VGV@X.c >XJX +Z GW -W !W 5X)X    5U>Z G_CZ I[>T FZC_ KZAZ HW -ZB_ \"\n\"M^BZ KW ,W ,W@Z FW ,^CZMVCZ;^BZ IZBZ I_CZ IZC_ M^ 5Y<S CW ,W6W W6W MW?\\\\?W.YAY JW6W 2Y 6W :V  MW     ;\\\\A\\\\%YDYLV NW>Y .W AXJa IZ<Q C^BZ MX8X =\\\\ ?W6W LW)\"\n\"W+YIXJY LW=W JWCWCW LZBZ K]F] ;W >W2W EWDW 9Y =X /X'X/YAXAY,X0X)X?X?X/X'X%X  JV  KX <V =X7X <V   CV -\\\\JSHT BX 4v DXHX BV -b   7SEV*S;V?W 2TBT     LSAV\"\n\"@VCS  9b !V AV  MU   ?W6W MhGU     KU 5V=V ATBT 3U8V HU8V ?UAV CX 1WDW ?WDW ?WDW ?WDW ?WDW ?WDW ?XBX NX +X -X -X -X -X -X -X -X ,X+X,XHW?X(X'X/X'X/X'X\"\n\"/X'X/X'X#Z?Z'X7WGX-X/X'X/X'X/X'X/X NXJX CX9Y MWFW <U>Z FU>Z FU>Z FU>Z FU>Z FU>Z FU>eBZ9[>T FZAZ HZAZ HZAZ HZAZ JW ,W ,W ,W )r J^BZ IZBZ GZBZ GZBZ GZBZ\"\n\" GZBZ 1Z EZB[ JW6W MW6W MW6W MW6W W6W K_CZ MW6W     V=V>V-V%V-VHZHYHV-V6YHV-V%V%W 7X7X     4X NU:T   <s Ae N~^'u\\\"X<X LW4W BWNW >W<W MW                \"\n\"$w   EX   2~X2WES ;WCWEV GY   9W #W 5XMTMX 'V       IV 4X4X >X !Y 0Y BVDX Dk CXJc -X BX>X LX5Y MX -X  Ee   Le 3Z ?U=bKUCU6XDX IX9Y X +X+X+X -X /X +X/X\"\n\"'X -X -XL[ <X -XIV@VIX0XHX@X(X'X-X8Y!X'X-X8X N[  X <X/X%X8X NX@VGV@X.c =XLX +Z FW ,V !W       AR9Y H]?Y KZ:R GY?] LY=Y IW -Y?] M]@Y KW ,W ,WAY DW ,]@X\"\n\"NV@X;]@Y JY>Y J]?Y KY?] M] 4X8P CW ,W6W X8X MW?\\\\?W-XAX IW7X 3Y 5W :V  MW     =_C_(YBXLV NW?Z -W CXC\\\\ KY ,]@Y LW8X >] ?W6W LW)W,YHWHY MW=W JWCWCW MY>Y \"\n\"L[B[ ;W >W2W FWBW 9Y >X 0X%X0X@X@X,X0X)X?X?X/X'X&Y  JV  KY =V >Y7Y =V   CV .[HSFR BX 3t BWHW AV .WN\\\\   9SFV)S;V?W 3UCU     LSAV@VCS  7_  V BV  LU   ?W\"\n\"6W MhGU     KU 5W?W AUCU 4U8V HU8V ?UAV CX 2XDX AXDX AXDX AXDX AXDX AXDX @XBX NX +X -X -X -X -X -X -X -X ,X+X,XHX@X(X'X/X'X/X'X/X'X/X'X\\\"ZAZ&X8WFX-X/X'\"\n\"X/X'X/X'X/X MXLX BX8X MWFW <R9Y GR9Y GR9Y GR9Y GR9Y GR9Y GR9a>Y;Z:R GY=Y JY=Y JY=Y JY=Y KW ,W ,W ,W *]E[ J]@Y JY>Y IY>Y IY>Y IY>Y IY>Y 2Z FY>Y JW6W MW\"\n\"6W MW6W MW6W W7X K]?Y NW7X     V=V=U-V$U-VGZJYFU-V7YFU-V$U%W 7X8X    &~X/X:T   =t @c L~\\\\'v\\\"W:W LW4W CXNX ?X>X MV                $x   EX   2~X2WES :VDW\"\n\"EV FZ   :W #W 7XKTKX )V       IV 4X4X >X !X 0Y BWDX Dm FXKf /Y AYBY KX5Y MX -X  Gd ~X d 5Y ?V>dLUCU6WBW IX;Z Y +X+Y,X -X 0Y +X/X'X -X -XM[ ;X -XIWBWIX\"\n\"0XGW@X)Y'Y.X8X!Y'Y.X9Y M] #X <X/X$X:X MX@VGV@X-a <YNY ,Z EW ,V !W       AP6X H\\\\=Y LY7P HY=\\\\ LX;X IW .Y=\\\\ M[=X KW ,W ,WBY CW ,[=]=W;[=X KY<Y K\\\\=Y MY=\\\\ \"\n\"M\\\\ 4X *W ,W6W NW8X MW@VNV@W,XCX GW8W 3Y 4W :V  MW     >aEa)X@XNW NWA[ ,W DW?[ LX +[=X KW:X =] ?W6W MW'W-XGWGX MW=W JWCWCW MX<Y NZ>Z <W >W2W FWBW 9Z ?X\"\n\" 0X%X0X@X@X,X0X(X@X@X/Y'Y(Y  IV  JY >V ?Y5Y >V   CV .YFSDP BX 2q @XJX AV /WK[   :SFV)S;V@X 4VDV     LSAV@VCS  6\\\\  MV CV  KU   ?W6W MhGU     KU 4V?V @V\"\n\"DV 5U9V GU9V >UBV BX 2WBW AWBW AWBW AWBW AWBW AXDX @XBX Y +X -X -X -X -X -X -X -X ,X+Y-XGW@X)Y'Y1Y'Y1Y'Y1Y'Y1Y'Y\\\"ZCZ&Y9WEY.X/X'X/X'X/X'X/X MYNY BX8Y N\"\n\"WFW <P6X GP6X GP6X GP6X GP6X GP6X GP6_<X;Y7P GX;X JX;X JX;X JX;X KW ,W ,W ,W *Z?Y K[=X KY<Y KY<Y KY<Y KY<Y KY<Y 3Z GY<Y KW6W MW6W MW6W MW6W NW8W J\\\\=Y \"\n\"NW8W     NV=V=V.V$V.VFZLYEV.V8YEV.V$V&W 6W8X    &~X2\\\\<T   =v Ab K~\\\\(x$W8W MW4W CXNX ?X>X NW                $w   DX   $VBV#XFS :WFXEV H]   ;W #W 9XITIX\"\n\" +V       JW 4X4X >X \\\"Y 3[ BWCX Dn GXLi 1X ?ZFZ JY7Z MX -X  Je M~X Me 9Y >U?gMUCV7WBW IX>\\\\ NX *X*X,X -X 0X *X/X'X -X -XNZ 9X -XHVBVHX0XGXAX)X%X.X9Y!X%\"\n\"X.X:Y La 'X <X/X$X:X LWAWGV@W+_ :XNX ,Z DW ,W \\\"W       &W H[;X MY .X;[ MX9X JW .X;[ M[<X LW ,W ,WCY BW ,Z<\\\\<X<[<X LX:X K[;X MX;[ M[ 3W )W ,W6W NW8W KW\"\n\"AVNVAW*XEX FW9X 4Y 3W :V  MW     ?cGc+Y?WNV MWD] +W DV=Z LX +Z;X LW:X >_ @W6W MW'W.YGWFX NW=W JWCWCW NX:X NY<Y <W >W2W FWBW 8Z @X 0X%X0X@X@X,X0X(X@X@X\"\n\"/X%X)Y  HV  IY ?V @Y3Y ?V   CV /YES 6X 1\\\\H[ JcJc LV 0WI\\\\   =TFV)S;WAX 5WEW     MTAVAWCS  3W 4~W.W  KV   ?W6W LgGU     KU 4WAW @WEW 6U9V GU9V ?VBV BX 2\"\n\"WBW AWBW AWBW AWBW AWBW AWBW AXAX X *X -X -X -X -X -X -X -X ,X*X-XGXAX)X%X1X%X1X%X1X%X1X%X!ZEZ%X9WCX.X/X'X/X'X/X'X/X LXNX AX7X NWFW !W ,W ,W ,W ,W ,W \"\n\",]:X=Y .X9X LX9X LX9X LX9X LW ,W ,W ,W +Z=X K[<X LX:X KX:X KX:X KX:X KX:X 3Z GX<Z KW6W MW6W MW6W MW6W NW9X J[;X NW9X     NU<V=V.U#V.UDZNYDV.U8YDV.U#V&\"\n\"V 5X9W    %~X3]<T   >x A` J~\\\\(y%W8W MW4W CXMW >W>W MV                $x   DX   $VCV\\\"XFS 9XIXEV H_   <W #W ;YHTHY -V       JV 3X4X >X #Y ?g AVBX Do HXM\"\n\"k 3Y >l HX7Z MX -X  Me J~X Je =Y >V?hNUBU8XBX Ju MX *X*X,w Lq IX *~R'X -X -c 8X -XHVBVHX0XFWAX)X%X.X9Y!X%X.X;Z Ke ,X <X/X$X:X LXBVEVBX+_ 9` +Y CW +V \\\"\"\n\"W       %W IZ9X NX .X9Z MW7W JW /X9Z MZ;X LW ,W ,WDY AW ,Z;[;W<Z;X MY:Y LZ9X X9Z MZ 2W )W ,W6W NX:X KWAVNVAW*YGY EW:W 4Z 3W :V  MW     ?XMYIe,X>WNV MW\"\n\"Ib +W EW;Y MW *Z;X KV:W =_ @W6W NW%W/XFWFX NW=W JWCWCW NW8X!Y:Y =W >| GW@W 8Y @X 0X%X1Y@X@Y-X0X(X@X@X/XImIX*Y  GV  HY @V AY1Y @V   CV /XDS 6X 0YDY JdL\"\n\"d LV 1WF[   >SFV'S<WBY 6XFX     MS@VAVAS    @~W/W  JU   >W6W LgGU     KU 3WCW ?XFX 7U:V FU:V >UBV AX 3XBX CXBX CXBX CXBX CXBX CXBX BXAw?X *w Lw Lw Lw \"\n\"LX -X -X -X ,X*X-XFWAX)X%X1X%X1X%X1X%X1X%X ZGZ$X:WBX.X/X'X/X'X/X'X/X K` @X7X NWFW  W ,W ,W ,W ,W ,W ,[8W=X -W7W LW7W LW7W LW7W LW ,W ,W ,W ,Y:X LZ;X M\"\n\"Y:Y MY:Y MY:Y MY:Y MY:Y  \\\"Y=\\\\ LW6W MW6W MW6W MW6W MW:W IZ9X NW:W     NV<V=V/V#V/VCcCV/V9YCV/V=X>V&V 4W:X    %~X2TNV<S   =y KWM^LW$~Z({&W7V MW4W CWLX ?\"\n\"X?W MV                 KX   ,X   %VBV!XGS 9gFV Ha   >W \\\"W ;WFTFW -V       JV 3X4X >X #Y ?f AWBX Dp IXNm 4X <j GX7Z MX -X !e G~X Ge AY =U?ZH^BU8W@W Jt \"\n\"LX *X*X,w Lq IX *~R'X -X -b 7X -XHWDWHX0XFXBX)X%X.X:Y X%X.X<Z Ih 0X <X/X#X<X KXBVEVBX*] 8` ,Z CW +V \\\"W       %W IZ9X X -X9Z NX7X KW /X9Z MY9W LW ,W ,W\"\n\"EY @W ,Y:Z:W<Y9W MX8X LZ9X X9Z MY 1W )W ,W6W MW:W JWAVNVAW)XGX DW:W 4Y 3X :V  MW     @VHXKWGV,W<^ MWIa *W FW9Y NW *Y9W KW<X >` @W6W NW%W/WEWEW NW=W JW\"\n\"CWCW X8X!X8X =W >| GW@W 7Y AX 0X%X1X?X?X-X0X(X@X@X/XImIX+Y  FV  GY AV BY/Y AV   DX 1XCS 6X 0W@X KdLd LV 1VCZ   ?SFV'S;WE[ 7XFX G~X  .S@VBWAS    @~W0W \"\n\".P>W   >W6W KfGU     KU 3XEX >XFX 8U;V:W3U;VCZ9P>WCV:W/Y 3W@W CW@W CW@W CW@W CW@W CXBX CX@w?X *w Lw Lw Lw LX -X -X -X 5p9X-XFXBX)X%X1X%X1X%X1X%X1X%X N\"\n\"ZIZ#X:VAX.X/X'X/X'X/X'X/X K` @X7X NWFW  W ,W ,W ,W ,W ,W ,[8X?X -X7X NX7X NX7X NX7X MW ,W ,W ,W ,X9X LY9W MX8X MX8X MX8X MX8X MX8X  \\\"X=] LW6W MW6W MW6\"\n\"W MW6W MW:W IZ9X NW:W     NVLuKU/VLuKU/VBaAU/V:YAU/V=X=U&V 4X;X    %~X2RLW>T   >{!z'~Z)}(W6W NW4W DXLX ?X@X MV                 KX   ,X   %VBV!YHS 8eEV\"\n\" Ic   ?W !W ;UETEU ,V       KW 3X4X >X $Y >c ?WAX DWD^ JbG] 5X 9d DY9[ MX -X #d D~X Dd DY <U@YD\\\\BU9X@X Kq IX *X*X,w Lq IX *~R'X -X -a 6X -XGVDVGX0XEWB\"\n\"X)X%X.X;Z X%X.X?\\\\ Gk 4X <X/X#X<X KXBVEVBX)[ 6^ ,Z BW +W #W       %W IY7W X -W7Y NW5W KW 0X7Y MY9W LW ,W ,WFY ?W ,Y:Z:W<Y9W MW6W LY7W W7Y MY 1W )W ,W6W\"\n\" MW:W JWBVLVBW(XIX CW;X 5Y 2X :V  MX     BUDVKVDU.X<] LWI_ :WEW FV7X NW *Y9W JV<X >a AW6W NW%W0XEWEX W=W JWCWCW W6W!X8X =W >| HX@X 7Y BX 0X%X1X?X?X-X0\"\n\"X(X@X@X/XImIX,Y  EV  FY BV CY-Y BV   DX 1XCS 6X 1W>W KeNe LV 1VB[   ASFV'S;YI] 9YGY F~X  .S@VDX@S    @~W1V ,TEZ   >W6W JeGU IX   +U 2YIY <YGY :U;V:W3U\"\n\";VGa<TEZCV:W/X 3X@X EX@X EX@X EX@X EX@X EX@X DX@w?X *w Lw Lw Lw LX -X -X -X 5p9X-XEWBX)X%X1X%X1X%X1X%X1X%X MZKZ\\\"X;WAX.X/X'X/X'X/X'X/X J^ ?X7X NWFX !W \"\n\",W ,W ,W ,W ,W ,Z6W?X -W5W NW5W NW5W NW5W MW ,W ,W ,W -X7W LY9W MW6W MW6W MW6W MW6W MW6W  \\\"W=^ LW6W MW6W MW6W MW6W MW;X IY7W NW;X     NVLuKU/VLuKU/VA_\"\n\"@U/V;Y@U/V=X=U&V 4X<X    $~X,W>T   ?|\\\"}(~X)~(W6W NW4W DXKW >W@X MV                 KX   ,X   %VBV!ZIS 7cEV IYNZ8W  0W !W :RCTCR +V       KW 3X4X >X %Y\"\n\" =b >V@X DS=\\\\ K`C[ 6Y 8b BX9[     Nd A~X Ad HY <VAX@ZBV:X?W Kq IX *X*X,w Lq IX *~R'X -X -a 6X -XGVDVGX0XEXCX)X%X.X=[ NX%X.u Fl 6X <X/X\\\"W<W IWCWEVBW([ \"\n\"5\\\\ ,Z AW +W #W       $V IY7X\\\"X -X7Y NW5W KW 0X7Y MX8X MW ,W ,WHZ >W ,X8X8W=X8X X6X MY7X\\\"X7Y MX 0W )W ,W6W MX<X IWCVLVCW&XKX AW<W 5Y 1W 9V  LW  4P  /TB\"\n\"VMVBT.X;\\\\ LWI` =\\\\HW GW7X NW *X8X KV=X >XMW AW6W NW%W0XEWDW W=W JWCWCW!X6X#X6X >W >| HW>W 6Y CX 0X%X1X?X?X-X0X'XAXAX.XImIX-Y  DV  EY CV DY+Y CV   DX 2X\"\n\"BS 6X 1V<V KeNe LV 2V?Y   ASFV'S:dNV :XFY E~X  .S@i?S    @~W2i >h   =W6W JeGU IX   4g :g :YFX DgEV:X<gEVHe>hCV:X/X 3X?W EX?W EX?W EX?W EX?W EX@X EX?w?\"\n\"X *w Lw Lw Lw LX -X -X -X 5p9X-XEXCX)X%X1X%X1X%X1X%X1X%X LZMZ!X<W@X.X/X'X/X'X/X'X/X I\\\\ >X7X NWFY !V +V +V +V +V +V +Y6W@X ,W5W NW5W NW5W NW5W MW ,W ,W\"\n\" ,W -X7X MX8X X6X X6X X6X X6X X6X  $X=_ MW6W MW6W MW6W MW6W LW<W HY7X NW<W     MVLuKU/VLuKU/V@]?U/V<Y?U/V=X=U&V 3W<X    $~X+V>S   >}%~R)~V(~P)W6W NW4W\"\n\" DWJX ?XAW L~^               $X   ,X   %VCV N\\\\LS 6aDVAW0XLZ9W  0W !W :PATAP +V       KV 2X4X >X &Z =e BW@X DP8[ L^?Z 7X :h EY;\\\\    \\\"d >~X ?e LY ;U@W>Y\"\n\"AU:W>W Ks KX *X*X,w Lq IX6f+~R'X -X -b 7X -XGWFWGX0XDWCX)X%X.X@^ NX%X.s Bl 8X <X/X\\\"X>X IXDVCVDX)[ 4\\\\ -Z @W *V #W       $W JX5W\\\"X -W5X W4W KW 0W5X MX7W\"\n\" MW ,W ,WIZ =W ,X8X8W=X7W W4W MX5W\\\"W5X MX 0X *W ,W6W LW<W HWCVLVCW&YMY AW=X 6Y 1X 9V  LX 1X.Q  /TA]AU/W:\\\\ LWIb A`JW GV5X NW +X7W KW>X >XMX BW6W W#W1WD\"\n\"WDW W=W JWCWCW!W4W#X6X >W >| HW>W 7Y BX 0X%X1X?X?X-X0X'XAXAX.XImIX.Y  CV  DY DV EY)Y DV   DX 2XBS 6X 2W<W =^ =V 2V>Y   BSFV'S9bMV ;XFY D~X  .S@h>S    \"\n\"@~W2i >g   <W6W HcGU IX   4g 9e 8YFX EgEV;Y<gEVHf?gBV;Y0Y 3W>W EW>W EW>W EW>W EW>W EW>W EX?w?X *w Lw Lw Lw LX -X -X -X 5p9X-XDWCX)X%X1X%X1X%X1X%X1X%X \"\n\"Ke X=W?X.X/X'X/X'X/X'X/X I\\\\ >X7X NWEY \\\"W ,W ,W ,W ,W ,W ,X5W@X -W4W W4W W4W W4W MW ,W ,W ,W -W6X MX7W W4W W4W W4W W4W W4W  $W=VMW MW6W MW6W MW6W MW6W \"\n\"LW=X HX5W NW=X     MVLuKU/VLuKU/V?[>U/V=Y>U/V=X=U&V 3X=W     7X FW@T   ?~&~T*~V)~R*W5V NW4W EXJX ?XBX L~^               $X   ,X   &VBV Mb 4]CVC]4XJZ:W\"\n\"  0W !W +T  KV       KV 2X4X >X 'Z <g EW?X +Z L]=Z 9Y <l GZ=]    %e    e!Y :UAW<XAU;X>X Lu MX *X*X,w Lq IX6f+~R'X -X -c 8X -XFVFVFX0XDXDX)X%X.u MX%X.r\"\n\" ?l :X <X/X\\\"X>X IXDVCVDX)\\\\ 4Z ,Y ?W *V #W       $W JX5W\\\"W ,W5X W3W LW 0W5X MX7W MW ,W ,WJY ;W ,X8X8W=X7W W4W MX5W\\\"W5X MX 0X *W ,W6W LW<W HWCVKUCW%XMX \"\n\"?W>W 6Y 0X 9V  LX 5`3R  0T?[?T/W:[ KWId DbKW HW5X NW +X7W JV>W =WLX BW6W W#W1WDWDW W=W JWCWCW!W4W#W4W >W >| IX>X 9Y AX 0X%X1X?X?X-X0X'XAXAX.XImIX/Y  B\"\n\"V  CY EV FY'Y EV   DX 2WAS ?r CV:V =^ =V 2V=Y   CSFV'S8`LV <XFX B~X  .S@e;S    @~W2i >e   :W6W GbGU IX   4g 8c 5XFX FgFV:Y<gFVGg@eAV:Y1Y 3X>X GX>X GX>\"\n\"X GX>X GX>X GX>X FX?w?X *w Lw Lw Lw LX -X -X -X 5p9X-XDXDX)X%X1X%X1X%X1X%X1X%X Jc NX>W>X.X/X'X/X'X/X'X/X HZ =X7X NWEZ #W ,W ,W ,W ,W ,W ,X4WAW ,W3W!W3\"\n\"W!W3W!W3W NW ,W ,W ,W .X5W MX7W W4W W4W W4W W4W W4W  $W>VLW MW6W MW6W MW6W MW6W KW>W GX5W MW>W     LVLuKU/VLuKU/V>Z>U/V>Y=U/V=X=U&V 2W>X     8Y FW@T  \"\n\" ?~P(~V*~T(~Q)V4V NW4W EXJX >WBX L~^               $X   ,X   &VBV Ld 4WAVD`6XHZ;W  0W !W +T  KV       LW 2X4X >X 'Y ;i GV>X *Z M\\\\;Y 9X =p HZ?^    'd  \"\n\"  Id$Y 9UAW<XAU;W<W Lw X *X*X,w Lq IX6f+~R'X -X -d 9X -XFVFVFX0XCWDX)X%X.t LX%X.p ;k ;X <X/X!X@X HXDVCVDX*^ 4X ,Z ?W *W $W       $W JX5W\\\"W ,W5X W3W LW\"\n\" 0W5X MW6W MW ,W ,WKY :W ,W7W7W=W6W W4W MX5W\\\"W5X MX /Y ,W ,W6W LX>X GWEVJVEW#a >W>W 7Y 1Y 8V  KY 9e8T  0T?Z>T0X:[ KWIf GdLW HW4W MW ,W6W JV?X >XKW BW6\"\n\"W W#W2XDWDX!W=W JWCWCW!W4W#W4W >W >| IW<W :Y @X 0X%X1X?X?X-X0X&XBXBX-XImIX0Y  AV  BY FV GY%Y FV   DX 2WAS ?r DW:W =\\\\ <V 2V;W   CSFV'S7]JV =XFX A~X  .S\"\n\"@d:S    (V Ii <a   8W6W FaGU IX   4g 6_ 2XFX GgGV:Z<gGVFUFY?a@V:Z2Y 2W<W GW<W GW<W GW<W GW<W GX>X GX>w?X *w Lw Lw Lw LX -X -X -X 5p9X-XCWDX)X%X1X%X1X%\",\n// Start of second string.\n\"X1X%X1X%X Ia MX?W=X.X/X'X/X'X/X'X/X GX <X7X NWDZ $W ,W ,W ,W ,W ,W ,X4WAW ,W3W!W3W!W3W!W3W NW ,W ,W ,W .W4W MW6W W4W W4W W4W W4W W4W  $W?VKW MW6W MW6W\"\n\" MW6W MW6W KW>W GX5W MW>W     LVLuKU/VLuKU/V?\\\\?U/V?Y<U/V=X=U&V 2W>X     8X DWBT   ?~Q)~W)~R&~(V4V NW4W EWHW >WBW K~^               $X   ,X   &VBV Kg \\\"\"\n\"VEc8WFZ=W  /W !W +T 4~W      5V 1X4X >X (Y -] IW>X )Y M[9X 9X >\\\\F\\\\ H[C`    'a    Ca$Y 9UAV:WAU;W<W LX<\\\\!X *X*X,X -X 0X6f+X/X'X -X -XN[ :X -XEVHVEX0XCX\"\n\"EX)X%X.s KX%X.o 6h <X <X/X!X@X GWDVCVDW*_ 4X -Z >W )V $W       6i JX5X$X -X5X V2W LW 1W3W MW6W MW ,W ,WLY 9W ,W7W7W=W6W!X4X NX5X$X5X MW .[ .W ,W6W KW>\"\n\"W FWEVJVEW#a >W?X 8Z 4\\\\ 8V  K[ =i<V  0S=Y=S0X:[ KW@^ IfMW HW4W MY .W6W JW@W =XKX CW6W W#W2WCWCW!W=W JWCWCW\\\"X4X%X4X ?W >W2W IW<W :Y @X 0X%X1X?X?X-X0X&X\"\n\"BXBX-X%X1~` GV H~` GV H~` GV   DX 3XAS ?r DV8V =\\\\ <V 2V;X   DSFV'S4W /XFX @~X  .S@VIX;S    (V Ii 8Z   5W6W D_GU IX   4g 3Y .XFX HgGV;TNU<gGVFQ@W;Z=V;T\"\n\"NU3Y 1W<W GW<W GW<W GW<W GW<W GW<W GX>X X *X -X -X -X -X -X -X -X ,X*X-XCXEX)X%X1X%X1X%X1X%X1X%X H_ LX@W<X.X/X'X/X'X/X'X/X GX <X7X NWD\\\\ 8i >i >i >i >i\"\n\" >i >i3WBX ,V2W!V2W!V2W!V2W NW ,W ,W ,W .W4W MW6W!X4X\\\"X4X\\\"X4X\\\"X4X\\\"X4X M~Y2X@VIW NW6W MW6W MW6W MW6W KW?X GX5X NW?X     LVLuKU/VLuKU/V@^@U/V@Y;U/V=X=U&\"\n\"V 2X?W     8X CWBT   ?~R*~X)~Q%}(V4W W4W FXHX ?XDX K~^               $X   ,X   'WCV Ii &VEe:XEZ>W  /W !W +T 4~W      5V 1X4X >X )Y )[ KW=X (Y N[9Y ;Y \"\n\"?Z@Z I]Gb    '^    =^$X 9U@V:WAU<X<X MX9Z\\\"X *X*X,X -X 0X6f+X/X'X -X -XM[ ;X -XEVHVEX0XBWEX)X%X.r JX%X.q 4e =X <X/X!X@X GXFVAVFX*` 5X .Z =W )V $W      \"\n\" :m JW3W$W ,W3W!W2W LW 1W3W MW6W MW ,W ,WMY 8W ,W7W7W=W6W!W2W NW3W$W3W MW -^ 2W ,W6W KX@X FWEVJVEW\\\"_ <W@W 7Y :b 7V  Jb FmAX  0S<W<S0W8Y JW<[ KYHVMV GV\"\n\"3X MZ 0W6W IVAX >XIW CW6W!W!W3WCWCW!W=W JWCWCW\\\"W2W%W3X ?W >W2W JW;X <Y ?X 0X&Y1X?X?X-X0X&YCXCY-X%X2~a GV H~a HV I~b HV   DX 3W@S ?r DV8V <Z ;V 2W;W   \"\n\"DSFV'S  <XFX  =V  .S@VGW<S    (V      \\\"W6W A\\\\GU IX       2XFX *V;TMU LV2V V;TMU4Z 2X<X IX<X IX<X IX<X IX<X IX<X IX=X X *X -X -X -X -X -X -X -X ,X*X-XB\"\n\"WEX)X%X1X%X1X%X1X%X1X%X G] KX@V;X.X/X'X/X'X/X'X/X GX <X8Y NWC\\\\ =m Bm Bm Bm Bm Bm Bm3WBW ,W2W\\\"W2W\\\"W2W\\\"W2W NW ,W ,W ,W /X4X NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W M~Y\"\n\"2W@VHW NW6W MW6W MW6W MW6W JW@W FW3W MW@W     KVLuKU/VLuKU/VA`AU/VAY:U/V=X=U&V 1W@X     9X BWBS   >~R+~Z*~P#{'V4W W4W FXHX ?XDX K~^               $X  \"\n\" ,X   'VBV Gi (VFg;WCZ?W  /W !W +T 4~W      6W 1X4X >X *Y &Z LW=X (Y NZ7X ;X ?Z>Z ImNX    '[    8\\\\%Y 9UAW:WAU<W:W MX7Y#X *X*X,X -X 0X6f+X/X'X -X -XL[ \"\n\"<X -XEWJWEX0XBXFX)X%X.p HX%X.r 0a >X <X/X XBX FXFVAVFX+b 6X /Z <W )W %W       =p JW3W$W ,W3W!| LW 1W3W MW6W MW ,W ,WNY 7W ,W7W7W=W6W!W2W NW3W$W3W MW -\"\n\"b 6W ,W6W JW@W EWFVHVFW!] ;WAX 8Y 9` 5V  H` HrG[  0S<W<S0W8Y JW:Y KXF^ HW2W Kc ;W6W IVAX >XIW CW6W!W!W3WCWCW!W=W JWCWCW\\\"W2W%W2W ?W >W2W JW:W =Y >X 0Y'\"\n\"X0X?X?X-X0X%XCXCX,X%X2~a GV H~a HV I~b HV   DX 3W@S ?r DV8V <Z   FW;W   DSFV'S  =XFX  <V  .S@VFW=S    (V      \\\"W6W <WGU IX       1XFX +V;SLU LV2V V;SL\"\n\"U5Z 1W:W IW:W IW:W IW:W IW:W IX<X IX=X X *X -X -X -X -X -X -X -X ,X*X-XBXFX)X%X1X%X1X%X1X%X1X%X F[ JXAW;X.X/X'X/X'X/X'X/X GX <X8X MWB] Bp Ep Ep Ep Ep \"\n\"Ep E~eBW ,|\\\"|\\\"|\\\"| NW ,W ,W ,W /W2W NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W M~Y2WAWHW NW6W MW6W MW6W MW6W JWAX FW3W MWAX     KV<V=V/V#V/VBbCV/VBY:V/V=X>V&V 1XAW     9\"\n\"X @WDT   ?~S+~Z)}!y'W4W W4W FWFW >WDW J~^               *r   ?V   &VBV Eh *VEXIX<XBZ@W  /W !W +T 4~W  5f   8V 0X4X >X +Y $Z NW<X 'X NZ7X ;X ?X:X HkMX \"\n\"   '[    7[%X 8UAV8VAU=X:X NX6X#X *X*X,X -X 0X6f+X/X'X -X -XK[ =X -XDVJVDX0XAWFX)X%X.m EX%X.XA\\\\ -^ ?X <X/X XBX FXFVAVFX,c 6X /Y ;W (V %W       ?r JW3W\"\n\"$W ,W3W!| LW 1W3W MW6W MW ,W ,a 6W ,W7W7W=W6W!W2W NW3W$W3W MW ,e :W ,W6W JW@W DWGVHVGW N[ 9WBW 8Y 8^ 3V  F^ I~X  0S;U;T1W8Y JW8X MXC\\\\ HW2W Ia ;W6W IWB\"\n\"W >XHX DW6W!W<W<W3WCWCW!W=W JWCWCW\\\"W2W%W2W ?W >W2W KX:X ?Y =X /X'X0Y@X@Y-X0X%YDXDY,X%X2~a GV H~a HV I~b HV   DX 3W@S ?r DV8V ;X   DW;V   DSFV'S  >XFX \"\n\" ;V  .S@VFW=S    (V      \\\"W6W :UGU IX       0XFX -V;TLU MV0U!V;TLU6Y 0X:X KX:X KX:X KX:X KX:X KX:X JW<X X *X -X -X -X -X -X -X -X ,X*X-XAWFX)X%X1X%X1X\"\n\"%X1X%X1X%X F[ JXBW:X.X/X'X/X'X/X'X/X GX <X9Y MWA] Er Gr Gr Gr Gr Gr G~gBW ,|\\\"|\\\"|\\\"| NW ,W ,W ,W /W2W NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W M~Y2WBWGW NW6W MW6W MW6W \"\n\"MW6W IWBW EW3W LWBW     IU<V=V.U#V.UCdDV.UCY9V.U=X>V&V 1XBX     :X ?WDT   ?~S,~[({ x&W4W W4W FWFX ?XFX JV                \\\"q   >V   &VBV Af -VEXGX=W@ZB\"\n\"W  .W !W +T 4~W  5f   8V 0X4X >X ,Y \\\"Y W;X 'X NZ7X <Y @Y:Y HiLX    '^    =^%X 8UAV8VAU=X:X NX5X$X *X*X,X -X 0X(X+X/X'X -X -XJ[ >X -XDVJVDX0XAXGX)X%X.i\"\n\" AX%X.X>Z ,\\\\ ?X <X/X NWBW DWFVAVFW+XMY 7X 0Z ;W (V %W       @s JW3W$W ,W3W!| LW 1W3W MW6W MW ,W ,` 5W ,W7W7W=W6W!W2W NW3W$W3W MW +g =W ,W6W JXBX DWGVH\"\n\"VGW N[ 9WBW 9Y 7^ 3V  F^ I[Gr  /S;U;T1W8X IW7X NWA[ HW2W F^ ;W6W HVCX >XGW DW6W!W<W<W3WCWCW!W=W JWCWCW\\\"W2W%W2W ?W >W2W KW9X ?Y =X /X'X/X@X@X,X0X$YEXEY\"\n\"+X%X2~a GV H~a HV I~b HV   DX 3W@S 6X 3V8V ;X   DX<V   DTFV)T  >WEW  :V  .TAVEW?T    (V      \\\"W6W :UGU IX       /WEW .V;TKU NV/U\\\"V;TKU7Y /X:X KX:X KX:\"\n\"X KX:X KX:X KX:X KX<X X *X -X -X -X -X -X -X -X ,X*X-XAXGX)X%X1X%X1X%X1X%X1X%X G] KXCW9X.X/X'X/X'X/X'X/X GX <X9Y MW?] Hs Hs Hs Hs Hs Hs H~hBW ,|\\\"|\\\"|\\\"|\"\n\" NW ,W ,W ,W /W2W NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W M~Y2WBVFW NW6W MW6W MW6W MW6W IWBW EW3W LWBW     IU<V=V.U#V.UDYMZEV.UDY8V.U#V&V 0WBX     ;X >WDS   >~T-~\\\\(y\"\n\" Mw&W4W W4W GXFX ?XFX JV                #r   >V   'WCV <c .VEWEW=W?ZCW  .W !W   :~W  5f   9W 0X4X >X -Y  Y!W;X 'Y Y5X =X @Y8Y HgKX    'a    Ca%X 8UAV8\"\n\"VAU=W8W NX4X%X *X+Y,X -X 0X(X+X/X'X -X -XI[ ?X -XDWLWDX0X@WGX)X&Y.X 0X&Y.X=Y *[ @X <X/X NXDX DXHW@VHX,YMZ 8X 1Z :W (W &W       At JW3W$W ,W3W!| LW 1W3\"\n\"W MW6W MW ,W ,` 5W ,W7W7W=W6W!W2W NW3W$W3W MW )g ?W ,W6W IWBW CWGVHVGW MY 8WCX :Y 6` 5V  H` IW@m  -S;V<T1W8X IW7X W@[ HW2W Ia ;W6W HVCW >XFX EW6W!W<W<\"\n\"W3WCWCW!W=W JWCWCW\\\"W2W%W2W ?W >W2W KW8W @Y <X /X'X/X@X@X,X0X#YFXFY*X&Y2~a GV H~a HV I~b HV   DX 3W@S 6X 3V8V ;X   CX=V   CSFV)S  =WEW  :V  -SAVDW@S   \"\n\" 'V      \\\"W6W :UGU IX       /WEW .V<TJU NV/U\\\"V<TJU8Z /W8W KW8W KW8W KW8W KW8W KX:X KX<X X *X -X -X -X -X -X -X -X ,X+Y-X@WGX)X&Y1X&Y1X&Y1X&Y1X&Y H_ LX\"\n\"DW9Y.X/X'X/X'X/X'X/X GX <X:Y LW>] Jt It It It It It I~iBW ,|\\\"|\\\"|\\\"| NW ,W ,W ,W /W2W NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W M~Y2WCVEW NW6W MW6W MW6W MW6W IWCX EW3W L\"\n\"WCX     IV=V=V.V$V.VFYKZFV.VFY7V.V$V&V 0XCW     ;Y =WFT   >~T-~\\\\'w Ku%W4W W4W GXEW >WFW IV                #q   =V   6~X JSN^ /VEWCW?W=ZDW  .W !W   :~W\"\n\"  5f   9V /X4X >X .Y  MX\\\"W:X &X Y5X >Y @X6X FcJX    &d    Id%X 8UAV8VAU>X8X X4X$X +X+X+X -X /X)X+X/X'X -X -XH[ @X -XCVLVCX0X@XHX(X'X-X /X'X-X<Y *Z @X \"\n\"<X/X NXDX DXHV?VHX-YKY 8X 2Z 9W 'V &W       B]?W JW3W$W ,W3W!| LW 1W3W MW6W MW ,W ,a 6W ,W7W7W=W6W!W2W NW3W$W3W MW 'g AW ,W6W IWBW CWHVFVHW NZ 7WDW :Z\"\n\" 6a 6V  Jb IU;i  ,S;V<S0W7W IW6W W?Z HW2W Kc ;W6W HWEX >XFX EW6W!W<W<W3WCWCW!W=W JWCWCW\\\"W2W%W2W ?W =V2V KX8X BY ;X /Y)Y/X@X@X,X0X#YFXGZ)X'X0~` GV H~` \"\n\"GV H~` GV   DX 3W@S 6X 3V8V M|  &Z?V   CSFV)S:m AXFX  ;V  -SAVDW@S    'V      \\\"W6W :UGU      *m 5XFX /V;SIU V.T\\\"V;SIU9Z /X8X MX8X MX8X MX8X MX8X MX8X \"\n\"MX;X NX +X -X -X -X -X -X -X -X ,X+X,X@XHX(X'X/X'X/X'X/X'X/X'X Ha LXFW8X-X/X'X/X'X/X'X/X GX <X;Z LW<\\\\ L]?W J]?W J]?W J]?W J]?W J]?W J]?{BW ,|\\\"|\\\"|\\\"| NW\"\n\" ,W ,W ,W /W2W NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W M~Y2WDVDW NW6W MW6W MW6W MW6W HWDW DW3W KWDW     HV=V>V-V%V-VGYIZHV-VGY7V-V%V%V /WDX     ;X <WFT   >~T-~\\\\'v Is\"\n\"$W4W W4W GWDX ?XGW HV                %r   =V   6~X JSJ[ 0VEVAV?W<ZFW  -W !W   \\\"V   Lf   9V /X5X =X /Z  MX\\\"V9X &X NX5X >X ?X6X D`IX    $d    Ne#X 8UAV8\"\n\"VBU=x X4X$X +X+X+X -X /X)X+X/X'X -X -XG[ AX -XCVLVCX0X?WHX(X'X-X /X'X-X;Y *Y @X <X/X MXFX CXHV?VHX-XIY 9X 3Z 8W 'V &W       CZ;W JW3W$W ,W3W!| LW 1W3W\"\n\" MW6W MW ,W ,b 7W ,W7W7W=W6W!W2W NW3W$W3W MW %f BW ,W6W IXDX BWIVFVIW N\\\\ 8WEX :Y .[ 7V  K\\\\ BT8e  *S<X=S0W7V HW6X\\\"W=X GW2W Me ;W6W GVEX >WDW EW6W!W<W<W\"\n\"3WCWCW!W=W JWCWCW\\\"W2W%W2W ?W =W4W KW6W CY :X .X)X.YAXAY,X0X\\\"ZHXHZ(X'X/Y  AV  BY FV GY%Y FV   DX 3W@S 6X 2V:V L|  %ZAV   BSEV*S:m @XFX  <V  -SAVCWAS   \"\n\" 'V      \\\"W6W :UGU      *m 6XFX .V<TIU V/U\\\"V<TIU9Y .x Mx Mx Mx Mx Mx Mu NX +X -X -X -X -X -X -X -X ,X+X,X?WHX(X'X/X'X/X'X/X'X/X'X Ic MXGW7X-X/X'X/X'X/\"\n\"X'X/X GX <X=[ KW:[ NZ;W KZ;W KZ;W KZ;W KZ;W KZ;W KZ;{BW ,|\\\"|\\\"|\\\"| NW ,W ,W ,W /W2W NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W  &WEVCW NW6W MW6W MW6W MW6W HWEX DW3W KWEX \"\n\"    GV>V>V,V&V,VIYGZIV,VIY6V,V&V&W /XEW     N~X'VGT   =~T-~\\\\&u Ir#W4W NV4W HXDX ?XHX HV                 KX   ,V   6~X JSHZ 2VDVAV?W;ZGW  -W !W   \\\"V   \"\n\"Lf   :W .X6X =X 0Z  LY#~ /X NX5X >X @X5Y AYFX    !d >~X >d X 8UAV8VBU>z!X3X%X +X+X+X -X /X)X+X/X'X -X -XF[ BX -XCWNWCX0X?XIX(X'X-X /X'X-X:X )Y AX <X/X\"\n\" MXFX BWHV?VHW-YIY 9X 3Y 7W 'W 'W       CX9W JW3W$W ,W3W!W 'W 1W3W MW6W MW ,W ,WNZ 8W ,W7W7W=W6W!W2W NW3W$W3W MW !c CW ,W6W HWDW AWIVFVIW N] 8WFW :Y *\"\n\"Y 8V  KY ?R3`  (S<X=S0W7V HW5W\\\"W=X GW2W N[ 0W6W GWFW >XDX FW6W!W<W<W3WCWCW!W=W JWCWCW\\\"W2W%W2W ?W =W4W LX6X DY :X .X)X-XAXAX+X0X!ZIXIZ'X'X.Y  BV  CY EV\"\n\" FY'Y EV   DX 3W@S 6X 2V:V L|  $[CV   BTFW,T:m ?XFX  =V  -TBVBVBT    'V      \\\"W6W :UGU      *m 7XFX .V<THU!V/U\\\"V<THU:Y .z z z z z Nx Nv NX +X -X -X -X\"\n\" -X -X -X -X ,X+X,X?XIX(X'X/X'X/X'X/X'X/X'X Je NXGV6X-X/X'X/X'X/X'X/X GX <X@^ KW9[ X9W KX9W KX9W KX9W KX9W KX9W KX9W MW ,W ,W ,W ,W )W ,W ,W ,W /W2W N\"\n\"W6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W  &WFVBW NW6W MW6W MW6W MW6W GWFW CW3W JWFW     FV>V?W,V'W,VJYEZKW,VJY6W,V'W&W /XFX     N~X'WHT   =~T-~\\\\%s Gp\\\"W4W NV4V GXCW >WH\"\n\"X HW                 LX   ,V   6~X JSGY 3VDWAW@W:ZIW  ,W !W   \\\"V   Lf   :W .X6X =X 1Z  JX#~ /X NX5X ?Y @X4X .X     Md A~X Ad LX 8UAV8VBU>z!X3X%X +X+X+\"\n\"X -X /X)X+X/X'X -X -XE[ CX -XBVNVBX0X>WIX(X'X-X /X'X-X9X *Y AX <X/X MXFX BXJW?WJX.YGY :X 4Z 7W 'W 'W       DX8W JW3W$W ,W3W!W 'W 1W3W MW6W MW ,W ,WLY \"\n\"9W ,W7W7W=W6W!W2W NW3W$W3W MW  K_ DW ,W6W HXFX AWIVFVIW ^ 8WFW ;Y (Y 9V  LY >Q.X  $T>Z?T0W8W HW5W\\\"W<W GW2W Y -W6W GWGX >WCX FW6W!W<W<W3WCWCW!W=W JWCWC\"\n\"W\\\"W2W%W2W ?W =W4W LX6X EY 9X .Y+Y-YBXBY+X0X ZJXJZ&X'X-Y  CV  DY DV EY)Y DV   DX 3W@S 6X 2W<W L|  #\\\\FW   ASFW,S9m >XFX  >V  ,SBVBWCS    &V      \\\"W6W :U\"\n\"GU      *m 8XFX .V<TGU\\\"V.U#V<TGU;Y -z z z z z z v NX +X -X -X -X -X -X -X -X ,X+X,X>WIX(X'X/X'X/X'X/X'X/X'X KZMZ XHW6X-X/X'X/X'X/X'X/X GX <u JW7Y!X8W \"\n\"LX8W LX8W LX8W LX8W LX8W LX8W MW ,W ,W ,W ,W )W ,W ,W ,W /W2W NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W  &WGWBW NW6W MW6W MW6W MW6W GWFW CW3W JWFW     FW?V?V+W(V+WKXCY\"\n\"KV+WKX5V+W(V%W .WFX     N~X'WHT   =~T-~\\\\$q Eo\\\"W4W NV4V GWBW >XIW GW                 LX       ;~X JSFX 3VDV?V@W9ZJW  +V \\\"W   !V       V -X6X =X 2Z  IX#\"\n\"~ /X NX5X ?X ?X4X .X     Jd D~X Dd IX 8UAV8VCV>z!X3X%Y ,X,Y+X -X /Y*X+X/X'X -X -XD[ DX -XBVNVBX0X>XJX(Y)X,X /Y)X,X9Y *X AX <X/X LXHX AXJV=VJX.XEY ;X 5\"\n\"Z 6W &V 'W       DW7W JW3W$W ,W3W!W 'W 1W3W MW6W MW ,W ,WKY :W ,W7W7W=W6W!W2W NW3W$W3W MW  H\\\\ DW ,W6W GWFW @WJVDVJW!` 9WGX <Y &X 9V  LX =P   (T?\\\\@T0W8\"\n\"X IW5W\\\"W<W GW2W X ,W6W FVGW >XBW FW6W!W<W<W3WCWCW!W=W JWCWCW\\\"W2W%W2W ?W =W4W LW4W FY 8X -X+X+YCXCY*X0X N\\\\MXM\\\\%Y)X+Y  DV  EY NQFVFQ Y+Y CV   DX 3W@S 6X\"\n\" 1V<V K|  ![HW   @TFW.T9m =XFX  ?V  ,TCVAVDT    &V      \\\"W6W :UGU      *m 9XFX -V<SFU\\\"V/U\\\"V<SFU;X ,z z z z z z v NY ,X -X -X -X -X -X -X -X ,X,Y,X>XJX\"\n\"(Y)X.Y)X.Y)X.Y)X.Y)X KZKZ!YJW6X,X/X'X/X'X/X'X/X GX <t IW6Y\\\"W7W LW7W LW7W LW7W LW7W LW7W LW7W MW ,W ,W ,W ,W )W ,W ,W ,W /W2W NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W \"\n\" &WHWAW NW6W MW6W MW6W MW6W GWGX CW3W JWGX     EV?V@W*V)W*VJVAWKW*VJV5W*V)W%W .XGW     M~X&WJT   <~S,kNn#o Cm!W4W NV4V HXBX ?XJX FW                 MY\"\n\"       <~X JSEX 5VCV?V@W8ZLW  *W #W   !V       V -X6X =X 3Z  HX#~ /X NX5X @Y ?X4X /X     Ge G~X Ge GX 8UAV9WCU>|\\\"X3X$X ,X,X*X -X .X*X+X/X'X -X -XC[ EX\"\n\" -XA\\\\AX0X=WJX'X)X,X .X)X,X8X *X AX <X/X LXHX AXJV=VJX/YEY ;X 6Z 5W &V 'W       DW7W JW3W$W ,W3W!W 'W 1W3W MW6W MW ,W ,WJY ;W ,W7W7W=W6W!W2W NW3W$W3W M\"\n\"W  EZ EW ,W6W GWFW ?WKVDVKW!b 9WHW <Y $W 9V  LW     BTAVNUAT/W8X IW5W#W;V FW2W!X +W6W FWIX >XBX GW6W!W<W<W3WCWCW!W=W JWCWCW\\\"W2W%W2W ?W =W4W MX4X HY 7X\"\n\" -Y-Y+ZDXDZ*X0X Mt#X)X*Y  EV  FY NSGVGS Y-Y MQFVFQ   X 3W@S 6X 1W>W 9X   =\\\\KW   >SEW<PCS  6XFX  @V  +SCVAWES    %V      \\\"W6W :UGU        &XFX -V<TFU#V\"\n\"/U\\\"V<TFU<X ,|\\\"|\\\"|\\\"|\\\"|\\\"|\\\"w MX ,X -X -X -X -X -X -X -X ,X,X+X=WJX'X)X-X)X-X)X-X)X-X)X LZIZ!XKW5X,X/X'X/X'X/X'X/X GX <s HW5X\\\"W7W LW7W LW7W LW7W LW7W LW7W\"\n\" LW7W MW ,W ,W ,W ,W )W ,W ,W ,W /W2W NW6W!W2W\\\"W2W\\\"W2W\\\"W2W\\\"W2W  &WIW@W NW6W MW6W MW6W MW6W FWHW BW3W IWHW     DW@VAW)W+W)WJT?UKW)WJT5W)W+W$W -WHX     \"\n\"M~X&WJT   ;eMQMe+jNQNj!m Bl W4W NW6W HXBX >WJX FW                 LX       <~X JSEX 6WCV?V@W7ZMW  *W #W   !V      !W -X6X =X 4Z  GX#~ /X NX5X @X >X4X \"\n\"/X     De J~X Je DX 8U@V:WDV>|\\\"X3X$X ,X-Y*X -X .X*X+X/X'X -X -XB[ FX -XA\\\\AX0X=XKX'X*Y,X .X*Y,X8Y +X AX <Y1Y KWHW ?WJV=VJW/YCY <X 7Z 4W &W (W       EW6\"\n\"W JX5X$X -X5X!X (W 0W5X MW6W MW ,W ,WIY <W ,W7W7W=W6W!X4X NX5X$X5X MW  CX EW ,W6W GXHX ?WKVDVKW!XNY :WIX =Y #X :V  MX     BUCVMVBT/W9Y IW5W#W<W FW3X!W\"\n\" *W6W EVIX ?X@W GW6W!W=Y=W3XDWDX!W=W JWCWCW\\\"X4X%X4W >W <W6W LX4X HY 7X ,X-X)ZEXEZ)X0X Lr\\\"X)X)Y  FV  GY NUHVHU Y/Y MSGVGS  !X 3XAS 6X 0W@W 8X   ;\\\\NW   \"\n\"=TEX@RDT  5XFY  BV  +TDV@WGT    %V      \\\"W6W :UGU        (YFX ,V=TEU#V0U!V=TEU<X ,|\\\"|\\\"|\\\"|\\\"|\\\"|\\\"w MX ,X -X -X -X -X -X -X -X ,X-Y+X=XKX'X*Y-X*Y-X*Y-X*Y-\"\n\"X*Y MZGZ\\\"XLW5Y,Y1Y'Y1Y'Y1Y'Y1Y GX <r GW4X$W6W MW6W MW6W MW6W MW6W MW6W MW6X NX -X -X -X -X *W ,W ,W ,W /W2W NW6W!X4X\\\"X4X\\\"X4X\\\"X4X\\\"X4X  &WIV@X NW6W MW6W\"\n\" MW6W MW6W FWIX BX5X IWIX     CWAVAW(W,W(WJR=SJW(WJR4W(W,W$W -XIX     M~X&WJS   :dLQLd+iMQNj!l @j NW4W NW6W HW@W >WJW DW                 MX       .VCV\"\n\" :SDW 6VBV?V@W6b  )W #W   !V      !V +X8X <X 5Z  FX#~ /X MW5X @X >X4X /X     Ad L~X Ld AX 8VAV:WDU=|\\\"X3X$Y -X-Y*X -X .Y+X+X/X'X -X -XA[ GX -XA\\\\AX0X<WK\"\n\"X'Y+X+X .Y+Y,X7X +X AX ;X1X JXJX ?XLW=WLX/XAY =X 7Y 3W %V (W       EW7X JX5W\\\"W ,W5X W (W 0W5X MW6W MW ,W ,WHY =W ,W7W7W=W6W W4W MX5W\\\"W5X MW  BX FW ,W6\"\n\"W FWHW >WKVDVKW\\\"XLX 9WJW =Z #X :V  MX     AUEVKVDU/X:Y IW5W#W<W EW4W!X *W6W EVJX >X@W GW6W!W=Y=W2WDWDW W=W JWCWCW\\\"X4W#W4W >W <W6W LW2W IY 6X ,Y/Y(ZFXF\"\n\"Z(X0X Kp!Y+X'Y  GV  HY NWIVIW Y1Y MUHVHU  \\\"X 2WAS 6X 0YDY 8X   :c   <TE[FUDS  3XFY  CV  *SDV@WGS    $V      \\\"W6W :UGU        )YFX ,V=TDU$V0V\\\"V=TDU=X +\"\n\"|\\\"|\\\"|\\\"|\\\"|\\\"|#x MY -X -X -X -X -X -X -X -X ,X-Y+X<WKX'Y+X,Y+X,Y+X,Y+X,Y+X MZEZ#YNW4X*X1X%X1X%X1X%X1X FX <p EW4X$W7X MW7X MW7X MW7X MW7X MW7X MW7Y MW ,W \"\n\",W ,W ,W *W ,W ,W ,W .W4W MW6W W4W W4W W4W W4W W4W  $WKV?W MW6W MW6W MW6W MW6W EWJW AX5W GWJW     BXBVBW'X.W'XJP;QJW'XJP4W'X.W#V ,XIW     L~X%WLT   :d\"\n\"LQLc*iMQMi k ?i NW4W NW6W IX@X ?XLX DW                 MY       0VBV :SDW 7VAV?V@X6a  )W #W   !V      !V +X8X <X 6Z  EX#~ 0Y MW5X AY >X4X 0X     =d ~X\"\n\" d   LUAW<XEV>X2X#X3X#X -X.Y)X -X -X+X+X/X'X -X -X@[ HX -X@Z@X0X<XLX&X+X+X -X+X+X7Y ,X AX ;X1X JXJX ?XLV;VLX0YAY =X 8Z 3W %V (W       EW7X JX5W\\\"W ,W5X\"\n\" W (W 0W5X MW6W MW ,W ,WGY >W ,W7W7W=W6W W4W MX5W\\\"W5X MW  BX FW ,W7X FWHW >WLVBVLW#YKX :WJW =Y !W :V  MW     @VHXJWHV-W:Y IW5W#W<W EW4W!W )W6W EWKX ?X\"\n\"?X HW6W!X>Y>W1WDWDW W=W JWCWCW\\\"X4W#W4W >W <W6W MX2X KY 5X +Y1Y'[GXH\\\\(X0X Jn NX+X&Y  HV  IY NYJVJY Y3Y MWIVIW  #X 2WAS 6X 0[H[ 8X :V %`   :TEiET  2YGY \"\n\" DV  *TEV?WIT    $V      \\\"W6W :UGU        *YGY ,V<SCU%V0V\\\"V<SCU=X ,X2X$X2X$X2X$X2X$X2X$X2X$X8X LX -X -X -X -X -X -X -X -X ,X.Y*X<XLX&X+X+X+X+X+X+X+X+X\"\n\"+X NZCZ#`3X*X1X%X1X%X1X%X1X FX <m BW3W$W7X MW7X MW7X MW7X MW7X MW7X MW7Y MW ,W ,W ,W ,W *W ,W ,W ,W .W4W MW6W W4W W4W W4W W4W W4W 5Z IWLV>W MW7X MW7X \"\n\"MW7X MW7X EWJW AX5W GWJW     AXCVCW%X0W%X0W%X0W%X0W\\\"V +WJX     ?X 2WLT   9bKQKb)gLQMh Mi =g MW4W MV6W IX@X ?XLX CW                 MX       0VBV :SDW \"\n\"7VAV?V@X5_  (W #W   !V      \\\"W +X8X <X 7Z  DX 5X 'X LX7X @X =X4X 0X     ;e   Le   JUAW<XFV=X1W#X3X#Y .X.Y)X -X -Y,X+X/X'X -X -X?[ IX -X@Z@X0X;XMX&Y-Y+\"\n\"X -Y-Y+X6X ,X AX ;X1X IXLX >XLV;VLX1Y?Y >X 9Z 2W %W )W       EW7X JX5W\\\"X -W5X X )W 0X7Y MW6W MW ,W ,WFY ?W ,W7W7W=W6W W4W MX5W\\\"W5X MW  AW FW ,W7X FXJX\"\n\" =WMVBVMW#YJY ;WKX >Y  W :V  MW     ?dId,W;Z IW5W#W=W DW4W!W )W6W DVKW >X>W HW6W W>Y>W1WDWDW W=W JWCWDX\\\"X4W#W4W >W ;V7W LX2X LY 4X *X1X%]JXJ]'X0X Hj L\"\n\"Y-Y%Y  IV  JY LYKVKY MY5Y MYJVJY  $X 2XBS 6X 2q 9X :V #\\\\   7TDgFT  /XFX  EV  )TFV>VJT    #V      \\\"W6W :UGU        +XFX *V=TCU%V1V!V=TCU=X ,X1W$X1W$X1W\"\n\"$X1W$X1W$X2X%X7X LY .X -X -X -X -X -X -X -X ,X.Y*X;XMX&Y-Y+Y-Y+Y-Y+Y-Y+Y-Y ZAZ$_3Y*X1X%X1X%X1X%X1X FX <i >W3W$W7X MW7X MW7X MW7X MW7X MW7X MW7Z NX -X \"\n\"-X -X -X +W ,W ,W ,W .W4W MW6W W4W W4W W4W W4W W4W 5Z IWMV=W MW7X MW7X MW7X MW7X EWKX AX5W GWKX     @XDVDX$X2X$X2X$X2X$X2X\\\"V +XKW     ?X 1WMT   7`JQKa\"\n\"'fLQLf Kg <f LW4W MW8W HW>W >WLW BX                 NY       1VBV :SDW 8V@V?V?W4]  &V $W    V      \\\"V *Y:Y <X 8Z  DY 5X 'X KW7X @X =X5Y 1Y     8e  #e \"\n\"  GU@W>YGW>X0X$X4Y\\\"Y /X/Y(X -X ,Y-X+X/X'X -X -X>[ JX -X@Z@X0X;XMX%Y/Y*X ,Y/Y*X6Y -X AX ;Y3Y IXLX =WLV;VLW0X=Y ?X :Z 1W $V )W       EW8Y JY7X\\\"X -X7Y X \"\n\")W 0X7Y MW6W MW ,W ,WEY @W ,W7W7W=W6W X6X MY7X\\\"X7Y MW  AW FW ,X8X EWJW <WMVBVMW#XHX :WLW >Y  NW :V  MW     >bGc,W;[ JW6X#W=W DX6X!W )W6W DVLX >W=X IW7\"\n\"X W>Y>W1XEWEX W=W IWDWDW!Y6X#X6X >W ;W8W MX0X MY 4X *Y3Y$^LXL^&X0X Ff IY/Y#Y  JV  KY JYLVLY KY7Y KYKVKY  #X 2XBS 6X 3t ;X :V ![   8TCfFT  .XFX  FV  )U\"\n\"GV>WKT            MW7X :UGU        ,XFX *V=TBU&V2W!V=TBU=X -X0X&X0X&X0X&X0X&X0X&X0W%X7X KY /X -X -X -X -X -X -X -X ,X/Y)X;XMX%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y Z?Z$\"\n\"^4Y)Y3Y%Y3Y%Y3Y%Y3Y FX <X -W3W$W8Y MW8Y MW8Y MW8Y MW8Y MW8Y MW8[ NX -X -X -X -X +W ,W ,W ,W .X6X MW6W X6X X6X X6X X6X X6X 5Z I_=X MX8X MX8X MX8X MX8X \"\n\"DWLW @Y7X FWLW     >XEVFY\\\"X5Y\\\"X5Y\\\"X5Y\\\"X5Y!V *WLX     @X /WNT   7`JQJ_&eKQKe Je :d KW4W MW8W HW>X ?XNX AX                 Y       1VCV 9SDW 9V?V?V?X4\\\\ \"\n\" &W %W    V      \\\"V )X:X ;X 9Z  CX 4X (Y KW7X AX <Y6Y 1X     4e  )e   DVAX@ZHW=X0X$X4Y\\\"Y*P&X0Z(X -X ,Y-X+X/X'X -X -X=[ KX -X?X?X0X:XNX%Y/Y*X ,Y/Y*X5X \"\n\".Y AX :X3X HXLX =XNW;WNX1Y=Y ?X ;Z 0W $V )W       EW8Y JY7W W ,W7Y NX *W /W8Z MW6W MW ,W ,WDY AW ,W7W7W=W6W NW6W LY7W W7Y MW  AW FW ,X9Y EWJW <WMVBVMW\"\n\"$XFX ;WMX ?Y  MW :V  MW     =`Ea+X<[ JW6W\\\"W>W BW6W W )W6W DWMX ?X=X IX8X W?[?W0WEWEW NW=W IWDWDW!Y6W!W6W =W ;W8W MX0X NY 3X )Y5Y\\\"z%X0X C` FY/Y\\\"X  JV  \"\n\"KX HYMVMY IX7X IYLVLY  \\\"X 1XCS 6X 4v <X :V  [   8TBbET  ,WEW  FV  (T$T            LX8X :UGU        ,WEW )V=m,V3W V=mCX -X0X&X0X&X0X&X0X&X0X&X0X&X7X KY\"\n\"*P&X -X -X -X -X -X -X -X ,X0Z)X:XNX%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y!Z=Z%]3Y(X3X#X3X#X3X#X3X EX <X -W3W$W8Y MW8Y MW8Y MW8Y MW8Y MW8Y MW8[ MW ,X -X -X -X ,W ,W ,W \"\n\",W -W6W LW6W NW6W MW6W MW6W MW6W MW6W 4Z H^=W LX9Y MX9Y MX9Y MX9Y DWMX @Y7W EWMX     =Y8Y Y8Y Y8Y Y8Y Y8Y V *WLX     AX .WNT   6^IQI]$cKRJc Id 8c KW4W\"\n\" MX:X IX>X ?XNX AY                 Y4P       VBV 9SDW 9V?V?V?Y4Z  %W %W    V      #W )X:X ;X :Z  CY 4X (Y KX9Y AX ;X6X 1Y     1e  /e   @U@XB[JX<X/W$X4\"\n\"X Y,Q&X1Z'X -X +Y.X+X/X'X -X -X<[ LX -X?X?X0X:XNX$Y1Y)X +Y1Y)X5Y /X @X :X4Y GXNX <XNV9VNX2Y;Y @X ;Y /W $W *W       EW9Z JZ9X X -X9Z NX *W /X9Z MW6W MW\"\n\" ,W ,WCY BW ,W7W7W=W6W NX8X LZ9X X9Z MW  AW FW +W9Y EXLX <WNV@VNW%YEX ;WNW ?Y  LW :V  MW     <^C_)W=\\\\ JX7W\\\"W>W BX8X W )W6W CVNX >W;W IX8X X@[@X0XFWEW \"\n\"NW=W IWDWEX!Z8X!X8X =W :W:W LX0X Y 2X (Y7Y Nv#X0X ?X AY1Y V  IV  JV FYNVNY GV5V GYMVMY  !X 1XCS 6X 5x =X :V  MZ   8T?ZBT  *VDV  FV  'T&T            KX\"\n\"8X :UGU        ,VDV )V<m-V3V NV<mCX -X/W&X/W&X/W&X/W&X/W&X0X'X6X JY,Q&X -X -X -X -X -X -X -X ,X1Z(X:XNX$Y1Y'Y1Y'Y1Y'Y1Y'Y1Y!Z;Z%[3Y'X4Y#X4Y#X4Y#X4Y EX\"\n\" <X -W3W$W9Z MW9Z MW9Z MW9Z MW9Z MW9Z MW9] NX -X -X -X -X ,W ,W ,W ,W -X8X LW6W NX8X MX8X MX8X MX8X MX8X 4Z H]=X KW9Y LW9Y LW9Y LW9Y CWNW ?Z9X DWNW   \"\n\"  ;Y;Z MY;Z MY;Z MY;Z MY;Z NV *XMW     AY -[   3ZHRH[\\\"aJRI` Fb 6a JW4W LW:W HX=W >WNX @Y                !Z6Q       VBV KP>SEW 9V>WAW>X3Z  &W %W    V  \"\n\"    #V 'X<X :X ;Z  BY 4X )Y IW9X AY ;Y8Y 2Y     .d  1d   >U?ZH^MZ<X.X%X5Y NY.R&X2Z&X -X *Y/X+X/X'X -X -X;[ MX -X&X0X9a$Z3Y(X *Y3Y(X4X$P-Y @X :Y5Y GXNX\"\n\" <XNV9VNX2X9Y AX <Z /W #V *W       EX:Z JZ9X NX .X9Z MX +W .X;[ MW6W MW ,W ,WBY CW ,W7W7W=W6W NX9Y LZ9X X9Z MW  AW FW +W:Z DWLW :^@^$XDY <WNW @Z  LW :\"\n\"V  MW     ;\\\\@['X>\\\\ JX8X\\\"W?W AX9Y X *W6W CVNX ?X;X JX9Y NW@[@W/XFWFX NW=W IXEWEX!Z8X!X8W ;W ;W;X MX.X\\\"Y 1X 'Y9Y Lt\\\"X0X ?X @Y3Y MT  HV  IT Dj ET3T EYNVN\"\n\"Y   X 0XDS 6X 6ZM`LY >X :V  LY   7T)T  (UCU     ET(T            JX9Y :UGU        ,UCU )V;m.V3V NV;mCY7P HX.X(X.X(X.X(X.X(X.X(X.X(X6X IY.R&X -X -X -X -\"\n\"X -X -X -X ,X2Z'X9a$Z3Y&Z3Y&Z3Y&Z3Y&Z3Y!Z9Z&Z3Y&Y5Y#Y5Y#Y5Y#Y5Y EX <X -W3W$X:Z MX:Z MX:Z MX:Z MX:Z MX:Z MX:^ NX -X -X -X -X -W ,W ,W ,W -X8X LW6W NX9Y\"\n\" MX9Y MX9Y MX9Y MX9Y 4Z H\\\\=Y KW:Z LW:Z LW:Z LW:Z CWNW ?Z9X DWNW     :[@[ K[@[ K[@[ K[@[ K[@[ MV )WNX     AX ,[   1WGRFW N_IRH^ Da 5_ IW4W LX<X HW<W >`\"\n\" >Y                !Y8S   MX   +VBV KQ?SFX 9V=VAV=Y6]  &V &W    NV BX   1X 1V 'Y>Y :X <Z  BY 3X GP3Z IX;Y AX :Y9Z 2X GX -X  7a  1a .X 6V@iNa;X.X%X6Z N\"\n\"Z1T&X4\\\\&X -X *Z0X+X/X'X -X -X:[ NX -X&X0X9a#Z5Z(X *Z5Z(X4Y%R/Y @X 9Y7Y EWNW :WNV9VNW2Y9Y AX =Z .W #V *W       EX;[ J[;X MY .X;[ MY2P JW .Y=\\\\ MW6W MW ,\"\n\"W ,WAY DW ,W7W7W=W6W MX:X K[;X MX;[ MW /P4X FX ,X<[ DXNX :^@^%XBX <` @Y  KW :V  MW     8V;W%X?^ KY9X!V@X @X:X NX *W6W C_ >X:W JY;Z NXB]BX.XGWGX MW=W H\"\n\"XFWFX [:X NX:X ;W :W<W LX.X\\\"Y 1X &Y;Y Ip X0X ?X @Z5Z LR  GV  HR Bh CR1R Cj   NX 0YES 6X 7ZJ\\\\IY ?X :V  KY   8U+U  'TBT     DU+T            IY;Z :UGU   \"\n\"     ,TBT (V;m.V4V MV;mCY8Q HX.X(X.X(X.X(X.X(X.X(X.X)X5X IZ1T&X -X -X -X -X -X -X -X ,X4\\\\'X9a#Z5Z%Z5Z%Z5Z%Z5Z%Z5Z\\\"Z7Z&Z5Z%Y7Y!Y7Y!Y7Y!Y7Y DX <X -W4X$X\"\n\";[ MX;[ MX;[ MX;[ MX;[ MX;[ MX;`3P=Y .Y2P LY2P LY2P LY2P LW ,W ,W ,W ,X:X KW6W MX:X KX:X KX:X KX:X KX:X 3Z GZ<X JX<[ LX<[ LX<[ LX<[ C` ?[;X C`     9_J\"\n\"_ I_J_ I_J_ I_J_ I_J_ LV )`     AX +Z    S <[GRFZ A_ 4^ HW4W KX>X HX<X ?` =Z                \\\"Y:T   MX   +VCV JSASFX :V<VAV<Y8_  'W 'W    NV BX   1X 2W\"\n\" &X>X 9X =Z 1P2Z 3X GQ5Z GX=Y @X 9Y:Y KP8Z GX -X  4^  1^ +X 5U?gM_9W,W%X7Z L[4U&X6]%X -X )[2X+X/X'X -X -X9[ X -X&X0X8`\\\"Z7Z'X )Z7Z'X3X%T2Y ?X 9Z9Z E` :\"\n\"_9_3Y7Y BX >Z -W #W +W       DX=\\\\ J\\\\=Y LY7P HY=\\\\ LY5R JW -Y?] MW6W MW ,W ,W@Y EW ,W7W7W=W6W MY<Y K\\\\=Y MY=\\\\ MW /R6W DW ,Y=[ CWNW 9^@^&X@X <^ @Y  JW :V \"\n\" MW       HXA` LZ;X V@W ?Y<Y MX +W6W B^ ?X9W JZ<Z NXB]BX.YHWHY MW=W HYGWGY \\\\<Y NY<X :W :X>X LX.X#Y 0X %Y=Z Gl MX0X ?X ?Z7Z JP  FV  GP @f AP/P Ah   MX \"\n\"/YFSDP BX 8ZFVEY @X :V  JX   7V.U  %SAS     CU.U            HZ<Z :UGU        ,SAS (V:m/V5W MV:mBY;S HW,W(W,W(W,W(W,W(W,W(X.X)X5X H[4U&X -X -X -X -X -X\"\n\" -X -X ,X6]&X8`\\\"Z7Z#Z7Z#Z7Z#Z7Z#Z7Z\\\"Z5Z&[8Z$Z9Z!Z9Z!Z9Z!Z9Z DX <X -W4W\\\"X=\\\\ LX=\\\\ LX=\\\\ LX=\\\\ LX=\\\\ LX=\\\\ LX=b6R<Y7P GY5R KY5R KY5R KY5R LW ,W ,W ,W ,Y<Y KW\"\n\"6W MY<Y KY<Y KY<Y KY<Y KY<Y 3Z GY<Y JY=[ LY=[ LY=[ LY=[ B^ >\\\\=Y B^     7r Gr Gr Gr Gr KV (_     BX )Y    S 8RBSCR <] 2\\\\ GW4W KZBZ HX;W >_ <[          \"\n\"      $[=U   MX   ,VBV JUCSHY :V;WCW<[<b  (W 'W    NV BX   1X 2W &Y@Y 9X >Z 0R5Z 2X GT9[ GY?Z AY 9[>[ KR;Z FX -X  1[  1[ (X 5V>dL^9X,X&X9[ J[7W&X9_$X \"\n\"-X (\\\\6Z+X/X'X -X -X8[!X -X&X0X8`![;[&X ([;[&X3Y&W7[ ?X 8Z;Z D` :^7^3X5Y CX ?Z ,W #W +W       DY?] J]?Y KZ:R GY?] LZ8T JW -ZA^ MW6W MW ,W ,W?Y FW ,W7W7\"\n\"W=W6W LY>Y J]?Y KY?] MW /T9X DX ,Y@] CWNW 9]>]'Y@Y =^ AY  IW :V  MW       HYCXNW L\\\\>Y VAX >Y>Y LY ,W6W B] >X9X K[>[ MXDVMVDX,YIWIY LW=W GYHWHY N]>Y LY\"\n\">Y :X :X@X LX,X%Y /X $ZAZ Ch KX0X ?X >[;[   ?V   6d   >f   LX /[HSFR BX 9Z3Y AX :V  IX   7V1V  #R@R     BU0U            G[>[ :UGU        ,R@R 'V(U)V6W\"\n\" LV(U<Z>U IX,X*X,X*X,X*X,X*X,X*X,X*W4X G[7W&X -X -X -X -X -X -X -X ,X9_%X8`![;[![;[![;[![;[![;[\\\"Z3Z(];[\\\"Z;Z NZ;Z NZ;Z NZ;Z CX <X -WJP;X\\\"Y?] LY?] LY?] \"\n\"LY?] LY?] LY?] LY?XNZ9T<Z:R GZ8T KZ8T KZ8T KZ8T LW ,W ,W ,W +Y>Y JW6W LY>Y IY>Y IY>Y IY>Y IY>Y 2Z FY>Y HY@] KY@] KY@] KY@] B^ >]?Y A^     6o Do Do Do \"\n\"Do IV (_     CX (Y    S (S ,[ 0[ GW4W J\\\\H\\\\ GW:W >^ :\\\\                %[@W   MX   ,VBV JXFSIZ :V:WEW:\\\\@e  (V 'V    MV BX   1X 2V $ZDZ 8X ?Z /U;] 2X GV=\"\n\"\\\\ EZC[ @X 7[@[ JT?[ EX -X  /Y  1Y &X 5V=bK\\\\7X,X&X<^ I]=Z&X=b#X -X ']:\\\\+X/X'X -X -X7[\\\"X -X&X0X7_ \\\\?\\\\%X '\\\\?\\\\%X2X&Z<\\\\ >X 7[?[ B^ 9^7^4Y5Y CX ?Y +W \\\"V +W \"\n\"      DZB_ J_CZ I[>T G[C_ K[=W JW ,\\\\GXNW MW6W MW ,W ,W>Y GW ,W7W7W=W6W KZBZ I_CZ J[C_ MW /W>Z DZ .ZB^ C` 8\\\\>\\\\&X>Y =\\\\ AY  HW :V  MW       GZFYNY N]AZ N\"\n\"WCX <ZBZ JZ:Q EW6W B] ?X7W K\\\\A^ NYFWMWFY,ZJWJY KW=X H[JWJ[ N_BZ JZBZ 8Y <ZDZ LX,X&Y .X #ZCZ >_ FX0X ?X =\\\\?\\\\   >V   5b   <d   KX .\\\\JSHT BX 8X2X @X :V  \"\n\"IX   5V4U   Q?Q     AV4V            F\\\\A^ ;UGU        ,Q?Q 'V'U*V6W LV'U<[AW IX,X*X,X*X,X*X,X*X,X*X,X+X4X F]=Z&X -X -X -X -X -X -X -X ,X=b$X7_ \\\\?\\\\ N\\\\?\\\\\"\n\" N\\\\?\\\\ N\\\\?\\\\ N\\\\?\\\\ X1X(`?\\\\ [?[ L[?[ L[?[ L[?[ BX <X -WJS@Z\\\"ZB_ LZB_ LZB_ LZB_ LZB_ LZB_ LZBYM\\\\>W;[>T F[=W J[=W J[=W J[=W LW ,W ,W ,W *ZBZ IW6W KZBZ GZBZ \"\n\"GZBZ GZBZ GZBZ 1Z F[BZ GZB^ KZB^ KZB^ KZB^ A\\\\ =_CZ ?\\\\     3l Al Al Al Al HV (^     BX (X    NS (S ,Z .Y FW4W In GX:X ?^ 9_                (]FZ   MX   \"\n\",VBV J[ISL\\\\ :V9XGX9^Fi  )W )W    MV BX   1X 3W #[H[ Et Mx MZC_ 1X GZD^ C[G\\\\ @Y 7^F] IXF] DX -X  ,V  1V #X 4V<^IY5X*X'y G_D^&{!y NX &`B`+X/X'X -X -X6[#\"\n\"w LX&X0X7_ N^E^$X &^E^$X2Y'^C^ =X 7^E^ B^ 8]7]4Y3Y DX @~U&W \\\"W ,W       C\\\\HYNW JWNXG\\\\ H]EX F\\\\GXNW J]D[ JW +kMW MW6W MW ,W ,W=Y HW ,W7W7W=W6W K]H] IWNX\"\n\"G\\\\ I\\\\GXNW MW /[E\\\\ Be 9[GXNW B^ 7\\\\>\\\\'X<X =\\\\ AX  GW :V  MW       G\\\\IYM^$`F\\\\ MWEX ;]H] J]BV EW6W A\\\\ ?X7X L_GaKP#ZJYMYJZ*[LWL[ KW=Y H\\\\LWL\\\\ MWNXG] J]H\\\\ 7a \"\n\"C[H[ L~W'x MX 1iEi HX CX0X ?X <^E^   =V   4`   :b   JX -^MSLX Lz V0V ?X :V  HW   4V7V   MP>P     @W8W    3~W      :_GaKP @UGU        ,P>P 'V&U+V6V KV&\"\n\"U;]GZ JX*X,X*X,X*X,X*X,X*X,Y,Y,X4y7_D^&y Ny Ny Ny NX -X -X -X ,{\\\"X7_ N^E^ L^E^ L^E^ L^E^ L^E^ MV/V(dE^ N^E^ L^E^ L^E^ L^E^ BX <X -WJWF[ \\\\HYNW K\\\\HYNW K\"\n\"\\\\HYNW K\\\\HYNW K\\\\HYNW K\\\\HYNW K\\\\H[K^E[:]EX E]D[ I]D[ I]D[ I]D[ LW ,W ,W ,W )[F[ HW6W K]H] G]H] G]H] G]H] G]H] 1Z F]G] F[GXNW J[GXNW J[GXNW J[GXNW A\\\\ =WNX\"\n\"G\\\\ ?\\\\     1h =h =h =h =h FV ']     AV &W    T )T +X -X EW4W Hl FX9W ?^ 8~R                Jp   MX   ,VCV It 9V8XIX7sLZ  *W )W    MV BX   1X 3W #n Et M\"\n\"x Mu 0X Gs Ao @X 5t In CX -X  )S  1S  X 4V9XFU1X*X'x Ex&z y NX %|*X/X'X -X -X5[$w LX&X0X6^ Mu#X %u#X1X'y =X 6u A^ 8]7]4X1X DX @~U&W \\\"W ,W       ClMW J\"\n\"WMk Fo EkMW Is JW *jMW MW6W MW ,W ,W<Y IW ,W7W7W=W6W Jp HWMk GkMW MW /q Ae 9kMW B^ 7\\\\=[(Y;X >\\\\ Av 6W :V  MW       FkL]$u LXGX 9p Hp EW6W A[ ?X6X LpN\\\\#\"\n\"hKh)s JW<] Lu LWNm Hp 6` Bl K~W'x MX 1iEi HX CX0X ?X ;u   <V   3^   8`   IX ,o Lz NT.T >X :V  HW   3X=X        )X<X    2~W      :pN\\\\ @UGU           V&\"\n\"U+V7i.V&U:o JX*X,X*X,X*X,X*X,X*X,X*X-X3y6x&y Ny Ny Ny NX -X -X -X ,z!X6^ Mu Ju Ju Ju Ju KT-T(} Lu Ju Ju Ju AX <X -WJk NlMW KlMW KlMW KlMW KlMW KlMW Kn\"\n\"Is9o Ds Hs Hs Hs LW ,W ,W ,W )p HW6W Jp Ep Ep Ep Ep   Ls EkMW JkMW JkMW JkMW A\\\\ =WMk >\\\\     /c 8c 8c 8c 8c CV '\\\\     ?T %W    U *T *W ,V DW4W Gj EW8W \"\n\">\\\\ 5~P                In   LX   -VBV Is 9V7g6qJZ  *V )V    LV BX   1X 3V !l Dt Mx Mt /X Gr ?m ?X 4r Hm BX -X  &P  1P  LX 3V 3X*X'w Cv%x My NX #x(X/X'X\"\n\" -X -X4[%w LX&X0X5] Ls\\\"X $s\\\"X1Y(w ;X 5s ?\\\\ 7\\\\5\\\\5Y1Y EX @~U&W !V ,W       BjLW JWMj Dn DjMW Hr JW )hLW MW6W MW ,W ,W;Y JW ,W7W7W=W6W In GWMj EjMW MW /p\"\n\" ?d 8iLW B^ 6Z<[)Y:Y >Z @v 6W :V  MW       EiK]$t JYLZ 7n Fo EW6W A[ ?X5W LWNfM\\\\\\\"gKg'q IW<] Ks KWMk Fn 5` Aj J~W'x MX 1iEi HX CX0X ?X :s   ;V   2\\\\   6\"\n\"^   HX +n Lz MR,R =X :V  HW   1ZEZ        %ZDZ    0~W      :WNfM\\\\ @UGU          !V%U,V6i/V%U9n JX*X,X*X,X*X,X*X,X*X,X*X-X3y5v%y Ny Ny Ny NX -X -X -X ,\"\n\"x NX5] Ls Hs Hs Hs Hs IR+R(WMs Js Hs Hs Hs @X <X -WJk MjLW JjLW JjLW JjLW JjLW JjLW JmHr8n Cr Gr Gr Gr LW ,W ,W ,W (n GW6W In Cn Cn Cn Cn   Ls CiLW Ii\"\n\"LW IiLW IiLW @Z <WMj <Z     +] 2] 2] 2] 2] @V &[     >R $V    NU *U *U *U DW4W Fh DW8X ?\\\\ 4~                Hl   KX   -VBV Hp 8V5e4nGZ  +W +W    LV BX\"\n\"   1X 3V  j Ct Mx Mr -X Gq =j >Y 3p Gl AX -X       2X 3W 5X(X(u ?s$v Ky NX \\\"v'X/X'X -X -X3[&w LX&X0X5] Kq!X #p X0X(v :X 4p =\\\\ 7\\\\5\\\\6Y/Y FX @~U&W !V ,W \"\n\"      AhKW JWLh Bm ChLW Gq JW (eJW MW6W MW ,W ,W:Y KW ,W7W7W=W6W Hl FWLh ChLW MW /o >d 7gKW A\\\\ 5Z<Z(X8X >Z @v 6W :V  MW       DgI\\\\$s He 5l Dn EW6W @Y \"\n\">W4X MWMeM\\\\!eIe%o HW<] Jq JWLi Dk 2_ @h J~Y(x MX 1iEi HX CX0X ?X 9q   :V   1Z   4\\\\   GX *m Lz LP*P <X :V  HW   0m        \\\"l    .~W      :WMeM\\\\ @UGU   \"\n\"       !V%U,V6i/V%U8l JX(X.X(X.X(X.X(X.X(X.Y)X/X2y3s$y Ny Ny Ny NX -X -X -X ,v LX5] Kq Fq Fq Fq Fq GP)P'VKp Gp Ep Ep Ep >X <X -WJj KhKW IhKW IhKW IhKW\"\n\" IhKW IhKW IjEq7m Bq Fq Fq Fq LW ,W ,W ,W &j EW6W Hl Al Al Al Al   Ls AgKW HgKW HgKW HgKW @Z <WLh ;Z               MV &[     =P \\\"U    V +V )S (S CW4W \"\n\"De DX8X ?\\\\ 2|                Fh   IX   -VBV Ek 6V4c1kEZ  +V +V    KV BW   0X 4W  Mf At Mx Mq ,X Go :h =X 0l Ej ?X -W       1X 2W 6X(X(s ;o\\\"s Hy NX  r%\"\n\"X/X'X -X -X2['w LX&X0X4\\\\ Im NX !m NX0Y(t 9X 2m ;Z 5[5[5X-X FX @~U&W !W -W       @fJW JWJe ?j AeJW En IW 'cIW MW6W MW ,W ,W9Y LW ,W7W7W=W6W Fh DWJe AeJ\"\n\"W MW .m ;b 6eJW A\\\\ 5Z<Z)X6X >X ?v 6W :V  MW       CeG[$r Fc 2h Am EW6W @Y ?X3W MWMdL\\\\ cGc#m GW;\\\\ Hm HWKg Ah /] ?f I~Y(x MX 1iEi HX CX0X ?X 7m   8V   0\"\n\"X   2Z   FX (j Kz   AX :V  HW   -g         Lh    ,~W      :WMdL\\\\ @UGU          \\\"V$U-V5i0V$U7i HX(X.X(X.X(X.X(X.X(X.X(X/X2y1o\\\"y Ny Ny Ny NX -X -X -X ,t\"\n\" JX4\\\\ Im Bm Bm Bm Bm  %VHm Dm Bm Bm Bm =X <X -WJh HfJW HfJW HfJW HfJW HfJW HfJW HhBn4j ?n Cn Cn Cn KW ,W ,W ,W %h DW6W Fh =h =h =h =h   KVMi >eJW GeJW\"\n\" GeJW GeJW ?X ;WJe 9X               MW &Z       =U    W ,W *R &Q BW4W B` AW6W >[ /y                Dd   GX   -VCV Af 5V2a.gBZ  ,W -W    KV CX   0X 4V \"\n\" Kd @t Mx Km *X Ek 6d ;X .h Bh >X .X       1X 1W 7X(X(q 7j Np Ey NX  Mm\\\"X/X'X -X -X1[(w LX&X0X4\\\\ Gi LX  Ni LX/X$n 7X 0i 9Z 5[5[6Y-Y GX @~U&W  V -W    \"\n\"   >cIW JWIb <g =bIW Ci FW %_GW MW6W MW ,W ,W8Y MW ,W7W7W=W6W Ef CWIb =bIW MW +h 8a 5cIW @Z 4Y:Y*Y5X ?X ?v 6W :V  MW       AbDY$WMf Ca 0f >k EW6W @Y ?\"\n\"W2W MWK`I[ NaEa i EW;\\\\ Fi FWIc >e ,\\\\ =b G~Y(x MX 1iEi HX CX0X ?X 5i   6V   /V   0X   EX &f Iz   AX :V /P;W   *c         Gb    )~W      :WK`I[ @UGU    \"\n\"      #V#U.V4i1V#U6f FX(X.X(X.X(X.X(X.X(X.X(X/X2y/j Ny Ny Ny Ny NX -X -X -X ,p FX4\\\\ Gi >i >i >i >i  $VEi @i >i >i >i ;X <X -WIf EcIW FcIW FcIW FcIW Fc\"\n\"IW FcIW Fd>i0g ;i >i >i >i HW ,W ,W ,W #d BW6W Ef ;f ;f ;f ;f   JUJe ;cIW FcIW FcIW FcIW ?X ;WIb 7X               MW %Y       =T    X -X )P %P AW4W ?Z\"\n\" >W6X ?Z ,w                B`   EX   .VBV <] 1V0]*b?[  -W -W    KV CW   /X 4V  I` >t Mx Hg 'X Bf 2` :X +d =b ;X .W       0X 1X 9X&X)m 0d Kj ?y NX  Jg \"\n\"NX/X'X -X -X0[)w LX&X0X3[ Dc IX  Kf LX/Y!g 4X .e 7Z 5Z3Z7Y+Y HX @~U&W  V -W       =`GW JWG^ 7b 9^GW Ad CW \\\"YDW MW6W MW ,W ,W7Y NW ,W7W7W=W6W B` @WG^ 9\"\n\"^GW MW (c 2] 3_GW @Z 3X:X*Y4Y @X ?v 6W :V  MW       ?_AW$WKb @^ +` 9g CW6W ?W ?X2X NWJ^GY K]B^ Ke CW:[ Dd CWG_ 9` 'Y ;^ F~[)x MX 1iEi HX CX0X ?X 2c   \"\n\"3V   .T   .V   DX $b Gz   AX :V /R>X   &[         ?Z    %~W      :WJ^GY ?UGU          #V +V +V 1b EX&X0X&X0X&X0X&X0X&X0Y'X1X1y,d Ky Ny Ny Ny NX -X -X \"\n\"-X ,j @X3[ Dc 8c 8c 8c 8c  !VBc ;e :e :e :e 9X <X -WFa B`GW E`GW E`GW E`GW E`GW E`GW D`:d*b 7d 9d 9d 9d EW ,W ,W ,W !` @W6W B` 5` 5` 5` 5`   HVHa 7_GW\"\n\" D_GW D_GW D_GW ?X ;WG^ 5X               MW         7S                   @r                >Y         BS .V,W#Z   ;V -V     7W     ;W  EX     ;\\\\   6] \"\n\"+Z   5\\\\ 5Z   <W         7X     %\\\\       <]    \\\"X         ([   4c   E]   /[          (W  W .W       :Y #X 0Z 2X *\\\\   $W    &W         .Z =WDX 3XDW   I[\"\n\"   0Y       8W   -W :V  MW       <Z ;WH[ 9Y &Z 1]  LW ?W   >WGXBU FX=X E` \\\"W >] @WDY 3Z   2X               C[           >T     :[       KV /TAY       \"\n\"                   EWGXBU =UGU   BT       6V +V +V ,Y               ?\\\\                    +[ 0[ 0[ 0[ 0[   KT=[ 2[ 0[ 0[ 0[     7Z ;Y .Y .Y .Y .Y .Y -\"\n\"Y2\\\\\\\"Z /\\\\ 1\\\\ 1\\\\ 1\\\\         CZ   3Z /Z /Z /Z /Z   FVCZ 1Y .Y .Y .Y ,W :WDX 2W               LW         7R                                             #S\"\n\"       >W /W     8W     :V                      \\\"W         5X                  )X             &Z                  CW  NV .W                   :W    %W\"\n\"           @W  :W              -X   -W :V  MW         LW        FW ?W   >W    NW   0W =W                                      3S       GV /XGZ        \"\n\"                  DW  HUGU   AT                            %T                               'R                             JT                         \"\n\"      #T         (X :W  NX               LW                                                       7S       =V /V     7W     :V                      \\\"W\"\n\"         4X'Q                 &Y             %Z                  DW  NV .W                   :W    %W           @W  :W              -W   ,W :V  MW    \"\n\"     LW        FW ?W   >W    NW   0W =W                                      3S       GV /j                          CW  HUGU   @T                    \"\n\"        %T                               'P                             HT                               \\\"Q         'W 9W  NW               KW        \"\n\"                                               7S       =W 1W     7V     :W                      \\\"V         2X)R                 &X             #Z    \"\n\"              EW  NW /W                   :W    %W           @W  :W              -W   ,X ;V  NX         LW        FW ?W   >W    NW   0W =W            \"\n\"                          3S       GV /j                          CW  HUGU   @U                            &U                                         \"\n\"                    U                               \\\"P         'W 9W  NW               KV                                                       6S    \"\n\"   <V 1V     6V     :V                      !V         1Y-U                 'X             \\\"Z                  FW  MV /W                   ;X    %W   \"\n\"        @W  :W              .X   +W ;V  NW         KW        FW ?W   >W    NW   0W =W                                      3S       GV /h             \"\n\"             AW  HUGU   ?T                            %T                                                             NT                               \"\n\"          )X 9W  X               KV                                                       6S       <W 3V     6V     9V                      \\\"V        \"\n\" /Z1X                 (X             !Z                  Ga (V 9a                   ;W    $W           @W  :W              .W   *W ;V  NW         KW  \"\n\"      FW ?W   >W    NW   0W =W                                      3S       GV .f                          @W  HUGU   ?U                            &\"\n\"U                                                             U                                         *W 8W  W               JV                     \"\n\"                                  6S       ;V 3V     6V     :W                      \\\"V         .[5[                 *Y              Z                 \"\n\" Ha (W :a                   <X    $W           @W  :W              /X   *X <V  X         KW        FW ?W   >W    NW   0W =W                           \"\n\"           3S       GV +a                          >W  HUGU   >T                            %T                                                        \"\n\"     NT                                         +X 8W !X              (VIV                                                       6S       :V 5V     5U\"\n\"     9W                      \\\"U         +\\\\;]                 )X              MZ                  Ia (W :a                   =Y    %W           ?W  :W \"\n\"             /W   )[ ?V #[         KW        FW ?W   >W    NW   0W =W                                      3S       GV 'Z                          ;W \"\n\" HUGU   >U                            &U                                                             U                                         ,W 7W !\"\n\"W              'VIV                                                       6S       :V 6W     6V                            4V         *_C`            \"\n\"     )Y              LZ                  Ja   :a                  (P7Y    $W           ?W  :W              0X   (b GV +b         JW        FW ?W   >W \"\n\"   NW   0W =W                                      3S       GV                            7W  HUGU   >U                            &U                 \"\n\"                                            U                                         -X 7W \\\"X              'VJW                                      \"\n\"                 6S       9V 7V     5U                            3U         'x                 (Z              KZ                  Ka   :a           \"\n\"       (R:Z    $W           ?W  :W              0X   (b GV +b         JW        FW ?W   >W    NW   0W =W                                      3S      \"\n\" GV                            7W     #U                            &U                                                             U                  \"\n\"                       -X 7W \\\"X              &UJW                                                       6S       9W 9W                                \"\n\"            Bu                 ([              IZ                  La   :a                  (T>[    $X           ?W  :W              1X   &a GV +a    \"\n\"     IW        FW ?W   >W    NW   0W =W                                      3S       GV                            7W     $V                         \"\n\"   'V                                                            !V                                         .X 6W #X              %VLW                \"\n\"                                       5S                                                     2p                 -a                                   \"\n\"                    8XE]    %Y           >W  :W              3Z   $_ GV +_         GW        FW ?W   >W    NW   0W =W                                 \"\n\"     3S       GV                            7W     /QGW                            2QGW                                                            ,QG\"\n\"W                                         0Z 6W %Z              %a                                                       5S                           \"\n\"                          0l                 +a                                                       8p    +_           >W  :W              ;a   !] G\"\n\"V +]         EW        FW ?W   >W    NW   0W =W                                      3S       GV                            7W     /`                 \"\n\"           1`                                                            +`                                         7a 5W -a              #`          \"\n\"                                                                                                   >e                 '`                              \"\n\"                         7o    *^           =W  :W              ;`    KY GV +Y         AW        FW ?W   >W    NW   0W =W                             \"\n\"         3S       GV                            7W     /`                            1`                                                            +` \"\n\"                                        7` 4W -`              \\\"_                                                                                      \"\n\"                       8\\\\                 #_                                       \\\"}              3n    )^           =W  :W              ;`     9V   \"\n\"        BW        FW ?W   >W    NW   0W =W                                             'V                            7W     /_                        \"\n\"    0_                                                            *_                                         6` 4W -`              !]                 \"\n\"                                                                                                              -]                                      \"\n\"  }              3l    ']           <W  :W              ;_     8V           BW        FW ?W   >W    NW   0W =W                                        \"\n\"     'V                            7W     /^                            /^                                                            )^              \"\n\"                           5_ 3W -_               N[                                                                                                  \"\n\"                             ,[                                        M}              2j    &\\\\           ;W  :W              ;^     7V           BW  \"\n\"      FW ?W   >W    NW   0W =W                                                                          7W     -Y                            *Y       \"\n\"                                                     $Y                                         2^ 2W -^               LX                             \"\n\"                                                                                                  *X                                        J}        \"\n\"      /d    #Z           9W  :W              ;\\\\     5V           BW        FW ?W   >W    NW   0W =W                                                   \"\n\"                       7W                                                                                                                             \"\n\"            /\\\\ 0W                 HT                                                                                                                  \"\n\"                                                      I}              *[     NW           6W  :W              ;Z     3V           BW        FW ?W   >W\"\n\"    NW   0W =W                                                                          7W                                                            \"\n\"                                                                             /Z .W                                                                    \"\n\"                                                                                                                     =}                               \"\n\"                                                                                                                                                      \"\n\"                                                                                                                              D\" };\n\n    // Define a 40x38 'danger' color logo (used by cimg::dialog()).\n    static const unsigned char logo40x38[4576] = {\n      177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200,\n      1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0,\n      0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200,\n      1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0,\n      2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255,\n      255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189,\n      189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189,\n      189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123,\n      22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200,\n      1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0,\n      0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1,\n      123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189,\n      189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255,\n      0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189,\n      189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,\n      255,0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,\n      123,123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,\n      1,189,189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,\n      255,255,0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,\n      1,189,189,189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,\n      255,255,0,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,\n      123,0,26,255,255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,\n      0,4,123,123,123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,\n      123,123,123,86,200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0 };\n\n    //! Get/set default output stream for the \\CImg library messages.\n    /**\n       \\param file Desired output stream. Set to \\c 0 to get the currently used output stream only.\n       \\return Currently used output stream.\n    **/\n    inline std::FILE* output(std::FILE *file) {\n      cimg::mutex(1);\n      static std::FILE *res = stderr;\n      if (file) res = file;\n      cimg::mutex(1,0);\n      return res;\n    }\n\n    // Return number of available CPU cores.\n    inline unsigned int nb_cpus() {\n      unsigned int res = 1;\n#if cimg_OS==2\n      SYSTEM_INFO sysinfo;\n      GetSystemInfo(&sysinfo);\n      res = (unsigned int)sysinfo.dwNumberOfProcessors;\n#else\n      res = (unsigned int)sysconf(_SC_NPROCESSORS_ONLN);\n#endif\n      return res?res:1U;\n    }\n\n    // Lock/unlock mutex for CImg multi-thread programming.\n    inline int mutex(const unsigned int n, const int lock_mode) {\n      switch (lock_mode) {\n      case 0 : cimg::Mutex_attr().unlock(n); return 0;\n      case 1 : cimg::Mutex_attr().lock(n); return 0;\n      default : return cimg::Mutex_attr().trylock(n);\n      }\n    }\n\n    //! Display a warning message on the default output stream.\n    /**\n       \\param format C-string containing the format of the message, as with <tt>std::printf()</tt>.\n       \\note If configuration macro \\c cimg_strict_warnings is set, this function throws a\n       \\c CImgWarningException instead.\n       \\warning As the first argument is a format string, it is highly recommended to write\n       \\code\n       cimg::warn(\"%s\",warning_message);\n       \\endcode\n       instead of\n       \\code\n       cimg::warn(warning_message);\n       \\endcode\n       if \\c warning_message can be arbitrary, to prevent nasty memory access.\n    **/\n    inline void warn(const char *const format, ...) {\n      if (cimg::exception_mode()>=1) {\n        char *const message = new char[16384];\n        std::va_list ap;\n        va_start(ap,format);\n        cimg_vsnprintf(message,16384,format,ap);\n        va_end(ap);\n#ifdef cimg_strict_warnings\n        throw CImgWarningException(message);\n#else\n        std::fprintf(cimg::output(),\"\\n%s[CImg] *** Warning ***%s%s\\n\",cimg::t_red,cimg::t_normal,message);\n#endif\n        delete[] message;\n      }\n    }\n\n    // Execute an external system command.\n    /**\n       \\param command C-string containing the command line to execute.\n       \\param module_name Module name.\n       \\return Status value of the executed command, whose meaning is OS-dependent.\n       \\note This function is similar to <tt>std::system()</tt>\n       but it does not open an extra console windows\n       on Windows-based systems.\n    **/\n    inline int system(const char *const command, const char *const module_name=0) {\n      cimg::unused(module_name);\n#ifdef cimg_no_system_calls\n      return -1;\n#else\n#if cimg_OS==1\n      const unsigned int l = (unsigned int)std::strlen(command);\n      if (l) {\n        char *const ncommand = new char[l + 16];\n        std::strncpy(ncommand,command,l);\n        std::strcpy(ncommand + l,\" 2> /dev/null\"); // Make command silent.\n        const int out_val = std::system(ncommand);\n        delete[] ncommand;\n        return out_val;\n      } else return -1;\n#elif cimg_OS==2\n      PROCESS_INFORMATION pi;\n      STARTUPINFO si;\n      std::memset(&pi,0,sizeof(PROCESS_INFORMATION));\n      std::memset(&si,0,sizeof(STARTUPINFO));\n      GetStartupInfo(&si);\n      si.cb = sizeof(si);\n      si.wShowWindow = SW_HIDE;\n      si.dwFlags |= SW_HIDE | STARTF_USESHOWWINDOW;\n      const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);\n      if (res) {\n        WaitForSingleObject(pi.hProcess, INFINITE);\n        CloseHandle(pi.hThread);\n        CloseHandle(pi.hProcess);\n        return 0;\n      } else return std::system(command);\n#endif\n#endif\n    }\n\n    //! Return a reference to a temporary variable of type T.\n    template<typename T>\n    inline T& temporary(const T&) {\n      static T temp;\n      return temp;\n    }\n\n    //! Exchange values of variables \\c a and \\c b.\n    template<typename T>\n    inline void swap(T& a, T& b) { T t = a; a = b; b = t; }\n\n    //! Exchange values of variables (\\c a1,\\c a2) and (\\c b1,\\c b2).\n    template<typename T1, typename T2>\n    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {\n      cimg::swap(a1,b1); cimg::swap(a2,b2);\n    }\n\n    //! Exchange values of variables (\\c a1,\\c a2,\\c a3) and (\\c b1,\\c b2,\\c b3).\n    template<typename T1, typename T2, typename T3>\n    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {\n      cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);\n    }\n\n    //! Exchange values of variables (\\c a1,\\c a2,...,\\c a4) and (\\c b1,\\c b2,...,\\c b4).\n    template<typename T1, typename T2, typename T3, typename T4>\n    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {\n      cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);\n    }\n\n    //! Exchange values of variables (\\c a1,\\c a2,...,\\c a5) and (\\c b1,\\c b2,...,\\c b5).\n    template<typename T1, typename T2, typename T3, typename T4, typename T5>\n    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {\n      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);\n    }\n\n    //! Exchange values of variables (\\c a1,\\c a2,...,\\c a6) and (\\c b1,\\c b2,...,\\c b6).\n    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>\n    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6) {\n      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);\n    }\n\n    //! Exchange values of variables (\\c a1,\\c a2,...,\\c a7) and (\\c b1,\\c b2,...,\\c b7).\n    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>\n    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,\n                     T7& a7, T7& b7) {\n      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);\n    }\n\n    //! Exchange values of variables (\\c a1,\\c a2,...,\\c a8) and (\\c b1,\\c b2,...,\\c b8).\n    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>\n    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,\n                     T7& a7, T7& b7, T8& a8, T8& b8) {\n      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);\n    }\n\n    //! Return the endianness of the current architecture.\n    /**\n       \\return \\c false for <i>Little Endian</i> or \\c true for <i>Big Endian</i>.\n    **/\n    inline bool endianness() {\n      const int x = 1;\n      return ((unsigned char*)&x)[0]?false:true;\n    }\n\n    //! Reverse endianness of all elements in a memory buffer.\n    /**\n       \\param[in,out] buffer Memory buffer whose endianness must be reversed.\n       \\param size Number of buffer elements to reverse.\n    **/\n    template<typename T>\n    inline void invert_endianness(T* const buffer, const cimg_ulong size) {\n      if (size) switch (sizeof(T)) {\n        case 1 : break;\n        case 2 : { for (unsigned short *ptr = (unsigned short*)buffer + size; ptr>(unsigned short*)buffer; ) {\n              const unsigned short val = *(--ptr);\n              *ptr = (unsigned short)((val>>8)|((val<<8)));\n            }\n        } break;\n        case 4 : { for (unsigned int *ptr = (unsigned int*)buffer + size; ptr>(unsigned int*)buffer; ) {\n              const unsigned int val = *(--ptr);\n              *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);\n            }\n        } break;\n        default : { for (T* ptr = buffer + size; ptr>buffer; ) {\n              unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);\n              for (int i = 0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));\n            }\n        }\n        }\n    }\n\n    //! Reverse endianness of a single variable.\n    /**\n       \\param[in,out] a Variable to reverse.\n       \\return Reference to reversed variable.\n    **/\n    template<typename T>\n    inline T& invert_endianness(T& a) {\n      invert_endianness(&a,1);\n      return a;\n    }\n\n    // Conversion functions to get more precision when trying to store unsigned ints values as floats.\n    inline unsigned int float2uint(const float f) {\n      int tmp = 0;\n      std::memcpy(&tmp,&f,sizeof(float));\n      if (tmp>=0) return (unsigned int)f;\n      unsigned int u;\n      // use memcpy instead of assignment to avoid undesired optimizations by C++-compiler.\n      std::memcpy(&u,&f,sizeof(float));\n      return ((u)<<1)>>1; // set sign bit to 0.\n    }\n\n    inline float uint2float(const unsigned int u) {\n      if (u<(1U<<19)) return (float)u;  // Consider safe storage of unsigned int as floats until 19bits (i.e 524287).\n      float f;\n      const unsigned int v = u|(1U<<(8*sizeof(unsigned int)-1)); // set sign bit to 1.\n      // use memcpy instead of simple assignment to avoid undesired optimizations by C++-compiler.\n      std::memcpy(&f,&v,sizeof(float));\n      return f;\n    }\n\n    //! Return the value of a system timer, with a millisecond precision.\n    /**\n       \\note The timer does not necessarily starts from \\c 0.\n    **/\n    inline cimg_ulong time() {\n#if cimg_OS==1\n      struct timeval st_time;\n      gettimeofday(&st_time,0);\n      return (cimg_ulong)(st_time.tv_usec/1000 + st_time.tv_sec*1000);\n#elif cimg_OS==2\n      SYSTEMTIME st_time;\n      GetLocalTime(&st_time);\n      return (cimg_ulong)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));\n#else\n      return 0;\n#endif\n    }\n\n    // Implement a tic/toc mechanism to display elapsed time of algorithms.\n    inline cimg_ulong tictoc(const bool is_tic);\n\n    //! Start tic/toc timer for time measurement between code instructions.\n    /**\n       \\return Current value of the timer (same value as time()).\n    **/\n    inline cimg_ulong tic() {\n      return cimg::tictoc(true);\n    }\n\n    //! End tic/toc timer and displays elapsed time from last call to tic().\n    /**\n       \\return Time elapsed (in ms) since last call to tic().\n    **/\n    inline cimg_ulong toc() {\n      return cimg::tictoc(false);\n    }\n\n    //! Sleep for a given numbers of milliseconds.\n    /**\n       \\param milliseconds Number of milliseconds to wait for.\n       \\note This function frees the CPU ressources during the sleeping time.\n       It can be used to temporize your program properly, without wasting CPU time.\n    **/\n    inline void sleep(const unsigned int milliseconds) {\n#if cimg_OS==1\n      struct timespec tv;\n      tv.tv_sec = milliseconds/1000;\n      tv.tv_nsec = (milliseconds%1000)*1000000;\n      nanosleep(&tv,0);\n#elif cimg_OS==2\n      Sleep(milliseconds);\n#endif\n    }\n\n    inline unsigned int _wait(const unsigned int milliseconds, cimg_ulong& timer) {\n      if (!timer) timer = cimg::time();\n      const cimg_ulong current_time = cimg::time();\n      if (current_time>=timer + milliseconds) { timer = current_time; return 0; }\n      const unsigned int time_diff = (unsigned int)(timer + milliseconds - current_time);\n      timer = current_time + time_diff;\n      cimg::sleep(time_diff);\n      return time_diff;\n    }\n\n    //! Wait for a given number of milliseconds since the last call to wait().\n    /**\n       \\param milliseconds Number of milliseconds to wait for.\n       \\return Number of milliseconds elapsed since the last call to wait().\n       \\note Same as sleep() with a waiting time computed with regard to the last call\n       of wait(). It may be used to temporize your program properly, without wasting CPU time.\n    **/\n    inline cimg_long wait(const unsigned int milliseconds) {\n      cimg::mutex(3);\n      static cimg_ulong timer = 0;\n      if (!timer) timer = cimg::time();\n      cimg::mutex(3,0);\n      return _wait(milliseconds,timer);\n    }\n\n    // Random number generators.\n    // CImg may use its own Random Number Generator (RNG) if configuration macro 'cimg_use_rng' is set.\n    // Use it for instance when you have to deal with concurrent threads trying to call std::srand()\n    // at the same time!\n#ifdef cimg_use_rng\n\n#include <stdint.h>\n\n    // Use a custom RNG.\n    inline unsigned int _rand(const unsigned int seed=0, const bool set_seed=false) {\n      static cimg_ulong next = 0xB16B00B5;\n      cimg::mutex(4);\n      if (set_seed) next = (cimg_ulong)seed;\n      next = next*1103515245 + 12345U;\n      cimg::mutex(4,0);\n      return (unsigned int)(next&0xFFFFFFU);\n    }\n\n    inline void srand() {\n      const unsigned int t = (unsigned int)cimg::time();\n#if cimg_OS==1\n      cimg::_rand(t + (unsigned int)getpid(),true);\n#elif cimg_OS==2\n      cimg::_rand(t + (unsigned int)_getpid(),true);\n#else\n      cimg::_rand(t,true);\n#endif\n    }\n\n    inline void srand(const unsigned int seed) {\n      _rand(seed,true);\n    }\n\n    inline double rand(const double val_min, const double val_max) {\n      const double val = cimg::_rand()/16777215.;\n      return val_min + (val_max - val_min)*val;\n    }\n\n#else\n\n    // Use the system RNG.\n    inline void srand() {\n      const unsigned int t = (unsigned int)cimg::time();\n#if cimg_OS==1\n      std::srand(t + (unsigned int)getpid());\n#elif cimg_OS==2\n      std::srand(t + (unsigned int)_getpid());\n#else\n      std::srand(t);\n#endif\n    }\n\n    inline void srand(const unsigned int seed) {\n      std::srand(seed);\n    }\n\n    //! Return a random variable uniformely distributed between [val_min,val_max].\n    /**\n    **/\n    inline double rand(const double val_min, const double val_max) {\n      const double val = (double)std::rand()/RAND_MAX;\n      return val_min + (val_max - val_min)*val;\n    }\n#endif\n\n    //! Return a random variable uniformely distributed between [0,val_max].\n    /**\n     **/\n    inline double rand(const double val_max=1) {\n      return cimg::rand(0,val_max);\n    }\n\n    //! Return a random variable following a gaussian distribution and a standard deviation of 1.\n    /**\n    **/\n    inline double grand() {\n      double x1, w;\n      do {\n        const double x2 = cimg::rand(-1,1);\n        x1 = cimg::rand(-1,1);\n        w = x1*x1 + x2*x2;\n      } while (w<=0 || w>=1.0);\n      return x1*std::sqrt((-2*std::log(w))/w);\n    }\n\n    //! Return a random variable following a Poisson distribution of parameter z.\n    /**\n    **/\n    inline unsigned int prand(const double z) {\n      if (z<=1.0e-10) return 0;\n      if (z>100) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);\n      unsigned int k = 0;\n      const double y = std::exp(-z);\n      for (double s = 1.0; s>=y; ++k) s*=cimg::rand();\n      return k - 1;\n    }\n\n    //! Bitwise-rotate value on the left.\n    template<typename T>\n    inline T rol(const T& a, const unsigned int n=1) {\n      return n?(T)((a<<n)|(a>>((sizeof(T)<<3) - n))):a;\n    }\n\n    inline float rol(const float a, const unsigned int n=1) {\n      return (float)rol((int)a,n);\n    }\n\n    inline double rol(const double a, const unsigned int n=1) {\n      return (double)rol((cimg_long)a,n);\n    }\n\n    inline double rol(const long double a, const unsigned int n=1) {\n      return (double)rol((cimg_long)a,n);\n    }\n\n    //! Bitwise-rotate value on the right.\n    template<typename T>\n    inline T ror(const T& a, const unsigned int n=1) {\n      return n?(T)((a>>n)|(a<<((sizeof(T)<<3) - n))):a;\n    }\n\n    inline float ror(const float a, const unsigned int n=1) {\n      return (float)ror((int)a,n);\n    }\n\n    inline double ror(const double a, const unsigned int n=1) {\n      return (double)ror((cimg_long)a,n);\n    }\n\n    inline double ror(const long double a, const unsigned int n=1) {\n      return (double)ror((cimg_long)a,n);\n    }\n\n    //! Return absolute value of a value.\n    template<typename T>\n    inline T abs(const T& a) {\n      return a>=0?a:-a;\n    }\n    inline bool abs(const bool a) {\n      return a;\n    }\n    inline int abs(const unsigned char a) {\n      return (int)a;\n    }\n    inline int abs(const unsigned short a) {\n      return (int)a;\n    }\n    inline int abs(const unsigned int a) {\n      return (int)a;\n    }\n    inline int abs(const int a) {\n      return std::abs(a);\n    }\n    inline cimg_int64 abs(const cimg_uint64 a) {\n      return (cimg_int64)a;\n    }\n    inline double abs(const double a) {\n      return std::fabs(a);\n    }\n    inline float abs(const float a) {\n      return (float)std::fabs((double)a);\n    }\n\n    //! Return square of a value.\n    template<typename T>\n    inline T sqr(const T& val) {\n      return val*val;\n    }\n\n    //! Return <tt>1 + log_10(x)</tt> of a value \\c x.\n    inline int xln(const int x) {\n      return x>0?(int)(1 + std::log10((double)x)):1;\n    }\n\n    //! Return the minimum between two values.\n    template<typename t1, typename t2>\n    inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) {\n      typedef typename cimg::superset<t1,t2>::type t1t2;\n      return (t1t2)(a<=b?a:b);\n    }\n\n    //! Return the minimum between three values.\n    template<typename t1, typename t2, typename t3>\n    inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) {\n      typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;\n      return (t1t2t3)cimg::min(cimg::min(a,b),c);\n    }\n\n    //! Return the minimum between four values.\n    template<typename t1, typename t2, typename t3, typename t4>\n    inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) {\n      typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;\n      return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d);\n    }\n\n    //! Return the maximum between two values.\n    template<typename t1, typename t2>\n    inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) {\n      typedef typename cimg::superset<t1,t2>::type t1t2;\n      return (t1t2)(a>=b?a:b);\n    }\n\n    //! Return the maximum between three values.\n    template<typename t1, typename t2, typename t3>\n    inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) {\n      typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;\n      return (t1t2t3)cimg::max(cimg::max(a,b),c);\n    }\n\n    //! Return the maximum between four values.\n    template<typename t1, typename t2, typename t3, typename t4>\n    inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) {\n      typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;\n      return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d);\n    }\n\n    //! Return the sign of a value.\n    template<typename T>\n    inline T sign(const T& x) {\n      return (x<0)?(T)(-1):(x==0?(T)0:(T)1);\n    }\n\n    //! Return the nearest power of 2 higher than given value.\n    template<typename T>\n    inline cimg_ulong nearest_pow2(const T& x) {\n      cimg_ulong i = 1;\n      while (x>i) i<<=1;\n      return i;\n    }\n\n    //! Return the sinc of a given value.\n    inline double sinc(const double x) {\n      return x?std::sin(x)/x:1;\n    }\n\n    //! Return the modulo of a value.\n    /**\n       \\param x Input value.\n       \\param m Modulo value.\n       \\note This modulo function accepts negative and floating-points modulo numbers, as well as variables of any type.\n    **/\n    template<typename T>\n    inline T mod(const T& x, const T& m) {\n      const double dx = (double)x, dm = (double)m;\n      return (T)(dx - dm * std::floor(dx / dm));\n    }\n    inline int mod(const bool x, const bool m) {\n      return m?(x?1:0):0;\n    }\n    inline int mod(const unsigned char x, const unsigned char m) {\n      return x%m;\n    }\n    inline int mod(const char x, const char m) {\n#if defined(CHAR_MAX) && CHAR_MAX==255\n      return x%m;\n#else\n      return x>=0?x%m:(x%m?m + x%m:0);\n#endif\n    }\n    inline int mod(const unsigned short x, const unsigned short m) {\n      return x%m;\n    }\n    inline int mod(const short x, const short m) {\n      return x>=0?x%m:(x%m?m + x%m:0);\n    }\n    inline int mod(const unsigned int x, const unsigned int m) {\n      return (int)(x%m);\n    }\n    inline int mod(const int x, const int m) {\n      return x>=0?x%m:(x%m?m + x%m:0);\n    }\n    inline cimg_int64 mod(const cimg_uint64 x, const cimg_uint64 m) {\n      return x%m;\n    }\n    inline cimg_int64 mod(const cimg_int64 x, const cimg_int64 m) {\n      return x>=0?x%m:(x%m?m + x%m:0);\n    }\n\n    //! Return the min-mod of two values.\n    /**\n       \\note <i>minmod(\\p a,\\p b)</i> is defined to be:\n       - <i>minmod(\\p a,\\p b) = min(\\p a,\\p b)</i>, if \\p a and \\p b have the same sign.\n       - <i>minmod(\\p a,\\p b) = 0</i>, if \\p a and \\p b have different signs.\n    **/\n    template<typename T>\n    inline T minmod(const T& a, const T& b) {\n      return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));\n    }\n\n    //! Return base-2 logarithm of a value.\n    inline double log2(const double x) {\n      const double base = std::log(2.0);\n      return std::log(x)/base;\n    }\n\n    //! Return rounded value.\n    /**\n       \\param x Value to be rounded.\n       \\param y Rounding precision.\n       \\param rounding_type Type of rounding operation (\\c 0 = nearest, \\c -1 = backward, \\c 1 = forward).\n       \\return Rounded value, having the same type as input value \\c x.\n    **/\n    template<typename T>\n    inline T round(const T& x, const double y=1, const int rounding_type=0) {\n      if (y<=0) return x;\n      const double sx = (double)x/y, floor = std::floor(sx), delta =  sx - floor;\n      return (T)(y*(rounding_type<0?floor:rounding_type>0?std::ceil(sx):delta<0.5?floor:std::ceil(sx)));\n    }\n\n    inline double _pythagore(double a, double b) {\n      const double absa = cimg::abs(a), absb = cimg::abs(b);\n      if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0 + tmp*tmp); }\n      else { const double tmp = absa/absb; return absb==0?0:absb*std::sqrt(1.0 + tmp*tmp); }\n    }\n\n    //! Return sqrt(x^2 + y^2).\n    inline double hypot(const double x, const double y) {\n      double nx = cimg::abs(x), ny = cimg::abs(y), t;\n      if (nx<ny) { t = nx; nx = ny; } else t = ny;\n      if (nx>0) { t/=nx; return nx*std::sqrt(1+t*t); }\n      return 0;\n    }\n\n    //! Convert ascii character to lower case.\n    inline char uncase(const char x) {\n      return (char)((x<'A'||x>'Z')?x:x - 'A' + 'a');\n    }\n\n    //! Convert C-string to lower case.\n    inline void uncase(char *const str) {\n      if (str) for (char *ptr = str; *ptr; ++ptr) *ptr = uncase(*ptr);\n    }\n\n    //! Read value in a C-string.\n    /**\n       \\param str C-string containing the float value to read.\n       \\return Read value.\n       \\note Same as <tt>std::atof()</tt> extended to manage the retrieval of fractions from C-strings,\n       as in <em>\"1/2\"</em>.\n    **/\n    inline double atof(const char *const str) {\n      double x = 0, y = 1;\n      return str && cimg_sscanf(str,\"%lf/%lf\",&x,&y)>0?x/y:0;\n    }\n\n    //! Compare the first \\p l characters of two C-strings, ignoring the case.\n    /**\n       \\param str1 C-string.\n       \\param str2 C-string.\n       \\param l Number of characters to compare.\n       \\return \\c 0 if the two strings are equal, something else otherwise.\n       \\note This function has to be defined since it is not provided by all C++-compilers (not ANSI).\n    **/\n    inline int strncasecmp(const char *const str1, const char *const str2, const int l) {\n      if (!l) return 0;\n      if (!str1) return str2?-1:0;\n      const char *nstr1 = str1, *nstr2 = str2;\n      int k, diff = 0; for (k = 0; k<l && !(diff = uncase(*nstr1) - uncase(*nstr2)); ++k) { ++nstr1; ++nstr2; }\n      return k!=l?diff:0;\n    }\n\n    //! Compare two C-strings, ignoring the case.\n    /**\n       \\param str1 C-string.\n       \\param str2 C-string.\n       \\return \\c 0 if the two strings are equal, something else otherwise.\n       \\note This function has to be defined since it is not provided by all C++-compilers (not ANSI).\n    **/\n    inline int strcasecmp(const char *const str1, const char *const str2) {\n      if (!str1) return str2?-1:0;\n      const int\n        l1 = (int)std::strlen(str1),\n        l2 = (int)std::strlen(str2);\n      return cimg::strncasecmp(str1,str2,1 + (l1<l2?l1:l2));\n    }\n\n    //! Ellipsize a string.\n    /**\n       \\param str C-string.\n       \\param l Max number of characters.\n       \\param is_ending Tell if the dots are placed at the end or at the center of the ellipsized string.\n    **/\n    inline char *strellipsize(char *const str, const unsigned int l=64,\n                              const bool is_ending=true) {\n      if (!str) return str;\n      const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str);\n      if (ls<=nl) return str;\n      if (is_ending) std::strcpy(str + nl - 5,\"(...)\");\n      else {\n        const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5;\n        std::strcpy(str + ll,\"(...)\");\n        std::memmove(str + ll + 5,str + ls - lr,lr);\n      }\n      str[nl] = 0;\n      return str;\n    }\n\n    //! Ellipsize a string.\n    /**\n       \\param str C-string.\n       \\param res output C-string.\n       \\param l Max number of characters.\n       \\param is_ending Tell if the dots are placed at the end or at the center of the ellipsized string.\n    **/\n    inline char *strellipsize(const char *const str, char *const res, const unsigned int l=64,\n                              const bool is_ending=true) {\n      const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str);\n      if (ls<=nl) { std::strcpy(res,str); return res; }\n      if (is_ending) {\n        std::strncpy(res,str,nl - 5);\n        std::strcpy(res + nl -5,\"(...)\");\n      } else {\n        const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5;\n        std::strncpy(res,str,ll);\n        std::strcpy(res + ll,\"(...)\");\n        std::strncpy(res + ll + 5,str + ls - lr,lr);\n      }\n      res[nl] = 0;\n      return res;\n    }\n\n    //! Remove delimiters on the start and/or end of a C-string.\n    /**\n       \\param[in,out] str C-string to work with (modified at output).\n       \\param delimiter Delimiter character code to remove.\n       \\param is_symmetric Tells if the removal is done only if delimiters are symmetric\n       (both at the beginning and the end of \\c s).\n       \\param is_iterative Tells if the removal is done if several iterations are possible.\n       \\return \\c true if delimiters have been removed, \\c false otherwise.\n   **/\n    inline bool strpare(char *const str, const char delimiter=' ',\n                        const bool is_symmetric=false, const bool is_iterative=false) {\n      if (!str) return false;\n      const int l = (int)std::strlen(str);\n      int p, q;\n      if (is_symmetric) for (p = 0, q = l - 1; p<q && str[p]==delimiter && str[q]==delimiter; ) {\n          --q; ++p; if (!is_iterative) break;\n        } else {\n        for (p = 0; p<l && str[p]==delimiter; ) { ++p; if (!is_iterative) break; }\n        for (q = l - 1; q>p && str[q]==delimiter; ) { --q; if (!is_iterative) break; }\n      }\n      const int n = q - p + 1;\n      if (n!=l) { std::memmove(str,str + p,(unsigned int)n); str[n] = 0; return true; }\n      return false;\n    }\n\n    //! Replace reserved characters (for Windows filename) by another character.\n    /**\n       \\param[in,out] str C-string to work with (modified at output).\n       \\param[in] c Replacement character.\n    **/\n    inline void strwindows_reserved(char *const str, const char c='_') {\n      for (char *s = str; *s; ++s) {\n        const char i = *s;\n        if (i=='<' || i=='>' || i==':' || i=='\\\"' || i=='/' || i=='\\\\' || i=='|' || i=='?' || i=='*') *s = c;\n      }\n    }\n\n    //! Replace escape sequences in C-strings by their binary ascii values.\n    /**\n       \\param[in,out] str C-string to work with (modified at output).\n    **/\n    inline void strunescape(char *const str) {\n#define cimg_strunescape(ci,co) case ci : *nd = co; ++ns; break;\n      unsigned int val = 0;\n      for (char *ns = str, *nd = str; *ns || (bool)(*nd=0); ++nd) if (*ns=='\\\\') switch (*(++ns)) {\n            cimg_strunescape('a','\\a');\n            cimg_strunescape('b','\\b');\n            cimg_strunescape('e',0x1B);\n            cimg_strunescape('f','\\f');\n            cimg_strunescape('n','\\n');\n            cimg_strunescape('r','\\r');\n            cimg_strunescape('t','\\t');\n            cimg_strunescape('v','\\v');\n            cimg_strunescape('\\\\','\\\\');\n            cimg_strunescape('\\'','\\'');\n            cimg_strunescape('\\\"','\\\"');\n            cimg_strunescape('\\?','\\?');\n          case 0 : *nd = 0; break;\n          case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' :\n            cimg_sscanf(ns,\"%o\",&val); while (*ns>='0' && *ns<='7') ++ns;\n            *nd = (char)val; break;\n          case 'x' :\n            cimg_sscanf(++ns,\"%x\",&val);\n            while ((*ns>='0' && *ns<='9') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns;\n            *nd = (char)val; break;\n          default : *nd = *(ns++);\n          } else *nd = *(ns++);\n    }\n\n    // Return a temporary string describing the size of a memory buffer.\n    inline const char *strbuffersize(const cimg_ulong size);\n\n    // Return string that identifies the running OS.\n    inline const char *stros() {\n#if defined(linux) || defined(__linux) || defined(__linux__)\n      static const char *const str = \"Linux\";\n#elif defined(sun) || defined(__sun)\n      static const char *const str = \"Sun OS\";\n#elif defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined (__DragonFly__)\n      static const char *const str = \"BSD\";\n#elif defined(sgi) || defined(__sgi)\n      static const char *const str = \"Irix\";\n#elif defined(__MACOSX__) || defined(__APPLE__)\n      static const char *const str = \"Mac OS\";\n#elif defined(unix) || defined(__unix) || defined(__unix__)\n      static const char *const str = \"Generic Unix\";\n#elif defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) || \\\n  defined(WIN64) || defined(_WIN64) || defined(__WIN64__)\n      static const char *const str = \"Windows\";\n#else\n      const char\n        *const _str1 = std::getenv(\"OSTYPE\"),\n        *const _str2 = _str1?_str1:std::getenv(\"OS\"),\n        *const str = _str2?_str2:\"Unknown OS\";\n#endif\n      return str;\n    }\n\n    //! Return the basename of a filename.\n    inline const char* basename(const char *const s, const char separator=cimg_file_separator)  {\n      const char *p = 0, *np = s;\n      while (np>=s && (p=np)) np = std::strchr(np,separator) + 1;\n      return p;\n    }\n\n    // Return a random filename.\n    inline const char* filenamerand() {\n      cimg::mutex(6);\n      static char randomid[9];\n      cimg::srand();\n      for (unsigned int k = 0; k<8; ++k) {\n        const int v = (int)cimg::rand(65535)%3;\n        randomid[k] = (char)(v==0?('0' + ((int)cimg::rand(65535)%10)):\n                             (v==1?('a' + ((int)cimg::rand(65535)%26)):('A' + ((int)cimg::rand(65535)%26))));\n      }\n      cimg::mutex(6,0);\n      return randomid;\n    }\n\n    // Convert filename as a Windows-style filename (short path name).\n    inline void winformat_string(char *const str) {\n      if (str && *str) {\n#if cimg_OS==2\n        char *const nstr = new char[MAX_PATH];\n        if (GetShortPathNameA(str,nstr,MAX_PATH)) std::strcpy(str,nstr);\n        delete[] nstr;\n#endif\n      }\n    }\n\n    //! Open a file.\n    /**\n       \\param path Path of the filename to open.\n       \\param mode C-string describing the opening mode.\n       \\return Opened file.\n       \\note Same as <tt>std::fopen()</tt> but throw a \\c CImgIOException when\n       the specified file cannot be opened, instead of returning \\c 0.\n    **/\n    inline std::FILE *fopen(const char *const path, const char *const mode) {\n      if (!path)\n        throw CImgArgumentException(\"cimg::fopen(): Specified file path is (null).\");\n      if (!mode)\n        throw CImgArgumentException(\"cimg::fopen(): File '%s', specified mode is (null).\",\n                                    path);\n      std::FILE *res = 0;\n      if (*path=='-' && (!path[1] || path[1]=='.')) {\n        res = (*mode=='r')?stdin:stdout;\n#if cimg_OS==2\n        if (*mode && mode[1]=='b') { // Force stdin/stdout to be in binary mode.\n          if (_setmode(_fileno(res),0x8000)==-1) res = 0;\n        }\n#endif\n      } else res = std::fopen(path,mode);\n      if (!res) throw CImgIOException(\"cimg::fopen(): Failed to open file '%s' with mode '%s'.\",\n                                      path,mode);\n      return res;\n    }\n\n    //! Close a file.\n    /**\n       \\param file File to close.\n       \\return \\c 0 if file has been closed properly, something else otherwise.\n       \\note Same as <tt>std::fclose()</tt> but display a warning message if\n       the file has not been closed properly.\n    **/\n    inline int fclose(std::FILE *file) {\n      if (!file) warn(\"cimg::fclose(): Specified file is (null).\");\n      if (!file || file==stdin || file==stdout) return 0;\n      const int errn = std::fclose(file);\n      if (errn!=0) warn(\"cimg::fclose(): Error code %d returned during file closing.\",\n                        errn);\n      return errn;\n    }\n\n    //! Version of 'fseek()' that supports >=64bits offsets everywhere (for Windows).\n    inline int fseek(FILE *stream, cimg_long offset, int origin) {\n#if cimg_OS==2\n      return _fseeki64(stream,(__int64)offset,origin);\n#else\n      return std::fseek(stream,offset,origin);\n#endif\n    }\n\n    //! Version of 'ftell()' that supports >=64bits offsets everywhere (for Windows).\n    inline cimg_long ftell(FILE *stream) {\n#if cimg_OS==2\n      return (cimg_long)_ftelli64(stream);\n#else\n      return (cimg_long)std::ftell(stream);\n#endif\n    }\n\n    //! Check if a path is a directory.\n    /**\n       \\param path Specified path to test.\n    **/\n    inline bool is_directory(const char *const path) {\n      if (!path || !*path) return false;\n#if cimg_OS==1\n      struct stat st_buf;\n      return (!stat(path,&st_buf) && S_ISDIR(st_buf.st_mode));\n#elif cimg_OS==2\n      const unsigned int res = (unsigned int)GetFileAttributesA(path);\n      return res==INVALID_FILE_ATTRIBUTES?false:(res&16);\n#endif\n    }\n\n    //! Check if a path is a file.\n    /**\n       \\param path Specified path to test.\n    **/\n    inline bool is_file(const char *const path) {\n      if (!path || !*path) return false;\n      std::FILE *const file = std::fopen(path,\"rb\");\n      if (!file) return false;\n      std::fclose(file);\n      return !is_directory(path);\n    }\n\n    //! Get last write time of a given file or directory.\n    /**\n       \\param path Specified path to get attributes from.\n       \\param attr Type of requested time attribute.\n                   Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second }\n       \\return -1 if requested attribute could not be read.\n    **/\n    inline int fdate(const char *const path, const unsigned int attr) {\n      int res = -1;\n      if (!path || !*path || attr>6) return -1;\n      cimg::mutex(6);\n#if cimg_OS==2\n      HANDLE file = CreateFileA(path,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);\n      if (file!=INVALID_HANDLE_VALUE) {\n        FILETIME _ft;\n        SYSTEMTIME ft;\n        if (GetFileTime(file,0,0,&_ft) && FileTimeToSystemTime(&_ft,&ft))\n          res = (int)(attr==0?ft.wYear:attr==1?ft.wMonth:attr==2?ft.wDay:attr==3?ft.wDayOfWeek:\n                      attr==4?ft.wHour:attr==5?ft.wMinute:ft.wSecond);\n        CloseHandle(file);\n      }\n#else\n      struct stat st_buf;\n      if (!stat(path,&st_buf)) {\n        const time_t _ft = st_buf.st_mtime;\n        const struct tm& ft = *std::localtime(&_ft);\n        res = (int)(attr==0?ft.tm_year + 1900:attr==1?ft.tm_mon + 1:attr==2?ft.tm_mday:attr==3?ft.tm_wday:\n                    attr==4?ft.tm_hour:attr==5?ft.tm_min:ft.tm_sec);\n      }\n#endif\n      cimg::mutex(6,0);\n      return res;\n    }\n\n    //! Get current local time.\n    /**\n       \\param attr Type of requested time attribute.\n                   Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second }\n    **/\n    inline int date(const unsigned int attr) {\n      int res;\n      cimg::mutex(6);\n#if cimg_OS==2\n      SYSTEMTIME st;\n      GetLocalTime(&st);\n      res = (int)(attr==0?st.wYear:attr==1?st.wMonth:attr==2?st.wDay:attr==3?st.wDayOfWeek:\n                  attr==4?st.wHour:attr==5?st.wMinute:st.wSecond);\n#else\n      time_t _st;\n      std::time(&_st);\n      struct tm *st = std::localtime(&_st);\n      res = (int)(attr==0?st->tm_year + 1900:attr==1?st->tm_mon + 1:attr==2?st->tm_mday:attr==3?st->tm_wday:\n                  attr==4?st->tm_hour:attr==5?st->tm_min:st->tm_sec);\n#endif\n      cimg::mutex(6,0);\n      return res;\n    }\n\n    // Get/set path to store temporary files.\n    inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false);\n\n    // Get/set path to the <i>Program Files/</i> directory (Windows only).\n#if cimg_OS==2\n    inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false);\n#endif\n\n    // Get/set path to the ImageMagick's \\c convert binary.\n    inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false);\n\n    // Get/set path to the GraphicsMagick's \\c gm binary.\n    inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false);\n\n    // Get/set path to the XMedcon's \\c medcon binary.\n    inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false);\n\n    // Get/set path to the FFMPEG's \\c ffmpeg binary.\n    inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false);\n\n    // Get/set path to the \\c gzip binary.\n    inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false);\n\n    // Get/set path to the \\c gunzip binary.\n    inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false);\n\n    // Get/set path to the \\c dcraw binary.\n    inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false);\n\n    // Get/set path to the \\c wget binary.\n    inline const char *wget_path(const char *const user_path=0, const bool reinit_path=false);\n\n    // Get/set path to the \\c curl binary.\n    inline const char *curl_path(const char *const user_path=0, const bool reinit_path=false);\n\n    //! Split filename into two C-strings \\c body and \\c extension.\n    /**\n       filename and body must not overlap!\n    **/\n    inline const char *split_filename(const char *const filename, char *const body=0) {\n      if (!filename) { if (body) *body = 0; return 0; }\n      const char *p = 0; for (const char *np = filename; np>=filename && (p=np); np = std::strchr(np,'.') + 1) {}\n      if (p==filename) {\n        if (body) std::strcpy(body,filename);\n        return filename + std::strlen(filename);\n      }\n      const unsigned int l = (unsigned int)(p - filename - 1);\n      if (body) { if (l) std::memcpy(body,filename,l); body[l] = 0; }\n      return p;\n    }\n\n    //! Generate a numbered version of a filename.\n    inline char* number_filename(const char *const filename, const int number,\n                                 const unsigned int digits, char *const str) {\n      if (!filename) { if (str) *str = 0; return 0; }\n      char *const format = new char[1024], *const body = new char[1024];\n      const char *const ext = cimg::split_filename(filename,body);\n      if (*ext) cimg_snprintf(format,1024,\"%%s_%%.%ud.%%s\",digits);\n      else cimg_snprintf(format,1024,\"%%s_%%.%ud\",digits);\n      cimg_sprintf(str,format,body,number,ext);\n      delete[] format; delete[] body;\n      return str;\n    }\n\n    //! Read data from file.\n    /**\n       \\param[out] ptr Pointer to memory buffer that will contain the binary data read from file.\n       \\param nmemb Number of elements to read.\n       \\param stream File to read data from.\n       \\return Number of read elements.\n       \\note Same as <tt>std::fread()</tt> but may display warning message if all elements could not be read.\n    **/\n    template<typename T>\n    inline size_t fread(T *const ptr, const size_t nmemb, std::FILE *stream) {\n      if (!ptr || !stream)\n        throw CImgArgumentException(\"cimg::fread(): Invalid reading request of %u %s%s from file %p to buffer %p.\",\n                                    nmemb,cimg::type<T>::string(),nmemb>1?\"s\":\"\",stream,ptr);\n      if (!nmemb) return 0;\n      const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);\n      size_t to_read = nmemb, al_read = 0, l_to_read = 0, l_al_read = 0;\n      do {\n        l_to_read = (to_read*sizeof(T))<wlimitT?to_read:wlimit;\n        l_al_read = std::fread((void*)(ptr + al_read),sizeof(T),l_to_read,stream);\n        al_read+=l_al_read;\n        to_read-=l_al_read;\n      } while (l_to_read==l_al_read && to_read>0);\n      if (to_read>0)\n        warn(\"cimg::fread(): Only %lu/%lu elements could be read from file.\",\n             (unsigned long)al_read,(unsigned long)nmemb);\n      return al_read;\n    }\n\n    //! Write data to file.\n    /**\n       \\param ptr Pointer to memory buffer containing the binary data to write on file.\n       \\param nmemb Number of elements to write.\n       \\param[out] stream File to write data on.\n       \\return Number of written elements.\n       \\note Similar to <tt>std::fwrite</tt> but may display warning messages if all elements could not be written.\n    **/\n    template<typename T>\n    inline size_t fwrite(const T *ptr, const size_t nmemb, std::FILE *stream) {\n      if (!ptr || !stream)\n        throw CImgArgumentException(\"cimg::fwrite(): Invalid writing request of %u %s%s from buffer %p to file %p.\",\n                                    nmemb,cimg::type<T>::string(),nmemb>1?\"s\":\"\",ptr,stream);\n      if (!nmemb) return 0;\n      const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);\n      size_t to_write = nmemb, al_write = 0, l_to_write = 0, l_al_write = 0;\n      do {\n        l_to_write = (to_write*sizeof(T))<wlimitT?to_write:wlimit;\n        l_al_write = std::fwrite((void*)(ptr + al_write),sizeof(T),l_to_write,stream);\n        al_write+=l_al_write;\n        to_write-=l_al_write;\n      } while (l_to_write==l_al_write && to_write>0);\n      if (to_write>0)\n        warn(\"cimg::fwrite(): Only %lu/%lu elements could be written in file.\",\n             (unsigned long)al_write,(unsigned long)nmemb);\n      return al_write;\n    }\n\n    //! Create an empty file.\n    /**\n       \\param file Input file (can be \\c 0 if \\c filename is set).\n       \\param filename Filename, as a C-string (can be \\c 0 if \\c file is set).\n    **/\n    inline void fempty(std::FILE *const file, const char *const filename) {\n      if (!file && !filename)\n        throw CImgArgumentException(\"cimg::fempty(): Specified filename is (null).\");\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      if (!file) cimg::fclose(nfile);\n    }\n\n    // Try to guess format from an image file.\n    inline const char *ftype(std::FILE *const file, const char *const filename);\n\n    // Load file from network as a local temporary file.\n    inline char *load_network(const char *const url, char *const filename_local,\n                              const unsigned int timeout=0, const bool try_fallback=false,\n                              const char *const referer=0);\n\n    //! Return options specified on the command line.\n    inline const char* option(const char *const name, const int argc, const char *const *const argv,\n                              const char *const defaut, const char *const usage, const bool reset_static) {\n      static bool first = true, visu = false;\n      if (reset_static) { first = true; return 0; }\n      const char *res = 0;\n      if (first) {\n        first = false;\n        visu = cimg::option(\"-h\",argc,argv,(char*)0,(char*)0,false)!=0;\n        visu |= cimg::option(\"-help\",argc,argv,(char*)0,(char*)0,false)!=0;\n        visu |= cimg::option(\"--help\",argc,argv,(char*)0,(char*)0,false)!=0;\n      }\n      if (!name && visu) {\n        if (usage) {\n          std::fprintf(cimg::output(),\"\\n %s%s%s\",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);\n          std::fprintf(cimg::output(),\": %s\",usage);\n          std::fprintf(cimg::output(),\" (%s, %s)\\n\\n\",__DATE__,__TIME__);\n        }\n        if (defaut) std::fprintf(cimg::output(),\"%s\\n\",defaut);\n      }\n      if (name) {\n        if (argc>0) {\n          int k = 0;\n          while (k<argc && std::strcmp(argv[k],name)) ++k;\n          res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));\n        } else res = defaut;\n        if (visu && usage) std::fprintf(cimg::output(),\"    %s%-16s%s %-24s %s%s%s\\n\",\n                                        cimg::t_bold,name,cimg::t_normal,res?res:\"0\",\n                                        cimg::t_green,usage,cimg::t_normal);\n      }\n      return res;\n    }\n\n    inline const char* option(const char *const name, const int argc, const char *const *const argv,\n                              const char *const defaut, const char *const usage=0) {\n      return option(name,argc,argv,defaut,usage,false);\n    }\n\n    inline bool option(const char *const name, const int argc, const char *const *const argv,\n                       const bool defaut, const char *const usage=0) {\n      const char *const s = cimg::option(name,argc,argv,(char*)0);\n      const bool res = s?(cimg::strcasecmp(s,\"false\") && cimg::strcasecmp(s,\"off\") && cimg::strcasecmp(s,\"0\")):defaut;\n      cimg::option(name,0,0,res?\"true\":\"false\",usage);\n      return res;\n    }\n\n    inline int option(const char *const name, const int argc, const char *const *const argv,\n                      const int defaut, const char *const usage=0) {\n      const char *const s = cimg::option(name,argc,argv,(char*)0);\n      const int res = s?std::atoi(s):defaut;\n      char *const tmp = new char[256];\n      cimg_snprintf(tmp,256,\"%d\",res);\n      cimg::option(name,0,0,tmp,usage);\n      delete[] tmp;\n      return res;\n    }\n\n    inline char option(const char *const name, const int argc, const char *const *const argv,\n                       const char defaut, const char *const usage=0) {\n      const char *const s = cimg::option(name,argc,argv,(char*)0);\n      const char res = s?*s:defaut;\n      char tmp[8];\n      *tmp = res; tmp[1] = 0;\n      cimg::option(name,0,0,tmp,usage);\n      return res;\n    }\n\n    inline float option(const char *const name, const int argc, const char *const *const argv,\n                        const float defaut, const char *const usage=0) {\n      const char *const s = cimg::option(name,argc,argv,(char*)0);\n      const float res = s?(float)cimg::atof(s):defaut;\n      char *const tmp = new char[256];\n      cimg_snprintf(tmp,256,\"%g\",res);\n      cimg::option(name,0,0,tmp,usage);\n      delete[] tmp;\n      return res;\n    }\n\n    inline double option(const char *const name, const int argc, const char *const *const argv,\n                         const double defaut, const char *const usage=0) {\n      const char *const s = cimg::option(name,argc,argv,(char*)0);\n      const double res = s?cimg::atof(s):defaut;\n      char *const tmp = new char[256];\n      cimg_snprintf(tmp,256,\"%g\",res);\n      cimg::option(name,0,0,tmp,usage);\n      delete[] tmp;\n      return res;\n    }\n\n    //! Print information about \\CImg environement variables.\n    /**\n       \\note Output is done on the default output stream.\n    **/\n    inline void info() {\n      std::fprintf(cimg::output(),\"\\n %s%sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags:\\n\\n\",\n                   cimg::t_red,cimg::t_bold,cimg_version/100,(cimg_version/10)%10,cimg_version%10,\n                   cimg::t_normal,__DATE__,__TIME__);\n\n      std::fprintf(cimg::output(),\"  > Operating System:       %s%-13s%s %s('cimg_OS'=%d)%s\\n\",\n                   cimg::t_bold,\n                   cimg_OS==1?\"Unix\":(cimg_OS==2?\"Windows\":\"Unknow\"),\n                   cimg::t_normal,cimg::t_green,\n                   cimg_OS,\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > CPU endianness:         %s%s Endian%s\\n\",\n                   cimg::t_bold,\n                   cimg::endianness()?\"Big\":\"Little\",\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > Verbosity mode:         %s%-13s%s %s('cimg_verbosity'=%d)%s\\n\",\n                   cimg::t_bold,\n                   cimg_verbosity==0?\"Quiet\":\n                   cimg_verbosity==1?\"Console\":\n                   cimg_verbosity==2?\"Dialog\":\n                   cimg_verbosity==3?\"Console+Warnings\":\"Dialog+Warnings\",\n                   cimg::t_normal,cimg::t_green,\n                   cimg_verbosity,\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > Stricts warnings:       %s%-13s%s %s('cimg_strict_warnings' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_strict_warnings\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > Using VT100 messages:   %s%-13s%s %s('cimg_use_vt100' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_vt100\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > Display type:           %s%-13s%s %s('cimg_display'=%d)%s\\n\",\n                   cimg::t_bold,\n                   cimg_display==0?\"No display\":cimg_display==1?\"X11\":cimg_display==2?\"Windows GDI\":\"Unknown\",\n                   cimg::t_normal,cimg::t_green,\n                   cimg_display,\n                   cimg::t_normal);\n\n#if cimg_display==1\n      std::fprintf(cimg::output(),\"  > Using XShm for X11:     %s%-13s%s %s('cimg_use_xshm' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_xshm\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > Using XRand for X11:    %s%-13s%s %s('cimg_use_xrandr' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_xrandr\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n#endif\n      std::fprintf(cimg::output(),\"  > Using OpenMP:           %s%-13s%s %s('cimg_use_openmp' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_openmp\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n      std::fprintf(cimg::output(),\"  > Using PNG library:      %s%-13s%s %s('cimg_use_png' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_png\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n      std::fprintf(cimg::output(),\"  > Using JPEG library:     %s%-13s%s %s('cimg_use_jpeg' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_jpeg\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > Using TIFF library:     %s%-13s%s %s('cimg_use_tiff' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_tiff\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > Using Magick++ library: %s%-13s%s %s('cimg_use_magick' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_magick\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > Using FFTW3 library:    %s%-13s%s %s('cimg_use_fftw3' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_fftw3\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"  > Using LAPACK library:   %s%-13s%s %s('cimg_use_lapack' %s)%s\\n\",\n                   cimg::t_bold,\n#ifdef cimg_use_lapack\n                   \"Yes\",cimg::t_normal,cimg::t_green,\"defined\",\n#else\n                   \"No\",cimg::t_normal,cimg::t_green,\"undefined\",\n#endif\n                   cimg::t_normal);\n\n      char *const tmp = new char[1024];\n      cimg_snprintf(tmp,1024,\"\\\"%.1020s\\\"\",cimg::imagemagick_path());\n      std::fprintf(cimg::output(),\"  > Path of ImageMagick:    %s%-13s%s\\n\",\n                   cimg::t_bold,\n                   tmp,\n                   cimg::t_normal);\n\n      cimg_snprintf(tmp,1024,\"\\\"%.1020s\\\"\",cimg::graphicsmagick_path());\n      std::fprintf(cimg::output(),\"  > Path of GraphicsMagick: %s%-13s%s\\n\",\n                   cimg::t_bold,\n                   tmp,\n                   cimg::t_normal);\n\n      cimg_snprintf(tmp,1024,\"\\\"%.1020s\\\"\",cimg::medcon_path());\n      std::fprintf(cimg::output(),\"  > Path of 'medcon':       %s%-13s%s\\n\",\n                   cimg::t_bold,\n                   tmp,\n                   cimg::t_normal);\n\n      cimg_snprintf(tmp,1024,\"\\\"%.1020s\\\"\",cimg::temporary_path());\n      std::fprintf(cimg::output(),\"  > Temporary path:         %s%-13s%s\\n\",\n                   cimg::t_bold,\n                   tmp,\n                   cimg::t_normal);\n\n      std::fprintf(cimg::output(),\"\\n\");\n      delete[] tmp;\n    }\n\n    // Declare LAPACK function signatures if LAPACK support is enabled.\n#ifdef cimg_use_lapack\n    template<typename T>\n    inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {\n      dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);\n    }\n\n    inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {\n      sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);\n    }\n\n    template<typename T>\n    inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {\n      dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);\n    }\n\n    inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {\n      sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);\n    }\n\n    template<typename T>\n    inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,\n                      T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {\n      dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);\n    }\n\n    inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,\n                      float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {\n      sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);\n    }\n\n    template<typename T>\n    inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {\n      int one = 1;\n      dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);\n    }\n\n    inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {\n      int one = 1;\n      sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);\n    }\n\n    template<typename T>\n    inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {\n      dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);\n    }\n\n    inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {\n      ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);\n    }\n\n    template<typename T>\n    inline void sgels(char & TRANS, int &M, int &N, int &NRHS, T* lapA, int &LDA,\n                      T* lapB, int &LDB, T* WORK, int &LWORK, int &INFO){\n      dgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO);\n    }\n\n    inline void sgels(char & TRANS, int &M, int &N, int &NRHS, float* lapA, int &LDA,\n                      float* lapB, int &LDB, float* WORK, int &LWORK, int &INFO){\n      sgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO);\n    }\n\n#endif\n\n    // End of the 'cimg' namespace\n  }\n\n  /*------------------------------------------------\n   #\n   #\n   #   Definition of mathematical operators and\n   #   external functions.\n   #\n   #\n   -------------------------------------------------*/\n\n#define _cimg_create_ext_operators(typ) \\\n  template<typename T> \\\n  inline CImg<typename cimg::superset<T,typ>::type> operator+(const typ val, const CImg<T>& img) { \\\n    return img + val; \\\n  } \\\n  template<typename T> \\\n  inline CImg<typename cimg::superset<T,typ>::type> operator-(const typ val, const CImg<T>& img) { \\\n    typedef typename cimg::superset<T,typ>::type Tt; \\\n    return CImg<Tt>(img._width,img._height,img._depth,img._spectrum,val)-=img; \\\n  } \\\n  template<typename T> \\\n  inline CImg<typename cimg::superset<T,typ>::type> operator*(const typ val, const CImg<T>& img) { \\\n    return img*val; \\\n  } \\\n  template<typename T> \\\n  inline CImg<typename cimg::superset<T,typ>::type> operator/(const typ val, const CImg<T>& img) { \\\n    return val*img.get_invert(); \\\n  } \\\n  template<typename T> \\\n  inline CImg<typename cimg::superset<T,typ>::type> operator&(const typ val, const CImg<T>& img) { \\\n    return img & val; \\\n  } \\\n  template<typename T> \\\n  inline CImg<typename cimg::superset<T,typ>::type> operator|(const typ val, const CImg<T>& img) { \\\n    return img | val; \\\n  } \\\n  template<typename T> \\\n  inline CImg<typename cimg::superset<T,typ>::type> operator^(const typ val, const CImg<T>& img) { \\\n    return img ^ val; \\\n  } \\\n  template<typename T> \\\n  inline bool operator==(const typ val, const CImg<T>& img) {   \\\n    return img == val; \\\n  } \\\n  template<typename T> \\\n  inline bool operator!=(const typ val, const CImg<T>& img) { \\\n    return img != val; \\\n  }\n\n  _cimg_create_ext_operators(bool)\n  _cimg_create_ext_operators(unsigned char)\n  _cimg_create_ext_operators(char)\n  _cimg_create_ext_operators(signed char)\n  _cimg_create_ext_operators(unsigned short)\n  _cimg_create_ext_operators(short)\n  _cimg_create_ext_operators(unsigned int)\n  _cimg_create_ext_operators(int)\n  _cimg_create_ext_operators(cimg_uint64)\n  _cimg_create_ext_operators(cimg_int64)\n  _cimg_create_ext_operators(float)\n  _cimg_create_ext_operators(double)\n  _cimg_create_ext_operators(long double)\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg<T>& img) {\n    return img + expression;\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg<T>& img) {\n    return CImg<_cimg_Tfloat>(img,false).fill(expression,true)-=img;\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> operator*(const char *const expression, const CImg<T>& img) {\n    return img*expression;\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> operator/(const char *const expression, const CImg<T>& img) {\n    return expression*img.get_invert();\n  }\n\n  template<typename T>\n  inline CImg<T> operator&(const char *const expression, const CImg<T>& img) {\n    return img & expression;\n  }\n\n  template<typename T>\n  inline CImg<T> operator|(const char *const expression, const CImg<T>& img) {\n    return img | expression;\n  }\n\n  template<typename T>\n  inline CImg<T> operator^(const char *const expression, const CImg<T>& img) {\n    return img ^ expression;\n  }\n\n  template<typename T>\n  inline bool operator==(const char *const expression, const CImg<T>& img) {\n    return img==expression;\n  }\n\n  template<typename T>\n  inline bool operator!=(const char *const expression, const CImg<T>& img) {\n    return img!=expression;\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {\n    return instance.get_sqr();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {\n    return instance.get_sqrt();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {\n    return instance.get_exp();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {\n    return instance.get_log();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> log2(const CImg<T>& instance) {\n    return instance.get_log2();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {\n    return instance.get_log10();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {\n    return instance.get_abs();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> sign(const CImg<T>& instance) {\n    return instance.get_sign();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {\n    return instance.get_cos();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {\n    return instance.get_sin();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> sinc(const CImg<T>& instance) {\n    return instance.get_sinc();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {\n    return instance.get_tan();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {\n    return instance.get_acos();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {\n    return instance.get_asin();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {\n    return instance.get_atan();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> cosh(const CImg<T>& instance) {\n    return instance.get_cosh();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> sinh(const CImg<T>& instance) {\n    return instance.get_sinh();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> tanh(const CImg<T>& instance) {\n    return instance.get_tanh();\n  }\n\n  template<typename T>\n  inline CImg<T> transpose(const CImg<T>& instance) {\n    return instance.get_transpose();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {\n    return instance.get_invert();\n  }\n\n  template<typename T>\n  inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {\n    return instance.get_pseudoinvert();\n  }\n\n  /*-----------------------------------\n   #\n   # Define the CImgDisplay structure\n   #\n   ----------------------------------*/\n  //! Allow the creation of windows, display images on them and manage user events (keyboard, mouse and windows events).\n  /**\n     CImgDisplay methods rely on a low-level graphic library to perform: it can be either \\b X-Window\n     (X11, for Unix-based systems) or \\b GDI32 (for Windows-based systems).\n     If both libraries are missing, CImgDisplay will not be able to display images on screen, and will enter\n     a minimal mode where warning messages will be outputed each time the program is trying to call one of the\n     CImgDisplay method.\n\n     The configuration variable \\c cimg_display tells about the graphic library used.\n     It is set automatically by \\CImg when one of these graphic libraries has been detected.\n     But, you can override its value if necessary. Valid choices are:\n     - 0: Disable display capabilities.\n     - 1: Use \\b X-Window (X11) library.\n     - 2: Use \\b GDI32 library.\n\n     Remember to link your program against \\b X11 or \\b GDI32 libraries if you use CImgDisplay.\n  **/\n  struct CImgDisplay {\n    cimg_ulong _timer, _fps_frames, _fps_timer;\n    unsigned int _width, _height, _normalization;\n    float _fps_fps, _min, _max;\n    bool _is_fullscreen;\n    char *_title;\n    unsigned int _window_width, _window_height, _button, *_keys, *_released_keys;\n    int _window_x, _window_y, _mouse_x, _mouse_y, _wheel;\n    bool _is_closed, _is_resized, _is_moved, _is_event,\n      _is_keyESC, _is_keyF1, _is_keyF2, _is_keyF3, _is_keyF4, _is_keyF5, _is_keyF6, _is_keyF7,\n      _is_keyF8, _is_keyF9, _is_keyF10, _is_keyF11, _is_keyF12, _is_keyPAUSE, _is_key1, _is_key2,\n      _is_key3, _is_key4, _is_key5, _is_key6, _is_key7, _is_key8, _is_key9, _is_key0,\n      _is_keyBACKSPACE, _is_keyINSERT, _is_keyHOME, _is_keyPAGEUP, _is_keyTAB, _is_keyQ, _is_keyW, _is_keyE,\n      _is_keyR, _is_keyT, _is_keyY, _is_keyU, _is_keyI, _is_keyO, _is_keyP, _is_keyDELETE,\n      _is_keyEND, _is_keyPAGEDOWN, _is_keyCAPSLOCK, _is_keyA, _is_keyS, _is_keyD, _is_keyF, _is_keyG,\n      _is_keyH, _is_keyJ, _is_keyK, _is_keyL, _is_keyENTER, _is_keySHIFTLEFT, _is_keyZ, _is_keyX,\n      _is_keyC, _is_keyV, _is_keyB, _is_keyN, _is_keyM, _is_keySHIFTRIGHT, _is_keyARROWUP, _is_keyCTRLLEFT,\n      _is_keyAPPLEFT, _is_keyALT, _is_keySPACE, _is_keyALTGR, _is_keyAPPRIGHT, _is_keyMENU, _is_keyCTRLRIGHT,\n      _is_keyARROWLEFT, _is_keyARROWDOWN, _is_keyARROWRIGHT, _is_keyPAD0, _is_keyPAD1, _is_keyPAD2, _is_keyPAD3,\n      _is_keyPAD4, _is_keyPAD5, _is_keyPAD6, _is_keyPAD7, _is_keyPAD8, _is_keyPAD9, _is_keyPADADD, _is_keyPADSUB,\n      _is_keyPADMUL, _is_keyPADDIV;\n\n    //@}\n    //---------------------------\n    //\n    //! \\name Plugins\n    //@{\n    //---------------------------\n\n#ifdef cimgdisplay_plugin\n#include cimgdisplay_plugin\n#endif\n#ifdef cimgdisplay_plugin1\n#include cimgdisplay_plugin1\n#endif\n#ifdef cimgdisplay_plugin2\n#include cimgdisplay_plugin2\n#endif\n#ifdef cimgdisplay_plugin3\n#include cimgdisplay_plugin3\n#endif\n#ifdef cimgdisplay_plugin4\n#include cimgdisplay_plugin4\n#endif\n#ifdef cimgdisplay_plugin5\n#include cimgdisplay_plugin5\n#endif\n#ifdef cimgdisplay_plugin6\n#include cimgdisplay_plugin6\n#endif\n#ifdef cimgdisplay_plugin7\n#include cimgdisplay_plugin7\n#endif\n#ifdef cimgdisplay_plugin8\n#include cimgdisplay_plugin8\n#endif\n\n    //@}\n    //--------------------------------------------------------\n    //\n    //! \\name Constructors / Destructor / Instance Management\n    //@{\n    //--------------------------------------------------------\n\n    //! Destructor.\n    /**\n       \\note If the associated window is visible on the screen, it is closed by the call to the destructor.\n    **/\n    ~CImgDisplay() {\n      assign();\n      delete[] _keys;\n      delete[] _released_keys;\n    }\n\n    //! Construct an empty display.\n    /**\n       \\note Constructing an empty CImgDisplay instance does not make a window appearing on the screen, until\n       display of valid data is performed.\n       \\par Example\n       \\code\n       CImgDisplay disp;  // Does actually nothing.\n       ...\n       disp.display(img); // Construct new window and display image in it.\n       \\endcode\n    **/\n    CImgDisplay():\n      _width(0),_height(0),_normalization(0),\n      _min(0),_max(0),\n      _is_fullscreen(false),\n      _title(0),\n      _window_width(0),_window_height(0),_button(0),\n      _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),\n      _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),\n      _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {\n      assign();\n    }\n\n    //! Construct a display with specified dimensions.\n    /** \\param width Window width.\n        \\param height Window height.\n        \\param title Window title.\n        \\param normalization Normalization type\n        (<tt>0</tt>=none, <tt>1</tt>=always, <tt>2</tt>=once, <tt>3</tt>=pixel type-dependent, see normalization()).\n        \\param is_fullscreen Tells if fullscreen mode is enabled.\n        \\param is_closed Tells if associated window is initially visible or not.\n        \\note A black background is initially displayed on the associated window.\n    **/\n    CImgDisplay(const unsigned int width, const unsigned int height,\n                const char *const title=0, const unsigned int normalization=3,\n                const bool is_fullscreen=false, const bool is_closed=false):\n      _width(0),_height(0),_normalization(0),\n      _min(0),_max(0),\n      _is_fullscreen(false),\n      _title(0),\n      _window_width(0),_window_height(0),_button(0),\n      _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),\n      _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),\n      _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {\n      assign(width,height,title,normalization,is_fullscreen,is_closed);\n    }\n\n    //! Construct a display from an image.\n    /** \\param img Image used as a model to create the window.\n        \\param title Window title.\n        \\param normalization Normalization type\n        (<tt>0</tt>=none, <tt>1</tt>=always, <tt>2</tt>=once, <tt>3</tt>=pixel type-dependent, see normalization()).\n        \\param is_fullscreen Tells if fullscreen mode is enabled.\n        \\param is_closed Tells if associated window is initially visible or not.\n        \\note The pixels of the input image are initially displayed on the associated window.\n    **/\n    template<typename T>\n    explicit CImgDisplay(const CImg<T>& img,\n                         const char *const title=0, const unsigned int normalization=3,\n                         const bool is_fullscreen=false, const bool is_closed=false):\n      _width(0),_height(0),_normalization(0),\n      _min(0),_max(0),\n      _is_fullscreen(false),\n      _title(0),\n      _window_width(0),_window_height(0),_button(0),\n      _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),\n      _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),\n      _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {\n      assign(img,title,normalization,is_fullscreen,is_closed);\n    }\n\n    //! Construct a display from an image list.\n    /** \\param list The images list to display.\n        \\param title Window title.\n        \\param normalization Normalization type\n        (<tt>0</tt>=none, <tt>1</tt>=always, <tt>2</tt>=once, <tt>3</tt>=pixel type-dependent, see normalization()).\n        \\param is_fullscreen Tells if fullscreen mode is enabled.\n        \\param is_closed Tells if associated window is initially visible or not.\n        \\note All images of the list, appended along the X-axis, are initially displayed on the associated window.\n    **/\n    template<typename T>\n    explicit CImgDisplay(const CImgList<T>& list,\n                         const char *const title=0, const unsigned int normalization=3,\n                         const bool is_fullscreen=false, const bool is_closed=false):\n      _width(0),_height(0),_normalization(0),\n      _min(0),_max(0),\n      _is_fullscreen(false),\n      _title(0),\n      _window_width(0),_window_height(0),_button(0),\n      _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),\n      _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),\n      _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {\n      assign(list,title,normalization,is_fullscreen,is_closed);\n    }\n\n    //! Construct a display as a copy of an existing one.\n    /**\n        \\param disp Display instance to copy.\n        \\note The pixel buffer of the input window is initially displayed on the associated window.\n    **/\n    CImgDisplay(const CImgDisplay& disp):\n      _width(0),_height(0),_normalization(0),\n      _min(0),_max(0),\n      _is_fullscreen(false),\n      _title(0),\n      _window_width(0),_window_height(0),_button(0),\n      _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),\n      _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),\n      _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {\n      assign(disp);\n    }\n\n#if cimg_display==0\n\n    static void _no_display_exception() {\n      throw CImgDisplayException(\"CImgDisplay(): No display available.\");\n    }\n\n    //! Destructor - Empty constructor \\inplace.\n    /**\n       \\note Replace the current instance by an empty display.\n    **/\n    CImgDisplay& assign() {\n      return flush();\n    }\n\n    //! Construct a display with specified dimensions \\inplace.\n    /**\n    **/\n    CImgDisplay& assign(const unsigned int width, const unsigned int height,\n                        const char *const title=0, const unsigned int normalization=3,\n                        const bool is_fullscreen=false, const bool is_closed=false) {\n      cimg::unused(width,height,title,normalization,is_fullscreen,is_closed);\n      _no_display_exception();\n      return assign();\n    }\n\n    //! Construct a display from an image \\inplace.\n    /**\n    **/\n    template<typename T>\n    CImgDisplay& assign(const CImg<T>& img,\n                        const char *const title=0, const unsigned int normalization=3,\n                        const bool is_fullscreen=false, const bool is_closed=false) {\n      _no_display_exception();\n      return assign(img._width,img._height,title,normalization,is_fullscreen,is_closed);\n    }\n\n    //! Construct a display from an image list \\inplace.\n    /**\n    **/\n    template<typename T>\n    CImgDisplay& assign(const CImgList<T>& list,\n                        const char *const title=0, const unsigned int normalization=3,\n                        const bool is_fullscreen=false, const bool is_closed=false) {\n      _no_display_exception();\n      return assign(list._width,list._width,title,normalization,is_fullscreen,is_closed);\n    }\n\n    //! Construct a display as a copy of another one \\inplace.\n    /**\n    **/\n    CImgDisplay& assign(const CImgDisplay &disp) {\n      _no_display_exception();\n      return assign(disp._width,disp._height);\n    }\n\n#endif\n\n    //! Return a reference to an empty display.\n    /**\n       \\note Can be useful for writing function prototypes where one of the argument (of type CImgDisplay&)\n       must have a default value.\n       \\par Example\n       \\code\n       void foo(CImgDisplay& disp=CImgDisplay::empty());\n       \\endcode\n    **/\n    static CImgDisplay& empty() {\n      static CImgDisplay _empty;\n      return _empty.assign();\n    }\n\n    //! Return a reference to an empty display \\const.\n    static const CImgDisplay& const_empty() {\n      static const CImgDisplay _empty;\n      return _empty;\n    }\n\n#define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false), \\\n                                 CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)\n    static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz,\n                                   const int dmin, const int dmax,const bool return_y) {\n      const unsigned int _nw = dx + (dz>1?dz:0), _nh = dy + (dz>1?dz:0);\n      unsigned int nw = _nw?_nw:1, nh = _nh?_nh:1;\n      const unsigned int\n        sw = (unsigned int)CImgDisplay::screen_width(),\n        sh = (unsigned int)CImgDisplay::screen_height(),\n        mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,\n        mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,\n        Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,\n        Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;\n      if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0?1:0); nw = mw; }\n      if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0?1:0); nh = mh; }\n      if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0?1:0); nw = Mw; }\n      if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0?1:0); nh = Mh; }\n      if (nw<mw) nw = mw;\n      if (nh<mh) nh = mh;\n      return return_y?nh:nw;\n    }\n\n    //@}\n    //------------------------------------------\n    //\n    //! \\name Overloaded Operators\n    //@{\n    //------------------------------------------\n\n    //! Display image on associated window.\n    /**\n       \\note <tt>disp = img</tt> is equivalent to <tt>disp.display(img)</tt>.\n    **/\n    template<typename t>\n    CImgDisplay& operator=(const CImg<t>& img) {\n      return display(img);\n    }\n\n    //! Display list of images on associated window.\n    /**\n       \\note <tt>disp = list</tt> is equivalent to <tt>disp.display(list)</tt>.\n    **/\n    template<typename t>\n    CImgDisplay& operator=(const CImgList<t>& list) {\n      return display(list);\n    }\n\n    //! Construct a display as a copy of another one \\inplace.\n    /**\n       \\note Equivalent to assign(const CImgDisplay&).\n     **/\n    CImgDisplay& operator=(const CImgDisplay& disp) {\n      return assign(disp);\n    }\n\n    //! Return \\c false if display is empty, \\c true otherwise.\n    /**\n       \\note <tt>if (disp) { ... }</tt> is equivalent to <tt>if (!disp.is_empty()) { ... }</tt>.\n    **/\n    operator bool() const {\n      return !is_empty();\n    }\n\n    //@}\n    //------------------------------------------\n    //\n    //! \\name Instance Checking\n    //@{\n    //------------------------------------------\n\n    //! Return \\c true if display is empty, \\c false otherwise.\n    /**\n    **/\n    bool is_empty() const {\n      return !(_width && _height);\n    }\n\n    //! Return \\c true if display is closed (i.e. not visible on the screen), \\c false otherwise.\n    /**\n       \\note\n       - When a user physically closes the associated window, the display is set to closed.\n       - A closed display is not destroyed. Its associated window can be show again on the screen using show().\n    **/\n    bool is_closed() const {\n      return _is_closed;\n    }\n\n    //! Return \\c true if associated window has been resized on the screen, \\c false otherwise.\n    /**\n    **/\n    bool is_resized() const {\n      return _is_resized;\n    }\n\n    //! Return \\c true if associated window has been moved on the screen, \\c false otherwise.\n    /**\n    **/\n    bool is_moved() const {\n      return _is_moved;\n    }\n\n    //! Return \\c true if any event has occured on the associated window, \\c false otherwise.\n    /**\n    **/\n    bool is_event() const {\n      return _is_event;\n    }\n\n    //! Return \\c true if current display is in fullscreen mode, \\c false otherwise.\n    /**\n    **/\n    bool is_fullscreen() const {\n      return _is_fullscreen;\n    }\n\n    //! Return \\c true if any key is being pressed on the associated window, \\c false otherwise.\n    /**\n       \\note The methods below do the same only for specific keys.\n    **/\n    bool is_key() const {\n      return _is_keyESC || _is_keyF1 || _is_keyF2 || _is_keyF3 ||\n        _is_keyF4 || _is_keyF5 || _is_keyF6 || _is_keyF7 ||\n        _is_keyF8 || _is_keyF9 || _is_keyF10 || _is_keyF11 ||\n        _is_keyF12 || _is_keyPAUSE || _is_key1 || _is_key2 ||\n        _is_key3 || _is_key4 || _is_key5 || _is_key6 ||\n        _is_key7 || _is_key8 || _is_key9 || _is_key0 ||\n        _is_keyBACKSPACE || _is_keyINSERT || _is_keyHOME ||\n        _is_keyPAGEUP || _is_keyTAB || _is_keyQ || _is_keyW ||\n        _is_keyE || _is_keyR || _is_keyT || _is_keyY ||\n        _is_keyU || _is_keyI || _is_keyO || _is_keyP ||\n        _is_keyDELETE || _is_keyEND || _is_keyPAGEDOWN ||\n        _is_keyCAPSLOCK || _is_keyA || _is_keyS || _is_keyD ||\n        _is_keyF || _is_keyG || _is_keyH || _is_keyJ ||\n        _is_keyK || _is_keyL || _is_keyENTER ||\n        _is_keySHIFTLEFT || _is_keyZ || _is_keyX || _is_keyC ||\n        _is_keyV || _is_keyB || _is_keyN || _is_keyM ||\n        _is_keySHIFTRIGHT || _is_keyARROWUP || _is_keyCTRLLEFT ||\n        _is_keyAPPLEFT || _is_keyALT || _is_keySPACE || _is_keyALTGR ||\n        _is_keyAPPRIGHT || _is_keyMENU || _is_keyCTRLRIGHT ||\n        _is_keyARROWLEFT || _is_keyARROWDOWN || _is_keyARROWRIGHT ||\n        _is_keyPAD0 || _is_keyPAD1 || _is_keyPAD2 ||\n        _is_keyPAD3 || _is_keyPAD4 || _is_keyPAD5 ||\n        _is_keyPAD6 || _is_keyPAD7 || _is_keyPAD8 ||\n        _is_keyPAD9 || _is_keyPADADD || _is_keyPADSUB ||\n        _is_keyPADMUL || _is_keyPADDIV;\n    }\n\n    //! Return \\c true if key specified by given keycode is being pressed on the associated window, \\c false otherwise.\n    /**\n       \\param keycode Keycode to test.\n       \\note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure\n       your code stay portable (see cimg::keyESC).\n       \\par Example\n       \\code\n       CImgDisplay disp(400,400);\n       while (!disp.is_closed()) {\n         if (disp.key(cimg::keyTAB)) { ... }  // Equivalent to 'if (disp.is_keyTAB())'.\n         disp.wait();\n       }\n       \\endcode\n    **/\n    bool is_key(const unsigned int keycode) const {\n#define _cimg_iskey_test(k) if (keycode==cimg::key##k) return _is_key##k;\n      _cimg_iskey_test(ESC); _cimg_iskey_test(F1); _cimg_iskey_test(F2); _cimg_iskey_test(F3);\n      _cimg_iskey_test(F4); _cimg_iskey_test(F5); _cimg_iskey_test(F6); _cimg_iskey_test(F7);\n      _cimg_iskey_test(F8); _cimg_iskey_test(F9); _cimg_iskey_test(F10); _cimg_iskey_test(F11);\n      _cimg_iskey_test(F12); _cimg_iskey_test(PAUSE); _cimg_iskey_test(1); _cimg_iskey_test(2);\n      _cimg_iskey_test(3); _cimg_iskey_test(4); _cimg_iskey_test(5); _cimg_iskey_test(6);\n      _cimg_iskey_test(7); _cimg_iskey_test(8); _cimg_iskey_test(9); _cimg_iskey_test(0);\n      _cimg_iskey_test(BACKSPACE); _cimg_iskey_test(INSERT); _cimg_iskey_test(HOME);\n      _cimg_iskey_test(PAGEUP); _cimg_iskey_test(TAB); _cimg_iskey_test(Q); _cimg_iskey_test(W);\n      _cimg_iskey_test(E); _cimg_iskey_test(R); _cimg_iskey_test(T); _cimg_iskey_test(Y);\n      _cimg_iskey_test(U); _cimg_iskey_test(I); _cimg_iskey_test(O); _cimg_iskey_test(P);\n      _cimg_iskey_test(DELETE); _cimg_iskey_test(END); _cimg_iskey_test(PAGEDOWN);\n      _cimg_iskey_test(CAPSLOCK); _cimg_iskey_test(A); _cimg_iskey_test(S); _cimg_iskey_test(D);\n      _cimg_iskey_test(F); _cimg_iskey_test(G); _cimg_iskey_test(H); _cimg_iskey_test(J);\n      _cimg_iskey_test(K); _cimg_iskey_test(L); _cimg_iskey_test(ENTER);\n      _cimg_iskey_test(SHIFTLEFT); _cimg_iskey_test(Z); _cimg_iskey_test(X); _cimg_iskey_test(C);\n      _cimg_iskey_test(V); _cimg_iskey_test(B); _cimg_iskey_test(N); _cimg_iskey_test(M);\n      _cimg_iskey_test(SHIFTRIGHT); _cimg_iskey_test(ARROWUP); _cimg_iskey_test(CTRLLEFT);\n      _cimg_iskey_test(APPLEFT); _cimg_iskey_test(ALT); _cimg_iskey_test(SPACE); _cimg_iskey_test(ALTGR);\n      _cimg_iskey_test(APPRIGHT); _cimg_iskey_test(MENU); _cimg_iskey_test(CTRLRIGHT);\n      _cimg_iskey_test(ARROWLEFT); _cimg_iskey_test(ARROWDOWN); _cimg_iskey_test(ARROWRIGHT);\n      _cimg_iskey_test(PAD0); _cimg_iskey_test(PAD1); _cimg_iskey_test(PAD2);\n      _cimg_iskey_test(PAD3); _cimg_iskey_test(PAD4); _cimg_iskey_test(PAD5);\n      _cimg_iskey_test(PAD6); _cimg_iskey_test(PAD7); _cimg_iskey_test(PAD8);\n      _cimg_iskey_test(PAD9); _cimg_iskey_test(PADADD); _cimg_iskey_test(PADSUB);\n      _cimg_iskey_test(PADMUL); _cimg_iskey_test(PADDIV);\n      return false;\n    }\n\n    //! Return \\c true if key specified by given keycode is being pressed on the associated window, \\c false otherwise.\n    /**\n       \\param keycode C-string containing the keycode label of the key to test.\n       \\note Use it when the key you want to test can be dynamically set by the user.\n       \\par Example\n       \\code\n       CImgDisplay disp(400,400);\n       const char *const keycode = \"TAB\";\n       while (!disp.is_closed()) {\n         if (disp.is_key(keycode)) { ... }  // Equivalent to 'if (disp.is_keyTAB())'.\n         disp.wait();\n       }\n       \\endcode\n    **/\n    bool& is_key(const char *const keycode) {\n      static bool f = false;\n      f = false;\n#define _cimg_iskey_test2(k) if (!cimg::strcasecmp(keycode,#k)) return _is_key##k;\n      _cimg_iskey_test2(ESC); _cimg_iskey_test2(F1); _cimg_iskey_test2(F2); _cimg_iskey_test2(F3);\n      _cimg_iskey_test2(F4); _cimg_iskey_test2(F5); _cimg_iskey_test2(F6); _cimg_iskey_test2(F7);\n      _cimg_iskey_test2(F8); _cimg_iskey_test2(F9); _cimg_iskey_test2(F10); _cimg_iskey_test2(F11);\n      _cimg_iskey_test2(F12); _cimg_iskey_test2(PAUSE); _cimg_iskey_test2(1); _cimg_iskey_test2(2);\n      _cimg_iskey_test2(3); _cimg_iskey_test2(4); _cimg_iskey_test2(5); _cimg_iskey_test2(6);\n      _cimg_iskey_test2(7); _cimg_iskey_test2(8); _cimg_iskey_test2(9); _cimg_iskey_test2(0);\n      _cimg_iskey_test2(BACKSPACE); _cimg_iskey_test2(INSERT); _cimg_iskey_test2(HOME);\n      _cimg_iskey_test2(PAGEUP); _cimg_iskey_test2(TAB); _cimg_iskey_test2(Q); _cimg_iskey_test2(W);\n      _cimg_iskey_test2(E); _cimg_iskey_test2(R); _cimg_iskey_test2(T); _cimg_iskey_test2(Y);\n      _cimg_iskey_test2(U); _cimg_iskey_test2(I); _cimg_iskey_test2(O); _cimg_iskey_test2(P);\n      _cimg_iskey_test2(DELETE); _cimg_iskey_test2(END); _cimg_iskey_test2(PAGEDOWN);\n      _cimg_iskey_test2(CAPSLOCK); _cimg_iskey_test2(A); _cimg_iskey_test2(S); _cimg_iskey_test2(D);\n      _cimg_iskey_test2(F); _cimg_iskey_test2(G); _cimg_iskey_test2(H); _cimg_iskey_test2(J);\n      _cimg_iskey_test2(K); _cimg_iskey_test2(L); _cimg_iskey_test2(ENTER);\n      _cimg_iskey_test2(SHIFTLEFT); _cimg_iskey_test2(Z); _cimg_iskey_test2(X); _cimg_iskey_test2(C);\n      _cimg_iskey_test2(V); _cimg_iskey_test2(B); _cimg_iskey_test2(N); _cimg_iskey_test2(M);\n      _cimg_iskey_test2(SHIFTRIGHT); _cimg_iskey_test2(ARROWUP); _cimg_iskey_test2(CTRLLEFT);\n      _cimg_iskey_test2(APPLEFT); _cimg_iskey_test2(ALT); _cimg_iskey_test2(SPACE); _cimg_iskey_test2(ALTGR);\n      _cimg_iskey_test2(APPRIGHT); _cimg_iskey_test2(MENU); _cimg_iskey_test2(CTRLRIGHT);\n      _cimg_iskey_test2(ARROWLEFT); _cimg_iskey_test2(ARROWDOWN); _cimg_iskey_test2(ARROWRIGHT);\n      _cimg_iskey_test2(PAD0); _cimg_iskey_test2(PAD1); _cimg_iskey_test2(PAD2);\n      _cimg_iskey_test2(PAD3); _cimg_iskey_test2(PAD4); _cimg_iskey_test2(PAD5);\n      _cimg_iskey_test2(PAD6); _cimg_iskey_test2(PAD7); _cimg_iskey_test2(PAD8);\n      _cimg_iskey_test2(PAD9); _cimg_iskey_test2(PADADD); _cimg_iskey_test2(PADSUB);\n      _cimg_iskey_test2(PADMUL); _cimg_iskey_test2(PADDIV);\n      return f;\n    }\n\n    //! Return \\c true if specified key sequence has been typed on the associated window, \\c false otherwise.\n    /**\n       \\param keycodes_sequence Buffer of keycodes to test.\n       \\param length Number of keys in the \\c keycodes_sequence buffer.\n       \\param remove_sequence Tells if the key sequence must be removed from the key history, if found.\n       \\note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure\n       your code stay portable (see cimg::keyESC).\n       \\par Example\n       \\code\n       CImgDisplay disp(400,400);\n       const unsigned int key_seq[] = { cimg::keyCTRLLEFT, cimg::keyD };\n       while (!disp.is_closed()) {\n         if (disp.is_key_sequence(key_seq,2)) { ... }  // Test for the 'CTRL+D' keyboard event.\n         disp.wait();\n       }\n       \\endcode\n    **/\n    bool is_key_sequence(const unsigned int *const keycodes_sequence, const unsigned int length,\n                         const bool remove_sequence=false) {\n      if (keycodes_sequence && length) {\n        const unsigned int\n          *const ps_end = keycodes_sequence + length - 1,\n          *const pk_end = (unsigned int*)_keys + 1 + 128 - length,\n          k = *ps_end;\n        for (unsigned int *pk = (unsigned int*)_keys; pk<pk_end; ) {\n          if (*(pk++)==k) {\n            bool res = true;\n            const unsigned int *ps = ps_end, *pk2 = pk;\n            for (unsigned int i = 1; i<length; ++i) res = (*(--ps)==*(pk2++));\n            if (res) {\n              if (remove_sequence) std::memset((void*)(pk - 1),0,sizeof(unsigned int)*length);\n              return true;\n            }\n          }\n        }\n      }\n      return false;\n    }\n\n#define _cimg_iskey_def(k) \\\n    bool is_key##k() const { \\\n      return _is_key##k; \\\n    }\n\n    //! Return \\c true if the \\c ESC key is being pressed on the associated window, \\c false otherwise.\n    /**\n       \\note Similar methods exist for all keys managed by \\CImg (see cimg::keyESC).\n    **/\n    _cimg_iskey_def(ESC); _cimg_iskey_def(F1); _cimg_iskey_def(F2); _cimg_iskey_def(F3);\n    _cimg_iskey_def(F4); _cimg_iskey_def(F5); _cimg_iskey_def(F6); _cimg_iskey_def(F7);\n    _cimg_iskey_def(F8); _cimg_iskey_def(F9); _cimg_iskey_def(F10); _cimg_iskey_def(F11);\n    _cimg_iskey_def(F12); _cimg_iskey_def(PAUSE); _cimg_iskey_def(1); _cimg_iskey_def(2);\n    _cimg_iskey_def(3); _cimg_iskey_def(4); _cimg_iskey_def(5); _cimg_iskey_def(6);\n    _cimg_iskey_def(7); _cimg_iskey_def(8); _cimg_iskey_def(9); _cimg_iskey_def(0);\n    _cimg_iskey_def(BACKSPACE); _cimg_iskey_def(INSERT); _cimg_iskey_def(HOME);\n    _cimg_iskey_def(PAGEUP); _cimg_iskey_def(TAB); _cimg_iskey_def(Q); _cimg_iskey_def(W);\n    _cimg_iskey_def(E); _cimg_iskey_def(R); _cimg_iskey_def(T); _cimg_iskey_def(Y);\n    _cimg_iskey_def(U); _cimg_iskey_def(I); _cimg_iskey_def(O); _cimg_iskey_def(P);\n    _cimg_iskey_def(DELETE); _cimg_iskey_def(END); _cimg_iskey_def(PAGEDOWN);\n    _cimg_iskey_def(CAPSLOCK); _cimg_iskey_def(A); _cimg_iskey_def(S); _cimg_iskey_def(D);\n    _cimg_iskey_def(F); _cimg_iskey_def(G); _cimg_iskey_def(H); _cimg_iskey_def(J);\n    _cimg_iskey_def(K); _cimg_iskey_def(L); _cimg_iskey_def(ENTER);\n    _cimg_iskey_def(SHIFTLEFT); _cimg_iskey_def(Z); _cimg_iskey_def(X); _cimg_iskey_def(C);\n    _cimg_iskey_def(V); _cimg_iskey_def(B); _cimg_iskey_def(N); _cimg_iskey_def(M);\n    _cimg_iskey_def(SHIFTRIGHT); _cimg_iskey_def(ARROWUP); _cimg_iskey_def(CTRLLEFT);\n    _cimg_iskey_def(APPLEFT); _cimg_iskey_def(ALT); _cimg_iskey_def(SPACE); _cimg_iskey_def(ALTGR);\n    _cimg_iskey_def(APPRIGHT); _cimg_iskey_def(MENU); _cimg_iskey_def(CTRLRIGHT);\n    _cimg_iskey_def(ARROWLEFT); _cimg_iskey_def(ARROWDOWN); _cimg_iskey_def(ARROWRIGHT);\n    _cimg_iskey_def(PAD0); _cimg_iskey_def(PAD1); _cimg_iskey_def(PAD2);\n    _cimg_iskey_def(PAD3); _cimg_iskey_def(PAD4); _cimg_iskey_def(PAD5);\n    _cimg_iskey_def(PAD6); _cimg_iskey_def(PAD7); _cimg_iskey_def(PAD8);\n    _cimg_iskey_def(PAD9); _cimg_iskey_def(PADADD); _cimg_iskey_def(PADSUB);\n    _cimg_iskey_def(PADMUL); _cimg_iskey_def(PADDIV);\n\n    //@}\n    //------------------------------------------\n    //\n    //! \\name Instance Characteristics\n    //@{\n    //------------------------------------------\n\n#if cimg_display==0\n\n    //! Return width of the screen (current resolution along the X-axis).\n    /**\n    **/\n    static int screen_width() {\n      _no_display_exception();\n      return 0;\n    }\n\n    //! Return height of the screen (current resolution along the Y-axis).\n    /**\n    **/\n    static int screen_height() {\n      _no_display_exception();\n      return 0;\n    }\n\n#endif\n\n    //! Return display width.\n    /**\n       \\note The width of the display (i.e. the width of the pixel data buffer associated to the CImgDisplay instance)\n       may be different from the actual width of the associated window.\n    **/\n    int width() const {\n      return (int)_width;\n    }\n\n    //! Return display height.\n    /**\n       \\note The height of the display (i.e. the height of the pixel data buffer associated to the CImgDisplay instance)\n       may be different from the actual height of the associated window.\n    **/\n    int height() const {\n      return (int)_height;\n    }\n\n    //! Return normalization type of the display.\n    /**\n       The normalization type tells about how the values of an input image are normalized by the CImgDisplay to be\n       correctly displayed. The range of values for pixels displayed on screen is <tt>[0,255]</tt>.\n       If the range of values of the data to display is different, a normalization may be required for displaying\n       the data in a correct way. The normalization type can be one of:\n       - \\c 0: Value normalization is disabled. It is then assumed that all input data to be displayed by the\n       CImgDisplay instance have values in range <tt>[0,255]</tt>.\n       - \\c 1: Value normalization is always performed (this is the default behavior).\n       Before displaying an input image, its values will be (virtually) stretched\n       in range <tt>[0,255]</tt>, so that the contrast of the displayed pixels will be maximum.\n       Use this mode for images whose minimum and maximum values are not prescribed to known values\n       (e.g. float-valued images).\n       Note that when normalized versions of images are computed for display purposes, the actual values of these\n       images are not modified.\n       - \\c 2: Value normalization is performed once (on the first image display), then the same normalization\n       coefficients are kept for next displayed frames.\n       - \\c 3: Value normalization depends on the pixel type of the data to display. For integer pixel types,\n       the normalization is done regarding the minimum/maximum values of the type (no normalization occurs then\n       for <tt>unsigned char</tt>).\n       For float-valued pixel types, the normalization is done regarding the minimum/maximum value of the image\n       data instead.\n    **/\n    unsigned int normalization() const {\n      return _normalization;\n    }\n\n    //! Return title of the associated window as a C-string.\n    /**\n       \\note Window title may be not visible, depending on the used window manager or if the current display is\n       in fullscreen mode.\n    **/\n    const char *title() const {\n      return _title?_title:\"\";\n    }\n\n    //! Return width of the associated window.\n    /**\n       \\note The width of the display (i.e. the width of the pixel data buffer associated to the CImgDisplay instance)\n       may be different from the actual width of the associated window.\n    **/\n    int window_width() const {\n      return (int)_window_width;\n    }\n\n    //! Return height of the associated window.\n    /**\n       \\note The height of the display (i.e. the height of the pixel data buffer associated to the CImgDisplay instance)\n       may be different from the actual height of the associated window.\n    **/\n    int window_height() const {\n      return (int)_window_height;\n    }\n\n    //! Return X-coordinate of the associated window.\n    /**\n       \\note The returned coordinate corresponds to the location of the upper-left corner of the associated window.\n    **/\n    int window_x() const {\n      return _window_x;\n    }\n\n    //! Return Y-coordinate of the associated window.\n    /**\n       \\note The returned coordinate corresponds to the location of the upper-left corner of the associated window.\n    **/\n    int window_y() const {\n      return _window_y;\n    }\n\n    //! Return X-coordinate of the mouse pointer.\n    /**\n       \\note\n       - If the mouse pointer is outside window area, \\c -1 is returned.\n       - Otherwise, the returned value is in the range [0,width()-1].\n    **/\n    int mouse_x() const {\n      return _mouse_x;\n    }\n\n    //! Return Y-coordinate of the mouse pointer.\n    /**\n       \\note\n       - If the mouse pointer is outside window area, \\c -1 is returned.\n       - Otherwise, the returned value is in the range [0,height()-1].\n    **/\n    int mouse_y() const {\n      return _mouse_y;\n    }\n\n    //! Return current state of the mouse buttons.\n    /**\n       \\note Three mouse buttons can be managed. If one button is pressed, its corresponding bit in the returned\n       value is set:\n       - bit \\c 0 (value \\c 0x1): State of the left mouse button.\n       - bit \\c 1 (value \\c 0x2): State of the right mouse button.\n       - bit \\c 2 (value \\c 0x4): State of the middle mouse button.\n\n       Several bits can be activated if more than one button are pressed at the same time.\n       \\par Example\n       \\code\n       CImgDisplay disp(400,400);\n       while (!disp.is_closed()) {\n         if (disp.button()&1) { // Left button clicked.\n           ...\n         }\n         if (disp.button()&2) { // Right button clicked.\n           ...\n         }\n         if (disp.button()&4) { // Middle button clicked.\n           ...\n         }\n         disp.wait();\n       }\n       \\endcode\n    **/\n    unsigned int button() const {\n      return _button;\n    }\n\n    //! Return current state of the mouse wheel.\n    /**\n       \\note\n       - The returned value can be positive or negative depending on whether the mouse wheel has been scrolled\n       forward or backward.\n       - Scrolling the wheel forward add \\c 1 to the wheel value.\n       - Scrolling the wheel backward substract \\c 1 to the wheel value.\n       - The returned value cumulates the number of forward of backward scrolls since the creation of the display,\n       or since the last reset of the wheel value (using set_wheel()). It is strongly recommended to quickly reset\n       the wheel counter when an action has been performed regarding the current wheel value.\n       Otherwise, the returned wheel value may be for instance \\c 0 despite the fact that many scrolls have been done\n       (as many in forward as in backward directions).\n       \\par Example\n       \\code\n       CImgDisplay disp(400,400);\n       while (!disp.is_closed()) {\n         if (disp.wheel()) {\n           int counter = disp.wheel();  // Read the state of the mouse wheel.\n           ...                          // Do what you want with 'counter'.\n           disp.set_wheel();            // Reset the wheel value to 0.\n         }\n         disp.wait();\n       }\n       \\endcode\n    **/\n    int wheel() const {\n      return _wheel;\n    }\n\n    //! Return one entry from the pressed keys history.\n    /**\n       \\param pos Indice to read from the pressed keys history (indice \\c 0 corresponds to latest entry).\n       \\return Keycode of a pressed key or \\c 0 for a released key.\n       \\note\n       - Each CImgDisplay stores a history of the pressed keys in a buffer of size \\c 128. When a new key is pressed,\n       its keycode is stored in the pressed keys history. When a key is released, \\c 0 is put instead.\n       This means that up to the 64 last pressed keys may be read from the pressed keys history.\n       When a new value is stored, the pressed keys history is shifted so that the latest entry is always\n       stored at position \\c 0.\n       - Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure\n       your code stay portable (see cimg::keyESC).\n    **/\n    unsigned int key(const unsigned int pos=0) const {\n      return pos<128?_keys[pos]:0;\n    }\n\n    //! Return one entry from the released keys history.\n    /**\n       \\param pos Indice to read from the released keys history (indice \\c 0 corresponds to latest entry).\n       \\return Keycode of a released key or \\c 0 for a pressed key.\n       \\note\n       - Each CImgDisplay stores a history of the released keys in a buffer of size \\c 128. When a new key is released,\n       its keycode is stored in the pressed keys history. When a key is pressed, \\c 0 is put instead.\n       This means that up to the 64 last released keys may be read from the released keys history.\n       When a new value is stored, the released keys history is shifted so that the latest entry is always\n       stored at position \\c 0.\n       - Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure\n       your code stay portable (see cimg::keyESC).\n    **/\n    unsigned int released_key(const unsigned int pos=0) const {\n      return pos<128?_released_keys[pos]:0;\n    }\n\n    //! Return keycode corresponding to the specified string.\n    /**\n       \\note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure\n       your code stay portable (see cimg::keyESC).\n       \\par Example\n       \\code\n       const unsigned int keyTAB = CImgDisplay::keycode(\"TAB\");  // Return cimg::keyTAB.\n       \\endcode\n    **/\n    static unsigned int keycode(const char *const keycode) {\n#define _cimg_keycode(k) if (!cimg::strcasecmp(keycode,#k)) return cimg::key##k;\n      _cimg_keycode(ESC); _cimg_keycode(F1); _cimg_keycode(F2); _cimg_keycode(F3);\n      _cimg_keycode(F4); _cimg_keycode(F5); _cimg_keycode(F6); _cimg_keycode(F7);\n      _cimg_keycode(F8); _cimg_keycode(F9); _cimg_keycode(F10); _cimg_keycode(F11);\n      _cimg_keycode(F12); _cimg_keycode(PAUSE); _cimg_keycode(1); _cimg_keycode(2);\n      _cimg_keycode(3); _cimg_keycode(4); _cimg_keycode(5); _cimg_keycode(6);\n      _cimg_keycode(7); _cimg_keycode(8); _cimg_keycode(9); _cimg_keycode(0);\n      _cimg_keycode(BACKSPACE); _cimg_keycode(INSERT); _cimg_keycode(HOME);\n      _cimg_keycode(PAGEUP); _cimg_keycode(TAB); _cimg_keycode(Q); _cimg_keycode(W);\n      _cimg_keycode(E); _cimg_keycode(R); _cimg_keycode(T); _cimg_keycode(Y);\n      _cimg_keycode(U); _cimg_keycode(I); _cimg_keycode(O); _cimg_keycode(P);\n      _cimg_keycode(DELETE); _cimg_keycode(END); _cimg_keycode(PAGEDOWN);\n      _cimg_keycode(CAPSLOCK); _cimg_keycode(A); _cimg_keycode(S); _cimg_keycode(D);\n      _cimg_keycode(F); _cimg_keycode(G); _cimg_keycode(H); _cimg_keycode(J);\n      _cimg_keycode(K); _cimg_keycode(L); _cimg_keycode(ENTER);\n      _cimg_keycode(SHIFTLEFT); _cimg_keycode(Z); _cimg_keycode(X); _cimg_keycode(C);\n      _cimg_keycode(V); _cimg_keycode(B); _cimg_keycode(N); _cimg_keycode(M);\n      _cimg_keycode(SHIFTRIGHT); _cimg_keycode(ARROWUP); _cimg_keycode(CTRLLEFT);\n      _cimg_keycode(APPLEFT); _cimg_keycode(ALT); _cimg_keycode(SPACE); _cimg_keycode(ALTGR);\n      _cimg_keycode(APPRIGHT); _cimg_keycode(MENU); _cimg_keycode(CTRLRIGHT);\n      _cimg_keycode(ARROWLEFT); _cimg_keycode(ARROWDOWN); _cimg_keycode(ARROWRIGHT);\n      _cimg_keycode(PAD0); _cimg_keycode(PAD1); _cimg_keycode(PAD2);\n      _cimg_keycode(PAD3); _cimg_keycode(PAD4); _cimg_keycode(PAD5);\n      _cimg_keycode(PAD6); _cimg_keycode(PAD7); _cimg_keycode(PAD8);\n      _cimg_keycode(PAD9); _cimg_keycode(PADADD); _cimg_keycode(PADSUB);\n      _cimg_keycode(PADMUL); _cimg_keycode(PADDIV);\n      return 0;\n    }\n\n    //! Return the current refresh rate, in frames per second.\n    /**\n       \\note Returns a significant value when the current instance is used to display successive frames.\n       It measures the delay between successive calls to frames_per_second().\n    **/\n    float frames_per_second() {\n      if (!_fps_timer) _fps_timer = cimg::time();\n      const float delta = (cimg::time() - _fps_timer)/1000.0f;\n      ++_fps_frames;\n      if (delta>=1) {\n        _fps_fps = _fps_frames/delta;\n        _fps_frames = 0;\n        _fps_timer = cimg::time();\n      }\n      return _fps_fps;\n    }\n\n    //@}\n    //---------------------------------------\n    //\n    //! \\name Window Manipulation\n    //@{\n    //---------------------------------------\n\n#if cimg_display==0\n\n    //! Display image on associated window.\n    /**\n       \\param img Input image to display.\n       \\note This method returns immediately.\n    **/\n    template<typename T>\n    CImgDisplay& display(const CImg<T>& img) {\n      return assign(img);\n    }\n\n#endif\n\n    //! Display list of images on associated window.\n    /**\n       \\param list List of images to display.\n       \\param axis Axis used to append the images along, for the visualization (can be \\c x, \\c y, \\c z or \\c c).\n       \\param align Relative position of aligned images when displaying lists with images of different sizes\n       (\\c 0 for upper-left, \\c 0.5 for centering and \\c 1 for lower-right).\n       \\note This method returns immediately.\n    **/\n    template<typename T>\n    CImgDisplay& display(const CImgList<T>& list, const char axis='x', const float align=0) {\n      if (list._width==1) {\n        const CImg<T>& img = list[0];\n        if (img._depth==1 && (img._spectrum==1 || img._spectrum>=3) && _normalization!=1) return display(img);\n      }\n      CImgList<typename CImg<T>::ucharT> visu(list._width);\n      unsigned int dims = 0;\n      cimglist_for(list,l) {\n        const CImg<T>& img = list._data[l];\n        img.__get_select(*this,_normalization,(img._width - 1)/2,(img._height - 1)/2,\n                         (img._depth - 1)/2).move_to(visu[l]);\n        dims = cimg::max(dims,visu[l]._spectrum);\n      }\n      cimglist_for(list,l) if (visu[l]._spectrum<dims) visu[l].resize(-100,-100,-100,dims,1);\n      visu.get_append(axis,align).display(*this);\n      return *this;\n    }\n\n#if cimg_display==0\n\n    //! Show (closed) associated window on the screen.\n    /**\n       \\note\n       - Force the associated window of a display to be visible on the screen, even if it has been closed before.\n       - Using show() on a visible display does nothing.\n    **/\n    CImgDisplay& show() {\n      return assign();\n    }\n\n    //! Close (visible) associated window and make it disappear from the screen.\n    /**\n       \\note\n       - A closed display only means the associated window is not visible anymore. This does not mean the display has\n       been destroyed.\n       Use show() to make the associated window reappear.\n       - Using close() on a closed display does nothing.\n    **/\n    CImgDisplay& close() {\n      return assign();\n    }\n\n    //! Move associated window to a new location.\n    /**\n       \\param pos_x X-coordinate of the new window location.\n       \\param pos_y Y-coordinate of the new window location.\n       \\note Depending on the window manager behavior, this method may not succeed (no exceptions are thrown\n       nevertheless).\n    **/\n    CImgDisplay& move(const int pos_x, const int pos_y) {\n      return assign(pos_x,pos_y);\n    }\n\n#endif\n\n    //! Resize display to the size of the associated window.\n    /**\n       \\param force_redraw Tells if the previous window content must be updated and refreshed as well.\n       \\note\n       - Calling this method ensures that width() and window_width() become equal, as well as height() and\n       window_height().\n       - The associated window is also resized to specified dimensions.\n    **/\n    CImgDisplay& resize(const bool force_redraw=true) {\n      resize(window_width(),window_height(),force_redraw);\n      return *this;\n    }\n\n#if cimg_display==0\n\n    //! Resize display to the specified size.\n    /**\n       \\param width Requested display width.\n       \\param height Requested display height.\n       \\param force_redraw Tells if the previous window content must be updated and refreshed as well.\n       \\note The associated window is also resized to specified dimensions.\n    **/\n    CImgDisplay& resize(const int width, const int height, const bool force_redraw=true) {\n      return assign(width,height,0,3,force_redraw);\n    }\n\n#endif\n\n    //! Resize display to the size of an input image.\n    /**\n       \\param img Input image to take size from.\n       \\param force_redraw Tells if the previous window content must be resized and updated as well.\n       \\note\n       - Calling this method ensures that width() and <tt>img.width()</tt> become equal, as well as height() and\n       <tt>img.height()</tt>.\n       - The associated window is also resized to specified dimensions.\n    **/\n    template<typename T>\n    CImgDisplay& resize(const CImg<T>& img, const bool force_redraw=true) {\n      return resize(img._width,img._height,force_redraw);\n    }\n\n    //! Resize display to the size of another CImgDisplay instance.\n    /**\n       \\param disp Input display to take size from.\n       \\param force_redraw Tells if the previous window content must be resized and updated as well.\n       \\note\n       - Calling this method ensures that width() and <tt>disp.width()</tt> become equal, as well as height() and\n       <tt>disp.height()</tt>.\n       - The associated window is also resized to specified dimensions.\n    **/\n    CImgDisplay& resize(const CImgDisplay& disp, const bool force_redraw=true) {\n      return resize(disp.width(),disp.height(),force_redraw);\n    }\n\n    // [internal] Render pixel buffer with size (wd,hd) from source buffer of size (ws,hs).\n    template<typename t, typename T>\n    static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,\n                               t *ptrd, const unsigned int wd, const unsigned int hd) {\n      unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd + 1], *poffx, *poffy;\n      float s, curr, old;\n      s = (float)ws/wd;\n      poffx = offx; curr = 0; for (unsigned int x = 0; x<wd; ++x) {\n        old = curr; curr+=s; *(poffx++) = (unsigned int)curr - (unsigned int)old;\n      }\n      s = (float)hs/hd;\n      poffy = offy; curr = 0; for (unsigned int y = 0; y<hd; ++y) {\n        old = curr; curr+=s; *(poffy++) = ws*((unsigned int)curr - (unsigned int)old);\n      }\n      *poffy = 0;\n      poffy = offy;\n      for (unsigned int y = 0; y<hd; ) {\n        const T *ptr = ptrs;\n        poffx = offx;\n        for (unsigned int x = 0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }\n        ++y;\n        unsigned int dy = *(poffy++);\n        for ( ; !dy && y<hd; std::memcpy(ptrd,ptrd - wd,sizeof(t)*wd), ++y, ptrd+=wd, dy = *(poffy++)) {}\n        ptrs+=dy;\n      }\n      delete[] offx; delete[] offy;\n    }\n\n    //! Set normalization type.\n    /**\n       \\param normalization New normalization mode.\n    **/\n    CImgDisplay& set_normalization(const unsigned int normalization) {\n      _normalization = normalization;\n      _min = _max = 0;\n      return *this;\n    }\n\n#if cimg_display==0\n\n    //! Set title of the associated window.\n    /**\n       \\param format C-string containing the format of the title, as with <tt>std::printf()</tt>.\n       \\warning As the first argument is a format string, it is highly recommended to write\n       \\code\n       disp.set_title(\"%s\",window_title);\n       \\endcode\n       instead of\n       \\code\n       disp.set_title(window_title);\n       \\endcode\n       if \\c window_title can be arbitrary, to prevent nasty memory access.\n    **/\n    CImgDisplay& set_title(const char *const format, ...) {\n      return assign(0,0,format);\n    }\n\n#endif\n\n    //! Enable or disable fullscreen mode.\n    /**\n       \\param is_fullscreen Tells is the fullscreen mode must be activated or not.\n       \\param force_redraw Tells if the previous window content must be displayed as well.\n       \\note\n       - When the fullscreen mode is enabled, the associated window fills the entire screen but the size of the\n       current display is not modified.\n       - The screen resolution may be switched to fit the associated window size and ensure it appears the largest\n       as possible.\n       For X-Window (X11) users, the configuration flag \\c cimg_use_xrandr has to be set to allow the screen\n       resolution change (requires the X11 extensions to be enabled).\n    **/\n    CImgDisplay& set_fullscreen(const bool is_fullscreen, const bool force_redraw=true) {\n      if (is_empty() || _is_fullscreen==is_fullscreen) return *this;\n      return toggle_fullscreen(force_redraw);\n    }\n\n#if cimg_display==0\n\n    //! Toggle fullscreen mode.\n    /**\n       \\param force_redraw Tells if the previous window content must be displayed as well.\n       \\note Enable fullscreen mode if it was not enabled, and disable it otherwise.\n    **/\n    CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {\n      return assign(_width,_height,0,3,force_redraw);\n    }\n\n    //! Show mouse pointer.\n    /**\n       \\note Depending on the window manager behavior, this method may not succeed\n       (no exceptions are thrown nevertheless).\n    **/\n    CImgDisplay& show_mouse() {\n      return assign();\n    }\n\n    //! Hide mouse pointer.\n    /**\n       \\note Depending on the window manager behavior, this method may not succeed\n       (no exceptions are thrown nevertheless).\n    **/\n    CImgDisplay& hide_mouse() {\n      return assign();\n    }\n\n    //! Move mouse pointer to a specified location.\n    /**\n       \\note Depending on the window manager behavior, this method may not succeed\n       (no exceptions are thrown nevertheless).\n    **/\n    CImgDisplay& set_mouse(const int pos_x, const int pos_y) {\n      return assign(pos_x,pos_y);\n    }\n\n#endif\n\n    //! Simulate a mouse button release event.\n    /**\n       \\note All mouse buttons are considered released at the same time.\n    **/\n    CImgDisplay& set_button() {\n      _button = 0;\n      _is_event = true;\n#if cimg_display==1\n      pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n#elif cimg_display==2\n      SetEvent(cimg::Win32_attr().wait_event);\n#endif\n      return *this;\n    }\n\n    //! Simulate a mouse button press or release event.\n    /**\n       \\param button Buttons event code, where each button is associated to a single bit.\n       \\param is_pressed Tells if the mouse button is considered as pressed or released.\n    **/\n    CImgDisplay& set_button(const unsigned int button, const bool is_pressed=true) {\n      const unsigned int buttoncode = button==1U?1U:button==2U?2U:button==3U?4U:0U;\n      if (is_pressed) _button |= buttoncode; else _button &= ~buttoncode;\n      _is_event = buttoncode?true:false;\n      if (buttoncode) {\n#if cimg_display==1\n        pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n#elif cimg_display==2\n        SetEvent(cimg::Win32_attr().wait_event);\n#endif\n      }\n      return *this;\n    }\n\n    //! Flush all mouse wheel events.\n    /**\n       \\note Make wheel() to return \\c 0, if called afterwards.\n    **/\n    CImgDisplay& set_wheel() {\n      _wheel = 0;\n      _is_event = true;\n#if cimg_display==1\n      pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n#elif cimg_display==2\n      SetEvent(cimg::Win32_attr().wait_event);\n#endif\n      return *this;\n    }\n\n    //! Simulate a wheel event.\n    /**\n       \\param amplitude Amplitude of the wheel scrolling to simulate.\n       \\note Make wheel() to return \\c amplitude, if called afterwards.\n    **/\n    CImgDisplay& set_wheel(const int amplitude) {\n      _wheel+=amplitude;\n      _is_event = amplitude?true:false;\n      if (amplitude) {\n#if cimg_display==1\n        pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n#elif cimg_display==2\n        SetEvent(cimg::Win32_attr().wait_event);\n#endif\n      }\n      return *this;\n    }\n\n    //! Flush all key events.\n    /**\n       \\note Make key() to return \\c 0, if called afterwards.\n    **/\n    CImgDisplay& set_key() {\n      std::memset((void*)_keys,0,128*sizeof(unsigned int));\n      std::memset((void*)_released_keys,0,128*sizeof(unsigned int));\n      _is_keyESC = _is_keyF1 = _is_keyF2 = _is_keyF3 = _is_keyF4 = _is_keyF5 = _is_keyF6 = _is_keyF7 = _is_keyF8 =\n        _is_keyF9 = _is_keyF10 = _is_keyF11 = _is_keyF12 = _is_keyPAUSE = _is_key1 = _is_key2 = _is_key3 = _is_key4 =\n        _is_key5 = _is_key6 = _is_key7 = _is_key8 = _is_key9 = _is_key0 = _is_keyBACKSPACE = _is_keyINSERT =\n        _is_keyHOME = _is_keyPAGEUP = _is_keyTAB = _is_keyQ = _is_keyW = _is_keyE = _is_keyR = _is_keyT = _is_keyY =\n        _is_keyU = _is_keyI = _is_keyO = _is_keyP = _is_keyDELETE = _is_keyEND = _is_keyPAGEDOWN = _is_keyCAPSLOCK =\n        _is_keyA = _is_keyS = _is_keyD = _is_keyF = _is_keyG = _is_keyH = _is_keyJ = _is_keyK = _is_keyL =\n        _is_keyENTER = _is_keySHIFTLEFT = _is_keyZ = _is_keyX = _is_keyC = _is_keyV = _is_keyB = _is_keyN =\n        _is_keyM = _is_keySHIFTRIGHT = _is_keyARROWUP = _is_keyCTRLLEFT = _is_keyAPPLEFT = _is_keyALT = _is_keySPACE =\n        _is_keyALTGR = _is_keyAPPRIGHT = _is_keyMENU = _is_keyCTRLRIGHT = _is_keyARROWLEFT = _is_keyARROWDOWN =\n        _is_keyARROWRIGHT = _is_keyPAD0 = _is_keyPAD1 = _is_keyPAD2 = _is_keyPAD3 = _is_keyPAD4 = _is_keyPAD5 =\n        _is_keyPAD6 = _is_keyPAD7 = _is_keyPAD8 = _is_keyPAD9 = _is_keyPADADD = _is_keyPADSUB = _is_keyPADMUL =\n        _is_keyPADDIV = false;\n      _is_event = true;\n#if cimg_display==1\n      pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n#elif cimg_display==2\n      SetEvent(cimg::Win32_attr().wait_event);\n#endif\n      return *this;\n    }\n\n    //! Simulate a keyboard press/release event.\n    /**\n       \\param keycode Keycode of the associated key.\n       \\param is_pressed Tells if the key is considered as pressed or released.\n       \\note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure\n       your code stay portable (see cimg::keyESC).\n    **/\n    CImgDisplay& set_key(const unsigned int keycode, const bool is_pressed=true) {\n#define _cimg_set_key(k) if (keycode==cimg::key##k) _is_key##k = is_pressed;\n      _cimg_set_key(ESC); _cimg_set_key(F1); _cimg_set_key(F2); _cimg_set_key(F3);\n      _cimg_set_key(F4); _cimg_set_key(F5); _cimg_set_key(F6); _cimg_set_key(F7);\n      _cimg_set_key(F8); _cimg_set_key(F9); _cimg_set_key(F10); _cimg_set_key(F11);\n      _cimg_set_key(F12); _cimg_set_key(PAUSE); _cimg_set_key(1); _cimg_set_key(2);\n      _cimg_set_key(3); _cimg_set_key(4); _cimg_set_key(5); _cimg_set_key(6);\n      _cimg_set_key(7); _cimg_set_key(8); _cimg_set_key(9); _cimg_set_key(0);\n      _cimg_set_key(BACKSPACE); _cimg_set_key(INSERT); _cimg_set_key(HOME);\n      _cimg_set_key(PAGEUP); _cimg_set_key(TAB); _cimg_set_key(Q); _cimg_set_key(W);\n      _cimg_set_key(E); _cimg_set_key(R); _cimg_set_key(T); _cimg_set_key(Y);\n      _cimg_set_key(U); _cimg_set_key(I); _cimg_set_key(O); _cimg_set_key(P);\n      _cimg_set_key(DELETE); _cimg_set_key(END); _cimg_set_key(PAGEDOWN);\n      _cimg_set_key(CAPSLOCK); _cimg_set_key(A); _cimg_set_key(S); _cimg_set_key(D);\n      _cimg_set_key(F); _cimg_set_key(G); _cimg_set_key(H); _cimg_set_key(J);\n      _cimg_set_key(K); _cimg_set_key(L); _cimg_set_key(ENTER);\n      _cimg_set_key(SHIFTLEFT); _cimg_set_key(Z); _cimg_set_key(X); _cimg_set_key(C);\n      _cimg_set_key(V); _cimg_set_key(B); _cimg_set_key(N); _cimg_set_key(M);\n      _cimg_set_key(SHIFTRIGHT); _cimg_set_key(ARROWUP); _cimg_set_key(CTRLLEFT);\n      _cimg_set_key(APPLEFT); _cimg_set_key(ALT); _cimg_set_key(SPACE); _cimg_set_key(ALTGR);\n      _cimg_set_key(APPRIGHT); _cimg_set_key(MENU); _cimg_set_key(CTRLRIGHT);\n      _cimg_set_key(ARROWLEFT); _cimg_set_key(ARROWDOWN); _cimg_set_key(ARROWRIGHT);\n      _cimg_set_key(PAD0); _cimg_set_key(PAD1); _cimg_set_key(PAD2);\n      _cimg_set_key(PAD3); _cimg_set_key(PAD4); _cimg_set_key(PAD5);\n      _cimg_set_key(PAD6); _cimg_set_key(PAD7); _cimg_set_key(PAD8);\n      _cimg_set_key(PAD9); _cimg_set_key(PADADD); _cimg_set_key(PADSUB);\n      _cimg_set_key(PADMUL); _cimg_set_key(PADDIV);\n      if (is_pressed) {\n        if (*_keys)\n          std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int));\n        *_keys = keycode;\n        if (*_released_keys) {\n          std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int));\n          *_released_keys = 0;\n        }\n      } else {\n        if (*_keys) {\n          std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int));\n          *_keys = 0;\n        }\n        if (*_released_keys)\n          std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int));\n        *_released_keys = keycode;\n      }\n      _is_event = keycode?true:false;\n      if (keycode) {\n#if cimg_display==1\n        pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n#elif cimg_display==2\n        SetEvent(cimg::Win32_attr().wait_event);\n#endif\n      }\n      return *this;\n    }\n\n    //! Flush all display events.\n    /**\n       \\note Remove all passed events from the current display.\n    **/\n    CImgDisplay& flush() {\n      set_key().set_button().set_wheel();\n      _is_resized = _is_moved = _is_event = false;\n      _fps_timer = _fps_frames = _timer = 0;\n      _fps_fps = 0;\n      return *this;\n    }\n\n    //! Wait for any user event occuring on the current display.\n    CImgDisplay& wait() {\n      wait(*this);\n      return *this;\n    }\n\n    //! Wait for a given number of milliseconds since the last call to wait().\n    /**\n       \\param milliseconds Number of milliseconds to wait for.\n       \\note Similar to cimg::wait().\n    **/\n    CImgDisplay& wait(const unsigned int milliseconds) {\n      cimg::_wait(milliseconds,_timer);\n      return *this;\n    }\n\n    //! Wait for any event occuring on the display \\c disp1.\n    static void wait(CImgDisplay& disp1) {\n      disp1._is_event = false;\n      while (!disp1._is_closed && !disp1._is_event) wait_all();\n    }\n\n    //! Wait for any event occuring either on the display \\c disp1 or \\c disp2.\n    static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {\n      disp1._is_event = disp2._is_event = false;\n      while ((!disp1._is_closed || !disp2._is_closed) &&\n             !disp1._is_event && !disp2._is_event) wait_all();\n    }\n\n    //! Wait for any event occuring either on the display \\c disp1, \\c disp2 or \\c disp3.\n    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {\n      disp1._is_event = disp2._is_event = disp3._is_event = false;\n      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed) &&\n             !disp1._is_event && !disp2._is_event && !disp3._is_event) wait_all();\n    }\n\n    //! Wait for any event occuring either on the display \\c disp1, \\c disp2, \\c disp3 or \\c disp4.\n    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {\n      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = false;\n      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed) &&\n             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event) wait_all();\n    }\n\n    //! Wait for any event occuring either on the display \\c disp1, \\c disp2, \\c disp3, \\c disp4 or \\c disp5.\n    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4,\n                     CImgDisplay& disp5) {\n      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = false;\n      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed) &&\n             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event)\n        wait_all();\n    }\n\n    //! Wait for any event occuring either on the display \\c disp1, \\c disp2, \\c disp3, \\c disp4, ... \\c disp6.\n    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,\n                     CImgDisplay& disp6) {\n      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =\n        disp6._is_event = false;\n      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||\n              !disp6._is_closed) &&\n             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&\n             !disp6._is_event) wait_all();\n    }\n\n    //! Wait for any event occuring either on the display \\c disp1, \\c disp2, \\c disp3, \\c disp4, ... \\c disp7.\n    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,\n                     CImgDisplay& disp6, CImgDisplay& disp7) {\n      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =\n        disp6._is_event = disp7._is_event = false;\n      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||\n              !disp6._is_closed || !disp7._is_closed) &&\n             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&\n             !disp6._is_event && !disp7._is_event) wait_all();\n    }\n\n    //! Wait for any event occuring either on the display \\c disp1, \\c disp2, \\c disp3, \\c disp4, ... \\c disp8.\n    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,\n                     CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8) {\n      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =\n        disp6._is_event = disp7._is_event = disp8._is_event = false;\n      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||\n              !disp6._is_closed || !disp7._is_closed || !disp8._is_closed) &&\n             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&\n             !disp6._is_event && !disp7._is_event && !disp8._is_event) wait_all();\n    }\n\n    //! Wait for any event occuring either on the display \\c disp1, \\c disp2, \\c disp3, \\c disp4, ... \\c disp9.\n    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,\n                     CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9) {\n      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =\n        disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = false;\n      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||\n              !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed) &&\n             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&\n             !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event) wait_all();\n    }\n\n    //! Wait for any event occuring either on the display \\c disp1, \\c disp2, \\c disp3, \\c disp4, ... \\c disp10.\n    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,\n                     CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9,\n                     CImgDisplay& disp10) {\n      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =\n        disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = disp10._is_event = false;\n      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||\n              !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed || !disp10._is_closed) &&\n             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&\n             !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event && !disp10._is_event)\n        wait_all();\n    }\n\n#if cimg_display==0\n\n    //! Wait for any window event occuring in any opened CImgDisplay.\n    static void wait_all() {\n      return _no_display_exception();\n    }\n\n    //! Render image into internal display buffer.\n    /**\n       \\param img Input image data to render.\n       \\note\n       - Convert image data representation into the internal display buffer (architecture-dependent structure).\n       - The content of the associated window is not modified, until paint() is called.\n       - Should not be used for common CImgDisplay uses, since display() is more useful.\n    **/\n    template<typename T>\n    CImgDisplay& render(const CImg<T>& img) {\n      return assign(img);\n    }\n\n    //! Paint internal display buffer on associated window.\n    /**\n       \\note\n       - Update the content of the associated window with the internal display buffer, e.g. after a render() call.\n       - Should not be used for common CImgDisplay uses, since display() is more useful.\n    **/\n    CImgDisplay& paint() {\n      return assign();\n    }\n\n    //! Take a snapshot of the associated window content.\n    /**\n       \\param[out] img Output snapshot. Can be empty on input.\n    **/\n    template<typename T>\n    const CImgDisplay& snapshot(CImg<T>& img) const {\n      cimg::unused(img);\n      _no_display_exception();\n      return *this;\n    }\n#endif\n\n    // X11-based implementation\n    //--------------------------\n#if cimg_display==1\n\n    Atom _wm_window_atom, _wm_protocol_atom;\n    Window _window, _background_window;\n    Colormap _colormap;\n    XImage *_image;\n    void *_data;\n#ifdef cimg_use_xshm\n    XShmSegmentInfo *_shminfo;\n#endif\n\n    static int screen_width() {\n      Display *const dpy = cimg::X11_attr().display;\n      int res = 0;\n      if (!dpy) {\n        Display *const _dpy = XOpenDisplay(0);\n        if (!_dpy)\n          throw CImgDisplayException(\"CImgDisplay::screen_width(): Failed to open X11 display.\");\n        res = DisplayWidth(_dpy,DefaultScreen(_dpy));\n        XCloseDisplay(_dpy);\n      } else {\n#ifdef cimg_use_xrandr\n        if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution)\n          res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width;\n        else res = DisplayWidth(dpy,DefaultScreen(dpy));\n#else\n        res = DisplayWidth(dpy,DefaultScreen(dpy));\n#endif\n      }\n      return res;\n    }\n\n    static int screen_height() {\n      Display *const dpy = cimg::X11_attr().display;\n      int res = 0;\n      if (!dpy) {\n        Display *const _dpy = XOpenDisplay(0);\n        if (!_dpy)\n          throw CImgDisplayException(\"CImgDisplay::screen_height(): Failed to open X11 display.\");\n        res = DisplayHeight(_dpy,DefaultScreen(_dpy));\n        XCloseDisplay(_dpy);\n      } else {\n#ifdef cimg_use_xrandr\n        if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution)\n          res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height;\n        else res = DisplayHeight(dpy,DefaultScreen(dpy));\n#else\n        res = DisplayHeight(dpy,DefaultScreen(dpy));\n#endif\n      }\n      return res;\n    }\n\n    static void wait_all() {\n      if (!cimg::X11_attr().display) return;\n      pthread_mutex_lock(&cimg::X11_attr().wait_event_mutex);\n      pthread_cond_wait(&cimg::X11_attr().wait_event,&cimg::X11_attr().wait_event_mutex);\n      pthread_mutex_unlock(&cimg::X11_attr().wait_event_mutex);\n    }\n\n    void _handle_events(const XEvent *const pevent) {\n      Display *const dpy = cimg::X11_attr().display;\n      XEvent event = *pevent;\n      switch (event.type) {\n      case ClientMessage : {\n        if ((int)event.xclient.message_type==(int)_wm_protocol_atom &&\n            (int)event.xclient.data.l[0]==(int)_wm_window_atom) {\n          XUnmapWindow(cimg::X11_attr().display,_window);\n          _is_closed = _is_event = true;\n          pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n        }\n      } break;\n      case ConfigureNotify : {\n        while (XCheckWindowEvent(dpy,_window,StructureNotifyMask,&event)) {}\n        const unsigned int nw = event.xconfigure.width, nh = event.xconfigure.height;\n        const int nx = event.xconfigure.x, ny = event.xconfigure.y;\n        if (nw && nh && (nw!=_window_width || nh!=_window_height)) {\n          _window_width = nw; _window_height = nh; _mouse_x = _mouse_y = -1;\n          XResizeWindow(dpy,_window,_window_width,_window_height);\n          _is_resized = _is_event = true;\n          pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n        }\n        if (nx!=_window_x || ny!=_window_y) {\n          _window_x = nx; _window_y = ny; _is_moved = _is_event = true;\n          pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n        }\n      } break;\n      case Expose : {\n        while (XCheckWindowEvent(dpy,_window,ExposureMask,&event)) {}\n        _paint(false);\n        if (_is_fullscreen) {\n          XWindowAttributes attr;\n          XGetWindowAttributes(dpy,_window,&attr);\n          while (attr.map_state!=IsViewable) XSync(dpy,0);\n          XSetInputFocus(dpy,_window,RevertToParent,CurrentTime);\n        }\n      } break;\n      case ButtonPress : {\n        do {\n          _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y;\n          if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;\n          switch (event.xbutton.button) {\n          case 1 : set_button(1); break;\n          case 3 : set_button(2); break;\n          case 2 : set_button(3); break;\n          }\n        } while (XCheckWindowEvent(dpy,_window,ButtonPressMask,&event));\n      } break;\n      case ButtonRelease : {\n        do {\n          _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y;\n          if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;\n          switch (event.xbutton.button) {\n          case 1 : set_button(1,false); break;\n          case 3 : set_button(2,false); break;\n          case 2 : set_button(3,false); break;\n          case 4 : set_wheel(1); break;\n          case 5 : set_wheel(-1); break;\n          }\n        } while (XCheckWindowEvent(dpy,_window,ButtonReleaseMask,&event));\n      } break;\n      case KeyPress : {\n        char tmp = 0; KeySym ksym;\n        XLookupString(&event.xkey,&tmp,1,&ksym,0);\n        set_key((unsigned int)ksym,true);\n      } break;\n      case KeyRelease : {\n        char keys_return[32];  // Check that the key has been physically unpressed.\n        XQueryKeymap(dpy,keys_return);\n        const unsigned int kc = event.xkey.keycode, kc1 = kc/8, kc2 = kc%8;\n        const bool is_key_pressed = kc1>=32?false:(keys_return[kc1]>>kc2)&1;\n        if (!is_key_pressed) {\n          char tmp = 0; KeySym ksym;\n          XLookupString(&event.xkey,&tmp,1,&ksym,0);\n          set_key((unsigned int)ksym,false);\n        }\n      } break;\n      case EnterNotify: {\n        while (XCheckWindowEvent(dpy,_window,EnterWindowMask,&event)) {}\n        _mouse_x = event.xmotion.x;\n        _mouse_y = event.xmotion.y;\n        if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;\n      } break;\n      case LeaveNotify : {\n        while (XCheckWindowEvent(dpy,_window,LeaveWindowMask,&event)) {}\n        _mouse_x = _mouse_y = -1; _is_event = true;\n        pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n      } break;\n      case MotionNotify : {\n        while (XCheckWindowEvent(dpy,_window,PointerMotionMask,&event)) {}\n        _mouse_x = event.xmotion.x;\n        _mouse_y = event.xmotion.y;\n        if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;\n        _is_event = true;\n        pthread_cond_broadcast(&cimg::X11_attr().wait_event);\n      } break;\n      }\n    }\n\n    static void* _events_thread(void *arg) { // Thread to manage events for all opened display windows.\n      Display *const dpy = cimg::X11_attr().display;\n      XEvent event;\n      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);\n      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);\n      if (!arg) for ( ; ; ) {\n        cimg_lock_display();\n        bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event);\n        if (!event_flag) event_flag = XCheckMaskEvent(dpy,\n                                                      ExposureMask | StructureNotifyMask | ButtonPressMask |\n                                                      KeyPressMask | PointerMotionMask | EnterWindowMask |\n                                                      LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask,&event);\n        if (event_flag)\n          for (unsigned int i = 0; i<cimg::X11_attr().nb_wins; ++i)\n            if (!cimg::X11_attr().wins[i]->_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window)\n              cimg::X11_attr().wins[i]->_handle_events(&event);\n        cimg_unlock_display();\n        pthread_testcancel();\n        cimg::sleep(8);\n      }\n      return 0;\n    }\n\n    void _set_colormap(Colormap& _colormap, const unsigned int dim) {\n      XColor *const colormap = new XColor[256];\n      switch (dim) {\n      case 1 : { // colormap for greyscale images\n        for (unsigned int index = 0; index<256; ++index) {\n          colormap[index].pixel = index;\n          colormap[index].red = colormap[index].green = colormap[index].blue = (unsigned short)(index<<8);\n          colormap[index].flags = DoRed | DoGreen | DoBlue;\n        }\n      } break;\n      case 2 : { // colormap for RG images\n        for (unsigned int index = 0, r = 8; r<256; r+=16)\n          for (unsigned int g = 8; g<256; g+=16) {\n            colormap[index].pixel = index;\n            colormap[index].red = colormap[index].blue = (unsigned short)(r<<8);\n            colormap[index].green = (unsigned short)(g<<8);\n            colormap[index++].flags = DoRed | DoGreen | DoBlue;\n          }\n      } break;\n      default : { // colormap for RGB images\n        for (unsigned int index = 0, r = 16; r<256; r+=32)\n          for (unsigned int g = 16; g<256; g+=32)\n            for (unsigned int b = 32; b<256; b+=64) {\n              colormap[index].pixel = index;\n              colormap[index].red = (unsigned short)(r<<8);\n              colormap[index].green = (unsigned short)(g<<8);\n              colormap[index].blue = (unsigned short)(b<<8);\n              colormap[index++].flags = DoRed | DoGreen | DoBlue;\n            }\n      }\n      }\n      XStoreColors(cimg::X11_attr().display,_colormap,colormap,256);\n      delete[] colormap;\n    }\n\n    void _map_window() {\n      Display *const dpy = cimg::X11_attr().display;\n      bool is_exposed = false, is_mapped = false;\n      XWindowAttributes attr;\n      XEvent event;\n      XMapRaised(dpy,_window);\n      do { // Wait for the window to be mapped.\n        XWindowEvent(dpy,_window,StructureNotifyMask | ExposureMask,&event);\n        switch (event.type) {\n        case MapNotify : is_mapped = true; break;\n        case Expose : is_exposed = true; break;\n        }\n      } while (!is_exposed || !is_mapped);\n      do { // Wait for the window to be visible.\n        XGetWindowAttributes(dpy,_window,&attr);\n        if (attr.map_state!=IsViewable) { XSync(dpy,0); cimg::sleep(10); }\n      } while (attr.map_state!=IsViewable);\n      _window_x = attr.x;\n      _window_y = attr.y;\n    }\n\n    void _paint(const bool wait_expose=true) {\n      if (_is_closed || !_image) return;\n      Display *const dpy = cimg::X11_attr().display;\n      if (wait_expose) { // Send an expose event sticked to display window to force repaint.\n        XEvent event;\n        event.xexpose.type = Expose;\n        event.xexpose.serial = 0;\n        event.xexpose.send_event = 1;\n        event.xexpose.display = dpy;\n        event.xexpose.window = _window;\n        event.xexpose.x = 0;\n        event.xexpose.y = 0;\n        event.xexpose.width = width();\n        event.xexpose.height = height();\n        event.xexpose.count = 0;\n        XSendEvent(dpy,_window,0,0,&event);\n      } else { // Repaint directly (may be called from the expose event).\n        GC gc = DefaultGC(dpy,DefaultScreen(dpy));\n#ifdef cimg_use_xshm\n        if (_shminfo) XShmPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height,1);\n        else XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);\n#else\n        XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);\n#endif\n      }\n    }\n\n    template<typename T>\n    void _resize(T pixel_type, const unsigned int ndimx, const unsigned int ndimy, const bool force_redraw) {\n      Display *const dpy = cimg::X11_attr().display;\n      cimg::unused(pixel_type);\n\n#ifdef cimg_use_xshm\n      if (_shminfo) {\n        XShmSegmentInfo *const nshminfo = new XShmSegmentInfo;\n        XImage *const nimage = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),\n                                               cimg::X11_attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);\n        if (!nimage) { delete nshminfo; return; }\n        else {\n          nshminfo->shmid = shmget(IPC_PRIVATE,ndimx*ndimy*sizeof(T),IPC_CREAT | 0777);\n          if (nshminfo->shmid==-1) { XDestroyImage(nimage); delete nshminfo; return; }\n          else {\n            nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);\n            if (nshminfo->shmaddr==(char*)-1) {\n              shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return;\n            } else {\n              nshminfo->readOnly = 0;\n              cimg::X11_attr().is_shm_enabled = true;\n              XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);\n              XShmAttach(dpy,nshminfo);\n              XFlush(dpy);\n              XSetErrorHandler(oldXErrorHandler);\n              if (!cimg::X11_attr().is_shm_enabled) {\n                shmdt(nshminfo->shmaddr);\n                shmctl(nshminfo->shmid,IPC_RMID,0);\n                XDestroyImage(nimage);\n                delete nshminfo;\n                return;\n              } else {\n                T *const ndata = (T*)nimage->data;\n                if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy);\n                else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);\n                XShmDetach(dpy,_shminfo);\n                XDestroyImage(_image);\n                shmdt(_shminfo->shmaddr);\n                shmctl(_shminfo->shmid,IPC_RMID,0);\n                delete _shminfo;\n                _shminfo = nshminfo;\n                _image = nimage;\n                _data = (void*)ndata;\n              }\n            }\n          }\n        }\n      } else\n#endif\n        {\n          T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T));\n          if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy);\n          else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);\n          _data = (void*)ndata;\n          XDestroyImage(_image);\n          _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),\n                                cimg::X11_attr().nb_bits,ZPixmap,0,(char*)_data,ndimx,ndimy,8,0);\n        }\n    }\n\n    void _init_fullscreen() {\n      if (!_is_fullscreen || _is_closed) return;\n      Display *const dpy = cimg::X11_attr().display;\n      _background_window = 0;\n\n#ifdef cimg_use_xrandr\n      int foo;\n      if (XRRQueryExtension(dpy,&foo,&foo)) {\n        XRRRotations(dpy,DefaultScreen(dpy),&cimg::X11_attr().curr_rotation);\n        if (!cimg::X11_attr().resolutions) {\n          cimg::X11_attr().resolutions = XRRSizes(dpy,DefaultScreen(dpy),&foo);\n          cimg::X11_attr().nb_resolutions = (unsigned int)foo;\n        }\n        if (cimg::X11_attr().resolutions) {\n          cimg::X11_attr().curr_resolution = 0;\n          for (unsigned int i = 0; i<cimg::X11_attr().nb_resolutions; ++i) {\n            const unsigned int\n              nw = (unsigned int)(cimg::X11_attr().resolutions[i].width),\n              nh = (unsigned int)(cimg::X11_attr().resolutions[i].height);\n            if (nw>=_width && nh>=_height &&\n                nw<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width) &&\n                nh<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height))\n              cimg::X11_attr().curr_resolution = i;\n          }\n          if (cimg::X11_attr().curr_resolution>0) {\n            XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy));\n            XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy),\n                               cimg::X11_attr().curr_resolution,cimg::X11_attr().curr_rotation,CurrentTime);\n            XRRFreeScreenConfigInfo(config);\n            XSync(dpy,0);\n          }\n        }\n      }\n      if (!cimg::X11_attr().resolutions)\n        cimg::warn(_cimgdisplay_instance\n                   \"init_fullscreen(): Xrandr extension not supported by the X server.\",\n                   cimgdisplay_instance);\n#endif\n\n      const unsigned int sx = screen_width(), sy = screen_height();\n      if (sx==_width && sy==_height) return;\n      XSetWindowAttributes winattr;\n      winattr.override_redirect = 1;\n      _background_window = XCreateWindow(dpy,DefaultRootWindow(dpy),0,0,sx,sy,0,0,\n                                         InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);\n      const cimg_ulong buf_size = (cimg_ulong)sx*sy*(cimg::X11_attr().nb_bits==8?1:\n                                                     (cimg::X11_attr().nb_bits==16?2:4));\n      void *background_data = std::malloc(buf_size);\n      std::memset(background_data,0,buf_size);\n      XImage *background_image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits,\n                                              ZPixmap,0,(char*)background_data,sx,sy,8,0);\n      XEvent event;\n      XSelectInput(dpy,_background_window,StructureNotifyMask);\n      XMapRaised(dpy,_background_window);\n      do XWindowEvent(dpy,_background_window,StructureNotifyMask,&event);\n      while (event.type!=MapNotify);\n      GC gc = DefaultGC(dpy,DefaultScreen(dpy));\n#ifdef cimg_use_xshm\n      if (_shminfo) XShmPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy,0);\n      else XPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy);\n#else\n      XPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy);\n#endif\n      XWindowAttributes attr;\n      XGetWindowAttributes(dpy,_background_window,&attr);\n      while (attr.map_state!=IsViewable) XSync(dpy,0);\n      XDestroyImage(background_image);\n    }\n\n    void _desinit_fullscreen() {\n      if (!_is_fullscreen) return;\n      Display *const dpy = cimg::X11_attr().display;\n      XUngrabKeyboard(dpy,CurrentTime);\n#ifdef cimg_use_xrandr\n      if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) {\n        XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy));\n        XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy),0,cimg::X11_attr().curr_rotation,CurrentTime);\n        XRRFreeScreenConfigInfo(config);\n        XSync(dpy,0);\n        cimg::X11_attr().curr_resolution = 0;\n      }\n#endif\n      if (_background_window) XDestroyWindow(dpy,_background_window);\n      _background_window = 0;\n      _is_fullscreen = false;\n    }\n\n    static int _assign_xshm(Display *dpy, XErrorEvent *error) {\n      cimg::unused(dpy,error);\n      cimg::X11_attr().is_shm_enabled = false;\n      return 0;\n    }\n\n    void _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0,\n                 const unsigned int normalization_type=3,\n                 const bool fullscreen_flag=false, const bool closed_flag=false) {\n      cimg::mutex(14);\n\n      // Allocate space for window title\n      const char *const nptitle = ptitle?ptitle:\"\";\n      const unsigned int s = (unsigned int)std::strlen(nptitle) + 1;\n      char *const tmp_title = s?new char[s]:0;\n      if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));\n\n      // Destroy previous display window if existing\n      if (!is_empty()) assign();\n\n      // Open X11 display and retrieve graphical properties.\n      Display* &dpy = cimg::X11_attr().display;\n      if (!dpy) {\n        dpy = XOpenDisplay(0);\n        if (!dpy)\n          throw CImgDisplayException(_cimgdisplay_instance\n                                     \"assign(): Failed to open X11 display.\",\n                                     cimgdisplay_instance);\n\n        cimg::X11_attr().nb_bits = DefaultDepth(dpy,DefaultScreen(dpy));\n        if (cimg::X11_attr().nb_bits!=8 && cimg::X11_attr().nb_bits!=16 &&\n            cimg::X11_attr().nb_bits!=24 && cimg::X11_attr().nb_bits!=32)\n          throw CImgDisplayException(_cimgdisplay_instance\n                                     \"assign(): Invalid %u bits screen mode detected \"\n                                     \"(only 8, 16, 24 and 32 bits modes are managed).\",\n                                     cimgdisplay_instance,\n                                     cimg::X11_attr().nb_bits);\n        XVisualInfo vtemplate;\n        vtemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy,DefaultScreen(dpy)));\n        int nb_visuals;\n        XVisualInfo *vinfo = XGetVisualInfo(dpy,VisualIDMask,&vtemplate,&nb_visuals);\n        if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11_attr().is_blue_first = true;\n        cimg::X11_attr().byte_order = ImageByteOrder(dpy);\n        XFree(vinfo);\n\n        cimg_lock_display();\n        cimg::X11_attr().events_thread = new pthread_t;\n        pthread_create(cimg::X11_attr().events_thread,0,_events_thread,0);\n      } else cimg_lock_display();\n\n      // Set display variables.\n      _width = cimg::min(dimw,(unsigned int)screen_width());\n      _height = cimg::min(dimh,(unsigned int)screen_height());\n      _normalization = normalization_type<4?normalization_type:3;\n      _is_fullscreen = fullscreen_flag;\n      _window_x = _window_y = 0;\n      _is_closed = closed_flag;\n      _title = tmp_title;\n      flush();\n\n      // Create X11 window (and LUT, if 8bits display)\n      if (_is_fullscreen) {\n        if (!_is_closed) _init_fullscreen();\n        const unsigned int sx = screen_width(), sy = screen_height();\n        XSetWindowAttributes winattr;\n        winattr.override_redirect = 1;\n        _window = XCreateWindow(dpy,DefaultRootWindow(dpy),(sx - _width)/2,(sy - _height)/2,_width,_height,0,0,\n                                InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);\n      } else\n        _window = XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,_width,_height,0,0L,0L);\n\n      XSelectInput(dpy,_window,\n                   ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |\n                   EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);\n\n      XStoreName(dpy,_window,_title?_title:\" \");\n      if (cimg::X11_attr().nb_bits==8) {\n        _colormap = XCreateColormap(dpy,_window,DefaultVisual(dpy,DefaultScreen(dpy)),AllocAll);\n        _set_colormap(_colormap,3);\n        XSetWindowColormap(dpy,_window,_colormap);\n      }\n\n      static const char *const _window_class = cimg_appname;\n      XClassHint *const window_class = XAllocClassHint();\n      window_class->res_name = (char*)_window_class;\n      window_class->res_class = (char*)_window_class;\n      XSetClassHint(dpy,_window,window_class);\n      XFree(window_class);\n\n      _window_width = _width;\n      _window_height = _height;\n\n      // Create XImage\n#ifdef cimg_use_xshm\n      _shminfo = 0;\n      if (XShmQueryExtension(dpy)) {\n        _shminfo = new XShmSegmentInfo;\n        _image = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits,\n                                 ZPixmap,0,_shminfo,_width,_height);\n        if (!_image) { delete _shminfo; _shminfo = 0; }\n        else {\n          _shminfo->shmid = shmget(IPC_PRIVATE,_image->bytes_per_line*_image->height,IPC_CREAT|0777);\n          if (_shminfo->shmid==-1) { XDestroyImage(_image); delete _shminfo; _shminfo = 0; }\n          else {\n            _shminfo->shmaddr = _image->data = (char*)(_data = shmat(_shminfo->shmid,0,0));\n            if (_shminfo->shmaddr==(char*)-1) {\n              shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image); delete _shminfo; _shminfo = 0;\n            } else {\n              _shminfo->readOnly = 0;\n              cimg::X11_attr().is_shm_enabled = true;\n              XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);\n              XShmAttach(dpy,_shminfo);\n              XSync(dpy,0);\n              XSetErrorHandler(oldXErrorHandler);\n              if (!cimg::X11_attr().is_shm_enabled) {\n                shmdt(_shminfo->shmaddr); shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image);\n                delete _shminfo; _shminfo = 0;\n              }\n            }\n          }\n        }\n      }\n      if (!_shminfo)\n#endif\n        {\n          const cimg_ulong buf_size = (cimg_ulong)_width*_height*(cimg::X11_attr().nb_bits==8?1:\n                                                                  (cimg::X11_attr().nb_bits==16?2:4));\n          _data = std::malloc(buf_size);\n          _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits,\n                                ZPixmap,0,(char*)_data,_width,_height,8,0);\n        }\n\n      _wm_window_atom = XInternAtom(dpy,\"WM_DELETE_WINDOW\",0);\n      _wm_protocol_atom = XInternAtom(dpy,\"WM_PROTOCOLS\",0);\n      XSetWMProtocols(dpy,_window,&_wm_window_atom,1);\n\n      if (_is_fullscreen) XGrabKeyboard(dpy,_window,1,GrabModeAsync,GrabModeAsync,CurrentTime);\n      cimg::X11_attr().wins[cimg::X11_attr().nb_wins++]=this;\n      if (!_is_closed) _map_window(); else { _window_x = _window_y = cimg::type<int>::min(); }\n      cimg_unlock_display();\n      cimg::mutex(14,0);\n    }\n\n    CImgDisplay& assign() {\n      if (is_empty()) return flush();\n      Display *const dpy = cimg::X11_attr().display;\n      cimg_lock_display();\n\n      // Remove display window from event thread list.\n      unsigned int i;\n      for (i = 0; i<cimg::X11_attr().nb_wins && cimg::X11_attr().wins[i]!=this; ++i) {}\n      for ( ; i<cimg::X11_attr().nb_wins - 1; ++i) cimg::X11_attr().wins[i] = cimg::X11_attr().wins[i + 1];\n      --cimg::X11_attr().nb_wins;\n\n      // Destroy window, image, colormap and title.\n      if (_is_fullscreen && !_is_closed) _desinit_fullscreen();\n      XDestroyWindow(dpy,_window);\n      _window = 0;\n#ifdef cimg_use_xshm\n      if (_shminfo) {\n        XShmDetach(dpy,_shminfo);\n        XDestroyImage(_image);\n        shmdt(_shminfo->shmaddr);\n        shmctl(_shminfo->shmid,IPC_RMID,0);\n        delete _shminfo;\n        _shminfo = 0;\n      } else\n#endif\n        XDestroyImage(_image);\n      _data = 0; _image = 0;\n      if (cimg::X11_attr().nb_bits==8) XFreeColormap(dpy,_colormap);\n      _colormap = 0;\n      XSync(dpy,0);\n\n      // Reset display variables.\n      delete[] _title;\n      _width = _height = _normalization = _window_width = _window_height = 0;\n      _window_x = _window_y = 0;\n      _is_fullscreen = false;\n      _is_closed = true;\n      _min = _max = 0;\n      _title = 0;\n      flush();\n\n      cimg_unlock_display();\n      return *this;\n    }\n\n    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0,\n                        const unsigned int normalization_type=3,\n                        const bool fullscreen_flag=false, const bool closed_flag=false) {\n      if (!dimw || !dimh) return assign();\n      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);\n      _min = _max = 0;\n      std::memset(_data,0,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char):\n                           (cimg::X11_attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*\n                  (size_t)_width*_height);\n      return paint();\n    }\n\n    template<typename T>\n    CImgDisplay& assign(const CImg<T>& img, const char *const title=0,\n                        const unsigned int normalization_type=3,\n                        const bool fullscreen_flag=false, const bool closed_flag=false) {\n      if (!img) return assign();\n      CImg<T> tmp;\n      const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,\n                                                                           (img._height - 1)/2,\n                                                                           (img._depth - 1)/2));\n      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);\n      if (_normalization==2) _min = (float)nimg.min_max(_max);\n      return render(nimg).paint();\n    }\n\n    template<typename T>\n    CImgDisplay& assign(const CImgList<T>& list, const char *const title=0,\n                        const unsigned int normalization_type=3,\n                        const bool fullscreen_flag=false, const bool closed_flag=false) {\n      if (!list) return assign();\n      CImg<T> tmp;\n      const CImg<T> img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,\n                                                                                           (img._height - 1)/2,\n                                                                                           (img._depth - 1)/2));\n      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);\n      if (_normalization==2) _min = (float)nimg.min_max(_max);\n      return render(nimg).paint();\n    }\n\n    CImgDisplay& assign(const CImgDisplay& disp) {\n      if (!disp) return assign();\n      _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed);\n      std::memcpy(_data,disp._data,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char):\n                                    cimg::X11_attr().nb_bits==16?sizeof(unsigned short):\n                                    sizeof(unsigned int))*(size_t)_width*_height);\n      return paint();\n    }\n\n    CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) {\n      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();\n      if (is_empty()) return assign(nwidth,nheight);\n      Display *const dpy = cimg::X11_attr().display;\n      const unsigned int\n        tmpdimx = (nwidth>0)?nwidth:(-nwidth*width()/100),\n        tmpdimy = (nheight>0)?nheight:(-nheight*height()/100),\n        dimx = tmpdimx?tmpdimx:1,\n        dimy = tmpdimy?tmpdimy:1;\n      if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) {\n        show();\n        cimg_lock_display();\n        if (_window_width!=dimx || _window_height!=dimy) {\n          XWindowAttributes attr;\n          for (unsigned int i = 0; i<10; ++i) {\n            XResizeWindow(dpy,_window,dimx,dimy);\n            XGetWindowAttributes(dpy,_window,&attr);\n            if (attr.width==(int)dimx && attr.height==(int)dimy) break;\n            cimg::wait(5);\n          }\n        }\n        if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) {\n          case 8 :  { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;\n          case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;\n          default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); }\n          }\n        _window_width = _width = dimx; _window_height = _height = dimy;\n        cimg_unlock_display();\n      }\n      _is_resized = false;\n      if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2);\n      if (force_redraw) return paint();\n      return *this;\n    }\n\n    CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {\n      if (is_empty()) return *this;\n      if (force_redraw) {\n        const cimg_ulong buf_size = (cimg_ulong)_width*_height*\n          (cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4));\n        void *image_data = std::malloc(buf_size);\n        std::memcpy(image_data,_data,buf_size);\n        assign(_width,_height,_title,_normalization,!_is_fullscreen,false);\n        std::memcpy(_data,image_data,buf_size);\n        std::free(image_data);\n        return paint();\n      }\n      return assign(_width,_height,_title,_normalization,!_is_fullscreen,false);\n    }\n\n    CImgDisplay& show() {\n      if (is_empty() || !_is_closed) return *this;\n      cimg_lock_display();\n      if (_is_fullscreen) _init_fullscreen();\n      _map_window();\n      _is_closed = false;\n      cimg_unlock_display();\n      return paint();\n    }\n\n    CImgDisplay& close() {\n      if (is_empty() || _is_closed) return *this;\n      Display *const dpy = cimg::X11_attr().display;\n      cimg_lock_display();\n      if (_is_fullscreen) _desinit_fullscreen();\n      XUnmapWindow(dpy,_window);\n      _window_x = _window_y = -1;\n      _is_closed = true;\n      cimg_unlock_display();\n      return *this;\n    }\n\n    CImgDisplay& move(const int posx, const int posy) {\n      if (is_empty()) return *this;\n      if (_window_x!=posx || _window_y!=posy) {\n        show();\n        Display *const dpy = cimg::X11_attr().display;\n        cimg_lock_display();\n        XMoveWindow(dpy,_window,posx,posy);\n        _window_x = posx; _window_y = posy;\n        cimg_unlock_display();\n      }\n      _is_moved = false;\n      return paint();\n    }\n\n    CImgDisplay& show_mouse() {\n      if (is_empty()) return *this;\n      Display *const dpy = cimg::X11_attr().display;\n      cimg_lock_display();\n      XUndefineCursor(dpy,_window);\n      cimg_unlock_display();\n      return *this;\n    }\n\n    CImgDisplay& hide_mouse() {\n      if (is_empty()) return *this;\n      Display *const dpy = cimg::X11_attr().display;\n      cimg_lock_display();\n      static const char pix_data[8] = { 0 };\n      XColor col;\n      col.red = col.green = col.blue = 0;\n      Pixmap pix = XCreateBitmapFromData(dpy,_window,pix_data,8,8);\n      Cursor cur = XCreatePixmapCursor(dpy,pix,pix,&col,&col,0,0);\n      XFreePixmap(dpy,pix);\n      XDefineCursor(dpy,_window,cur);\n      cimg_unlock_display();\n      return *this;\n    }\n\n    CImgDisplay& set_mouse(const int posx, const int posy) {\n      if (is_empty() || _is_closed) return *this;\n      Display *const dpy = cimg::X11_attr().display;\n      cimg_lock_display();\n      XWarpPointer(dpy,0L,_window,0,0,0,0,posx,posy);\n      _mouse_x = posx; _mouse_y = posy;\n      _is_moved = false;\n      XSync(dpy,0);\n      cimg_unlock_display();\n      return *this;\n    }\n\n    CImgDisplay& set_title(const char *const format, ...) {\n      if (is_empty()) return *this;\n      char *const tmp = new char[1024];\n      va_list ap;\n      va_start(ap, format);\n      cimg_vsnprintf(tmp,1024,format,ap);\n      va_end(ap);\n      if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; }\n      delete[] _title;\n      const unsigned int s = (unsigned int)std::strlen(tmp) + 1;\n      _title = new char[s];\n      std::memcpy(_title,tmp,s*sizeof(char));\n      Display *const dpy = cimg::X11_attr().display;\n      cimg_lock_display();\n      XStoreName(dpy,_window,tmp);\n      cimg_unlock_display();\n      delete[] tmp;\n      return *this;\n    }\n\n    template<typename T>\n    CImgDisplay& display(const CImg<T>& img) {\n      if (!img)\n        throw CImgArgumentException(_cimgdisplay_instance\n                                    \"display(): Empty specified image.\",\n                                    cimgdisplay_instance);\n      if (is_empty()) return assign(img);\n      return render(img).paint(false);\n    }\n\n    CImgDisplay& paint(const bool wait_expose=true) {\n      if (is_empty()) return *this;\n      cimg_lock_display();\n      _paint(wait_expose);\n      cimg_unlock_display();\n      return *this;\n    }\n\n    template<typename T>\n    CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {\n      if (!img)\n        throw CImgArgumentException(_cimgdisplay_instance\n                                    \"render(): Empty specified image.\",\n                                    cimgdisplay_instance);\n      if (is_empty()) return *this;\n      if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2,\n                                                             (img._depth - 1)/2));\n      if (cimg::X11_attr().nb_bits==8 && (img._width!=_width || img._height!=_height))\n        return render(img.get_resize(_width,_height,1,-100,1));\n      if (cimg::X11_attr().nb_bits==8 && !flag8 && img._spectrum==3) {\n        static const CImg<typename CImg<T>::ucharT> default_colormap = CImg<typename CImg<T>::ucharT>::default_LUT256();\n        return render(img.get_index(default_colormap,1,false));\n      }\n\n      const T\n        *data1 = img._data,\n        *data2 = (img._spectrum>1)?img.data(0,0,0,1):data1,\n        *data3 = (img._spectrum>2)?img.data(0,0,0,2):data1;\n\n      if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3);\n      cimg_lock_display();\n\n      if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {\n        _min = _max = 0;\n        switch (cimg::X11_attr().nb_bits) {\n        case 8 : { // 256 colormap, no normalization\n          _set_colormap(_colormap,img._spectrum);\n          unsigned char\n            *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:\n            new unsigned char[(size_t)img._width*img._height],\n            *ptrd = (unsigned char*)ndata;\n          switch (img._spectrum) {\n          case 1 :\n            for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)\n              (*ptrd++) = (unsigned char)*(data1++);\n            break;\n          case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n              const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);\n              (*ptrd++) = (R&0xf0) | (G>>4);\n            } break;\n          default : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n              const unsigned char\n                R = (unsigned char)*(data1++),\n                G = (unsigned char)*(data2++),\n                B = (unsigned char)*(data3++);\n              (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);\n            }\n          }\n          if (ndata!=_data) {\n            _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height);\n            delete[] ndata;\n          }\n        } break;\n        case 16 : { // 16 bits colors, no normalization\n          unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:\n            new unsigned short[(size_t)img._width*img._height];\n          unsigned char *ptrd = (unsigned char*)ndata;\n          const unsigned int M = 248;\n          switch (img._spectrum) {\n          case 1 :\n            if (cimg::X11_attr().byte_order)\n              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char val = (unsigned char)*(data1++), G = val>>2;\n                *(ptrd++) = (val&M) | (G>>3);\n                *(ptrd++) = (G<<5) | (G>>1);\n              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char val = (unsigned char)*(data1++), G = val>>2;\n                *(ptrd++) = (G<<5) | (G>>1);\n                *(ptrd++) = (val&M) | (G>>3);\n              }\n            break;\n          case 2 :\n            if (cimg::X11_attr().byte_order)\n              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char G = (unsigned char)*(data2++)>>2;\n                *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);\n                *(ptrd++) = (G<<5);\n              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char G = (unsigned char)*(data2++)>>2;\n                *(ptrd++) = (G<<5);\n                *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);\n              }\n            break;\n          default :\n            if (cimg::X11_attr().byte_order)\n              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char G = (unsigned char)*(data2++)>>2;\n                *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);\n                *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);\n              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char G = (unsigned char)*(data2++)>>2;\n                *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);\n                *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);\n              }\n          }\n          if (ndata!=_data) {\n            _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height);\n            delete[] ndata;\n          }\n        } break;\n        default : { // 24 bits colors, no normalization\n          unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:\n            new unsigned int[(size_t)img._width*img._height];\n          if (sizeof(int)==4) { // 32 bits int uses optimized version\n            unsigned int *ptrd = ndata;\n            switch (img._spectrum) {\n            case 1 :\n              if (cimg::X11_attr().byte_order==cimg::endianness())\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  const unsigned char val = (unsigned char)*(data1++);\n                  *(ptrd++) = (val<<16) | (val<<8) | val;\n                }\n              else\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                 const unsigned char val = (unsigned char)*(data1++);\n                  *(ptrd++) = (val<<16) | (val<<8) | val;\n                }\n              break;\n            case 2 :\n              if (cimg::X11_attr().byte_order==cimg::endianness())\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)\n                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);\n              else\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)\n                  *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);\n              break;\n            default :\n              if (cimg::X11_attr().byte_order==cimg::endianness())\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)\n                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) |\n                    (unsigned char)*(data3++);\n              else\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)\n                  *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) |\n                    ((unsigned char)*(data1++)<<8);\n            }\n          } else {\n            unsigned char *ptrd = (unsigned char*)ndata;\n            switch (img._spectrum) {\n            case 1 :\n              if (cimg::X11_attr().byte_order)\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  *(ptrd++) = 0;\n                  *(ptrd++) = (unsigned char)*(data1++);\n                  *(ptrd++) = 0;\n                  *(ptrd++) = 0;\n                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  *(ptrd++) = 0;\n                  *(ptrd++) = 0;\n                  *(ptrd++) = (unsigned char)*(data1++);\n                  *(ptrd++) = 0;\n                }\n              break;\n            case 2 :\n              if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);\n              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                *(ptrd++) = 0;\n                *(ptrd++) = (unsigned char)*(data2++);\n                *(ptrd++) = (unsigned char)*(data1++);\n                *(ptrd++) = 0;\n              }\n              break;\n            default :\n              if (cimg::X11_attr().byte_order)\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  *(ptrd++) = 0;\n                  *(ptrd++) = (unsigned char)*(data1++);\n                  *(ptrd++) = (unsigned char)*(data2++);\n                  *(ptrd++) = (unsigned char)*(data3++);\n                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  *(ptrd++) = (unsigned char)*(data3++);\n                  *(ptrd++) = (unsigned char)*(data2++);\n                  *(ptrd++) = (unsigned char)*(data1++);\n                  *(ptrd++) = 0;\n                }\n            }\n          }\n          if (ndata!=_data) {\n            _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height);\n            delete[] ndata;\n          }\n        }\n        }\n      } else {\n        if (_normalization==3) {\n          if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max);\n          else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); }\n        } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max);\n        const float delta = _max - _min, mm = 255/(delta?delta:1.0f);\n        switch (cimg::X11_attr().nb_bits) {\n        case 8 : { // 256 colormap, with normalization\n          _set_colormap(_colormap,img._spectrum);\n          unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:\n            new unsigned char[(size_t)img._width*img._height];\n          unsigned char *ptrd = (unsigned char*)ndata;\n          switch (img._spectrum) {\n          case 1 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n              const unsigned char R = (unsigned char)((*(data1++) - _min)*mm);\n              *(ptrd++) = R;\n            } break;\n          case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n              const unsigned char\n                R = (unsigned char)((*(data1++) - _min)*mm),\n                G = (unsigned char)((*(data2++) - _min)*mm);\n            (*ptrd++) = (R&0xf0) | (G>>4);\n          } break;\n          default :\n            for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n              const unsigned char\n                R = (unsigned char)((*(data1++) - _min)*mm),\n                G = (unsigned char)((*(data2++) - _min)*mm),\n                B = (unsigned char)((*(data3++) - _min)*mm);\n              *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);\n            }\n          }\n          if (ndata!=_data) {\n            _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height);\n            delete[] ndata;\n          }\n        } break;\n        case 16 : { // 16 bits colors, with normalization\n          unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:\n            new unsigned short[(size_t)img._width*img._height];\n          unsigned char *ptrd = (unsigned char*)ndata;\n          const unsigned int M = 248;\n          switch (img._spectrum) {\n          case 1 :\n            if (cimg::X11_attr().byte_order)\n              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2;\n                *(ptrd++) = (val&M) | (G>>3);\n                *(ptrd++) = (G<<5) | (val>>3);\n              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2;\n                *(ptrd++) = (G<<5) | (val>>3);\n                *(ptrd++) = (val&M) | (G>>3);\n              }\n            break;\n          case 2 :\n            if (cimg::X11_attr().byte_order)\n              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;\n                *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);\n                *(ptrd++) = (G<<5);\n              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;\n                *(ptrd++) = (G<<5);\n                *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);\n              }\n            break;\n          default :\n            if (cimg::X11_attr().byte_order)\n              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;\n                *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);\n                *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3);\n              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;\n                *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3);\n                *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);\n              }\n          }\n          if (ndata!=_data) {\n            _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height);\n            delete[] ndata;\n          }\n        } break;\n        default : { // 24 bits colors, with normalization\n          unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:\n            new unsigned int[(size_t)img._width*img._height];\n          if (sizeof(int)==4) { // 32 bits int uses optimized version\n            unsigned int *ptrd = ndata;\n            switch (img._spectrum) {\n            case 1 :\n              if (cimg::X11_attr().byte_order==cimg::endianness())\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);\n                  *(ptrd++) = (val<<16) | (val<<8) | val;\n                }\n              else\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);\n                  *(ptrd++) = (val<<24) | (val<<16) | (val<<8);\n                }\n              break;\n            case 2 :\n              if (cimg::X11_attr().byte_order==cimg::endianness())\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)\n                  *(ptrd++) =\n                    ((unsigned char)((*(data1++) - _min)*mm)<<16) |\n                    ((unsigned char)((*(data2++) - _min)*mm)<<8);\n              else\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)\n                  *(ptrd++) =\n                    ((unsigned char)((*(data2++) - _min)*mm)<<16) |\n                    ((unsigned char)((*(data1++) - _min)*mm)<<8);\n              break;\n            default :\n              if (cimg::X11_attr().byte_order==cimg::endianness())\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)\n                  *(ptrd++) =\n                    ((unsigned char)((*(data1++) - _min)*mm)<<16) |\n                    ((unsigned char)((*(data2++) - _min)*mm)<<8) |\n                    (unsigned char)((*(data3++) - _min)*mm);\n              else\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)\n                  *(ptrd++) =\n                    ((unsigned char)((*(data3++) - _min)*mm)<<24) |\n                    ((unsigned char)((*(data2++) - _min)*mm)<<16) |\n                    ((unsigned char)((*(data1++) - _min)*mm)<<8);\n            }\n          } else {\n            unsigned char *ptrd = (unsigned char*)ndata;\n            switch (img._spectrum) {\n            case 1 :\n              if (cimg::X11_attr().byte_order)\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);\n                  (*ptrd++) = 0;\n                  (*ptrd++) = val;\n                  (*ptrd++) = val;\n                  (*ptrd++) = val;\n                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);\n                  (*ptrd++) = val;\n                  (*ptrd++) = val;\n                  (*ptrd++) = val;\n                  (*ptrd++) = 0;\n                }\n              break;\n            case 2 :\n              if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);\n              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                (*ptrd++) = 0;\n                (*ptrd++) = (unsigned char)((*(data2++) - _min)*mm);\n                (*ptrd++) = (unsigned char)((*(data1++) - _min)*mm);\n                (*ptrd++) = 0;\n              }\n              break;\n            default :\n              if (cimg::X11_attr().byte_order)\n                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  (*ptrd++) = 0;\n                  (*ptrd++) = (unsigned char)((*(data1++) - _min)*mm);\n                  (*ptrd++) = (unsigned char)((*(data2++) - _min)*mm);\n                  (*ptrd++) = (unsigned char)((*(data3++) - _min)*mm);\n                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n                  (*ptrd++) = (unsigned char)((*(data3++) - _min)*mm);\n                  (*ptrd++) = (unsigned char)((*(data2++) - _min)*mm);\n                  (*ptrd++) = (unsigned char)((*(data1++) - _min)*mm);\n                  (*ptrd++) = 0;\n                }\n            }\n          }\n          if (ndata!=_data) {\n            _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height);\n            delete[] ndata;\n          }\n        }\n        }\n      }\n      cimg_unlock_display();\n      return *this;\n    }\n\n    template<typename T>\n    const CImgDisplay& snapshot(CImg<T>& img) const {\n      if (is_empty()) { img.assign(); return *this; }\n      const unsigned char *ptrs = (unsigned char*)_data;\n      img.assign(_width,_height,1,3);\n      T\n        *data1 = img.data(0,0,0,0),\n        *data2 = img.data(0,0,0,1),\n        *data3 = img.data(0,0,0,2);\n      if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3);\n      switch (cimg::X11_attr().nb_bits) {\n      case 8 : {\n        for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n          const unsigned char val = *(ptrs++);\n          *(data1++) = (T)(val&0xe0);\n          *(data2++) = (T)((val&0x1c)<<3);\n          *(data3++) = (T)(val<<6);\n        }\n      } break;\n      case 16 : {\n        if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n          const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);\n          *(data1++) = (T)(val0&0xf8);\n          *(data2++) = (T)((val0<<5) | ((val1&0xe0)>>5));\n          *(data3++) = (T)(val1<<3);\n          } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n          const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);\n          *(data1++) = (T)(val1&0xf8);\n          *(data2++) = (T)((val1<<5) | ((val0&0xe0)>>5));\n          *(data3++) = (T)(val0<<3);\n        }\n      } break;\n      default : {\n        if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n          ++ptrs;\n          *(data1++) = (T)*(ptrs++);\n          *(data2++) = (T)*(ptrs++);\n          *(data3++) = (T)*(ptrs++);\n          } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n            *(data3++) = (T)*(ptrs++);\n            *(data2++) = (T)*(ptrs++);\n            *(data1++) = (T)*(ptrs++);\n            ++ptrs;\n          }\n      }\n      }\n      return *this;\n    }\n\n    // Windows-based implementation.\n    //-------------------------------\n#elif cimg_display==2\n\n    bool _is_mouse_tracked, _is_cursor_visible;\n    HANDLE _thread, _is_created, _mutex;\n    HWND _window, _background_window;\n    CLIENTCREATESTRUCT _ccs;\n    unsigned int *_data;\n    DEVMODE _curr_mode;\n    BITMAPINFO _bmi;\n    HDC _hdc;\n\n    static int screen_width() {\n      DEVMODE mode;\n      mode.dmSize = sizeof(DEVMODE);\n      mode.dmDriverExtra = 0;\n      EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);\n      return (int)mode.dmPelsWidth;\n    }\n\n    static int screen_height() {\n      DEVMODE mode;\n      mode.dmSize = sizeof(DEVMODE);\n      mode.dmDriverExtra = 0;\n      EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);\n      return (int)mode.dmPelsHeight;\n    }\n\n    static void wait_all() {\n      WaitForSingleObject(cimg::Win32_attr().wait_event,INFINITE);\n    }\n\n    static LRESULT APIENTRY _handle_events(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {\n#ifdef _WIN64\n      CImgDisplay *const disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);\n#else\n      CImgDisplay *const disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);\n#endif\n      MSG st_msg;\n      switch (msg) {\n      case WM_CLOSE :\n        disp->_mouse_x = disp->_mouse_y = -1;\n        disp->_window_x = disp->_window_y = 0;\n        disp->set_button().set_key(0).set_key(0,false)._is_closed = true;\n        ReleaseMutex(disp->_mutex);\n        ShowWindow(disp->_window,SW_HIDE);\n        disp->_is_event = true;\n        SetEvent(cimg::Win32_attr().wait_event);\n        return 0;\n      case WM_SIZE : {\n        while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}\n        WaitForSingleObject(disp->_mutex,INFINITE);\n        const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);\n        if (nw && nh && (nw!=disp->_width || nh!=disp->_height)) {\n          disp->_window_width = nw;\n          disp->_window_height = nh;\n          disp->_mouse_x = disp->_mouse_y = -1;\n          disp->_is_resized = disp->_is_event = true;\n          SetEvent(cimg::Win32_attr().wait_event);\n        }\n        ReleaseMutex(disp->_mutex);\n      } break;\n      case WM_MOVE : {\n        while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}\n        WaitForSingleObject(disp->_mutex,INFINITE);\n        const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));\n        if (nx!=disp->_window_x || ny!=disp->_window_y) {\n          disp->_window_x = nx;\n          disp->_window_y = ny;\n          disp->_is_moved = disp->_is_event = true;\n          SetEvent(cimg::Win32_attr().wait_event);\n        }\n        ReleaseMutex(disp->_mutex);\n      } break;\n      case WM_PAINT :\n        disp->paint();\n        cimg::mutex(15);\n        if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);\n        cimg::mutex(15,0);\n        break;\n      case WM_ERASEBKGND :\n        //        return 0;\n        break;\n      case WM_KEYDOWN :\n        disp->set_key((unsigned int)wParam);\n        SetEvent(cimg::Win32_attr().wait_event);\n        break;\n      case WM_KEYUP :\n        disp->set_key((unsigned int)wParam,false);\n        SetEvent(cimg::Win32_attr().wait_event);\n        break;\n      case WM_MOUSEMOVE : {\n        while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}\n        disp->_mouse_x = LOWORD(lParam);\n        disp->_mouse_y = HIWORD(lParam);\n#if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)\n        if (!disp->_is_mouse_tracked) {\n          TRACKMOUSEEVENT tme;\n          tme.cbSize = sizeof(TRACKMOUSEEVENT);\n          tme.dwFlags = TME_LEAVE;\n          tme.hwndTrack = disp->_window;\n          if (TrackMouseEvent(&tme)) disp->_is_mouse_tracked = true;\n        }\n#endif\n        if (disp->_mouse_x<0 || disp->_mouse_y<0 || disp->_mouse_x>=disp->width() || disp->_mouse_y>=disp->height())\n          disp->_mouse_x = disp->_mouse_y = -1;\n        disp->_is_event = true;\n        SetEvent(cimg::Win32_attr().wait_event);\n        cimg::mutex(15);\n        if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);\n        cimg::mutex(15,0);\n      } break;\n      case WM_MOUSELEAVE : {\n        disp->_mouse_x = disp->_mouse_y = -1;\n        disp->_is_mouse_tracked = false;\n        cimg::mutex(15);\n        while (ShowCursor(TRUE)<0);\n        cimg::mutex(15,0);\n      } break;\n      case WM_LBUTTONDOWN :\n        disp->set_button(1);\n        SetEvent(cimg::Win32_attr().wait_event);\n        break;\n      case WM_RBUTTONDOWN :\n        disp->set_button(2);\n        SetEvent(cimg::Win32_attr().wait_event);\n        break;\n      case WM_MBUTTONDOWN :\n        disp->set_button(3);\n        SetEvent(cimg::Win32_attr().wait_event);\n        break;\n      case WM_LBUTTONUP :\n        disp->set_button(1,false);\n        SetEvent(cimg::Win32_attr().wait_event);\n        break;\n      case WM_RBUTTONUP :\n        disp->set_button(2,false);\n        SetEvent(cimg::Win32_attr().wait_event);\n        break;\n      case WM_MBUTTONUP :\n        disp->set_button(3,false);\n        SetEvent(cimg::Win32_attr().wait_event);\n        break;\n      case 0x020A : // WM_MOUSEWHEEL:\n        disp->set_wheel((int)((short)HIWORD(wParam))/120);\n        SetEvent(cimg::Win32_attr().wait_event);\n      }\n      return DefWindowProc(window,msg,wParam,lParam);\n    }\n\n    static DWORD WINAPI _events_thread(void* arg) {\n      CImgDisplay *const disp = (CImgDisplay*)(((void**)arg)[0]);\n      const char *const title = (const char*)(((void**)arg)[1]);\n      MSG msg;\n      delete[] (void**)arg;\n      disp->_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n      disp->_bmi.bmiHeader.biWidth = disp->width();\n      disp->_bmi.bmiHeader.biHeight = -disp->height();\n      disp->_bmi.bmiHeader.biPlanes = 1;\n      disp->_bmi.bmiHeader.biBitCount = 32;\n      disp->_bmi.bmiHeader.biCompression = BI_RGB;\n      disp->_bmi.bmiHeader.biSizeImage = 0;\n      disp->_bmi.bmiHeader.biXPelsPerMeter = 1;\n      disp->_bmi.bmiHeader.biYPelsPerMeter = 1;\n      disp->_bmi.bmiHeader.biClrUsed = 0;\n      disp->_bmi.bmiHeader.biClrImportant = 0;\n      disp->_data = new unsigned int[(size_t)disp->_width*disp->_height];\n      if (!disp->_is_fullscreen) { // Normal window\n        RECT rect;\n        rect.left = rect.top = 0; rect.right = (LONG)disp->_width - 1; rect.bottom = (LONG)disp->_height - 1;\n        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);\n        const int\n          border1 = (int)((rect.right - rect.left + 1 - disp->_width)/2),\n          border2 = (int)(rect.bottom - rect.top + 1 - disp->_height - border1);\n        disp->_window = CreateWindowA(\"MDICLIENT\",title?title:\" \",\n                                     WS_OVERLAPPEDWINDOW | (disp->_is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,\n                                     disp->_width + 2*border1, disp->_height + border1 + border2,\n                                     0,0,0,&(disp->_ccs));\n        if (!disp->_is_closed) {\n          GetWindowRect(disp->_window,&rect);\n          disp->_window_x = rect.left + border1;\n          disp->_window_y = rect.top + border2;\n        } else disp->_window_x = disp->_window_y = 0;\n      } else { // Fullscreen window\n        const unsigned int\n          sx = (unsigned int)screen_width(),\n          sy = (unsigned int)screen_height();\n        disp->_window = CreateWindowA(\"MDICLIENT\",title?title:\" \",\n                                     WS_POPUP | (disp->_is_closed?0:WS_VISIBLE),\n                                      (sx - disp->_width)/2,\n                                      (sy - disp->_height)/2,\n                                     disp->_width,disp->_height,0,0,0,&(disp->_ccs));\n        disp->_window_x = disp->_window_y = 0;\n      }\n      SetForegroundWindow(disp->_window);\n      disp->_hdc = GetDC(disp->_window);\n      disp->_window_width = disp->_width;\n      disp->_window_height = disp->_height;\n      disp->flush();\n#ifdef _WIN64\n      SetWindowLongPtr(disp->_window,GWLP_USERDATA,(LONG_PTR)disp);\n      SetWindowLongPtr(disp->_window,GWLP_WNDPROC,(LONG_PTR)_handle_events);\n#else\n      SetWindowLong(disp->_window,GWL_USERDATA,(LONG)disp);\n      SetWindowLong(disp->_window,GWL_WNDPROC,(LONG)_handle_events);\n#endif\n      SetEvent(disp->_is_created);\n      while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);\n      return 0;\n    }\n\n    CImgDisplay& _update_window_pos() {\n      if (_is_closed) _window_x = _window_y = -1;\n      else {\n        RECT rect;\n        rect.left = rect.top = 0; rect.right = (LONG)_width - 1; rect.bottom = (LONG)_height - 1;\n        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);\n        const int\n          border1 = (int)((rect.right - rect.left + 1 - _width)/2),\n          border2 = (int)(rect.bottom - rect.top + 1 - _height - border1);\n        GetWindowRect(_window,&rect);\n        _window_x = rect.left + border1;\n        _window_y = rect.top + border2;\n      }\n      return *this;\n    }\n\n    void _init_fullscreen() {\n      _background_window = 0;\n      if (!_is_fullscreen || _is_closed) _curr_mode.dmSize = 0;\n      else {\n        DEVMODE mode;\n        unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;\n        for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {\n          const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;\n          if (nw>=_width && nh>=_height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {\n            bestbpp = mode.dmBitsPerPel;\n            ibest = imode;\n            bw = nw; bh = nh;\n          }\n        }\n        if (bestbpp) {\n          _curr_mode.dmSize = sizeof(DEVMODE); _curr_mode.dmDriverExtra = 0;\n          EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&_curr_mode);\n          EnumDisplaySettings(0,ibest,&mode);\n          ChangeDisplaySettings(&mode,0);\n        } else _curr_mode.dmSize = 0;\n\n        const unsigned int\n          sx = (unsigned int)screen_width(),\n          sy = (unsigned int)screen_height();\n        if (sx!=_width || sy!=_height) {\n          CLIENTCREATESTRUCT background_ccs;\n          _background_window = CreateWindowA(\"MDICLIENT\",\"\",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);\n          SetForegroundWindow(_background_window);\n        }\n      }\n    }\n\n    void _desinit_fullscreen() {\n      if (!_is_fullscreen) return;\n      if (_background_window) DestroyWindow(_background_window);\n      _background_window = 0;\n      if (_curr_mode.dmSize) ChangeDisplaySettings(&_curr_mode,0);\n      _is_fullscreen = false;\n    }\n\n    CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0,\n                         const unsigned int normalization_type=3,\n                         const bool fullscreen_flag=false, const bool closed_flag=false) {\n\n      // Allocate space for window title\n      const char *const nptitle = ptitle?ptitle:\"\";\n      const unsigned int s = (unsigned int)std::strlen(nptitle) + 1;\n      char *const tmp_title = s?new char[s]:0;\n      if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));\n\n      // Destroy previous window if existing\n      if (!is_empty()) assign();\n\n      // Set display variables\n      _width = cimg::min(dimw,(unsigned int)screen_width());\n      _height = cimg::min(dimh,(unsigned int)screen_height());\n      _normalization = normalization_type<4?normalization_type:3;\n      _is_fullscreen = fullscreen_flag;\n      _window_x = _window_y = 0;\n      _is_closed = closed_flag;\n      _is_cursor_visible = true;\n      _is_mouse_tracked = false;\n      _title = tmp_title;\n      flush();\n      if (_is_fullscreen) _init_fullscreen();\n\n      // Create event thread\n      void *const arg = (void*)(new void*[2]);\n      ((void**)arg)[0] = (void*)this;\n      ((void**)arg)[1] = (void*)_title;\n      _mutex = CreateMutex(0,FALSE,0);\n      _is_created = CreateEvent(0,FALSE,FALSE,0);\n      _thread = CreateThread(0,0,_events_thread,arg,0,0);\n      WaitForSingleObject(_is_created,INFINITE);\n      return *this;\n    }\n\n    CImgDisplay& assign() {\n      if (is_empty()) return flush();\n      DestroyWindow(_window);\n      TerminateThread(_thread,0);\n      delete[] _data;\n      delete[] _title;\n      _data = 0;\n      _title = 0;\n      if (_is_fullscreen) _desinit_fullscreen();\n      _width = _height = _normalization = _window_width = _window_height = 0;\n      _window_x = _window_y = 0;\n      _is_fullscreen = false;\n      _is_closed = true;\n      _min = _max = 0;\n      _title = 0;\n      flush();\n      return *this;\n    }\n\n    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0,\n                        const unsigned int normalization_type=3,\n                        const bool fullscreen_flag=false, const bool closed_flag=false) {\n      if (!dimw || !dimh) return assign();\n      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);\n      _min = _max = 0;\n      std::memset(_data,0,sizeof(unsigned int)*_width*_height);\n      return paint();\n    }\n\n    template<typename T>\n    CImgDisplay& assign(const CImg<T>& img, const char *const title=0,\n                        const unsigned int normalization_type=3,\n                        const bool fullscreen_flag=false, const bool closed_flag=false) {\n      if (!img) return assign();\n      CImg<T> tmp;\n      const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,\n                                                                           (img._height - 1)/2,\n                                                                           (img._depth - 1)/2));\n      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);\n      if (_normalization==2) _min = (float)nimg.min_max(_max);\n      return display(nimg);\n    }\n\n    template<typename T>\n    CImgDisplay& assign(const CImgList<T>& list, const char *const title=0,\n                        const unsigned int normalization_type=3,\n                        const bool fullscreen_flag=false, const bool closed_flag=false) {\n      if (!list) return assign();\n      CImg<T> tmp;\n      const CImg<T> img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,\n                                                                                           (img._height - 1)/2,\n                                                                                           (img._depth - 1)/2));\n      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);\n      if (_normalization==2) _min = (float)nimg.min_max(_max);\n      return display(nimg);\n    }\n\n    CImgDisplay& assign(const CImgDisplay& disp) {\n      if (!disp) return assign();\n      _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed);\n      std::memcpy(_data,disp._data,sizeof(unsigned int)*_width*_height);\n      return paint();\n    }\n\n    CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) {\n      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();\n      if (is_empty()) return assign(nwidth,nheight);\n      const unsigned int\n        tmpdimx = (nwidth>0)?nwidth:(-nwidth*_width/100),\n        tmpdimy = (nheight>0)?nheight:(-nheight*_height/100),\n        dimx = tmpdimx?tmpdimx:1,\n        dimy = tmpdimy?tmpdimy:1;\n      if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) {\n        if (_window_width!=dimx || _window_height!=dimy) {\n          RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1;\n          AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);\n          const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1;\n          SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);\n        }\n        if (_width!=dimx || _height!=dimy) {\n          unsigned int *const ndata = new unsigned int[dimx*dimy];\n          if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy);\n          else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);\n          delete[] _data;\n          _data = ndata;\n          _bmi.bmiHeader.biWidth = (LONG)dimx;\n          _bmi.bmiHeader.biHeight = -(int)dimy;\n          _width = dimx;\n          _height = dimy;\n        }\n        _window_width = dimx; _window_height = dimy;\n        show();\n      }\n      _is_resized = false;\n      if (_is_fullscreen) move((screen_width() - width())/2,(screen_height() - height())/2);\n      if (force_redraw) return paint();\n      return *this;\n    }\n\n    CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {\n      if (is_empty()) return *this;\n      if (force_redraw) {\n        const cimg_ulong buf_size = (cimg_ulong)_width*_height*4;\n        void *odata = std::malloc(buf_size);\n        if (odata) {\n          std::memcpy(odata,_data,buf_size);\n          assign(_width,_height,_title,_normalization,!_is_fullscreen,false);\n          std::memcpy(_data,odata,buf_size);\n          std::free(odata);\n        }\n        return paint();\n      }\n      return assign(_width,_height,_title,_normalization,!_is_fullscreen,false);\n    }\n\n    CImgDisplay& show() {\n      if (is_empty() || !_is_closed) return *this;\n      _is_closed = false;\n      if (_is_fullscreen) _init_fullscreen();\n      ShowWindow(_window,SW_SHOW);\n      _update_window_pos();\n      return paint();\n    }\n\n    CImgDisplay& close() {\n      if (is_empty() || _is_closed) return *this;\n      _is_closed = true;\n      if (_is_fullscreen) _desinit_fullscreen();\n      ShowWindow(_window,SW_HIDE);\n      _window_x = _window_y = 0;\n      return *this;\n    }\n\n    CImgDisplay& move(const int posx, const int posy) {\n      if (is_empty()) return *this;\n      if (_window_x!=posx || _window_y!=posy) {\n        if (!_is_fullscreen) {\n          RECT rect;\n          rect.left = rect.top = 0; rect.right = (LONG)_window_width - 1; rect.bottom = (LONG)_window_height - 1;\n          AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);\n          const int\n            border1 = (int)((rect.right - rect.left + 1 -_width)/2),\n            border2 = (int)(rect.bottom - rect.top + 1 - _height - border1);\n          SetWindowPos(_window,0,posx - border1,posy - border2,0,0,SWP_NOSIZE | SWP_NOZORDER);\n        } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);\n        _window_x = posx;\n        _window_y = posy;\n        show();\n      }\n      _is_moved = false;\n      return *this;\n    }\n\n    CImgDisplay& show_mouse() {\n      if (is_empty()) return *this;\n      _is_cursor_visible = true;\n      return *this;\n    }\n\n    CImgDisplay& hide_mouse() {\n      if (is_empty()) return *this;\n      _is_cursor_visible = false;\n      return *this;\n    }\n\n    CImgDisplay& set_mouse(const int posx, const int posy) {\n      if (is_empty() || _is_closed || posx<0 || posy<0) return *this;\n      _update_window_pos();\n      const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy);\n      if (res) { _mouse_x = posx; _mouse_y = posy; }\n      return *this;\n    }\n\n    CImgDisplay& set_title(const char *const format, ...) {\n      if (is_empty()) return *this;\n      char *const tmp = new char[1024];\n      va_list ap;\n      va_start(ap, format);\n      cimg_vsnprintf(tmp,1024,format,ap);\n      va_end(ap);\n      if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; }\n      delete[] _title;\n      const unsigned int s = (unsigned int)std::strlen(tmp) + 1;\n      _title = new char[s];\n      std::memcpy(_title,tmp,s*sizeof(char));\n      SetWindowTextA(_window, tmp);\n      delete[] tmp;\n      return *this;\n    }\n\n    template<typename T>\n    CImgDisplay& display(const CImg<T>& img) {\n      if (!img)\n        throw CImgArgumentException(_cimgdisplay_instance\n                                    \"display(): Empty specified image.\",\n                                    cimgdisplay_instance);\n      if (is_empty()) return assign(img);\n      return render(img).paint();\n    }\n\n    CImgDisplay& paint() {\n      if (_is_closed) return *this;\n      WaitForSingleObject(_mutex,INFINITE);\n      SetDIBitsToDevice(_hdc,0,0,_width,_height,0,0,0,_height,_data,&_bmi,DIB_RGB_COLORS);\n      ReleaseMutex(_mutex);\n      return *this;\n    }\n\n    template<typename T>\n    CImgDisplay& render(const CImg<T>& img) {\n      if (!img)\n        throw CImgArgumentException(_cimgdisplay_instance\n                                    \"render(): Empty specified image.\",\n                                    cimgdisplay_instance);\n\n      if (is_empty()) return *this;\n      if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2,\n                                                             (img._depth - 1)/2));\n\n      const T\n        *data1 = img._data,\n        *data2 = (img._spectrum>=2)?img.data(0,0,0,1):data1,\n        *data3 = (img._spectrum>=3)?img.data(0,0,0,2):data1;\n\n      WaitForSingleObject(_mutex,INFINITE);\n      unsigned int\n        *const ndata = (img._width==_width && img._height==_height)?_data:\n        new unsigned int[(size_t)img._width*img._height],\n        *ptrd = ndata;\n\n      if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {\n        _min = _max = 0;\n        switch (img._spectrum) {\n        case 1 : {\n          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n            const unsigned char val = (unsigned char)*(data1++);\n            *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val);\n          }\n        } break;\n        case 2 : {\n          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n            const unsigned char\n              R = (unsigned char)*(data1++),\n              G = (unsigned char)*(data2++);\n            *(ptrd++) = (unsigned int)((R<<16) | (G<<8));\n          }\n        } break;\n        default : {\n          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n            const unsigned char\n              R = (unsigned char)*(data1++),\n              G = (unsigned char)*(data2++),\n              B = (unsigned char)*(data3++);\n            *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B);\n          }\n        }\n        }\n      } else {\n        if (_normalization==3) {\n          if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max);\n          else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); }\n        } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max);\n        const float delta = _max - _min, mm = 255/(delta?delta:1.0f);\n        switch (img._spectrum) {\n        case 1 : {\n          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n            const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);\n            *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val);\n          }\n        } break;\n        case 2 : {\n          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n            const unsigned char\n              R = (unsigned char)((*(data1++) - _min)*mm),\n              G = (unsigned char)((*(data2++) - _min)*mm);\n            *(ptrd++) = (unsigned int)((R<<16) | (G<<8));\n          }\n        } break;\n        default : {\n          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n            const unsigned char\n              R = (unsigned char)((*(data1++) - _min)*mm),\n              G = (unsigned char)((*(data2++) - _min)*mm),\n              B = (unsigned char)((*(data3++) - _min)*mm);\n            *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B);\n          }\n        }\n        }\n      }\n      if (ndata!=_data) { _render_resize(ndata,img._width,img._height,_data,_width,_height); delete[] ndata; }\n      ReleaseMutex(_mutex);\n      return *this;\n    }\n\n    template<typename T>\n    const CImgDisplay& snapshot(CImg<T>& img) const {\n      if (is_empty()) { img.assign(); return *this; }\n      const unsigned int *ptrs = _data;\n      img.assign(_width,_height,1,3);\n      T\n        *data1 = img.data(0,0,0,0),\n        *data2 = img.data(0,0,0,1),\n        *data3 = img.data(0,0,0,2);\n      for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {\n        const unsigned int val = *(ptrs++);\n        *(data1++) = (T)(unsigned char)(val>>16);\n        *(data2++) = (T)(unsigned char)((val>>8)&0xFF);\n        *(data3++) = (T)(unsigned char)(val&0xFF);\n      }\n      return *this;\n    }\n#endif\n\n    //@}\n  };\n\n  /*\n   #--------------------------------------\n   #\n   #\n   #\n   # Definition of the CImg<T> structure\n   #\n   #\n   #\n   #--------------------------------------\n   */\n\n  //! Class representing an image (up to 4 dimensions wide), each pixel being of type \\c T.\n  /**\n     This is the main class of the %CImg Library. It declares and constructs\n     an image, allows access to its pixel values, and is able to perform various image operations.\n\n     \\par Image representation\n\n     A %CImg image is defined as an instance of the container \\c CImg<T>, which contains a regular grid of pixels,\n     each pixel value being of type \\c T. The image grid can have up to 4 dimensions: width, height, depth\n     and number of channels.\n     Usually, the three first dimensions are used to describe spatial coordinates <tt>(x,y,z)</tt>,\n     while the number of channels is rather used as a vector-valued dimension\n     (it may describe the R,G,B color channels for instance).\n     If you need a fifth dimension, you can use image lists \\c CImgList<T> rather than simple images \\c CImg<T>.\n\n     Thus, the \\c CImg<T> class is able to represent volumetric images of vector-valued pixels,\n     as well as images with less dimensions (1d scalar signal, 2d color images, ...).\n     Most member functions of the class CImg<\\c T> are designed to handle this maximum case of (3+1) dimensions.\n\n     Concerning the pixel value type \\c T:\n     fully supported template types are the basic C++ types: <tt>unsigned char, char, short, unsigned int, int,\n     unsigned long, long, float, double, ... </tt>.\n     Typically, fast image display can be done using <tt>CImg<unsigned char></tt> images,\n     while complex image processing algorithms may be rather coded using <tt>CImg<float></tt> or <tt>CImg<double></tt>\n     images that have floating-point pixel values. The default value for the template T is \\c float.\n     Using your own template types may be possible. However, you will certainly have to define the complete set\n     of arithmetic and logical operators for your class.\n\n     \\par Image structure\n\n     The \\c CImg<T> structure contains \\e six fields:\n     - \\c _width defines the number of \\a columns of the image (size along the X-axis).\n     - \\c _height defines the number of \\a rows of the image (size along the Y-axis).\n     - \\c _depth defines the number of \\a slices of the image (size along the Z-axis).\n     - \\c _spectrum defines the number of \\a channels of the image (size along the C-axis).\n     - \\c _data defines a \\a pointer to the \\a pixel \\a data (of type \\c T).\n     - \\c _is_shared is a boolean that tells if the memory buffer \\c data is shared with\n       another image.\n\n     You can access these fields publicly although it is recommended to use the dedicated functions\n     width(), height(), depth(), spectrum() and ptr() to do so.\n     Image dimensions are not limited to a specific range (as long as you got enough available memory).\n     A value of \\e 1 usually means that the corresponding dimension is \\a flat.\n     If one of the dimensions is \\e 0, or if the data pointer is null, the image is considered as \\e empty.\n     Empty images should not contain any pixel data and thus, will not be processed by CImg member functions\n     (a CImgInstanceException will be thrown instead).\n     Pixel data are stored in memory, in a non interlaced mode (See \\ref cimg_storage).\n\n     \\par Image declaration and construction\n\n     Declaring an image can be done by using one of the several available constructors.\n     Here is a list of the most used:\n\n     - Construct images from arbitrary dimensions:\n         - <tt>CImg<char> img;</tt> declares an empty image.\n         - <tt>CImg<unsigned char> img(128,128);</tt> declares a 128x128 greyscale image with\n         \\c unsigned \\c char pixel values.\n         - <tt>CImg<double> img(3,3);</tt> declares a 3x3 matrix with \\c double coefficients.\n         - <tt>CImg<unsigned char> img(256,256,1,3);</tt> declares a 256x256x1x3 (color) image\n         (colors are stored as an image with three channels).\n         - <tt>CImg<double> img(128,128,128);</tt> declares a 128x128x128 volumetric and greyscale image\n         (with \\c double pixel values).\n         - <tt>CImg<> img(128,128,128,3);</tt> declares a 128x128x128 volumetric color image\n         (with \\c float pixels, which is the default value of the template parameter \\c T).\n         - \\b Note: images pixels are <b>not automatically initialized to 0</b>. You may use the function \\c fill() to\n         do it, or use the specific constructor taking 5 parameters like this:\n         <tt>CImg<> img(128,128,128,3,0);</tt> declares a 128x128x128 volumetric color image with all pixel values to 0.\n\n     - Construct images from filenames:\n         - <tt>CImg<unsigned char> img(\"image.jpg\");</tt> reads a JPEG color image from the file \"image.jpg\".\n         - <tt>CImg<float> img(\"analyze.hdr\");</tt> reads a volumetric image (ANALYZE7.5 format) from the\n         file \"analyze.hdr\".\n         - \\b Note: You need to install <a href=\"http://www.imagemagick.org\">ImageMagick</a>\n         to be able to read common compressed image formats (JPG,PNG, ...) (See \\ref cimg_files_io).\n\n     - Construct images from C-style arrays:\n         - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \\c int* buffer\n         \\c data_buffer (of size 256x256=65536).\n         - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3);</tt> constructs a 256x256 color image\n         from a \\c unsigned \\c char* buffer \\c data_buffer (where R,G,B channels follow each others).\n\n         The complete list of constructors can be found <a href=\"#constructors\">here</a>.\n\n     \\par Most useful functions\n\n     The \\c CImg<T> class contains a lot of functions that operates on images.\n     Some of the most useful are:\n\n     - operator()(): Read or write pixel values.\n     - display(): displays the image in a new window.\n  **/\n  template<typename T>\n  struct CImg {\n\n    unsigned int _width, _height, _depth, _spectrum;\n    bool _is_shared;\n    T *_data;\n\n    //! Simple iterator type, to loop through each pixel value of an image instance.\n    /**\n       \\note\n       - The \\c CImg<T>::iterator type is defined to be a <tt>T*</tt>.\n       - You will seldom have to use iterators in %CImg, most classical operations\n         being achieved (often in a faster way) using methods of \\c CImg<T>.\n       \\par Example\n       \\code\n       CImg<float> img(\"reference.jpg\");                                         // Load image from file.\n       for (CImg<float>::iterator it = img.begin(), it<img.end(); ++it) *it = 0; // Set all pixels to '0', with a CImg iterator.\n       img.fill(0);                                                              // Do the same with a built-in method.\n       \\endcode\n   **/\n    typedef T* iterator;\n\n    //! Simple const iterator type, to loop through each pixel value of a \\c const image instance.\n    /**\n       \\note\n       - The \\c CImg<T>::const_iterator type is defined to be a \\c const \\c T*.\n       - You will seldom have to use iterators in %CImg, most classical operations\n         being achieved (often in a faster way) using methods of \\c CImg<T>.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\");                                    // Load image from file.\n       float sum = 0;\n       for (CImg<float>::iterator it = img.begin(), it<img.end(); ++it) sum+=*it; // Compute sum of all pixel values, with a CImg iterator.\n       const float sum2 = img.sum();                                              // Do the same with a built-in method.\n       \\endcode\n    **/\n    typedef const T* const_iterator;\n\n    //! Pixel value type.\n    /**\n       Refer to the type of the pixel values of an image instance.\n       \\note\n       - The \\c CImg<T>::value_type type of a \\c CImg<T> is defined to be a \\c T.\n       - \\c CImg<T>::value_type is actually not used in %CImg methods. It has been mainly defined for\n         compatibility with STL naming conventions.\n    **/\n    typedef T value_type;\n\n    // Define common types related to template type T.\n    typedef typename cimg::superset<T,bool>::type Tbool;\n    typedef typename cimg::superset<T,unsigned char>::type Tuchar;\n    typedef typename cimg::superset<T,char>::type Tchar;\n    typedef typename cimg::superset<T,unsigned short>::type Tushort;\n    typedef typename cimg::superset<T,short>::type Tshort;\n    typedef typename cimg::superset<T,unsigned int>::type Tuint;\n    typedef typename cimg::superset<T,int>::type Tint;\n    typedef typename cimg::superset<T,cimg_ulong>::type Tulong;\n    typedef typename cimg::superset<T,cimg_long>::type Tlong;\n    typedef typename cimg::superset<T,float>::type Tfloat;\n    typedef typename cimg::superset<T,double>::type Tdouble;\n    typedef typename cimg::last<T,bool>::type boolT;\n    typedef typename cimg::last<T,unsigned char>::type ucharT;\n    typedef typename cimg::last<T,char>::type charT;\n    typedef typename cimg::last<T,unsigned short>::type ushortT;\n    typedef typename cimg::last<T,short>::type shortT;\n    typedef typename cimg::last<T,unsigned int>::type uintT;\n    typedef typename cimg::last<T,int>::type intT;\n    typedef typename cimg::last<T,cimg_ulong>::type ulongT;\n    typedef typename cimg::last<T,cimg_long>::type longT;\n    typedef typename cimg::last<T,cimg_uint64>::type uint64T;\n    typedef typename cimg::last<T,cimg_int64>::type int64T;\n    typedef typename cimg::last<T,float>::type floatT;\n    typedef typename cimg::last<T,double>::type doubleT;\n\n    //@}\n    //---------------------------\n    //\n    //! \\name Plugins\n    //@{\n    //---------------------------\n#ifdef cimg_plugin\n#include cimg_plugin\n#endif\n#ifdef cimg_plugin1\n#include cimg_plugin1\n#endif\n#ifdef cimg_plugin2\n#include cimg_plugin2\n#endif\n#ifdef cimg_plugin3\n#include cimg_plugin3\n#endif\n#ifdef cimg_plugin4\n#include cimg_plugin4\n#endif\n#ifdef cimg_plugin5\n#include cimg_plugin5\n#endif\n#ifdef cimg_plugin6\n#include cimg_plugin6\n#endif\n#ifdef cimg_plugin7\n#include cimg_plugin7\n#endif\n#ifdef cimg_plugin8\n#include cimg_plugin8\n#endif\n\n    //@}\n    //---------------------------------------------------------\n    //\n    //! \\name Constructors / Destructor / Instance Management\n    //@{\n    //---------------------------------------------------------\n\n    //! Destroy image.\n    /**\n       \\note\n       - The pixel buffer data() is deallocated if necessary, e.g. for non-empty and non-shared image instances.\n       - Destroying an empty or shared image does nothing actually.\n       \\warning\n       - When destroying a non-shared image, make sure that you will \\e not operate on a remaining shared image\n         that shares its buffer with the destroyed instance, in order to avoid further invalid memory access\n         (to a deallocated buffer).\n    **/\n    ~CImg() {\n      if (!_is_shared) delete[] _data;\n    }\n\n    //! Construct empty image.\n    /**\n       \\note\n       - An empty image has no pixel data and all of its dimensions width(), height(), depth(), spectrum()\n         are set to \\c 0, as well as its pixel buffer pointer data().\n       - An empty image may be re-assigned afterwards, e.g. with the family of\n         assign(unsigned int,unsigned int,unsigned int,unsigned int) methods,\n         or by operator=(const CImg<t>&). In all cases, the type of pixels stays \\c T.\n       - An empty image is never shared.\n       \\par Example\n       \\code\n       CImg<float> img1, img2;      // Construct two empty images.\n       img1.assign(256,256,1,3);    // Re-assign 'img1' to be a 256x256x1x3 (color) image.\n       img2 = img1.get_rand(0,255); // Re-assign 'img2' to be a random-valued version of 'img1'.\n       img2.assign();               // Re-assign 'img2' to be an empty image again.\n       \\endcode\n    **/\n    CImg():_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {}\n\n    //! Construct image with specified size.\n    /**\n       \\param size_x Image width().\n       \\param size_y Image height().\n       \\param size_z Image depth().\n       \\param size_c Image spectrum() (number of channels).\n       \\note\n       - It is able to create only \\e non-shared images, and allocates thus a pixel buffer data()\n         for each constructed image instance.\n       - Setting one dimension \\c size_x,\\c size_y,\\c size_z or \\c size_c to \\c 0 leads to the construction of\n         an \\e empty image.\n       - A \\c CImgInstanceException is thrown when the pixel buffer cannot be allocated\n         (e.g. when requested size is too big for available memory).\n       \\warning\n       - The allocated pixel buffer is \\e not filled with a default value, and is likely to contain garbage values.\n         In order to initialize pixel values during construction (e.g. with \\c 0), use constructor\n         CImg(unsigned int,unsigned int,unsigned int,unsigned int,T) instead.\n       \\par Example\n       \\code\n       CImg<float> img1(256,256,1,3);   // Construct a 256x256x1x3 (color) image, filled with garbage values.\n       CImg<float> img2(256,256,1,3,0); // Construct a 256x256x1x3 (color) image, filled with value '0'.\n       \\endcode\n    **/\n    explicit CImg(const unsigned int size_x, const unsigned int size_y=1,\n                  const unsigned int size_z=1, const unsigned int size_c=1):\n      _is_shared(false) {\n      size_t siz = (size_t)size_x*size_y*size_z*size_c;\n      if (siz) {\n        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;\n        try { _data = new T[siz]; } catch (...) {\n          _width = _height = _depth = _spectrum = 0; _data = 0;\n          throw CImgInstanceException(_cimg_instance\n                                      \"CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                      cimg_instance,\n                                      cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),\n                                      size_x,size_y,size_z,size_c);\n        }\n      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }\n    }\n\n    //! Construct image with specified size and initialize pixel values.\n    /**\n       \\param size_x Image width().\n       \\param size_y Image height().\n       \\param size_z Image depth().\n       \\param size_c Image spectrum() (number of channels).\n       \\param value Initialization value.\n       \\note\n       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int),\n         but it also fills the pixel buffer with the specified \\c value.\n       \\warning\n       - It cannot be used to construct a vector-valued image and initialize it with \\e vector-valued pixels\n         (e.g. RGB vector, for color images).\n         For this task, you may use fillC() after construction.\n    **/\n    CImg(const unsigned int size_x, const unsigned int size_y,\n         const unsigned int size_z, const unsigned int size_c, const T& value):\n      _is_shared(false) {\n      const size_t siz = (size_t)size_x*size_y*size_z*size_c;\n      if (siz) {\n        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;\n        try { _data = new T[siz]; } catch (...) {\n          _width = _height = _depth = _spectrum = 0; _data = 0;\n          throw CImgInstanceException(_cimg_instance\n                                      \"CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                      cimg_instance,\n                                      cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),\n                                      size_x,size_y,size_z,size_c);\n        }\n        fill(value);\n      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }\n    }\n\n    //! Construct image with specified size and initialize pixel values from a sequence of integers.\n    /**\n       Construct a new image instance of size \\c size_x x \\c size_y x \\c size_z x \\c size_c,\n       with pixels of type \\c T, and initialize pixel\n       values from the specified sequence of integers \\c value0,\\c value1,\\c ...\n       \\param size_x Image width().\n       \\param size_y Image height().\n       \\param size_z Image depth().\n       \\param size_c Image spectrum() (number of channels).\n       \\param value0 First value of the initialization sequence (must be an \\e integer).\n       \\param value1 Second value of the initialization sequence (must be an \\e integer).\n       \\param ...\n       \\note\n       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills\n         the pixel buffer with a sequence of specified integer values.\n       \\warning\n       - You must specify \\e exactly \\c size_x*\\c size_y*\\c size_z*\\c size_c integers in the initialization sequence.\n         Otherwise, the constructor may crash or fill your image pixels with garbage.\n       \\par Example\n       \\code\n       const CImg<float> img(2,2,1,3,      // Construct a 2x2 color (RGB) image.\n                             0,255,0,255,  // Set the 4 values for the red component.\n                             0,0,255,255,  // Set the 4 values for the green component.\n                             64,64,64,64); // Set the 4 values for the blue component.\n       img.resize(150,150).display();\n       \\endcode\n       \\image html ref_constructor1.jpg\n     **/\n    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,\n         const int value0, const int value1, ...):\n      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n#define _CImg_stdarg(img,a0,a1,N,t) { \\\n        size_t _siz = (size_t)N; \\\n        if (_siz--) { \\\n          va_list ap; \\\n          va_start(ap,a1); \\\n          T *ptrd = (img)._data; \\\n          *(ptrd++) = (T)a0; \\\n          if (_siz--) { \\\n            *(ptrd++) = (T)a1; \\\n            for ( ; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \\\n          } \\\n          va_end(ap); \\\n        } \\\n      }\n      assign(size_x,size_y,size_z,size_c);\n      _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,int);\n    }\n\n#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0\n    //! Construct image with specified size and initialize pixel values from an initializer list of integers.\n    /**\n       Construct a new image instance of size \\c size_x x \\c size_y x \\c size_z x \\c size_c,\n       with pixels of type \\c T, and initialize pixel\n       values from the specified initializer list of integers { \\c value0,\\c value1,\\c ... }\n       \\param size_x Image width().\n       \\param size_y Image height().\n       \\param size_z Image depth().\n       \\param size_c Image spectrum() (number of channels).\n       \\param { value0, value1, ... } Initialization list\n       \\param repeat_values Tells if the value filling process is repeated over the image.\n\n       \\note\n       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills\n         the pixel buffer with a sequence of specified integer values.\n       \\par Example\n       \\code\n       const CImg<float> img(2,2,1,3,      // Construct a 2x2 color (RGB) image.\n                             { 0,255,0,255,    // Set the 4 values for the red component.\n                               0,0,255,255,    // Set the 4 values for the green component.\n                               64,64,64,64 }); // Set the 4 values for the blue component.\n       img.resize(150,150).display();\n       \\endcode\n       \\image html ref_constructor1.jpg\n    **/\n    template<typename t>\n    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,\n         const std::initializer_list<t> values,\n         const bool repeat_values=true):\n      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n#define _cimg_constructor_cpp11(repeat_values) \\\n  auto it = values.begin(); \\\n  size_t siz = size(); \\\n  if (repeat_values) for (T *ptrd = _data; siz--; ) { \\\n    *(ptrd++) = (T)(*(it++)); if (it==values.end()) it = values.begin(); } \\\n  else { siz = cimg::min(siz,values.size()); for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++)); }\n      assign(size_x,size_y,size_z,size_c);\n      _cimg_constructor_cpp11(repeat_values);\n    }\n\n    template<typename t>\n    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z,\n         std::initializer_list<t> values,\n         const bool repeat_values=true):\n      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      assign(size_x,size_y,size_z);\n      _cimg_constructor_cpp11(repeat_values);\n    }\n\n    template<typename t>\n    CImg(const unsigned int size_x, const unsigned int size_y,\n         std::initializer_list<t> values,\n         const bool repeat_values=true):\n      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      assign(size_x,size_y);\n      _cimg_constructor_cpp11(repeat_values);\n    }\n\n    template<typename t>\n    CImg(const unsigned int size_x,\n         std::initializer_list<t> values,\n         const bool repeat_values=true):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      assign(size_x);\n      _cimg_constructor_cpp11(repeat_values);\n    }\n\n    //! Construct single channel 1D image with pixel values and width obtained from an initializer list of integers.\n    /**\n       Construct a new image instance of size \\c width x \\c 1 x \\c 1 x \\c 1,\n       with pixels of type \\c T, and initialize pixel\n       values from the specified initializer list of integers { \\c value0,\\c value1,\\c ... }. Image width is\n       given by the size of the initializer list.\n       \\param { value0, value1, ... } Initialization list\n       \\note\n       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int) with height=1, depth=1, and spectrum=1,\n         but it also fills the pixel buffer with a sequence of specified integer values.\n       \\par Example\n       \\code\n       const CImg<float> img = {10,20,30,20,10 }; // Construct a 5x1 image with one channel, and set its pixel values.\n       img.resize(150,150).display();\n       \\endcode\n       \\image html ref_constructor1.jpg\n     **/\n    template<typename t>\n    CImg(const std::initializer_list<t> values):\n      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      assign(values.size(),1,1,1);\n      auto it = values.begin();\n      unsigned int siz = _width;\n      for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++));\n    }\n\n    template<typename t>\n    CImg<T> & operator=(std::initializer_list<t> values) {\n      _cimg_constructor_cpp11(siz>values.size());\n      return *this;\n    }\n#endif\n\n    //! Construct image with specified size and initialize pixel values from a sequence of doubles.\n    /**\n       Construct a new image instance of size \\c size_x x \\c size_y x \\c size_z x \\c size_c, with pixels of type \\c T,\n       and initialize pixel values from the specified sequence of doubles \\c value0,\\c value1,\\c ...\n       \\param size_x Image width().\n       \\param size_y Image height().\n       \\param size_z Image depth().\n       \\param size_c Image spectrum() (number of channels).\n       \\param value0 First value of the initialization sequence (must be a \\e double).\n       \\param value1 Second value of the initialization sequence (must be a \\e double).\n       \\param ...\n       \\note\n       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...), but\n         takes a sequence of double values instead of integers.\n       \\warning\n       - You must specify \\e exactly \\c dx*\\c dy*\\c dz*\\c dc doubles in the initialization sequence.\n         Otherwise, the constructor may crash or fill your image with garbage.\n         For instance, the code below will probably crash on most platforms:\n         \\code\n         const CImg<float> img(2,2,1,1, 0.5,0.5,255,255); // FAIL: The two last arguments are 'int', not 'double'!\n         \\endcode\n     **/\n    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,\n         const double value0, const double value1, ...):\n      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      assign(size_x,size_y,size_z,size_c);\n      _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,double);\n    }\n\n    //! Construct image with specified size and initialize pixel values from a value string.\n    /**\n       Construct a new image instance of size \\c size_x x \\c size_y x \\c size_z x \\c size_c, with pixels of type \\c T,\n       and initializes pixel values from the specified string \\c values.\n       \\param size_x Image width().\n       \\param size_y Image height().\n       \\param size_z Image depth().\n       \\param size_c Image spectrum() (number of channels).\n       \\param values Value string describing the way pixel values are set.\n       \\param repeat_values Tells if the value filling process is repeated over the image.\n       \\note\n       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills\n         the pixel buffer with values described in the value string \\c values.\n       - Value string \\c values may describe two different filling processes:\n         - Either \\c values is a sequences of values assigned to the image pixels, as in <tt>\"1,2,3,7,8,2\"</tt>.\n           In this case, set \\c repeat_values to \\c true to periodically fill the image with the value sequence.\n         - Either, \\c values is a formula, as in <tt>\"cos(x/10)*sin(y/20)\"</tt>.\n           In this case, parameter \\c repeat_values is pointless.\n       - For both cases, specifying \\c repeat_values is mandatory.\n         It disambiguates the possible overloading of constructor\n         CImg(unsigned int,unsigned int,unsigned int,unsigned int,T) with \\c T being a <tt>const char*</tt>.\n       - A \\c CImgArgumentException is thrown when an invalid value string \\c values is specified.\n       \\par Example\n       \\code\n       const CImg<float> img1(129,129,1,3,\"0,64,128,192,255\",true),                   // Construct image filled from a value sequence.\n                         img2(129,129,1,3,\"if(c==0,255*abs(cos(x/10)),1.8*y)\",false); // Construct image filled from a formula.\n       (img1,img2).display();\n       \\endcode\n       \\image html ref_constructor2.jpg\n     **/\n    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,\n         const char *const values, const bool repeat_values):_is_shared(false) {\n      const size_t siz = (size_t)size_x*size_y*size_z*size_c;\n      if (siz) {\n        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;\n        try { _data = new T[siz]; } catch (...) {\n          _width = _height = _depth = _spectrum = 0; _data = 0;\n          throw CImgInstanceException(_cimg_instance\n                                      \"CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                      cimg_instance,\n                                      cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),\n                                      size_x,size_y,size_z,size_c);\n        }\n        fill(values,repeat_values);\n      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }\n    }\n\n    //! Construct image with specified size and initialize pixel values from a memory buffer.\n    /**\n       Construct a new image instance of size \\c size_x x \\c size_y x \\c size_z x \\c size_c, with pixels of type \\c T,\n       and initializes pixel values from the specified \\c t* memory buffer.\n       \\param values Pointer to the input memory buffer.\n       \\param size_x Image width().\n       \\param size_y Image height().\n       \\param size_z Image depth().\n       \\param size_c Image spectrum() (number of channels).\n       \\param is_shared Tells if input memory buffer must be shared by the current instance.\n       \\note\n       - If \\c is_shared is \\c false, the image instance allocates its own pixel buffer,\n         and values from the specified input buffer are copied to the instance buffer.\n         If buffer types \\c T and \\c t are different, a regular static cast is performed during buffer copy.\n       - Otherwise, the image instance does \\e not allocate a new buffer, and uses the input memory buffer as its\n         own pixel buffer. This case requires that types \\c T and \\c t are the same. Later, destroying such a shared\n         image will not deallocate the pixel buffer, this task being obviously charged to the initial buffer allocator.\n       - A \\c CImgInstanceException is thrown when the pixel buffer cannot be allocated\n         (e.g. when requested size is too big for available memory).\n       \\warning\n       - You must take care when operating on a shared image, since it may have an invalid pixel buffer pointer data()\n         (e.g. already deallocated).\n       \\par Example\n       \\code\n       unsigned char tab[256*256] = { 0 };\n       CImg<unsigned char> img1(tab,256,256,1,1,false), // Construct new non-shared image from buffer 'tab'.\n                           img2(tab,256,256,1,1,true);  // Construct new shared-image from buffer 'tab'.\n       tab[1024] = 255;                                 // Here, 'img2' is indirectly modified, but not 'img1'.\n       \\endcode\n    **/\n    template<typename t>\n    CImg(const t *const values, const unsigned int size_x, const unsigned int size_y=1,\n         const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false):_is_shared(false) {\n      if (is_shared) {\n        _width = _height = _depth = _spectrum = 0; _data = 0;\n        throw CImgArgumentException(_cimg_instance\n                                    \"CImg(): Invalid construction request of a (%u,%u,%u,%u) shared instance \"\n                                    \"from a (%s*) buffer (pixel types are different).\",\n                                    cimg_instance,\n                                    size_x,size_y,size_z,size_c,CImg<t>::pixel_type());\n      }\n      const size_t siz = (size_t)size_x*size_y*size_z*size_c;\n      if (values && siz) {\n        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;\n        try { _data = new T[siz]; } catch (...) {\n          _width = _height = _depth = _spectrum = 0; _data = 0;\n          throw CImgInstanceException(_cimg_instance\n                                      \"CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                      cimg_instance,\n                                      cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),\n                                      size_x,size_y,size_z,size_c);\n\n        }\n        const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);\n      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }\n    }\n\n    //! Construct image with specified size and initialize pixel values from a memory buffer \\specialization.\n    CImg(const T *const values, const unsigned int size_x, const unsigned int size_y=1,\n         const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false) {\n      const size_t siz = (size_t)size_x*size_y*size_z*size_c;\n      if (values && siz) {\n        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = is_shared;\n        if (_is_shared) _data = const_cast<T*>(values);\n        else {\n          try { _data = new T[siz]; } catch (...) {\n            _width = _height = _depth = _spectrum = 0; _data = 0;\n            throw CImgInstanceException(_cimg_instance\n                                        \"CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                        cimg_instance,\n                                        cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),\n                                        size_x,size_y,size_z,size_c);\n          }\n          std::memcpy(_data,values,siz*sizeof(T));\n        }\n      } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }\n    }\n\n    //! Construct image from reading an image file.\n    /**\n       Construct a new image instance with pixels of type \\c T, and initialize pixel values with the data read from\n       an image file.\n       \\param filename Filename, as a C-string.\n       \\note\n       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it reads the image\n         dimensions and pixel values from the specified image file.\n       - The recognition of the image file format by %CImg higly depends on the tools installed on your system\n         and on the external libraries you used to link your code against.\n       - Considered pixel type \\c T should better fit the file format specification, or data loss may occur during\n         file load (e.g. constructing a \\c CImg<unsigned char> from a float-valued image file).\n       - A \\c CImgIOException is thrown when the specified \\c filename cannot be read, or if the file format is not\n         recognized.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\");\n       img.display();\n       \\endcode\n       \\image html ref_image.jpg\n    **/\n    explicit CImg(const char *const filename):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      assign(filename);\n    }\n\n    //! Construct image copy.\n    /**\n       Construct a new image instance with pixels of type \\c T, as a copy of an existing \\c CImg<t> instance.\n       \\param img Input image to copy.\n       \\note\n       - Constructed copy has the same size width() x height() x depth() x spectrum() and pixel values as the\n         input image \\c img.\n       - If input image \\c img is \\e shared and if types \\c T and \\c t are the same, the constructed copy is also\n         \\e shared, and shares its pixel buffer with \\c img.\n         Modifying a pixel value in the constructed copy will thus also modifies it in the input image \\c img.\n         This behavior is needful to allow functions to return shared images.\n       - Otherwise, the constructed copy allocates its own pixel buffer, and copies pixel values from the input\n         image \\c img into its buffer. The copied pixel values may be eventually statically casted if types \\c T and\n         \\c t are different.\n       - Constructing a copy from an image \\c img when types \\c t and \\c T are the same is significantly faster than\n         with different types.\n       - A \\c CImgInstanceException is thrown when the pixel buffer cannot be allocated\n         (e.g. not enough available memory).\n    **/\n    template<typename t>\n    CImg(const CImg<t>& img):_is_shared(false) {\n      const size_t siz = (size_t)img.size();\n      if (img._data && siz) {\n        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;\n        try { _data = new T[siz]; } catch (...) {\n          _width = _height = _depth = _spectrum = 0; _data = 0;\n          throw CImgInstanceException(_cimg_instance\n                                      \"CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                      cimg_instance,\n                                      cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),\n                                      img._width,img._height,img._depth,img._spectrum);\n        }\n        const t *ptrs = img._data; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);\n      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }\n    }\n\n    //! Construct image copy \\specialization.\n    CImg(const CImg<T>& img) {\n      const size_t siz = (size_t)img.size();\n      if (img._data && siz) {\n        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;\n        _is_shared = img._is_shared;\n        if (_is_shared) _data = const_cast<T*>(img._data);\n        else {\n          try { _data = new T[siz]; } catch (...) {\n            _width = _height = _depth = _spectrum = 0; _data = 0;\n            throw CImgInstanceException(_cimg_instance\n                                        \"CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                        cimg_instance,\n                                        cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),\n                                        img._width,img._height,img._depth,img._spectrum);\n\n          }\n          std::memcpy(_data,img._data,siz*sizeof(T));\n        }\n      } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }\n    }\n\n    //! Advanced copy constructor.\n    /**\n       Construct a new image instance with pixels of type \\c T, as a copy of an existing \\c CImg<t> instance,\n       while forcing the shared state of the constructed copy.\n       \\param img Input image to copy.\n       \\param is_shared Tells about the shared state of the constructed copy.\n       \\note\n       - Similar to CImg(const CImg<t>&), except that it allows to decide the shared state of\n         the constructed image, which does not depend anymore on the shared state of the input image \\c img:\n         - If \\c is_shared is \\c true, the constructed copy will share its pixel buffer with the input image \\c img.\n           For that case, the pixel types \\c T and \\c t \\e must be the same.\n         - If \\c is_shared is \\c false, the constructed copy will allocate its own pixel buffer, whether the input\n           image \\c img is shared or not.\n       - A \\c CImgArgumentException is thrown when a shared copy is requested with different pixel types \\c T and \\c t.\n    **/\n    template<typename t>\n    CImg(const CImg<t>& img, const bool is_shared):_is_shared(false) {\n      if (is_shared) {\n        _width = _height = _depth = _spectrum = 0; _data = 0;\n        throw CImgArgumentException(_cimg_instance\n                                    \"CImg(): Invalid construction request of a shared instance from a \"\n                                    \"CImg<%s> image (%u,%u,%u,%u,%p) (pixel types are different).\",\n                                    cimg_instance,\n                                    CImg<t>::pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data);\n      }\n      const size_t siz = (size_t)img.size();\n      if (img._data && siz) {\n        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;\n        try { _data = new T[siz]; } catch (...) {\n          _width = _height = _depth = _spectrum = 0; _data = 0;\n          throw CImgInstanceException(_cimg_instance\n                                      \"CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                      cimg_instance,\n                                      cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),\n                                      img._width,img._height,img._depth,img._spectrum);\n        }\n        const t *ptrs = img._data; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);\n      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }\n    }\n\n    //! Advanced copy constructor \\specialization.\n    CImg(const CImg<T>& img, const bool is_shared) {\n      const size_t siz = (size_t)img.size();\n      if (img._data && siz) {\n        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;\n        _is_shared = is_shared;\n        if (_is_shared) _data = const_cast<T*>(img._data);\n        else {\n          try { _data = new T[siz]; } catch (...) {\n            _width = _height = _depth = _spectrum = 0; _data = 0;\n            throw CImgInstanceException(_cimg_instance\n                                        \"CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                        cimg_instance,\n                                        cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),\n                                        img._width,img._height,img._depth,img._spectrum);\n          }\n          std::memcpy(_data,img._data,siz*sizeof(T));\n        }\n      } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }\n    }\n\n    //! Construct image with dimensions borrowed from another image.\n    /**\n       Construct a new image instance with pixels of type \\c T, and size get from some dimensions of an existing\n       \\c CImg<t> instance.\n       \\param img Input image from which dimensions are borrowed.\n       \\param dimensions C-string describing the image size along the X,Y,Z and C-dimensions.\n       \\note\n       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it takes the image dimensions\n         (\\e not its pixel values) from an existing \\c CImg<t> instance.\n       - The allocated pixel buffer is \\e not filled with a default value, and is likely to contain garbage values.\n         In order to initialize pixel values (e.g. with \\c 0), use constructor CImg(const CImg<t>&,const char*,T)\n         instead.\n       \\par Example\n       \\code\n       const CImg<float> img1(256,128,1,3),      // 'img1' is a 256x128x1x3 image.\n                         img2(img1,\"xyzc\"),      // 'img2' is a 256x128x1x3 image.\n                         img3(img1,\"y,x,z,c\"),   // 'img3' is a 128x256x1x3 image.\n                         img4(img1,\"c,x,y,3\",0), // 'img4' is a 3x128x256x3 image (with pixels initialized to '0').\n       \\endcode\n     **/\n    template<typename t>\n    CImg(const CImg<t>& img, const char *const dimensions):\n      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      assign(img,dimensions);\n    }\n\n    //! Construct image with dimensions borrowed from another image and initialize pixel values.\n    /**\n       Construct a new image instance with pixels of type \\c T, and size get from the dimensions of an existing\n       \\c CImg<t> instance, and set all pixel values to specified \\c value.\n       \\param img Input image from which dimensions are borrowed.\n       \\param dimensions String describing the image size along the X,Y,Z and V-dimensions.\n       \\param value Value used for initialization.\n       \\note\n       - Similar to CImg(const CImg<t>&,const char*), but it also fills the pixel buffer with the specified \\c value.\n     **/\n    template<typename t>\n    CImg(const CImg<t>& img, const char *const dimensions, const T& value):\n      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      assign(img,dimensions).fill(value);\n    }\n\n    //! Construct image from a display window.\n    /**\n       Construct a new image instance with pixels of type \\c T, as a snapshot of an existing \\c CImgDisplay instance.\n       \\param disp Input display window.\n       \\note\n       - The width() and height() of the constructed image instance are the same as the specified \\c CImgDisplay.\n       - The depth() and spectrum() of the constructed image instance are respectively set to \\c 1 and \\c 3\n         (i.e. a 2d color image).\n       - The image pixels are read as 8-bits RGB values.\n     **/\n    explicit CImg(const CImgDisplay &disp):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      disp.snapshot(*this);\n    }\n\n    // Constructor and assignment operator for rvalue references (c++11).\n    // This avoids an additional image copy for methods returning new images. Can save RAM for big images !\n#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0\n    CImg(CImg<T>&& img):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {\n      swap(img);\n    }\n    CImg<T>& operator=(CImg<T>&& img) {\n      if (_is_shared) return assign(img);\n      return img.swap(*this);\n    }\n#endif\n\n    //! Construct empty image \\inplace.\n    /**\n       In-place version of the default constructor CImg(). It simply resets the instance to an empty image.\n    **/\n    CImg<T>& assign() {\n      if (!_is_shared) delete[] _data;\n      _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0;\n      return *this;\n    }\n\n    //! Construct image with specified size \\inplace.\n    /**\n       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int).\n    **/\n    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y=1,\n                    const unsigned int size_z=1, const unsigned int size_c=1) {\n      const size_t siz = (size_t)size_x*size_y*size_z*size_c;\n      if (!siz) return assign();\n      const size_t curr_siz = (size_t)size();\n      if (siz!=curr_siz) {\n        if (_is_shared)\n          throw CImgArgumentException(_cimg_instance\n                                      \"assign(): Invalid assignement request of shared instance from specified \"\n                                      \"image (%u,%u,%u,%u).\",\n                                      cimg_instance,\n                                      size_x,size_y,size_z,size_c);\n        else {\n          delete[] _data;\n          try { _data = new T[siz]; } catch (...) {\n            _width = _height = _depth = _spectrum = 0; _data = 0;\n            throw CImgInstanceException(_cimg_instance\n                                        \"assign(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                        cimg_instance,\n                                        cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),\n                                        size_x,size_y,size_z,size_c);\n          }\n        }\n      }\n      _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;\n      return *this;\n    }\n\n    //! Construct image with specified size and initialize pixel values \\inplace.\n    /**\n       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,T).\n    **/\n    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y,\n                    const unsigned int size_z, const unsigned int size_c, const T& value) {\n      return assign(size_x,size_y,size_z,size_c).fill(value);\n    }\n\n    //! Construct image with specified size and initialize pixel values from a sequence of integers \\inplace.\n    /**\n       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...).\n    **/\n    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y,\n                    const unsigned int size_z, const unsigned int size_c,\n                    const int value0, const int value1, ...) {\n      assign(size_x,size_y,size_z,size_c);\n      _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,int);\n      return *this;\n    }\n\n    //! Construct image with specified size and initialize pixel values from a sequence of doubles \\inplace.\n    /**\n       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,double,double,...).\n    **/\n    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y,\n                    const unsigned int size_z, const unsigned int size_c,\n                    const double value0, const double value1, ...) {\n      assign(size_x,size_y,size_z,size_c);\n      _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,double);\n      return *this;\n    }\n\n    //! Construct image with specified size and initialize pixel values from a value string \\inplace.\n    /**\n       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,const char*,bool).\n    **/\n    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y,\n                    const unsigned int size_z, const unsigned int size_c,\n                    const char *const values, const bool repeat_values) {\n      return assign(size_x,size_y,size_z,size_c).fill(values,repeat_values);\n    }\n\n    //! Construct image with specified size and initialize pixel values from a memory buffer \\inplace.\n    /**\n       In-place version of the constructor CImg(const t*,unsigned int,unsigned int,unsigned int,unsigned int).\n    **/\n    template<typename t>\n    CImg<T>& assign(const t *const values, const unsigned int size_x, const unsigned int size_y=1,\n                    const unsigned int size_z=1, const unsigned int size_c=1) {\n      const size_t siz = (size_t)size_x*size_y*size_z*size_c;\n      if (!values || !siz) return assign();\n      assign(size_x,size_y,size_z,size_c);\n      const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);\n      return *this;\n    }\n\n    //! Construct image with specified size and initialize pixel values from a memory buffer \\specialization.\n    CImg<T>& assign(const T *const values, const unsigned int size_x, const unsigned int size_y=1,\n                    const unsigned int size_z=1, const unsigned int size_c=1) {\n      const size_t siz = (size_t)size_x*size_y*size_z*size_c;\n      if (!values || !siz) return assign();\n      const size_t curr_siz = (size_t)size();\n      if (values==_data && siz==curr_siz) return assign(size_x,size_y,size_z,size_c);\n      if (_is_shared || values + siz<_data || values>=_data + size()) {\n        assign(size_x,size_y,size_z,size_c);\n        if (_is_shared) std::memmove(_data,values,siz*sizeof(T));\n        else std::memcpy(_data,values,siz*sizeof(T));\n      } else {\n        T *new_data = 0;\n        try { new_data = new T[siz]; } catch (...) {\n          _width = _height = _depth = _spectrum = 0; _data = 0;\n          throw CImgInstanceException(_cimg_instance\n                                      \"assign(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).\",\n                                      cimg_instance,\n                                      cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),\n                                      size_x,size_y,size_z,size_c);\n        }\n        std::memcpy(new_data,values,siz*sizeof(T));\n        delete[] _data; _data = new_data; _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;\n      }\n      return *this;\n    }\n\n    //! Construct image with specified size and initialize pixel values from a memory buffer \\overloading.\n    template<typename t>\n    CImg<T>& assign(const t *const values, const unsigned int size_x, const unsigned int size_y,\n                    const unsigned int size_z, const unsigned int size_c, const bool is_shared) {\n      if (is_shared)\n        throw CImgArgumentException(_cimg_instance\n                                    \"assign(): Invalid assignment request of shared instance from (%s*) buffer\"\n                                    \"(pixel types are different).\",\n                                    cimg_instance,\n                                    CImg<t>::pixel_type());\n      return assign(values,size_x,size_y,size_z,size_c);\n    }\n\n    //! Construct image with specified size and initialize pixel values from a memory buffer \\overloading.\n    CImg<T>& assign(const T *const values, const unsigned int size_x, const unsigned int size_y,\n                    const unsigned int size_z, const unsigned int size_c, const bool is_shared) {\n      const size_t siz = (size_t)size_x*size_y*size_z*size_c;\n      if (!values || !siz) return assign();\n      if (!is_shared) { if (_is_shared) assign(); assign(values,size_x,size_y,size_z,size_c); }\n      else {\n        if (!_is_shared) {\n          if (values + siz<_data || values>=_data + size()) assign();\n          else cimg::warn(_cimg_instance\n                          \"assign(): Shared image instance has overlapping memory.\",\n                          cimg_instance);\n        }\n        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = true;\n        _data = const_cast<T*>(values);\n      }\n      return *this;\n    }\n\n    //! Construct image from reading an image file \\inplace.\n    /**\n       In-place version of the constructor CImg(const char*).\n    **/\n    CImg<T>& assign(const char *const filename) {\n      return load(filename);\n    }\n\n    //! Construct image copy \\inplace.\n    /**\n       In-place version of the constructor CImg(const CImg<t>&).\n    **/\n    template<typename t>\n    CImg<T>& assign(const CImg<t>& img) {\n      return assign(img._data,img._width,img._height,img._depth,img._spectrum);\n    }\n\n    //! In-place version of the advanced copy constructor.\n    /**\n       In-place version of the constructor CImg(const CImg<t>&,bool).\n     **/\n    template<typename t>\n    CImg<T>& assign(const CImg<t>& img, const bool is_shared) {\n      return assign(img._data,img._width,img._height,img._depth,img._spectrum,is_shared);\n    }\n\n    //! Construct image with dimensions borrowed from another image \\inplace.\n    /**\n       In-place version of the constructor CImg(const CImg<t>&,const char*).\n    **/\n    template<typename t>\n    CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {\n      if (!dimensions || !*dimensions) return assign(img._width,img._height,img._depth,img._spectrum);\n      unsigned int siz[4] = { 0,1,1,1 }, k = 0;\n      CImg<charT> item(256);\n      for (const char *s = dimensions; *s && k<4; ++k) {\n        if (cimg_sscanf(s,\"%255[^0-9%xyzvwhdcXYZVWHDC]\",item._data)>0) s+=std::strlen(item);\n        if (*s) {\n          unsigned int val = 0; char sep = 0;\n          if (cimg_sscanf(s,\"%u%c\",&val,&sep)>0) {\n            if (sep=='%') siz[k] = val*(k==0?_width:k==1?_height:k==2?_depth:_spectrum)/100;\n            else siz[k] = val;\n            while (*s>='0' && *s<='9') ++s; if (sep=='%') ++s;\n          } else switch (cimg::uncase(*s)) {\n          case 'x' : case 'w' : siz[k] = img._width; ++s; break;\n          case 'y' : case 'h' : siz[k] = img._height; ++s; break;\n          case 'z' : case 'd' : siz[k] = img._depth; ++s; break;\n          case 'c' : case 's' : siz[k] = img._spectrum; ++s; break;\n          default :\n            throw CImgArgumentException(_cimg_instance\n                                        \"assign(): Invalid character '%c' detected in specified dimension string '%s'.\",\n                                        cimg_instance,\n                                        *s,dimensions);\n          }\n        }\n      }\n      return assign(siz[0],siz[1],siz[2],siz[3]);\n    }\n\n    //! Construct image with dimensions borrowed from another image and initialize pixel values \\inplace.\n    /**\n       In-place version of the constructor CImg(const CImg<t>&,const char*,T).\n    **/\n    template<typename t>\n    CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T& value) {\n      return assign(img,dimensions).fill(value);\n    }\n\n    //! Construct image from a display window \\inplace.\n    /**\n       In-place version of the constructor CImg(const CImgDisplay&).\n    **/\n    CImg<T>& assign(const CImgDisplay &disp) {\n      disp.snapshot(*this);\n      return *this;\n    }\n\n    //! Construct empty image \\inplace.\n    /**\n       Equivalent to assign().\n       \\note\n       - It has been defined for compatibility with STL naming conventions.\n    **/\n    CImg<T>& clear() {\n      return assign();\n    }\n\n    //! Transfer content of an image instance into another one.\n    /**\n       Transfer the dimensions and the pixel buffer content of an image instance into another one,\n       and replace instance by an empty image. It avoids the copy of the pixel buffer\n       when possible.\n       \\param img Destination image.\n       \\note\n       - Pixel types \\c T and \\c t of source and destination images can be different, though the process is\n         designed to be instantaneous when \\c T and \\c t are the same.\n       \\par Example\n       \\code\n       CImg<float> src(256,256,1,3,0), // Construct a 256x256x1x3 (color) image filled with value '0'.\n                   dest(16,16);        // Construct a 16x16x1x1 (scalar) image.\n       src.move_to(dest);              // Now, 'src' is empty and 'dest' is the 256x256x1x3 image.\n       \\endcode\n    **/\n    template<typename t>\n    CImg<t>& move_to(CImg<t>& img) {\n      img.assign(*this);\n      assign();\n      return img;\n    }\n\n    //! Transfer content of an image instance into another one \\specialization.\n    CImg<T>& move_to(CImg<T>& img) {\n      if (_is_shared || img._is_shared) img.assign(*this);\n      else swap(img);\n      assign();\n      return img;\n    }\n\n    //! Transfer content of an image instance into a new image in an image list.\n    /**\n       Transfer the dimensions and the pixel buffer content of an image instance\n       into a newly inserted image at position \\c pos in specified \\c CImgList<t> instance.\n       \\param list Destination list.\n       \\param pos Position of the newly inserted image in the list.\n       \\note\n       - When optionnal parameter \\c pos is ommited, the image instance is transfered as a new\n         image at the end of the specified \\c list.\n       - It is convenient to sequentially insert new images into image lists, with no\n         additional copies of memory buffer.\n       \\par Example\n       \\code\n       CImgList<float> list;             // Construct an empty image list.\n       CImg<float> img(\"reference.jpg\"); // Read image from filename.\n       img.move_to(list);                // Transfer image content as a new item in the list (no buffer copy).\n       \\endcode\n    **/\n    template<typename t>\n    CImgList<t>& move_to(CImgList<t>& list, const unsigned int pos=~0U) {\n      const unsigned int npos = pos>list._width?list._width:pos;\n      move_to(list.insert(1,npos)[npos]);\n      return list;\n    }\n\n    //! Swap fields of two image instances.\n    /**\n      \\param img Image to swap fields with.\n      \\note\n      - It can be used to interchange the content of two images in a very fast way. Can be convenient when dealing\n        with algorithms requiring two swapping buffers.\n      \\par Example\n      \\code\n      CImg<float> img1(\"lena.jpg\"),\n                  img2(\"milla.jpg\");\n      img1.swap(img2);               // Now, 'img1' is 'milla' and 'img2' is 'lena'.\n      \\endcode\n    **/\n    CImg<T>& swap(CImg<T>& img) {\n      cimg::swap(_width,img._width,_height,img._height,_depth,img._depth,_spectrum,img._spectrum);\n      cimg::swap(_data,img._data);\n      cimg::swap(_is_shared,img._is_shared);\n      return img;\n    }\n\n    //! Return a reference to an empty image.\n    /**\n       \\note\n       This function is useful mainly to declare optional parameters having type \\c CImg<T> in functions prototypes,\n       e.g.\n       \\code\n       void f(const int x=0, const int y=0, const CImg<float>& img=CImg<float>::empty());\n       \\endcode\n     **/\n    static CImg<T>& empty() {\n      static CImg<T> _empty;\n      return _empty.assign();\n    }\n\n    //! Return a reference to an empty image \\const.\n    static const CImg<T>& const_empty() {\n      static const CImg<T> _empty;\n      return _empty;\n    }\n\n    //@}\n    //------------------------------------------\n    //\n    //! \\name Overloaded Operators\n    //@{\n    //------------------------------------------\n\n    //! Access to a pixel value.\n    /**\n       Return a reference to a located pixel value of the image instance,\n       being possibly \\e const, whether the image instance is \\e const or not.\n       This is the standard method to get/set pixel values in \\c CImg<T> images.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note\n       - Range of pixel coordinates start from <tt>(0,0,0,0)</tt> to\n         <tt>(width() - 1,height() - 1,depth() - 1,spectrum() - 1)</tt>.\n       - Due to the particular arrangement of the pixel buffers defined in %CImg, you can omit one coordinate if the\n         corresponding dimension is equal to \\c 1.\n         For instance, pixels of a 2d image (depth() equal to \\c 1) can be accessed by <tt>img(x,y,c)</tt> instead of\n         <tt>img(x,y,0,c)</tt>.\n       \\warning\n       - There is \\e no boundary checking done in this operator, to make it as fast as possible.\n         You \\e must take care of out-of-bounds access by yourself, if necessary.\n         For debuging purposes, you may want to define macro \\c 'cimg_verbosity'>=3 to enable additional boundary\n         checking operations in this operator. In that case, warning messages will be printed on the error output\n         when accessing out-of-bounds pixels.\n       \\par Example\n       \\code\n       CImg<float> img(100,100,1,3,0);                   // Construct a 100x100x1x3 (color) image with pixels set to '0'.\n       const float\n          valR = img(10,10,0,0),                         // Read red value at coordinates (10,10).\n          valG = img(10,10,0,1),                         // Read green value at coordinates (10,10)\n          valB = img(10,10,2),                           // Read blue value at coordinates (10,10) (Z-coordinate can be omitted).\n          avg = (valR + valG + valB)/3;                  // Compute average pixel value.\n       img(10,10,0) = img(10,10,1) = img(10,10,2) = avg; // Replace the color pixel (10,10) by the average grey value.\n       \\endcode\n    **/\n#if cimg_verbosity>=3\n    T& operator()(const unsigned int x, const unsigned int y=0,\n                  const unsigned int z=0, const unsigned int c=0) {\n      const ulongT off = (ulongT)offset(x,y,z,c);\n      if (!_data || off>=size()) {\n        cimg::warn(_cimg_instance\n                   \"operator(): Invalid pixel request, at coordinates (%d,%d,%d,%d) [offset=%u].\",\n                   cimg_instance,\n                   (int)x,(int)y,(int)z,(int)c,off);\n        return *_data;\n      }\n      else return _data[off];\n    }\n\n    //! Access to a pixel value \\const.\n    const T& operator()(const unsigned int x, const unsigned int y=0,\n                        const unsigned int z=0, const unsigned int c=0) const {\n      return const_cast<CImg<T>*>(this)->operator()(x,y,z,c);\n    }\n\n    //! Access to a pixel value.\n    /**\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param wh Precomputed offset, must be equal to <tt>width()*\\ref height()</tt>.\n       \\param whd Precomputed offset, must be equal to <tt>width()*\\ref height()*\\ref depth()</tt>.\n       \\note\n       - Similar to (but faster than) operator()().\n         It uses precomputed offsets to optimize memory access. You may use it to optimize\n         the reading/writing of several pixel values in the same image (e.g. in a loop).\n     **/\n    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,\n                  const ulongT wh, const ulongT whd=0) {\n      cimg::unused(wh,whd);\n      return (*this)(x,y,z,c);\n    }\n\n    //! Access to a pixel value \\const.\n    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,\n                        const ulongT wh, const ulongT whd=0) const {\n      cimg::unused(wh,whd);\n      return (*this)(x,y,z,c);\n    }\n#else\n    T& operator()(const unsigned int x) {\n      return _data[x];\n    }\n\n    const T& operator()(const unsigned int x) const {\n      return _data[x];\n    }\n\n    T& operator()(const unsigned int x, const unsigned int y) {\n      return _data[x + y*_width];\n    }\n\n    const T& operator()(const unsigned int x, const unsigned int y) const {\n      return _data[x + y*_width];\n    }\n\n    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) {\n      return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height];\n   }\n\n    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) const {\n      return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height];\n    }\n\n    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) {\n      return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth];\n    }\n\n    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) const {\n      return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth];\n    }\n\n    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int,\n                  const ulongT wh) {\n      return _data[x + y*_width + z*wh];\n    }\n\n    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int,\n                        const ulongT wh) const {\n      return _data[x + y*_width + z*wh];\n    }\n\n    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,\n                  const ulongT wh, const ulongT whd) {\n      return _data[x + y*_width + z*wh + c*whd];\n    }\n\n    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,\n                        const ulongT wh, const ulongT whd) const {\n      return _data[x + y*_width + z*wh + c*whd];\n    }\n#endif\n\n    //! Implicitely cast an image into a \\c T*.\n    /**\n       Implicitely cast a \\c CImg<T> instance into a \\c T* or \\c const \\c T* pointer, whether the image instance\n       is \\e const or not. The returned pointer points on the first value of the image pixel buffer.\n       \\note\n       - It simply returns the pointer data() to the pixel buffer.\n       - This implicit conversion is convenient to test the empty state of images (data() being \\c 0 in this case), e.g.\n       \\code\n       CImg<float> img1(100,100), img2; // 'img1' is a 100x100 image, 'img2' is an empty image.\n       if (img1) {                      // Test succeeds, 'img1' is not an empty image.\n         if (!img2) {                   // Test succeeds, 'img2' is an empty image.\n           std::printf(\"'img1' is not empty, 'img2' is empty.\");\n         }\n       }\n       \\endcode\n       - It also allows to use brackets to access pixel values, without need for a \\c CImg<T>::operator[](), e.g.\n       \\code\n       CImg<float> img(100,100);\n       const float value = img[99]; // Access to value of the last pixel on the first row.\n       img[510] = 255;              // Set pixel value at (10,5).\n       \\endcode\n    **/\n    operator T*() {\n      return _data;\n    }\n\n    //! Implicitely cast an image into a \\c T* \\const.\n    operator const T*() const {\n      return _data;\n    }\n\n    //! Assign a value to all image pixels.\n    /**\n       Assign specified \\c value to each pixel value of the image instance.\n       \\param value Value that will be assigned to image pixels.\n       \\note\n       - The image size is never modified.\n       - The \\c value may be casted to pixel type \\c T if necessary.\n       \\par Example\n       \\code\n       CImg<char> img(100,100); // Declare image (with garbage values).\n       img = 0;                 // Set all pixel values to '0'.\n       img = 1.2;               // Set all pixel values to '1' (cast of '1.2' as a 'char').\n       \\endcode\n    **/\n    CImg<T>& operator=(const T& value) {\n      return fill(value);\n    }\n\n    //! Assign pixels values from a specified expression.\n    /**\n       Initialize all pixel values from the specified string \\c expression.\n       \\param expression Value string describing the way pixel values are set.\n       \\note\n       - String parameter \\c expression may describe different things:\n         - If \\c expression is a list of values (as in \\c \"1,2,3,8,3,2\"), or a formula (as in \\c \"(x*y)%255\"),\n           the pixel values are set from specified \\c expression and the image size is not modified.\n         - If \\c expression is a filename (as in \\c \"reference.jpg\"), the corresponding image file is loaded and\n           replace the image instance. The image size is modified if necessary.\n       \\par Example\n       \\code\n       CImg<float> img1(100,100), img2(img1), img3(img1); // Declare three 100x100 scalar images with unitialized pixel values.\n       img1 = \"0,50,100,150,200,250,200,150,100,50\";      // Set pixel values of 'img1' from a value sequence.\n       img2 = \"10*((x*y)%25)\";                            // Set pixel values of 'img2' from a formula.\n       img3 = \"reference.jpg\";                            // Set pixel values of 'img3' from a file (image size is modified).\n       (img1,img2,img3).display();\n       \\endcode\n       \\image html ref_operator_eq.jpg\n    **/\n    CImg<T>& operator=(const char *const expression) {\n      const unsigned int omode = cimg::exception_mode();\n      cimg::exception_mode(0);\n      try {\n        _fill(expression,true,true,0,0,\"operator=\",0);\n      } catch (CImgException&) {\n        cimg::exception_mode(omode);\n        load(expression);\n      }\n      cimg::exception_mode(omode);\n      return *this;\n    }\n\n    //! Copy an image into the current image instance.\n    /**\n       Similar to the in-place copy constructor assign(const CImg<t>&).\n    **/\n    template<typename t>\n    CImg<T>& operator=(const CImg<t>& img) {\n      return assign(img);\n    }\n\n    //! Copy an image into the current image instance \\specialization.\n    CImg<T>& operator=(const CImg<T>& img) {\n      return assign(img);\n    }\n\n    //! Copy the content of a display window to the current image instance.\n    /**\n       Similar to assign(const CImgDisplay&).\n    **/\n    CImg<T>& operator=(const CImgDisplay& disp) {\n      disp.snapshot(*this);\n      return *this;\n    }\n\n    //! In-place addition operator.\n    /**\n       Add specified \\c value to all pixels of an image instance.\n       \\param value Value to add.\n       \\note\n       - Resulting pixel values are casted to fit the pixel type \\c T.\n         For instance, adding \\c 0.2 to a \\c CImg<char> is possible but does nothing indeed.\n       - Overflow values are treated as with standard C++ numeric types. For instance,\n       \\code\n       CImg<unsigned char> img(100,100,1,1,255); // Construct a 100x100 image with pixel values '255'.\n       img+=1;                                   // Add '1' to each pixels -> Overflow.\n       // here all pixels of image 'img' are equal to '0'.\n       \\endcode\n       - To prevent value overflow, you may want to consider pixel type \\c T as \\c float or \\c double,\n         and use cut() after addition.\n       \\par Example\n       \\code\n       CImg<unsigned char> img1(\"reference.jpg\");          // Load a 8-bits RGB image (values in [0,255]).\n       CImg<float> img2(img1);                             // Construct a float-valued copy of 'img1'.\n       img2+=100;                                          // Add '100' to pixel values -> goes out of [0,255] but no problems with floats.\n       img2.cut(0,255);                                    // Cut values in [0,255] to fit the 'unsigned char' constraint.\n       img1 = img2;                                        // Rewrite safe result in 'unsigned char' version 'img1'.\n       const CImg<unsigned char> img3 = (img1 + 100).cut(0,255); // Do the same in a more simple and elegant way.\n       (img1,img2,img3).display();\n       \\endcode\n       \\image html ref_operator_plus.jpg\n     **/\n    template<typename t>\n    CImg<T>& operator+=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=524288)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd + value);\n      return *this;\n    }\n\n    //! In-place addition operator.\n    /**\n       Add values to image pixels, according to the specified string \\c expression.\n       \\param expression Value string describing the way pixel values are added.\n       \\note\n       - Similar to operator=(const char*), except that it adds values to the pixels of the current image instance,\n         instead of assigning them.\n    **/\n    CImg<T>& operator+=(const char *const expression) {\n      return *this+=(+*this)._fill(expression,true,true,0,0,\"operator+=\",this);\n    }\n\n    //! In-place addition operator.\n    /**\n       Add values to image pixels, according to the values of the input image \\c img.\n       \\param img Input image to add.\n       \\note\n       - The size of the image instance is never modified.\n       - It is not mandatory that input image \\c img has the same size as the image instance.\n         If less values are available in \\c img, then the values are added periodically. For instance, adding one\n         WxH scalar image (spectrum() equal to \\c 1) to one WxH color image (spectrum() equal to \\c 3)\n         means each color channel will be incremented with the same values at the same locations.\n       \\par Example\n       \\code\n       CImg<float> img1(\"reference.jpg\");                                   // Load a RGB color image (img1.spectrum()==3)\n       const CImg<float> img2(img1.width(),img.height(),1,1,\"255*(x/w)^2\"); // Construct a scalar shading (img2.spectrum()==1).\n       img1+=img2;                                                          // Add shading to each channel of 'img1'.\n       img1.cut(0,255);                                                     // Prevent [0,255] overflow.\n       (img2,img1).display();\n       \\endcode\n       \\image html ref_operator_plus1.jpg\n    **/\n    template<typename t>\n    CImg<T>& operator+=(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return *this+=+img;\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)(*ptrd + *(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd + *(ptrs++));\n      }\n      return *this;\n    }\n\n    //! In-place increment operator (prefix).\n    /**\n       Add \\c 1 to all image pixels, and return a reference to the current incremented image instance.\n       \\note\n       - Writing \\c ++img is equivalent to \\c img+=1.\n     **/\n    CImg<T>& operator++() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=524288)\n#endif\n      cimg_rof(*this,ptrd,T) ++*ptrd;\n      return *this;\n    }\n\n    //! In-place increment operator (postfix).\n    /**\n       Add \\c 1 to all image pixels, and return a new copy of the initial (pre-incremented) image instance.\n       \\note\n       - Use the prefixed version operator++() if you don't need a copy of the initial\n         (pre-incremented) image instance, since a useless image copy may be expensive in terms of memory usage.\n     **/\n    CImg<T> operator++(int) {\n      const CImg<T> copy(*this,false);\n      ++*this;\n      return copy;\n    }\n\n    //! Return a non-shared copy of the image instance.\n    /**\n       \\note\n       - Use this operator to ensure you get a non-shared copy of an image instance with same pixel type \\c T.\n         Indeed, the usual copy constructor CImg<T>(const CImg<T>&) returns a shared copy of a shared input image,\n         and it may be not desirable to work on a regular copy (e.g. for a resize operation) if you have no\n         information about the shared state of the input image.\n       - Writing \\c (+img) is equivalent to \\c CImg<T>(img,false).\n    **/\n    CImg<T> operator+() const {\n      return CImg<T>(*this,false);\n    }\n\n    //! Addition operator.\n    /**\n       Similar to operator+=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n     **/\n    template<typename t>\n    CImg<_cimg_Tt> operator+(const t value) const {\n      return CImg<_cimg_Tt>(*this,false)+=value;\n    }\n\n    //! Addition operator.\n    /**\n       Similar to operator+=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n     **/\n    CImg<Tfloat> operator+(const char *const expression) const {\n      return CImg<Tfloat>(*this,false)+=expression;\n    }\n\n    //! Addition operator.\n    /**\n       Similar to operator+=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n     **/\n    template<typename t>\n    CImg<_cimg_Tt> operator+(const CImg<t>& img) const {\n      return CImg<_cimg_Tt>(*this,false)+=img;\n    }\n\n    //! In-place substraction operator.\n    /**\n       Similar to operator+=(const t), except that it performs a substraction instead of an addition.\n     **/\n    template<typename t>\n    CImg<T>& operator-=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=524288)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd - value);\n      return *this;\n    }\n\n    //! In-place substraction operator.\n    /**\n       Similar to operator+=(const char*), except that it performs a substraction instead of an addition.\n     **/\n    CImg<T>& operator-=(const char *const expression) {\n      return *this-=(+*this)._fill(expression,true,true,0,0,\"operator-=\",this);\n    }\n\n    //! In-place substraction operator.\n    /**\n       Similar to operator+=(const CImg<t>&), except that it performs a substraction instead of an addition.\n     **/\n    template<typename t>\n    CImg<T>& operator-=(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return *this-=+img;\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)(*ptrd - *(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd - *(ptrs++));\n      }\n      return *this;\n    }\n\n    //! In-place decrement operator (prefix).\n    /**\n       Similar to operator++(), except that it performs a decrement instead of an increment.\n    **/\n    CImg<T>& operator--() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=524288)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = *ptrd - (T)1;\n      return *this;\n    }\n\n    //! In-place decrement operator (postfix).\n    /**\n       Similar to operator++(int), except that it performs a decrement instead of an increment.\n    **/\n    CImg<T> operator--(int) {\n      const CImg<T> copy(*this,false);\n      --*this;\n      return copy;\n    }\n\n    //! Replace each pixel by its opposite value.\n    /**\n       \\note\n       - If the computed opposite values are out-of-range, they are treated as with standard C++ numeric types.\n         For instance, the \\c unsigned \\c char opposite of \\c 1 is \\c 255.\n       \\par Example\n       \\code\n       const CImg<unsigned char>\n         img1(\"reference.jpg\"),   // Load a RGB color image.\n         img2 = -img1;            // Compute its opposite (in 'unsigned char').\n       (img1,img2).display();\n       \\endcode\n       \\image html ref_operator_minus.jpg\n     **/\n    CImg<T> operator-() const {\n      return CImg<T>(_width,_height,_depth,_spectrum,(T)0)-=*this;\n    }\n\n    //! Substraction operator.\n    /**\n       Similar to operator-=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    template<typename t>\n    CImg<_cimg_Tt> operator-(const t value) const {\n      return CImg<_cimg_Tt>(*this,false)-=value;\n    }\n\n    //! Substraction operator.\n    /**\n       Similar to operator-=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    CImg<Tfloat> operator-(const char *const expression) const {\n      return CImg<Tfloat>(*this,false)-=expression;\n    }\n\n    //! Substraction operator.\n    /**\n       Similar to operator-=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    template<typename t>\n    CImg<_cimg_Tt> operator-(const CImg<t>& img) const {\n      return CImg<_cimg_Tt>(*this,false)-=img;\n    }\n\n    //! In-place multiplication operator.\n    /**\n       Similar to operator+=(const t), except that it performs a multiplication instead of an addition.\n     **/\n    template<typename t>\n    CImg<T>& operator*=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=262144)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd * value);\n      return *this;\n    }\n\n    //! In-place multiplication operator.\n    /**\n       Similar to operator+=(const char*), except that it performs a multiplication instead of an addition.\n     **/\n    CImg<T>& operator*=(const char *const expression) {\n      return mul((+*this)._fill(expression,true,true,0,0,\"operator*=\",this));\n    }\n\n    //! In-place multiplication operator.\n    /**\n       Replace the image instance by the matrix multiplication between the image instance and the specified matrix\n       \\c img.\n       \\param img Second operand of the matrix multiplication.\n       \\note\n       - It does \\e not compute a pointwise multiplication between two images. For this purpose, use\n         mul(const CImg<t>&) instead.\n       - The size of the image instance can be modified by this operator.\n       \\par Example\n       \\code\n       CImg<float> A(2,2,1,1, 1,2,3,4);   // Construct 2x2 matrix A = [1,2;3,4].\n       const CImg<float> X(1,2,1,1, 1,2); // Construct 1x2 vector X = [1;2].\n       A*=X;                              // Assign matrix multiplication A*X to 'A'.\n       // 'A' is now a 1x2 vector whose values are [5;11].\n       \\endcode\n    **/\n    template<typename t>\n    CImg<T>& operator*=(const CImg<t>& img) {\n      return ((*this)*img).move_to(*this);\n    }\n\n    //! Multiplication operator.\n    /**\n       Similar to operator*=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    template<typename t>\n    CImg<_cimg_Tt> operator*(const t value) const {\n      return CImg<_cimg_Tt>(*this,false)*=value;\n    }\n\n    //! Multiplication operator.\n    /**\n       Similar to operator*=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    CImg<Tfloat> operator*(const char *const expression) const {\n      return CImg<Tfloat>(*this,false)*=expression;\n    }\n\n    //! Multiplication operator.\n    /**\n       Similar to operator*=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    template<typename t>\n    CImg<_cimg_Tt> operator*(const CImg<t>& img) const {\n      if (_width!=img._height || _depth!=1 || _spectrum!=1)\n        throw CImgArgumentException(_cimg_instance\n                                    \"operator*(): Invalid multiplication of instance by specified \"\n                                    \"matrix (%u,%u,%u,%u,%p)\",\n                                    cimg_instance,\n                                    img._width,img._height,img._depth,img._spectrum,img._data);\n      CImg<_cimg_Tt> res(img._width,_height);\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) cimg_openmp_if(size()>1024 && img.size()>1024)\n      cimg_forXY(res,i,j) {\n        _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); res(i,j) = (_cimg_Tt)value;\n      }\n#else\n      _cimg_Tt *ptrd = res._data;\n      cimg_forXY(res,i,j) {\n        _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); *(ptrd++) = (_cimg_Tt)value;\n      }\n#endif\n      return res;\n    }\n\n    //! In-place division operator.\n    /**\n       Similar to operator+=(const t), except that it performs a division instead of an addition.\n     **/\n    template<typename t>\n    CImg<T>& operator/=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd / value);\n      return *this;\n    }\n\n    //! In-place division operator.\n    /**\n       Similar to operator+=(const char*), except that it performs a division instead of an addition.\n     **/\n    CImg<T>& operator/=(const char *const expression) {\n      return div((+*this)._fill(expression,true,true,0,0,\"operator/=\",this));\n    }\n\n    //! In-place division operator.\n    /**\n       Replace the image instance by the (right) matrix division between the image instance and the specified\n       matrix \\c img.\n       \\param img Second operand of the matrix division.\n       \\note\n       - It does \\e not compute a pointwise division between two images. For this purpose, use\n         div(const CImg<t>&) instead.\n       - It returns the matrix operation \\c A*inverse(img).\n       - The size of the image instance can be modified by this operator.\n     **/\n    template<typename t>\n    CImg<T>& operator/=(const CImg<t>& img) {\n      return (*this*img.get_invert()).move_to(*this);\n    }\n\n    //! Division operator.\n    /**\n       Similar to operator/=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    template<typename t>\n    CImg<_cimg_Tt> operator/(const t value) const {\n      return CImg<_cimg_Tt>(*this,false)/=value;\n    }\n\n    //! Division operator.\n    /**\n       Similar to operator/=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    CImg<Tfloat> operator/(const char *const expression) const {\n      return CImg<Tfloat>(*this,false)/=expression;\n    }\n\n    //! Division operator.\n    /**\n       Similar to operator/=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    template<typename t>\n    CImg<_cimg_Tt> operator/(const CImg<t>& img) const {\n      return (*this)*img.get_invert();\n    }\n\n    //! In-place modulo operator.\n    /**\n       Similar to operator+=(const t), except that it performs a modulo operation instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator%=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=16384)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)value);\n      return *this;\n    }\n\n    //! In-place modulo operator.\n    /**\n       Similar to operator+=(const char*), except that it performs a modulo operation instead of an addition.\n    **/\n    CImg<T>& operator%=(const char *const expression) {\n      return *this%=(+*this)._fill(expression,true,true,0,0,\"operator%=\",this);\n    }\n\n    //! In-place modulo operator.\n    /**\n       Similar to operator+=(const CImg<t>&), except that it performs a modulo operation instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator%=(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return *this%=+img;\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = cimg::mod(*ptrd,(T)*(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = cimg::mod(*ptrd,(T)*(ptrs++));\n      }\n      return *this;\n    }\n\n    //! Modulo operator.\n    /**\n       Similar to operator%=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    template<typename t>\n    CImg<_cimg_Tt> operator%(const t value) const {\n      return CImg<_cimg_Tt>(*this,false)%=value;\n    }\n\n    //! Modulo operator.\n    /**\n       Similar to operator%=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    CImg<Tfloat> operator%(const char *const expression) const {\n      return CImg<Tfloat>(*this,false)%=expression;\n    }\n\n    //! Modulo operator.\n    /**\n       Similar to operator%=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image may be a superset of the initial pixel type \\c T, if necessary.\n    **/\n    template<typename t>\n    CImg<_cimg_Tt> operator%(const CImg<t>& img) const {\n      return CImg<_cimg_Tt>(*this,false)%=img;\n    }\n\n    //! In-place bitwise AND operator.\n    /**\n       Similar to operator+=(const t), except that it performs a bitwise AND operation instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator&=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd & (ulongT)value);\n      return *this;\n    }\n\n    //! In-place bitwise AND operator.\n    /**\n       Similar to operator+=(const char*), except that it performs a bitwise AND operation instead of an addition.\n    **/\n    CImg<T>& operator&=(const char *const expression) {\n      return *this&=(+*this)._fill(expression,true,true,0,0,\"operator&=\",this);\n    }\n\n    //! In-place bitwise AND operator.\n    /**\n       Similar to operator+=(const CImg<t>&), except that it performs a bitwise AND operation instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator&=(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return *this&=+img;\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)((ulongT)*ptrd & (ulongT)*(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((ulongT)*ptrd & (ulongT)*(ptrs++));\n      }\n      return *this;\n    }\n\n    //! Bitwise AND operator.\n    /**\n       Similar to operator&=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator&(const t value) const {\n      return (+*this)&=value;\n    }\n\n    //! Bitwise AND operator.\n    /**\n       Similar to operator&=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    CImg<T> operator&(const char *const expression) const {\n      return (+*this)&=expression;\n    }\n\n    //! Bitwise AND operator.\n    /**\n       Similar to operator&=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator&(const CImg<t>& img) const {\n      return (+*this)&=img;\n    }\n\n    //! In-place bitwise OR operator.\n    /**\n       Similar to operator+=(const t), except that it performs a bitwise OR operation instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator|=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd | (ulongT)value);\n      return *this;\n    }\n\n    //! In-place bitwise OR operator.\n    /**\n       Similar to operator+=(const char*), except that it performs a bitwise OR operation instead of an addition.\n    **/\n    CImg<T>& operator|=(const char *const expression) {\n      return *this|=(+*this)._fill(expression,true,true,0,0,\"operator|=\",this);\n    }\n\n    //! In-place bitwise OR operator.\n    /**\n       Similar to operator+=(const CImg<t>&), except that it performs a bitwise OR operation instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator|=(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return *this|=+img;\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)((ulongT)*ptrd | (ulongT)*(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((ulongT)*ptrd | (ulongT)*(ptrs++));\n      }\n      return *this;\n    }\n\n    //! Bitwise OR operator.\n    /**\n       Similar to operator|=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator|(const t value) const {\n      return (+*this)|=value;\n    }\n\n    //! Bitwise OR operator.\n    /**\n       Similar to operator|=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    CImg<T> operator|(const char *const expression) const {\n      return (+*this)|=expression;\n    }\n\n    //! Bitwise OR operator.\n    /**\n       Similar to operator|=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator|(const CImg<t>& img) const {\n      return (+*this)|=img;\n    }\n\n    //! In-place bitwise XOR operator.\n    /**\n       Similar to operator+=(const t), except that it performs a bitwise XOR operation instead of an addition.\n       \\warning\n       - It does \\e not compute the \\e power of pixel values. For this purpose, use pow(const t) instead.\n    **/\n    template<typename t>\n    CImg<T>& operator^=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd ^ (ulongT)value);\n      return *this;\n    }\n\n    //! In-place bitwise XOR operator.\n    /**\n       Similar to operator+=(const char*), except that it performs a bitwise XOR operation instead of an addition.\n       \\warning\n       - It does \\e not compute the \\e power of pixel values. For this purpose, use pow(const char*) instead.\n    **/\n    CImg<T>& operator^=(const char *const expression) {\n      return *this^=(+*this)._fill(expression,true,true,0,0,\"operator^=\",this);\n    }\n\n    //! In-place bitwise XOR operator.\n    /**\n       Similar to operator+=(const CImg<t>&), except that it performs a bitwise XOR operation instead of an addition.\n       \\warning\n       - It does \\e not compute the \\e power of pixel values. For this purpose, use pow(const CImg<t>&) instead.\n    **/\n    template<typename t>\n    CImg<T>& operator^=(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return *this^=+img;\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)((ulongT)*ptrd ^ (ulongT)*(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((ulongT)*ptrd ^ (ulongT)*(ptrs++));\n      }\n      return *this;\n    }\n\n    //! Bitwise XOR operator.\n    /**\n       Similar to operator^=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator^(const t value) const {\n      return (+*this)^=value;\n    }\n\n    //! Bitwise XOR operator.\n    /**\n       Similar to operator^=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    CImg<T> operator^(const char *const expression) const {\n      return (+*this)^=expression;\n    }\n\n    //! Bitwise XOR operator.\n    /**\n       Similar to operator^=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator^(const CImg<t>& img) const {\n      return (+*this)^=img;\n    }\n\n    //! In-place bitwise left shift operator.\n    /**\n       Similar to operator+=(const t), except that it performs a bitwise left shift instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator<<=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=65536)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)(((longT)*ptrd) << (int)value);\n      return *this;\n    }\n\n    //! In-place bitwise left shift operator.\n    /**\n       Similar to operator+=(const char*), except that it performs a bitwise left shift instead of an addition.\n    **/\n    CImg<T>& operator<<=(const char *const expression) {\n      return *this<<=(+*this)._fill(expression,true,true,0,0,\"operator<<=\",this);\n    }\n\n    //! In-place bitwise left shift operator.\n    /**\n       Similar to operator+=(const CImg<t>&), except that it performs a bitwise left shift instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator<<=(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return *this^=+img;\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)((longT)*ptrd << (int)*(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((longT)*ptrd << (int)*(ptrs++));\n      }\n      return *this;\n    }\n\n    //! Bitwise left shift operator.\n    /**\n       Similar to operator<<=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator<<(const t value) const {\n      return (+*this)<<=value;\n    }\n\n    //! Bitwise left shift operator.\n    /**\n       Similar to operator<<=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    CImg<T> operator<<(const char *const expression) const {\n      return (+*this)<<=expression;\n    }\n\n    //! Bitwise left shift operator.\n    /**\n       Similar to operator<<=(const CImg<t>&), except that it returns a new image instance instead of\n       operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator<<(const CImg<t>& img) const {\n      return (+*this)<<=img;\n    }\n\n    //! In-place bitwise right shift operator.\n    /**\n       Similar to operator+=(const t), except that it performs a bitwise right shift instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator>>=(const t value) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=65536)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)(((longT)*ptrd) >> (int)value);\n      return *this;\n    }\n\n    //! In-place bitwise right shift operator.\n    /**\n       Similar to operator+=(const char*), except that it performs a bitwise right shift instead of an addition.\n    **/\n    CImg<T>& operator>>=(const char *const expression) {\n      return *this>>=(+*this)._fill(expression,true,true,0,0,\"operator>>=\",this);\n    }\n\n    //! In-place bitwise right shift operator.\n    /**\n       Similar to operator+=(const CImg<t>&), except that it performs a bitwise right shift instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& operator>>=(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return *this^=+img;\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)((longT)*ptrd >> (int)*(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((longT)*ptrd >> (int)*(ptrs++));\n      }\n      return *this;\n    }\n\n    //! Bitwise right shift operator.\n    /**\n       Similar to operator>>=(const t), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator>>(const t value) const {\n      return (+*this)>>=value;\n    }\n\n    //! Bitwise right shift operator.\n    /**\n       Similar to operator>>=(const char*), except that it returns a new image instance instead of operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    CImg<T> operator>>(const char *const expression) const {\n      return (+*this)>>=expression;\n    }\n\n    //! Bitwise right shift operator.\n    /**\n       Similar to operator>>=(const CImg<t>&), except that it returns a new image instance instead of\n       operating in-place.\n       The pixel type of the returned image is \\c T.\n    **/\n    template<typename t>\n    CImg<T> operator>>(const CImg<t>& img) const {\n      return (+*this)>>=img;\n    }\n\n    //! Bitwise inversion operator.\n    /**\n       Similar to operator-(), except that it compute the bitwise inverse instead of the opposite value.\n    **/\n    CImg<T> operator~() const {\n      CImg<T> res(_width,_height,_depth,_spectrum);\n      const T *ptrs = _data;\n      cimg_for(res,ptrd,T) { const ulongT value = (ulongT)*(ptrs++); *ptrd = (T)~value; }\n      return res;\n    }\n\n    //! Test if all pixels of an image have the same value.\n    /**\n       Return \\c true is all pixels of the image instance are equal to the specified \\c value.\n       \\param value Reference value to compare with.\n    **/\n    template<typename t>\n    bool operator==(const t value) const {\n      if (is_empty()) return false;\n      typedef _cimg_Tt Tt;\n      bool is_equal = true;\n      for (T *ptrd = _data + size(); is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)value)) {}\n      return is_equal;\n    }\n\n    //! Test if all pixel values of an image follow a specified expression.\n    /**\n       Return \\c true is all pixels of the image instance are equal to the specified \\c expression.\n       \\param expression Value string describing the way pixel values are compared.\n    **/\n    bool operator==(const char *const expression) const {\n      return *this==(+*this)._fill(expression,true,true,0,0,\"operator==\",this);\n    }\n\n    //! Test if two images have the same size and values.\n    /**\n       Return \\c true if the image instance and the input image \\c img have the same dimensions and pixel values,\n       and \\c false otherwise.\n       \\param img Input image to compare with.\n       \\note\n       - The pixel buffer pointers data() of the two compared images do not have to be the same for operator==()\n         to return \\c true.\n         Only the dimensions and the pixel values matter. Thus, the comparison can be \\c true even for different\n         pixel types \\c T and \\c t.\n       \\par Example\n       \\code\n       const CImg<float> img1(1,3,1,1, 0,1,2); // Construct a 1x3 vector [0;1;2] (with 'float' pixel values).\n       const CImg<char> img2(1,3,1,1, 0,1,2);  // Construct a 1x3 vector [0;1;2] (with 'char' pixel values).\n       if (img1==img2) {                       // Test succeeds, image dimensions and values are the same.\n         std::printf(\"'img1' and 'img2' have same dimensions and values.\");\n       }\n       \\endcode\n    **/\n    template<typename t>\n    bool operator==(const CImg<t>& img) const {\n      typedef _cimg_Tt Tt;\n      const ulongT siz = size();\n      bool is_equal = true;\n      if (siz!=img.size()) return false;\n      t *ptrs = img._data + siz;\n      for (T *ptrd = _data + siz; is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)*(--ptrs))) {}\n      return is_equal;\n    }\n\n    //! Test if pixels of an image are all different from a value.\n    /**\n       Return \\c true is all pixels of the image instance are different than the specified \\c value.\n       \\param value Reference value to compare with.\n    **/\n    template<typename t>\n    bool operator!=(const t value) const {\n      return !((*this)==value);\n    }\n\n    //! Test if all pixel values of an image are different from a specified expression.\n    /**\n       Return \\c true is all pixels of the image instance are different to the specified \\c expression.\n       \\param expression Value string describing the way pixel values are compared.\n    **/\n    bool operator!=(const char *const expression) const {\n      return !((*this)==expression);\n    }\n\n    //! Test if two images have different sizes or values.\n    /**\n       Return \\c true if the image instance and the input image \\c img have different dimensions or pixel values,\n       and \\c false otherwise.\n       \\param img Input image to compare with.\n       \\note\n       - Writing \\c img1!=img2 is equivalent to \\c !(img1==img2).\n    **/\n    template<typename t>\n    bool operator!=(const CImg<t>& img) const {\n      return !((*this)==img);\n    }\n\n    //! Construct an image list from two images.\n    /**\n       Return a new list of image (\\c CImgList instance) containing exactly two elements:\n         - A copy of the image instance, at position [\\c 0].\n         - A copy of the specified image \\c img, at position [\\c 1].\n\n       \\param img Input image that will be the second image of the resulting list.\n       \\note\n       - The family of operator,() is convenient to easily create list of images, but it is also \\e quite \\e slow\n         in practice (see warning below).\n       - Constructed lists contain no shared images. If image instance or input image \\c img are shared, they are\n         inserted as new non-shared copies in the resulting list.\n       - The pixel type of the returned list may be a superset of the initial pixel type \\c T, if necessary.\n       \\warning\n       - Pipelining operator,() \\c N times will perform \\c N copies of the entire content of a (growing) image list.\n         This may become very expensive in terms of speed and used memory. You should avoid using this technique to\n         build a new CImgList instance from several images, if you are seeking for performance.\n         Fast insertions of images in an image list are possible with\n         CImgList<T>::insert(const CImg<t>&,unsigned int,bool) or move_to(CImgList<t>&,unsigned int).\n       \\par Example\n       \\code\n       const CImg<float>\n          img1(\"reference.jpg\"),\n          img2 = img1.get_mirror('x'),\n          img3 = img2.get_blur(5);\n       const CImgList<float> list = (img1,img2); // Create list of two elements from 'img1' and 'img2'.\n       (list,img3).display();                    // Display image list containing copies of 'img1','img2' and 'img3'.\n       \\endcode\n       \\image html ref_operator_comma.jpg\n    **/\n    template<typename t>\n    CImgList<_cimg_Tt> operator,(const CImg<t>& img) const {\n      return CImgList<_cimg_Tt>(*this,img);\n    }\n\n    //! Construct an image list from image instance and an input image list.\n    /**\n       Return a new list of images (\\c CImgList instance) containing exactly \\c list.size() \\c + \\c 1 elements:\n         - A copy of the image instance, at position [\\c 0].\n         - A copy of the specified image list \\c list, from positions [\\c 1] to [\\c list.size()].\n\n       \\param list Input image list that will be appended to the image instance.\n       \\note\n       - Similar to operator,(const CImg<t>&) const, except that it takes an image list as an argument.\n    **/\n    template<typename t>\n    CImgList<_cimg_Tt> operator,(const CImgList<t>& list) const {\n      return CImgList<_cimg_Tt>(list,false).insert(*this,0);\n    }\n\n    //! Split image along specified axis.\n    /**\n       Return a new list of images (\\c CImgList instance) containing the splitted components\n       of the instance image along the specified axis.\n       \\param axis Splitting axis (can be '\\c x','\\c y','\\c z' or '\\c c')\n       \\note\n       - Similar to get_split(char,int) const, with default second argument.\n       \\par Example\n       \\code\n       const CImg<unsigned char> img(\"reference.jpg\"); // Load a RGB color image.\n       const CImgList<unsigned char> list = (img<'c'); // Get a list of its three R,G,B channels.\n       (img,list).display();\n       \\endcode\n       \\image html ref_operator_less.jpg\n    **/\n    CImgList<T> operator<(const char axis) const {\n      return get_split(axis);\n    }\n\n    //@}\n    //-------------------------------------\n    //\n    //! \\name Instance Characteristics\n    //@{\n    //-------------------------------------\n\n    //! Return the type of image pixel values as a C string.\n    /**\n       Return a \\c char* string containing the usual type name of the image pixel values\n       (i.e. a stringified version of the template parameter \\c T).\n       \\note\n       - The returned string may contain spaces (as in \\c \"unsigned char\").\n       - If the pixel type \\c T does not correspond to a registered type, the string <tt>\"unknown\"</tt> is returned.\n    **/\n    static const char* pixel_type() {\n      return cimg::type<T>::string();\n    }\n\n    //! Return the number of image columns.\n    /**\n       Return the image width, i.e. the image dimension along the X-axis.\n       \\note\n       - The width() of an empty image is equal to \\c 0.\n       - width() is typically equal to \\c 1 when considering images as \\e vectors for matrix calculations.\n       - width() returns an \\c int, although the image width is internally stored as an \\c unsigned \\c int.\n         Using an \\c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving\n         \\c unsigned \\c int variables.\n         Access to the initial \\c unsigned \\c int variable is possible (though not recommended) by\n         <tt>(*this)._width</tt>.\n    **/\n    int width() const {\n      return (int)_width;\n    }\n\n    //! Return the number of image rows.\n    /**\n       Return the image height, i.e. the image dimension along the Y-axis.\n       \\note\n       - The height() of an empty image is equal to \\c 0.\n       - height() returns an \\c int, although the image height is internally stored as an \\c unsigned \\c int.\n         Using an \\c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving\n         \\c unsigned \\c int variables.\n         Access to the initial \\c unsigned \\c int variable is possible (though not recommended) by\n         <tt>(*this)._height</tt>.\n    **/\n    int height() const {\n      return (int)_height;\n    }\n\n    //! Return the number of image slices.\n    /**\n       Return the image depth, i.e. the image dimension along the Z-axis.\n       \\note\n       - The depth() of an empty image is equal to \\c 0.\n       - depth() is typically equal to \\c 1 when considering usual 2d images. When depth()\\c > \\c 1, the image\n         is said to be \\e volumetric.\n       - depth() returns an \\c int, although the image depth is internally stored as an \\c unsigned \\c int.\n         Using an \\c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving\n         \\c unsigned \\c int variables.\n         Access to the initial \\c unsigned \\c int variable is possible (though not recommended) by\n         <tt>(*this)._depth</tt>.\n    **/\n    int depth() const {\n      return (int)_depth;\n    }\n\n    //! Return the number of image channels.\n    /**\n       Return the number of image channels, i.e. the image dimension along the C-axis.\n       \\note\n       - The spectrum() of an empty image is equal to \\c 0.\n       - spectrum() is typically equal to \\c 1 when considering scalar-valued images, to \\c 3\n         for RGB-coded color images, and to \\c 4 for RGBA-coded color images (with alpha-channel).\n         The number of channels of an image instance is not limited. The meaning of the pixel values is not linked\n         up to the number of channels (e.g. a 4-channel image may indifferently stands for a RGBA or CMYK color image).\n       - spectrum() returns an \\c int, although the image spectrum is internally stored as an \\c unsigned \\c int.\n         Using an \\c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving\n         \\c unsigned \\c int variables.\n         Access to the initial \\c unsigned \\c int variable is possible (though not recommended) by\n         <tt>(*this)._spectrum</tt>.\n    **/\n    int spectrum() const {\n      return (int)_spectrum;\n    }\n\n    //! Return the total number of pixel values.\n    /**\n       Return <tt>width()*\\ref height()*\\ref depth()*\\ref spectrum()</tt>,\n       i.e. the total number of values of type \\c T in the pixel buffer of the image instance.\n       \\note\n       - The size() of an empty image is equal to \\c 0.\n       - The allocated memory size for a pixel buffer of a non-shared \\c CImg<T> instance is equal to\n         <tt>size()*sizeof(T)</tt>.\n       \\par Example\n       \\code\n       const CImg<float> img(100,100,1,3);               // Construct new 100x100 color image.\n       if (img.size()==30000)                            // Test succeeds.\n         std::printf(\"Pixel buffer uses %lu bytes\",\n                     img.size()*sizeof(float));\n       \\endcode\n    **/\n    ulongT size() const {\n      return (ulongT)_width*_height*_depth*_spectrum;\n    }\n\n    //! Return a pointer to the first pixel value.\n    /**\n       Return a \\c T*, or a \\c const \\c T* pointer to the first value in the pixel buffer of the image instance,\n       whether the instance is \\c const or not.\n       \\note\n       - The data() of an empty image is equal to \\c 0 (null pointer).\n       - The allocated pixel buffer for the image instance starts from \\c data()\n         and goes to <tt>data()+\\ref size() - 1</tt> (included).\n       - To get the pointer to one particular location of the pixel buffer, use\n         data(unsigned int,unsigned int,unsigned int,unsigned int) instead.\n    **/\n    T* data() {\n      return _data;\n    }\n\n    //! Return a pointer to the first pixel value \\const.\n    const T* data() const {\n      return _data;\n    }\n\n    //! Return a pointer to a located pixel value.\n    /**\n       Return a \\c T*, or a \\c const \\c T* pointer to the value located at (\\c x,\\c y,\\c z,\\c c) in the pixel buffer\n       of the image instance,\n       whether the instance is \\c const or not.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note\n       - Writing \\c img.data(x,y,z,c) is equivalent to <tt>&(img(x,y,z,c))</tt>. Thus, this method has the same\n         properties as operator()(unsigned int,unsigned int,unsigned int,unsigned int).\n     **/\n#if cimg_verbosity>=3\n    T *data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) {\n      const ulongT off = (ulongT)offset(x,y,z,c);\n      if (off>=size())\n        cimg::warn(_cimg_instance\n                   \"data(): Invalid pointer request, at coordinates (%u,%u,%u,%u) [offset=%u].\",\n                   cimg_instance,\n                   x,y,z,c,off);\n      return _data + off;\n    }\n\n    //! Return a pointer to a located pixel value \\const.\n    const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const {\n      return const_cast<CImg<T>*>(this)->data(x,y,z,c);\n    }\n#else\n    T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) {\n      return _data + x + (ulongT)y*_width + (ulongT)z*_width*_height + (ulongT)c*_width*_height*_depth;\n    }\n\n    const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const {\n      return _data + x + (ulongT)y*_width + (ulongT)z*_width*_height + (ulongT)c*_width*_height*_depth;\n    }\n#endif\n\n    //! Return the offset to a located pixel value, with respect to the beginning of the pixel buffer.\n    /**\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note\n       - Writing \\c img.data(x,y,z,c) is equivalent to <tt>&(img(x,y,z,c)) - img.data()</tt>.\n         Thus, this method has the same properties as operator()(unsigned int,unsigned int,unsigned int,unsigned int).\n       \\par Example\n       \\code\n       const CImg<float> img(100,100,1,3);      // Define a 100x100 RGB-color image.\n       const long off = img.offset(10,10,0,2);  // Get the offset of the blue value of the pixel located at (10,10).\n       const float val = img[off];              // Get the blue value of this pixel.\n       \\endcode\n    **/\n    longT offset(const int x, const int y=0, const int z=0, const int c=0) const {\n      return x + (longT)y*_width + (longT)z*_width*_height + (longT)c*_width*_height*_depth;\n    }\n\n    //! Return a CImg<T>::iterator pointing to the first pixel value.\n    /**\n       \\note\n       - Equivalent to data().\n       - It has been mainly defined for compatibility with STL naming conventions.\n     **/\n    iterator begin() {\n      return _data;\n    }\n\n    //! Return a CImg<T>::iterator pointing to the first value of the pixel buffer \\const.\n    const_iterator begin() const {\n      return _data;\n    }\n\n    //! Return a CImg<T>::iterator pointing next to the last pixel value.\n    /**\n       \\note\n       - Writing \\c img.end() is equivalent to <tt>img.data() + img.size()</tt>.\n       - It has been mainly defined for compatibility with STL naming conventions.\n       \\warning\n       - The returned iterator actually points to a value located \\e outside the acceptable bounds of the pixel buffer.\n         Trying to read or write the content of the returned iterator will probably result in a crash.\n         Use it mainly as a strict upper bound for a CImg<T>::iterator.\n       \\par Example\n       \\code\n       CImg<float> img(100,100,1,3);                                     // Define a 100x100 RGB color image.\n       for (CImg<float>::iterator it = img.begin(); it<img.end(); ++it)  // 'img.end()' used here as an upper bound for the iterator.\n         *it = 0;\n       \\endcode\n    **/\n    iterator end() {\n      return _data + size();\n    }\n\n    //! Return a CImg<T>::iterator pointing next to the last pixel value \\const.\n    const_iterator end() const {\n      return _data + size();\n    }\n\n    //! Return a reference to the first pixel value.\n    /**\n       \\note\n       - Writing \\c img.front() is equivalent to <tt>img[0]</tt>, or <tt>img(0,0,0,0)</tt>.\n       - It has been mainly defined for compatibility with STL naming conventions.\n    **/\n    T& front() {\n      return *_data;\n    }\n\n    //! Return a reference to the first pixel value \\const.\n    const T& front() const {\n      return *_data;\n    }\n\n    //! Return a reference to the last pixel value.\n    /**\n       \\note\n       - Writing \\c img.end() is equivalent to <tt>img[img.size() - 1]</tt>, or\n         <tt>img(img.width() - 1,img.height() - 1,img.depth() - 1,img.spectrum() - 1)</tt>.\n       - It has been mainly defined for compatibility with STL naming conventions.\n    **/\n    T& back() {\n      return *(_data + size() - 1);\n    }\n\n    //! Return a reference to the last pixel value \\const.\n    const T& back() const {\n      return *(_data + size() - 1);\n    }\n\n    //! Access to a pixel value at a specified offset, using Dirichlet boundary conditions.\n    /**\n       Return a reference to the pixel value of the image instance located at a specified \\c offset,\n       or to a specified default value in case of out-of-bounds access.\n       \\param offset Offset to the desired pixel value.\n       \\param out_value Default value returned if \\c offset is outside image bounds.\n       \\note\n       - Writing \\c img.at(offset,out_value) is similar to <tt>img[offset]</tt>, except that if \\c offset\n         is outside bounds (e.g. \\c offset<0 or \\c offset>=img.size()), a reference to a value \\c out_value\n         is safely returned instead.\n       - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when\n         you are \\e not sure about the validity of the specified pixel offset.\n    **/\n    T& at(const int offset, const T& out_value) {\n      return (offset<0 || offset>=(int)size())?(cimg::temporary(out_value)=out_value):(*this)[offset];\n    }\n\n    //! Access to a pixel value at a specified offset, using Dirichlet boundary conditions \\const.\n    T at(const int offset, const T& out_value) const {\n      return (offset<0 || offset>=(int)size())?out_value:(*this)[offset];\n    }\n\n    //! Access to a pixel value at a specified offset, using Neumann boundary conditions.\n    /**\n       Return a reference to the pixel value of the image instance located at a specified \\c offset,\n       or to the nearest pixel location in the image instance in case of out-of-bounds access.\n       \\param offset Offset to the desired pixel value.\n       \\note\n       - Similar to at(int,const T), except that an out-of-bounds access returns the value of the\n         nearest pixel in the image instance, regarding the specified offset, i.e.\n         - If \\c offset<0, then \\c img[0] is returned.\n         - If \\c offset>=img.size(), then \\c img[img.size() - 1] is returned.\n       - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when\n         you are \\e not sure about the validity of the specified pixel offset.\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method \\c _at(int).\n     **/\n    T& at(const int offset) {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"at(): Empty instance.\",\n                                    cimg_instance);\n      return _at(offset);\n    }\n\n    T& _at(const int offset) {\n      const unsigned int siz = (unsigned int)size();\n      return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset];\n    }\n\n    //! Access to a pixel value at a specified offset, using Neumann boundary conditions \\const.\n    const T& at(const int offset) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"at(): Empty instance.\",\n                                    cimg_instance);\n      return _at(offset);\n    }\n\n    const T& _at(const int offset) const {\n      const unsigned int siz = (unsigned int)size();\n      return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset];\n    }\n\n    //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate.\n    /**\n       Return a reference to the pixel value of the image instance located at (\\c x,\\c y,\\c z,\\c c),\n       or to a specified default value in case of out-of-bounds access along the X-axis.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param out_value Default value returned if \\c (\\c x,\\c y,\\c z,\\c c) is outside image bounds.\n       \\note\n       - Similar to operator()(), except that an out-of-bounds access along the X-axis returns the specified value\n         \\c out_value.\n       - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when\n         you are \\e not sure about the validity of the specified pixel coordinates.\n       \\warning\n       - There is \\e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.\n    **/\n    T& atX(const int x, const int y, const int z, const int c, const T& out_value) {\n      return (x<0 || x>=width())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);\n    }\n\n    //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate \\const.\n    T atX(const int x, const int y, const int z, const int c, const T& out_value) const {\n      return (x<0 || x>=width())?out_value:(*this)(x,y,z,c);\n    }\n\n    //! Access to a pixel value, using Neumann boundary conditions for the X-coordinate.\n    /**\n       Return a reference to the pixel value of the image instance located at (\\c x,\\c y,\\c z,\\c c),\n       or to the nearest pixel location in the image instance in case of out-of-bounds access along the X-axis.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note\n       - Similar to at(int,int,int,int,const T), except that an out-of-bounds access returns the value of the\n         nearest pixel in the image instance, regarding the specified X-coordinate.\n       - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when\n         you are \\e not sure about the validity of the specified pixel coordinates.\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _at(int,int,int,int).\n       \\warning\n       - There is \\e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.\n     **/\n    T& atX(const int x, const int y=0, const int z=0, const int c=0) {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"atX(): Empty instance.\",\n                                    cimg_instance);\n      return _atX(x,y,z,c);\n    }\n\n    T& _atX(const int x, const int y=0, const int z=0, const int c=0) {\n      return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c);\n    }\n\n    //! Access to a pixel value, using Neumann boundary conditions for the X-coordinate \\const.\n    const T& atX(const int x, const int y=0, const int z=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"atX(): Empty instance.\",\n                                    cimg_instance);\n      return _atX(x,y,z,c);\n    }\n\n    const T& _atX(const int x, const int y=0, const int z=0, const int c=0) const {\n      return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c);\n    }\n\n    //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y-coordinates.\n    /**\n       Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on X and Y-coordinates.\n    **/\n    T& atXY(const int x, const int y, const int z, const int c, const T& out_value) {\n      return (x<0 || y<0 || x>=width() || y>=height())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);\n    }\n\n    //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y coordinates \\const.\n    T atXY(const int x, const int y, const int z, const int c, const T& out_value) const {\n      return (x<0 || y<0 || x>=width() || y>=height())?out_value:(*this)(x,y,z,c);\n    }\n\n    //! Access to a pixel value, using Neumann boundary conditions for the X and Y-coordinates.\n    /**\n       Similar to atX(int,int,int,int), except that boundary checking is performed both on X and Y-coordinates.\n       \\note\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _atXY(int,int,int,int).\n     **/\n    T& atXY(const int x, const int y, const int z=0, const int c=0) {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"atXY(): Empty instance.\",\n                                    cimg_instance);\n      return _atXY(x,y,z,c);\n    }\n\n    T& _atXY(const int x, const int y, const int z=0, const int c=0) {\n      return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y),z,c);\n    }\n\n    //! Access to a pixel value, using Neumann boundary conditions for the X and Y-coordinates \\const.\n    const T& atXY(const int x, const int y, const int z=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"atXY(): Empty instance.\",\n                                    cimg_instance);\n      return _atXY(x,y,z,c);\n    }\n\n    const T& _atXY(const int x, const int y, const int z=0, const int c=0) const {\n      return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y),z,c);\n    }\n\n    //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates.\n    /**\n       Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on\n       X,Y and Z-coordinates.\n    **/\n    T& atXYZ(const int x, const int y, const int z, const int c, const T& out_value) {\n      return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?\n        (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);\n    }\n\n    //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates \\const.\n    T atXYZ(const int x, const int y, const int z, const int c, const T& out_value) const {\n      return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?out_value:(*this)(x,y,z,c);\n    }\n\n    //! Access to a pixel value, using Neumann boundary conditions for the X,Y and Z-coordinates.\n    /**\n       Similar to atX(int,int,int,int), except that boundary checking is performed both on X,Y and Z-coordinates.\n       \\note\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _atXYZ(int,int,int,int).\n    **/\n    T& atXYZ(const int x, const int y, const int z, const int c=0) {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"atXYZ(): Empty instance.\",\n                                    cimg_instance);\n      return _atXYZ(x,y,z,c);\n    }\n\n    T& _atXYZ(const int x, const int y, const int z, const int c=0) {\n      return (*this)(x<0?0:x>=width()?width() - 1:x,y<0?0:y>=height()?height() - 1:y,\n                     z<0?0:z>=depth()?depth() - 1:z,c);\n    }\n\n    //! Access to a pixel value, using Neumann boundary conditions for the X,Y and Z-coordinates \\const.\n    const T& atXYZ(const int x, const int y, const int z, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"atXYZ(): Empty instance.\",\n                                    cimg_instance);\n      return _atXYZ(x,y,z,c);\n    }\n\n    const T& _atXYZ(const int x, const int y, const int z, const int c=0) const {\n      return (*this)(x<0?0:(x>=width()?width() - 1:x),y<0?0:(y>=height()?height() - 1:y),\n                     z<0?0:(z>=depth()?depth() - 1:z),c);\n    }\n\n    //! Access to a pixel value, using Dirichlet boundary conditions.\n    /**\n       Similar to atX(int,int,int,int,const T), except that boundary checking is performed on all\n       X,Y,Z and C-coordinates.\n    **/\n    T& atXYZC(const int x, const int y, const int z, const int c, const T& out_value) {\n      return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?\n        (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);\n    }\n\n    //! Access to a pixel value, using Dirichlet boundary conditions \\const.\n    T atXYZC(const int x, const int y, const int z, const int c, const T& out_value) const {\n      return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?out_value:\n        (*this)(x,y,z,c);\n    }\n\n    //! Access to a pixel value, using Neumann boundary conditions.\n    /**\n       Similar to atX(int,int,int,int), except that boundary checking is performed on all X,Y,Z and C-coordinates.\n       \\note\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _atXYZC(int,int,int,int).\n    **/\n    T& atXYZC(const int x, const int y, const int z, const int c) {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"atXYZC(): Empty instance.\",\n                                    cimg_instance);\n      return _atXYZC(x,y,z,c);\n    }\n\n    T& _atXYZC(const int x, const int y, const int z, const int c) {\n      return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y),\n                     z<0?0:(z>=depth()?depth() - 1:z), c<0?0:(c>=spectrum()?spectrum() - 1:c));\n    }\n\n    //! Access to a pixel value, using Neumann boundary conditions \\const.\n    const T& atXYZC(const int x, const int y, const int z, const int c) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"atXYZC(): Empty instance.\",\n                                    cimg_instance);\n      return _atXYZC(x,y,z,c);\n    }\n\n    const T& _atXYZC(const int x, const int y, const int z, const int c) const {\n      return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y),\n                     z<0?0:(z>=depth()?depth() - 1:z), c<0?0:(c>=spectrum()?spectrum() - 1:c));\n    }\n\n    //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X-coordinate.\n    /**\n       Return a linearly-interpolated pixel value of the image instance located at (\\c fx,\\c y,\\c z,\\c c),\n       or a specified default value in case of out-of-bounds access along the X-axis.\n       \\param fx X-coordinate of the pixel value (float-valued).\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param out_value Default value returned if \\c (\\c fx,\\c y,\\c z,\\c c) is outside image bounds.\n       \\note\n       - Similar to atX(int,int,int,int,const T), except that the returned pixel value is approximated by\n         a linear interpolation along the X-axis, if corresponding coordinates are not integers.\n       - The type of the returned pixel value is extended to \\c float, if the pixel type \\c T is not float-valued.\n       \\warning\n       - There is \\e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.\n    **/\n    Tfloat linear_atX(const float fx, const int y, const int z, const int c, const T& out_value) const {\n      const int\n        x = (int)fx - (fx>=0?0:1), nx = x + 1;\n      const float\n        dx = fx - x;\n      const Tfloat\n        Ic = (Tfloat)atX(x,y,z,c,out_value), In = (Tfloat)atXY(nx,y,z,c,out_value);\n      return Ic + dx*(In - Ic);\n    }\n\n    //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X-coordinate.\n    /**\n       Return a linearly-interpolated pixel value of the image instance located at (\\c fx,\\c y,\\c z,\\c c),\n       or the value of the nearest pixel location in the image instance in case of out-of-bounds access along\n       the X-axis.\n       \\param fx X-coordinate of the pixel value (float-valued).\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note\n       - Similar to linear_atX(float,int,int,int,const T) const, except that an out-of-bounds access returns\n         the value of the nearest pixel in the image instance, regarding the specified X-coordinate.\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _linear_atX(float,int,int,int).\n       \\warning\n       - There is \\e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.\n    **/\n    Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"linear_atX(): Empty instance.\",\n                                    cimg_instance);\n\n      return _linear_atX(fx,y,z,c);\n    }\n\n    Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const {\n      const float\n        nfx = fx<0?0:(fx>_width - 1?_width - 1:fx);\n      const unsigned int\n        x = (unsigned int)nfx;\n      const float\n        dx = nfx - x;\n      const unsigned int\n        nx = dx>0?x + 1:x;\n      const Tfloat\n        Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c);\n      return Ic + dx*(In - Ic);\n    }\n\n    //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X and Y-coordinates.\n    /**\n       Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the\n       boundary checking are achieved both for X and Y-coordinates.\n    **/\n    Tfloat linear_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const {\n      const int\n        x = (int)fx - (fx>=0?0:1), nx = x + 1,\n        y = (int)fy - (fy>=0?0:1), ny = y + 1;\n      const float\n        dx = fx - x,\n        dy = fy - y;\n      const Tfloat\n        Icc = (Tfloat)atXY(x,y,z,c,out_value),  Inc = (Tfloat)atXY(nx,y,z,c,out_value),\n        Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value);\n      return Icc + dx*(Inc - Icc + dy*(Icc + Inn - Icn - Inc)) + dy*(Icn - Icc);\n    }\n\n    //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X and Y-coordinates.\n    /**\n       Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking\n       are achieved both for X and Y-coordinates.\n       \\note\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _linear_atXY(float,float,int,int).\n    **/\n    Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"linear_atXY(): Empty instance.\",\n                                    cimg_instance);\n\n      return _linear_atXY(fx,fy,z,c);\n    }\n\n    Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const {\n      const float\n        nfx = fx<0?0:(fx>_width - 1?_width - 1:fx),\n        nfy = fy<0?0:(fy>_height - 1?_height - 1:fy);\n      const unsigned int\n        x = (unsigned int)nfx,\n        y = (unsigned int)nfy;\n      const float\n        dx = nfx - x,\n        dy = nfy - y;\n      const unsigned int\n        nx = dx>0?x + 1:x,\n        ny = dy>0?y + 1:y;\n      const Tfloat\n        Icc = (Tfloat)(*this)(x,y,z,c),  Inc = (Tfloat)(*this)(nx,y,z,c),\n        Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c);\n      return Icc + dx*(Inc - Icc + dy*(Icc + Inn - Icn - Inc)) + dy*(Icn - Icc);\n    }\n\n    //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates.\n    /**\n       Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the\n       boundary checking are achieved both for X,Y and Z-coordinates.\n    **/\n    Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const {\n      const int\n        x = (int)fx - (fx>=0?0:1), nx = x + 1,\n        y = (int)fy - (fy>=0?0:1), ny = y + 1,\n        z = (int)fz - (fz>=0?0:1), nz = z + 1;\n      const float\n        dx = fx - x,\n        dy = fy - y,\n        dz = fz - z;\n      const Tfloat\n        Iccc = (Tfloat)atXYZ(x,y,z,c,out_value), Incc = (Tfloat)atXYZ(nx,y,z,c,out_value),\n        Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value), Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value),\n        Iccn = (Tfloat)atXYZ(x,y,nz,c,out_value), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value),\n        Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value);\n      return Iccc +\n        dx*(Incc - Iccc +\n            dy*(Iccc + Innc - Icnc - Incc +\n                dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) +\n            dz*(Iccc + Incn - Iccn - Incc)) +\n        dy*(Icnc - Iccc +\n            dz*(Iccc + Icnn - Iccn - Icnc)) +\n        dz*(Iccn - Iccc);\n    }\n\n    //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X,Y and Z-coordinates.\n    /**\n       Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking\n       are achieved both for X,Y and Z-coordinates.\n       \\note\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _linear_atXYZ(float,float,float,int).\n    **/\n    Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"linear_atXYZ(): Empty instance.\",\n                                    cimg_instance);\n\n      return _linear_atXYZ(fx,fy,fz,c);\n    }\n\n    Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const {\n      const float\n        nfx = fx<0?0:(fx>_width - 1?_width - 1:fx),\n        nfy = fy<0?0:(fy>_height - 1?_height - 1:fy),\n        nfz = fz<0?0:(fz>_depth - 1?_depth - 1:fz);\n      const unsigned int\n        x = (unsigned int)nfx,\n        y = (unsigned int)nfy,\n        z = (unsigned int)nfz;\n      const float\n        dx = nfx - x,\n        dy = nfy - y,\n        dz = nfz - z;\n      const unsigned int\n        nx = dx>0?x + 1:x,\n        ny = dy>0?y + 1:y,\n        nz = dz>0?z + 1:z;\n      const Tfloat\n        Iccc = (Tfloat)(*this)(x,y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c),\n        Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c),\n        Iccn = (Tfloat)(*this)(x,y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c),\n        Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c);\n      return Iccc +\n        dx*(Incc - Iccc +\n            dy*(Iccc + Innc - Icnc - Incc +\n                dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) +\n            dz*(Iccc + Incn - Iccn - Incc)) +\n        dy*(Icnc - Iccc +\n            dz*(Iccc + Icnn - Iccn - Icnc)) +\n        dz*(Iccn - Iccc);\n    }\n\n    //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for all X,Y,Z,C-coordinates.\n    /**\n       Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the\n       boundary checking are achieved for all X,Y,Z and C-coordinates.\n    **/\n    Tfloat linear_atXYZC(const float fx, const float fy, const float fz, const float fc, const T& out_value) const {\n      const int\n        x = (int)fx - (fx>=0?0:1), nx = x + 1,\n        y = (int)fy - (fy>=0?0:1), ny = y + 1,\n        z = (int)fz - (fz>=0?0:1), nz = z + 1,\n        c = (int)fc - (fc>=0?0:1), nc = c + 1;\n      const float\n        dx = fx - x,\n        dy = fy - y,\n        dz = fz - z,\n        dc = fc - c;\n      const Tfloat\n        Icccc = (Tfloat)atXYZC(x,y,z,c,out_value), Inccc = (Tfloat)atXYZC(nx,y,z,c,out_value),\n        Icncc = (Tfloat)atXYZC(x,ny,z,c,out_value), Inncc = (Tfloat)atXYZC(nx,ny,z,c,out_value),\n        Iccnc = (Tfloat)atXYZC(x,y,nz,c,out_value), Incnc = (Tfloat)atXYZC(nx,y,nz,c,out_value),\n        Icnnc = (Tfloat)atXYZC(x,ny,nz,c,out_value), Innnc = (Tfloat)atXYZC(nx,ny,nz,c,out_value),\n        Icccn = (Tfloat)atXYZC(x,y,z,nc,out_value), Inccn = (Tfloat)atXYZC(nx,y,z,nc,out_value),\n        Icncn = (Tfloat)atXYZC(x,ny,z,nc,out_value), Inncn = (Tfloat)atXYZC(nx,ny,z,nc,out_value),\n        Iccnn = (Tfloat)atXYZC(x,y,nz,nc,out_value), Incnn = (Tfloat)atXYZC(nx,y,nz,nc,out_value),\n        Icnnn = (Tfloat)atXYZC(x,ny,nz,nc,out_value), Innnn = (Tfloat)atXYZC(nx,ny,nz,nc,out_value);\n      return Icccc +\n        dx*(Inccc - Icccc +\n            dy*(Icccc + Inncc - Icncc - Inccc +\n                dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc +\n                    dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc -\n                        Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) +\n                dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) +\n            dz*(Icccc + Incnc - Iccnc - Inccc +\n                dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) +\n            dc*(Icccc + Inccn - Inccc - Icccn)) +\n        dy*(Icncc - Icccc +\n            dz*(Icccc + Icnnc - Iccnc - Icncc +\n                dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) +\n            dc*(Icccc + Icncn - Icncc - Icccn)) +\n        dz*(Iccnc - Icccc +\n            dc*(Icccc + Iccnn - Iccnc - Icccn)) +\n        dc*(Icccn  -Icccc);\n    }\n\n    //! Return pixel value, using linear interpolation and Neumann boundary conditions for all X,Y,Z and C-coordinates.\n    /**\n       Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking\n       are achieved for all X,Y,Z and C-coordinates.\n       \\note\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _linear_atXYZC(float,float,float,float).\n    **/\n    Tfloat linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"linear_atXYZC(): Empty instance.\",\n                                    cimg_instance);\n\n      return _linear_atXYZC(fx,fy,fz,fc);\n    }\n\n    Tfloat _linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const {\n      const float\n        nfx = fx<0?0:(fx>_width - 1?_width - 1:fx),\n        nfy = fy<0?0:(fy>_height - 1?_height - 1:fy),\n        nfz = fz<0?0:(fz>_depth - 1?_depth - 1:fz),\n        nfc = fc<0?0:(fc>_spectrum - 1?_spectrum - 1:fc);\n      const unsigned int\n        x = (unsigned int)nfx,\n        y = (unsigned int)nfy,\n        z = (unsigned int)nfz,\n        c = (unsigned int)nfc;\n      const float\n        dx = nfx - x,\n        dy = nfy - y,\n        dz = nfz - z,\n        dc = nfc - c;\n      const unsigned int\n        nx = dx>0?x + 1:x,\n        ny = dy>0?y + 1:y,\n        nz = dz>0?z + 1:z,\n        nc = dc>0?c + 1:c;\n      const Tfloat\n        Icccc = (Tfloat)(*this)(x,y,z,c), Inccc = (Tfloat)(*this)(nx,y,z,c),\n        Icncc = (Tfloat)(*this)(x,ny,z,c), Inncc = (Tfloat)(*this)(nx,ny,z,c),\n        Iccnc = (Tfloat)(*this)(x,y,nz,c), Incnc = (Tfloat)(*this)(nx,y,nz,c),\n        Icnnc = (Tfloat)(*this)(x,ny,nz,c), Innnc = (Tfloat)(*this)(nx,ny,nz,c),\n        Icccn = (Tfloat)(*this)(x,y,z,nc), Inccn = (Tfloat)(*this)(nx,y,z,nc),\n        Icncn = (Tfloat)(*this)(x,ny,z,nc), Inncn = (Tfloat)(*this)(nx,ny,z,nc),\n        Iccnn = (Tfloat)(*this)(x,y,nz,nc), Incnn = (Tfloat)(*this)(nx,y,nz,nc),\n        Icnnn = (Tfloat)(*this)(x,ny,nz,nc), Innnn = (Tfloat)(*this)(nx,ny,nz,nc);\n      return Icccc +\n        dx*(Inccc - Icccc +\n            dy*(Icccc + Inncc - Icncc - Inccc +\n                dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc +\n                    dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc -\n                        Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) +\n                dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) +\n            dz*(Icccc + Incnc - Iccnc - Inccc +\n                dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) +\n            dc*(Icccc + Inccn - Inccc - Icccn)) +\n        dy*(Icncc - Icccc +\n            dz*(Icccc + Icnnc - Iccnc - Icncc +\n                dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) +\n            dc*(Icccc + Icncn - Icncc - Icccn)) +\n        dz*(Iccnc - Icccc +\n            dc*(Icccc + Iccnn - Iccnc - Icccn)) +\n        dc*(Icccn - Icccc);\n    }\n\n    //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate.\n    /**\n       Return a cubicly-interpolated pixel value of the image instance located at (\\c fx,\\c y,\\c z,\\c c),\n       or a specified default value in case of out-of-bounds access along the X-axis.\n       The cubic interpolation uses Hermite splines.\n       \\param fx d X-coordinate of the pixel value (float-valued).\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param out_value Default value returned if \\c (\\c fx,\\c y,\\c z,\\c c) is outside image bounds.\n       \\note\n       - Similar to linear_atX(float,int,int,int,const T) const, except that the returned pixel value is\n         approximated by a \\e cubic interpolation along the X-axis.\n       - The type of the returned pixel value is extended to \\c float, if the pixel type \\c T is not float-valued.\n       \\warning\n       - There is \\e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.\n    **/\n    Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T& out_value) const {\n      const int\n        x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2;\n      const float\n        dx = fx - x;\n      const Tfloat\n        Ip = (Tfloat)atX(px,y,z,c,out_value), Ic = (Tfloat)atX(x,y,z,c,out_value),\n        In = (Tfloat)atX(nx,y,z,c,out_value), Ia = (Tfloat)atX(ax,y,z,c,out_value);\n      return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia));\n    }\n\n    //! Return damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate.\n    /**\n       Similar to cubic_atX(float,int,int,int,const T) const, except that you can specify the authorized minimum\n       and maximum of the returned value.\n    **/\n    Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T& out_value,\n                     const Tfloat min_value, const Tfloat max_value) const {\n      const Tfloat val = cubic_atX(fx,y,z,c,out_value);\n      return val<min_value?min_value:val>max_value?max_value:val;\n    }\n\n    //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate.\n    /**\n       Return a cubicly-interpolated pixel value of the image instance located at (\\c fx,\\c y,\\c z,\\c c),\n       or the value of the nearest pixel location in the image instance in case of out-of-bounds access\n       along the X-axis. The cubic interpolation uses Hermite splines.\n       \\param fx X-coordinate of the pixel value (float-valued).\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note\n       - Similar to cubic_atX(float,int,int,int,const T) const, except that the returned pixel value is\n         approximated by a cubic interpolation along the X-axis.\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _cubic_atX(float,int,int,int).\n       \\warning\n       - There is \\e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.\n    **/\n    Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"cubic_atX(): Empty instance.\",\n                                    cimg_instance);\n      return _cubic_atX(fx,y,z,c);\n    }\n\n    Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const {\n      const float\n        nfx = fx<0?0:(fx>_width - 1?_width - 1:fx);\n      const int\n        x = (int)nfx;\n      const float\n        dx = nfx - x;\n      const int\n        px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2;\n      const Tfloat\n        Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c),\n        In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c);\n      return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia));\n    }\n\n    //! Return damped pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate.\n    /**\n       Similar to cubic_atX(float,int,int,int) const, except that you can specify the authorized minimum and maximum\n       of the returned value.\n    **/\n    Tfloat cubic_atX(const float fx, const int y, const int z, const int c,\n                     const Tfloat min_value, const Tfloat max_value) const {\n      const Tfloat val = cubic_atX(fx,y,z,c);\n      return val<min_value?min_value:val>max_value?max_value:val;\n    }\n\n    Tfloat _cubic_atX(const float fx, const int y, const int z, const int c,\n                      const Tfloat min_value, const Tfloat max_value) const {\n      const Tfloat val = _cubic_atX(fx,y,z,c);\n      return val<min_value?min_value:val>max_value?max_value:val;\n    }\n\n    //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X and Y-coordinates.\n    /**\n       Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking\n       are achieved both for X and Y-coordinates.\n    **/\n    Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const {\n      const int\n        x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2,\n        y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2;\n      const float dx = fx - x, dy = fy - y;\n      const Tfloat\n        Ipp = (Tfloat)atXY(px,py,z,c,out_value), Icp = (Tfloat)atXY(x,py,z,c,out_value),\n        Inp = (Tfloat)atXY(nx,py,z,c,out_value), Iap = (Tfloat)atXY(ax,py,z,c,out_value),\n        Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)),\n        Ipc = (Tfloat)atXY(px,y,z,c,out_value),  Icc = (Tfloat)atXY(x, y,z,c,out_value),\n        Inc = (Tfloat)atXY(nx,y,z,c,out_value),  Iac = (Tfloat)atXY(ax,y,z,c,out_value),\n        Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)),\n        Ipn = (Tfloat)atXY(px,ny,z,c,out_value), Icn = (Tfloat)atXY(x,ny,z,c,out_value),\n        Inn = (Tfloat)atXY(nx,ny,z,c,out_value), Ian = (Tfloat)atXY(ax,ny,z,c,out_value),\n        In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)),\n        Ipa = (Tfloat)atXY(px,ay,z,c,out_value), Ica = (Tfloat)atXY(x,ay,z,c,out_value),\n        Ina = (Tfloat)atXY(nx,ay,z,c,out_value), Iaa = (Tfloat)atXY(ax,ay,z,c,out_value),\n        Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa));\n      return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia));\n    }\n\n    //! Return damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X,Y-coordinates.\n    /**\n       Similar to cubic_atXY(float,float,int,int,const T) const, except that you can specify the authorized\n       minimum and maximum of the returned value.\n    **/\n    Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T& out_value,\n                      const Tfloat min_value, const Tfloat max_value) const {\n      const Tfloat val = cubic_atXY(fx,fy,z,c,out_value);\n      return val<min_value?min_value:val>max_value?max_value:val;\n    }\n\n    //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X and Y-coordinates.\n    /**\n       Similar to cubic_atX(float,int,int,int) const, except that the cubic interpolation and boundary checking\n       are achieved for both X and Y-coordinates.\n       \\note\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n       \\c _cubic_atXY(float,float,int,int).\n    **/\n    Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"cubic_atXY(): Empty instance.\",\n                                    cimg_instance);\n      return _cubic_atXY(fx,fy,z,c);\n    }\n\n    Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const {\n      const float\n        nfx = fx<0?0:(fx>_width - 1?_width - 1:fx),\n        nfy = fy<0?0:(fy>_height - 1?_height - 1:fy);\n      const int x = (int)nfx, y = (int)nfy;\n      const float dx = nfx - x, dy = nfy - y;\n      const int\n        px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2,\n        py = y - 1<0?0:y - 1, ny = dy>0?y + 1:y, ay = y + 2>=height()?height() - 1:y + 2;\n      const Tfloat\n        Ipp = (Tfloat)(*this)(px,py,z,c), Icp = (Tfloat)(*this)(x,py,z,c), Inp = (Tfloat)(*this)(nx,py,z,c),\n        Iap = (Tfloat)(*this)(ax,py,z,c),\n        Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)),\n        Ipc = (Tfloat)(*this)(px,y,z,c),  Icc = (Tfloat)(*this)(x, y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c),\n        Iac = (Tfloat)(*this)(ax,y,z,c),\n        Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)),\n        Ipn = (Tfloat)(*this)(px,ny,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c),\n        Ian = (Tfloat)(*this)(ax,ny,z,c),\n        In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)),\n        Ipa = (Tfloat)(*this)(px,ay,z,c), Ica = (Tfloat)(*this)(x,ay,z,c), Ina = (Tfloat)(*this)(nx,ay,z,c),\n        Iaa = (Tfloat)(*this)(ax,ay,z,c),\n        Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa));\n      return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia));\n    }\n\n    //! Return damped pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y-coordinates.\n    /**\n       Similar to cubic_atXY(float,float,int,int) const, except that you can specify the authorized minimum and\n       maximum of the returned value.\n    **/\n    Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c,\n                      const Tfloat min_value, const Tfloat max_value) const {\n      const Tfloat val = cubic_atXY(fx,fy,z,c);\n      return val<min_value?min_value:val>max_value?max_value:val;\n    }\n\n    Tfloat _cubic_atXY(const float fx, const float fy, const int z, const int c,\n                       const Tfloat min_value, const Tfloat max_value) const {\n      const Tfloat val = _cubic_atXY(fx,fy,z,c);\n      return val<min_value?min_value:val>max_value?max_value:val;\n    }\n\n    //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates.\n    /**\n       Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking\n       are achieved both for X,Y and Z-coordinates.\n    **/\n    Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const {\n      const int\n        x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2,\n        y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2,\n        z = (int)fz - (fz>=0?0:1), pz = z - 1, nz = z + 1, az = z + 2;\n      const float dx = fx - x, dy = fy - y, dz = fz - z;\n      const Tfloat\n        Ippp = (Tfloat)atXYZ(px,py,pz,c,out_value), Icpp = (Tfloat)atXYZ(x,py,pz,c,out_value),\n        Inpp = (Tfloat)atXYZ(nx,py,pz,c,out_value), Iapp = (Tfloat)atXYZ(ax,py,pz,c,out_value),\n        Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) +\n                           dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)),\n        Ipcp = (Tfloat)atXYZ(px,y,pz,c,out_value),  Iccp = (Tfloat)atXYZ(x, y,pz,c,out_value),\n        Incp = (Tfloat)atXYZ(nx,y,pz,c,out_value),  Iacp = (Tfloat)atXYZ(ax,y,pz,c,out_value),\n        Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) +\n                           dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)),\n        Ipnp = (Tfloat)atXYZ(px,ny,pz,c,out_value), Icnp = (Tfloat)atXYZ(x,ny,pz,c,out_value),\n        Innp = (Tfloat)atXYZ(nx,ny,pz,c,out_value), Ianp = (Tfloat)atXYZ(ax,ny,pz,c,out_value),\n        Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) +\n                           dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)),\n        Ipap = (Tfloat)atXYZ(px,ay,pz,c,out_value), Icap = (Tfloat)atXYZ(x,ay,pz,c,out_value),\n        Inap = (Tfloat)atXYZ(nx,ay,pz,c,out_value), Iaap = (Tfloat)atXYZ(ax,ay,pz,c,out_value),\n        Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) +\n                           dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)),\n        Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) +\n                         dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)),\n        Ippc = (Tfloat)atXYZ(px,py,z,c,out_value), Icpc = (Tfloat)atXYZ(x,py,z,c,out_value),\n        Inpc = (Tfloat)atXYZ(nx,py,z,c,out_value), Iapc = (Tfloat)atXYZ(ax,py,z,c,out_value),\n        Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) +\n                           dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)),\n        Ipcc = (Tfloat)atXYZ(px,y,z,c,out_value),  Iccc = (Tfloat)atXYZ(x, y,z,c,out_value),\n        Incc = (Tfloat)atXYZ(nx,y,z,c,out_value),  Iacc = (Tfloat)atXYZ(ax,y,z,c,out_value),\n        Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) +\n                           dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)),\n        Ipnc = (Tfloat)atXYZ(px,ny,z,c,out_value), Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value),\n        Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value), Ianc = (Tfloat)atXYZ(ax,ny,z,c,out_value),\n        Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) +\n                           dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)),\n        Ipac = (Tfloat)atXYZ(px,ay,z,c,out_value), Icac = (Tfloat)atXYZ(x,ay,z,c,out_value),\n        Inac = (Tfloat)atXYZ(nx,ay,z,c,out_value), Iaac = (Tfloat)atXYZ(ax,ay,z,c,out_value),\n        Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) +\n                           dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)),\n        Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) +\n                         dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)),\n        Ippn = (Tfloat)atXYZ(px,py,nz,c,out_value), Icpn = (Tfloat)atXYZ(x,py,nz,c,out_value),\n        Inpn = (Tfloat)atXYZ(nx,py,nz,c,out_value), Iapn = (Tfloat)atXYZ(ax,py,nz,c,out_value),\n        Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) +\n                           dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)),\n        Ipcn = (Tfloat)atXYZ(px,y,nz,c,out_value),  Iccn = (Tfloat)atXYZ(x, y,nz,c,out_value),\n        Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value),  Iacn = (Tfloat)atXYZ(ax,y,nz,c,out_value),\n        Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) +\n                           dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)),\n        Ipnn = (Tfloat)atXYZ(px,ny,nz,c,out_value), Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value),\n        Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value), Iann = (Tfloat)atXYZ(ax,ny,nz,c,out_value),\n        Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) +\n                           dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)),\n        Ipan = (Tfloat)atXYZ(px,ay,nz,c,out_value), Ican = (Tfloat)atXYZ(x,ay,nz,c,out_value),\n        Inan = (Tfloat)atXYZ(nx,ay,nz,c,out_value), Iaan = (Tfloat)atXYZ(ax,ay,nz,c,out_value),\n        Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) +\n                           dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)),\n        In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) +\n                         dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)),\n        Ippa = (Tfloat)atXYZ(px,py,az,c,out_value), Icpa = (Tfloat)atXYZ(x,py,az,c,out_value),\n        Inpa = (Tfloat)atXYZ(nx,py,az,c,out_value), Iapa = (Tfloat)atXYZ(ax,py,az,c,out_value),\n        Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) +\n                           dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)),\n        Ipca = (Tfloat)atXYZ(px,y,az,c,out_value),  Icca = (Tfloat)atXYZ(x, y,az,c,out_value),\n        Inca = (Tfloat)atXYZ(nx,y,az,c,out_value),  Iaca = (Tfloat)atXYZ(ax,y,az,c,out_value),\n        Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) +\n                           dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)),\n        Ipna = (Tfloat)atXYZ(px,ny,az,c,out_value), Icna = (Tfloat)atXYZ(x,ny,az,c,out_value),\n        Inna = (Tfloat)atXYZ(nx,ny,az,c,out_value), Iana = (Tfloat)atXYZ(ax,ny,az,c,out_value),\n        Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) +\n                           dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)),\n        Ipaa = (Tfloat)atXYZ(px,ay,az,c,out_value), Icaa = (Tfloat)atXYZ(x,ay,az,c,out_value),\n        Inaa = (Tfloat)atXYZ(nx,ay,az,c,out_value), Iaaa = (Tfloat)atXYZ(ax,ay,az,c,out_value),\n        Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) +\n                           dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)),\n        Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) +\n                         dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa));\n      return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia));\n    }\n\n    //! Return damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the XYZ-coordinates.\n    /**\n       Similar to cubic_atXYZ(float,float,float,int,const T) const, except that you can specify the authorized\n       minimum and maximum of the returned value.\n    **/\n    Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value,\n                       const Tfloat min_value, const Tfloat max_value) const {\n      const Tfloat val = cubic_atXYZ(fx,fy,fz,c,out_value);\n      return val<min_value?min_value:val>max_value?max_value:val;\n    }\n\n    //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y and Z-coordinates.\n    /**\n       Similar to cubic_atX(float,int,int,int) const, except that the cubic interpolation and boundary checking\n       are achieved both for X,Y and Z-coordinates.\n       \\note\n       - If you know your image instance is \\e not empty, you may rather use the slightly faster method\n         \\c _cubic_atXYZ(float,float,float,int).\n    **/\n    Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"cubic_atXYZ(): Empty instance.\",\n                                    cimg_instance);\n      return _cubic_atXYZ(fx,fy,fz,c);\n    }\n\n    Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const {\n      const float\n        nfx = fx<0?0:(fx>_width - 1?_width - 1:fx),\n        nfy = fy<0?0:(fy>_height - 1?_height - 1:fy),\n        nfz = fz<0?0:(fz>_depth - 1?_depth - 1:fz);\n      const int x = (int)nfx, y = (int)nfy, z = (int)nfz;\n      const float dx = nfx - x, dy = nfy - y, dz = nfz - z;\n      const int\n        px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2,\n        py = y - 1<0?0:y - 1, ny = dy>0?y + 1:y, ay = y + 2>=height()?height() - 1:y + 2,\n        pz = z - 1<0?0:z - 1, nz = dz>0?z + 1:z, az = z + 2>=depth()?depth() - 1:z + 2;\n      const Tfloat\n        Ippp = (Tfloat)(*this)(px,py,pz,c), Icpp = (Tfloat)(*this)(x,py,pz,c),\n        Inpp = (Tfloat)(*this)(nx,py,pz,c), Iapp = (Tfloat)(*this)(ax,py,pz,c),\n        Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) +\n                           dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)),\n        Ipcp = (Tfloat)(*this)(px,y,pz,c),  Iccp = (Tfloat)(*this)(x, y,pz,c),\n        Incp = (Tfloat)(*this)(nx,y,pz,c),  Iacp = (Tfloat)(*this)(ax,y,pz,c),\n        Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) +\n                           dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)),\n        Ipnp = (Tfloat)(*this)(px,ny,pz,c), Icnp = (Tfloat)(*this)(x,ny,pz,c),\n        Innp = (Tfloat)(*this)(nx,ny,pz,c), Ianp = (Tfloat)(*this)(ax,ny,pz,c),\n        Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) +\n                           dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)),\n        Ipap = (Tfloat)(*this)(px,ay,pz,c), Icap = (Tfloat)(*this)(x,ay,pz,c),\n        Inap = (Tfloat)(*this)(nx,ay,pz,c), Iaap = (Tfloat)(*this)(ax,ay,pz,c),\n        Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) +\n                           dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)),\n        Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) +\n                         dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)),\n        Ippc = (Tfloat)(*this)(px,py,z,c), Icpc = (Tfloat)(*this)(x,py,z,c),\n        Inpc = (Tfloat)(*this)(nx,py,z,c), Iapc = (Tfloat)(*this)(ax,py,z,c),\n        Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) +\n                           dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)),\n        Ipcc = (Tfloat)(*this)(px,y,z,c),  Iccc = (Tfloat)(*this)(x, y,z,c),\n        Incc = (Tfloat)(*this)(nx,y,z,c),  Iacc = (Tfloat)(*this)(ax,y,z,c),\n        Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) +\n                           dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)),\n        Ipnc = (Tfloat)(*this)(px,ny,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c),\n        Innc = (Tfloat)(*this)(nx,ny,z,c), Ianc = (Tfloat)(*this)(ax,ny,z,c),\n        Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) +\n                           dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)),\n        Ipac = (Tfloat)(*this)(px,ay,z,c), Icac = (Tfloat)(*this)(x,ay,z,c),\n        Inac = (Tfloat)(*this)(nx,ay,z,c), Iaac = (Tfloat)(*this)(ax,ay,z,c),\n        Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) +\n                           dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)),\n        Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) +\n                         dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)),\n        Ippn = (Tfloat)(*this)(px,py,nz,c), Icpn = (Tfloat)(*this)(x,py,nz,c),\n        Inpn = (Tfloat)(*this)(nx,py,nz,c), Iapn = (Tfloat)(*this)(ax,py,nz,c),\n        Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) +\n                           dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)),\n        Ipcn = (Tfloat)(*this)(px,y,nz,c),  Iccn = (Tfloat)(*this)(x, y,nz,c),\n        Incn = (Tfloat)(*this)(nx,y,nz,c),  Iacn = (Tfloat)(*this)(ax,y,nz,c),\n        Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) +\n                           dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)),\n        Ipnn = (Tfloat)(*this)(px,ny,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c),\n        Innn = (Tfloat)(*this)(nx,ny,nz,c), Iann = (Tfloat)(*this)(ax,ny,nz,c),\n        Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) +\n                           dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)),\n        Ipan = (Tfloat)(*this)(px,ay,nz,c), Ican = (Tfloat)(*this)(x,ay,nz,c),\n        Inan = (Tfloat)(*this)(nx,ay,nz,c), Iaan = (Tfloat)(*this)(ax,ay,nz,c),\n        Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) +\n                           dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)),\n        In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) +\n                         dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)),\n        Ippa = (Tfloat)(*this)(px,py,az,c), Icpa = (Tfloat)(*this)(x,py,az,c),\n        Inpa = (Tfloat)(*this)(nx,py,az,c), Iapa = (Tfloat)(*this)(ax,py,az,c),\n        Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) +\n                           dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)),\n        Ipca = (Tfloat)(*this)(px,y,az,c),  Icca = (Tfloat)(*this)(x, y,az,c),\n        Inca = (Tfloat)(*this)(nx,y,az,c),  Iaca = (Tfloat)(*this)(ax,y,az,c),\n        Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) +\n                           dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)),\n        Ipna = (Tfloat)(*this)(px,ny,az,c), Icna = (Tfloat)(*this)(x,ny,az,c),\n        Inna = (Tfloat)(*this)(nx,ny,az,c), Iana = (Tfloat)(*this)(ax,ny,az,c),\n        Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) +\n                           dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)),\n        Ipaa = (Tfloat)(*this)(px,ay,az,c), Icaa = (Tfloat)(*this)(x,ay,az,c),\n        Inaa = (Tfloat)(*this)(nx,ay,az,c), Iaaa = (Tfloat)(*this)(ax,ay,az,c),\n        Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) +\n                           dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)),\n        Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) +\n                         dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa));\n      return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia));\n    }\n\n    //! Return damped pixel value, using cubic interpolation and Neumann boundary conditions for the XYZ-coordinates.\n    /**\n       Similar to cubic_atXYZ(float,float,float,int) const, except that you can specify the authorized minimum and\n       maximum of the returned value.\n    **/\n    Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c,\n                       const Tfloat min_value, const Tfloat max_value) const {\n      const Tfloat val = cubic_atXYZ(fx,fy,fz,c);\n      return val<min_value?min_value:val>max_value?max_value:val;\n    }\n\n    Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c,\n                        const Tfloat min_value, const Tfloat max_value) const {\n      const Tfloat val = _cubic_atXYZ(fx,fy,fz,c);\n      return val<min_value?min_value:val>max_value?max_value:val;\n    }\n\n    //! Set pixel value, using linear interpolation for the X-coordinates.\n    /**\n       Set pixel value at specified coordinates (\\c fx,\\c y,\\c z,\\c c) in the image instance, in a way that\n       the value is spread amongst several neighbors if the pixel coordinates are float-valued.\n       \\param value Pixel value to set.\n       \\param fx X-coordinate of the pixel value (float-valued).\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param is_added Tells if the pixel value is added to (\\c true), or simply replace (\\c false) the current image\n         pixel(s).\n       \\return A reference to the current image instance.\n       \\note\n       - Calling this method with out-of-bounds coordinates does nothing.\n    **/\n    CImg<T>& set_linear_atX(const T& value, const float fx, const int y=0, const int z=0, const int c=0,\n                            const bool is_added=false) {\n      const int\n        x = (int)fx - (fx>=0?0:1), nx = x + 1;\n      const float\n        dx = fx - x;\n      if (y>=0 && y<height() && z>=0 && z<depth() && c>=0 && c<spectrum()) {\n        if (x>=0 && x<width()) {\n          const float w1 = 1 - dx, w2 = is_added?1:(1 - w1);\n          (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));\n        }\n        if (nx>=0 && nx<width()) {\n          const float w1 = dx, w2 = is_added?1:(1 - w1);\n          (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));\n        }\n      }\n      return *this;\n    }\n\n    //! Set pixel value, using linear interpolation for the X and Y-coordinates.\n    /**\n       Similar to set_linear_atX(const T&,float,int,int,int,bool), except that the linear interpolation\n       is achieved both for X and Y-coordinates.\n    **/\n    CImg<T>& set_linear_atXY(const T& value, const float fx, const float fy=0, const int z=0, const int c=0,\n                             const bool is_added=false) {\n      const int\n        x = (int)fx - (fx>=0?0:1), nx = x + 1,\n        y = (int)fy - (fy>=0?0:1), ny = y + 1;\n      const float\n        dx = fx - x,\n        dy = fy - y;\n      if (z>=0 && z<depth() && c>=0 && c<spectrum()) {\n        if (y>=0 && y<height()) {\n          if (x>=0 && x<width()) {\n            const float w1 = (1 - dx)*(1 - dy), w2 = is_added?1:(1 - w1);\n            (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));\n          }\n          if (nx>=0 && nx<width()) {\n            const float w1 = dx*(1 - dy), w2 = is_added?1:(1 - w1);\n            (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));\n          }\n        }\n        if (ny>=0 && ny<height()) {\n          if (x>=0 && x<width()) {\n            const float w1 = (1 - dx)*dy, w2 = is_added?1:(1 - w1);\n            (*this)(x,ny,z,c) = (T)(w1*value + w2*(*this)(x,ny,z,c));\n          }\n          if (nx>=0 && nx<width()) {\n            const float w1 = dx*dy, w2 = is_added?1:(1 - w1);\n            (*this)(nx,ny,z,c) = (T)(w1*value + w2*(*this)(nx,ny,z,c));\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Set pixel value, using linear interpolation for the X,Y and Z-coordinates.\n    /**\n       Similar to set_linear_atXY(const T&,float,float,int,int,bool), except that the linear interpolation\n       is achieved both for X,Y and Z-coordinates.\n    **/\n    CImg<T>& set_linear_atXYZ(const T& value, const float fx, const float fy=0, const float fz=0, const int c=0,\n                              const bool is_added=false) {\n      const int\n        x = (int)fx - (fx>=0?0:1), nx = x + 1,\n        y = (int)fy - (fy>=0?0:1), ny = y + 1,\n        z = (int)fz - (fz>=0?0:1), nz = z + 1;\n      const float\n        dx = fx - x,\n        dy = fy - y,\n        dz = fz - z;\n      if (c>=0 && c<spectrum()) {\n        if (z>=0 && z<depth()) {\n          if (y>=0 && y<height()) {\n            if (x>=0 && x<width()) {\n              const float w1 = (1 - dx)*(1 - dy)*(1 - dz), w2 = is_added?1:(1 - w1);\n              (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));\n            }\n            if (nx>=0 && nx<width()) {\n              const float w1 = dx*(1 - dy)*(1 - dz), w2 = is_added?1:(1 - w1);\n              (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));\n            }\n          }\n          if (ny>=0 && ny<height()) {\n            if (x>=0 && x<width()) {\n              const float w1 = (1 - dx)*dy*(1 - dz), w2 = is_added?1:(1 - w1);\n              (*this)(x,ny,z,c) = (T)(w1*value + w2*(*this)(x,ny,z,c));\n            }\n            if (nx>=0 && nx<width()) {\n              const float w1 = dx*dy*(1 - dz), w2 = is_added?1:(1 - w1);\n              (*this)(nx,ny,z,c) = (T)(w1*value + w2*(*this)(nx,ny,z,c));\n            }\n          }\n        }\n        if (nz>=0 && nz<depth()) {\n          if (y>=0 && y<height()) {\n            if (x>=0 && x<width()) {\n              const float w1 = (1 - dx)*(1 - dy)*dz, w2 = is_added?1:(1 - w1);\n              (*this)(x,y,nz,c) = (T)(w1*value + w2*(*this)(x,y,nz,c));\n            }\n            if (nx>=0 && nx<width()) {\n              const float w1 = dx*(1 - dy)*dz, w2 = is_added?1:(1 - w1);\n              (*this)(nx,y,nz,c) = (T)(w1*value + w2*(*this)(nx,y,nz,c));\n            }\n          }\n          if (ny>=0 && ny<height()) {\n            if (x>=0 && x<width()) {\n              const float w1 = (1 - dx)*dy*dz, w2 = is_added?1:(1 - w1);\n              (*this)(x,ny,nz,c) = (T)(w1*value + w2*(*this)(x,ny,nz,c));\n            }\n            if (nx>=0 && nx<width()) {\n              const float w1 = dx*dy*dz, w2 = is_added?1:(1 - w1);\n              (*this)(nx,ny,nz,c) = (T)(w1*value + w2*(*this)(nx,ny,nz,c));\n            }\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Return a C-string containing a list of all values of the image instance.\n    /**\n       Return a new \\c CImg<char> image whose buffer data() is a \\c char* string describing the list of all pixel values\n       of the image instance (written in base 10), separated by specified \\c separator character.\n       \\param separator A \\c char character which specifies the separator between values in the returned C-string.\n       \\param max_size Maximum size of the returned image.\n       \\param format For float-values, tell the printf format used to generate the ascii representation of the numbers.\n         (or \\c 0 for default representation).\n       \\note\n       - The returned image is never empty.\n       - For an empty image instance, the returned string is <tt>\"\"</tt>.\n       - If \\c max_size is equal to \\c 0, there are no limits on the size of the returned string.\n       - Otherwise, if the maximum number of string characters is exceeded, the value string is cut off\n         and terminated by character \\c '\\0'. In that case, the returned image size is <tt>max_size + 1</tt>.\n    **/\n    CImg<charT> value_string(const char separator=',', const unsigned int max_size=0,\n                             const char *const format=0) const {\n      if (is_empty()) return CImg<charT>::string(\"\");\n      CImgList<charT> items;\n      CImg<charT> s_item(256); *s_item = 0;\n      const T *ptrs = _data;\n      unsigned int string_size = 0;\n      const char *const _format = format?format:cimg::type<T>::format();\n\n      for (ulongT off = 0, siz = size(); off<siz && string_size<=max_size; ++off) {\n        const unsigned int printed_size = 1U + cimg_snprintf(s_item,s_item._width,_format,\n                                                             cimg::type<T>::format(*(ptrs++)));\n        CImg<charT> item(s_item._data,printed_size);\n        item[printed_size - 1] = separator;\n        item.move_to(items);\n        if (max_size) string_size+=printed_size;\n      }\n      CImg<charT> res;\n      (items>'x').move_to(res);\n      if (max_size && res._width>max_size) res.crop(0,max_size);\n      res.back() = 0;\n      return res;\n    }\n\n    //@}\n    //-------------------------------------\n    //\n    //! \\name Instance Checking\n    //@{\n    //-------------------------------------\n\n    //! Test shared state of the pixel buffer.\n    /**\n       Return \\c true if image instance has a shared memory buffer, and \\c false otherwise.\n       \\note\n       - A shared image do not own his pixel buffer data() and will not deallocate it on destruction.\n       - Most of the time, a \\c CImg<T> image instance will \\e not be shared.\n       - A shared image can only be obtained by a limited set of constructors and methods (see list below).\n    **/\n    bool is_shared() const {\n      return _is_shared;\n    }\n\n    //! Test if image instance is empty.\n    /**\n       Return \\c true, if image instance is empty, i.e. does \\e not contain any pixel values, has dimensions\n       \\c 0 x \\c 0 x \\c 0 x \\c 0 and a pixel buffer pointer set to \\c 0 (null pointer), and \\c false otherwise.\n    **/\n    bool is_empty() const {\n      return !(_data && _width && _height && _depth && _spectrum);\n    }\n\n    //! Test if image instance contains a 'inf' value.\n    /**\n       Return \\c true, if image instance contains a 'inf' value, and \\c false otherwise.\n    **/\n    bool is_inf() const {\n      if (cimg::type<T>::is_float()) cimg_for(*this,p,T) if (cimg::type<T>::is_inf((float)*p)) return true;\n      return false;\n    }\n\n    //! Test if image instance contains a NaN value.\n    /**\n       Return \\c true, if image instance contains a NaN value, and \\c false otherwise.\n    **/\n    bool is_nan() const {\n      if (cimg::type<T>::is_float()) cimg_for(*this,p,T) if (cimg::type<T>::is_nan((float)*p)) return true;\n      return false;\n    }\n\n    //! Test if image width is equal to specified value.\n    bool is_sameX(const unsigned int size_x) const {\n      return _width==size_x;\n    }\n\n    //! Test if image width is equal to specified value.\n    template<typename t>\n    bool is_sameX(const CImg<t>& img) const {\n      return is_sameX(img._width);\n    }\n\n    //! Test if image width is equal to specified value.\n    bool is_sameX(const CImgDisplay& disp) const {\n      return is_sameX(disp._width);\n    }\n\n    //! Test if image height is equal to specified value.\n    bool is_sameY(const unsigned int size_y) const {\n      return _height==size_y;\n    }\n\n    //! Test if image height is equal to specified value.\n    template<typename t>\n    bool is_sameY(const CImg<t>& img) const {\n      return is_sameY(img._height);\n    }\n\n    //! Test if image height is equal to specified value.\n    bool is_sameY(const CImgDisplay& disp) const {\n      return is_sameY(disp._height);\n    }\n\n    //! Test if image depth is equal to specified value.\n    bool is_sameZ(const unsigned int size_z) const {\n      return _depth==size_z;\n    }\n\n    //! Test if image depth is equal to specified value.\n    template<typename t>\n    bool is_sameZ(const CImg<t>& img) const {\n      return is_sameZ(img._depth);\n    }\n\n    //! Test if image spectrum is equal to specified value.\n    bool is_sameC(const unsigned int size_c) const {\n      return _spectrum==size_c;\n    }\n\n    //! Test if image spectrum is equal to specified value.\n    template<typename t>\n    bool is_sameC(const CImg<t>& img) const {\n      return is_sameC(img._spectrum);\n    }\n\n    //! Test if image width and height are equal to specified values.\n    /**\n       Test if is_sameX(unsigned int) const and is_sameY(unsigned int) const are both verified.\n    **/\n    bool is_sameXY(const unsigned int size_x, const unsigned int size_y) const {\n      return _width==size_x && _height==size_y;\n    }\n\n    //! Test if image width and height are the same as that of another image.\n    /**\n       Test if is_sameX(const CImg<t>&) const and is_sameY(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameXY(const CImg<t>& img) const {\n      return is_sameXY(img._width,img._height);\n    }\n\n    //! Test if image width and height are the same as that of an existing display window.\n    /**\n       Test if is_sameX(const CImgDisplay&) const and is_sameY(const CImgDisplay&) const are both verified.\n    **/\n    bool is_sameXY(const CImgDisplay& disp) const {\n      return is_sameXY(disp._width,disp._height);\n    }\n\n    //! Test if image width and depth are equal to specified values.\n    /**\n       Test if is_sameX(unsigned int) const and is_sameZ(unsigned int) const are both verified.\n    **/\n    bool is_sameXZ(const unsigned int size_x, const unsigned int size_z) const {\n      return _width==size_x && _depth==size_z;\n    }\n\n    //! Test if image width and depth are the same as that of another image.\n    /**\n       Test if is_sameX(const CImg<t>&) const and is_sameZ(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameXZ(const CImg<t>& img) const {\n      return is_sameXZ(img._width,img._depth);\n    }\n\n    //! Test if image width and spectrum are equal to specified values.\n    /**\n       Test if is_sameX(unsigned int) const and is_sameC(unsigned int) const are both verified.\n    **/\n    bool is_sameXC(const unsigned int size_x, const unsigned int size_c) const {\n      return _width==size_x && _spectrum==size_c;\n    }\n\n    //! Test if image width and spectrum are the same as that of another image.\n    /**\n       Test if is_sameX(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameXC(const CImg<t>& img) const {\n      return is_sameXC(img._width,img._spectrum);\n    }\n\n    //! Test if image height and depth are equal to specified values.\n    /**\n       Test if is_sameY(unsigned int) const and is_sameZ(unsigned int) const are both verified.\n    **/\n    bool is_sameYZ(const unsigned int size_y, const unsigned int size_z) const {\n      return _height==size_y && _depth==size_z;\n    }\n\n    //! Test if image height and depth are the same as that of another image.\n    /**\n       Test if is_sameY(const CImg<t>&) const and is_sameZ(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameYZ(const CImg<t>& img) const {\n      return is_sameYZ(img._height,img._depth);\n    }\n\n    //! Test if image height and spectrum are equal to specified values.\n    /**\n       Test if is_sameY(unsigned int) const and is_sameC(unsigned int) const are both verified.\n    **/\n    bool is_sameYC(const unsigned int size_y, const unsigned int size_c) const {\n      return _height==size_y && _spectrum==size_c;\n    }\n\n    //! Test if image height and spectrum are the same as that of another image.\n    /**\n       Test if is_sameY(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameYC(const CImg<t>& img) const {\n      return is_sameYC(img._height,img._spectrum);\n    }\n\n    //! Test if image depth and spectrum are equal to specified values.\n    /**\n       Test if is_sameZ(unsigned int) const and is_sameC(unsigned int) const are both verified.\n    **/\n    bool is_sameZC(const unsigned int size_z, const unsigned int size_c) const {\n      return _depth==size_z && _spectrum==size_c;\n    }\n\n    //! Test if image depth and spectrum are the same as that of another image.\n    /**\n       Test if is_sameZ(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameZC(const CImg<t>& img) const {\n      return is_sameZC(img._depth,img._spectrum);\n    }\n\n    //! Test if image width, height and depth are equal to specified values.\n    /**\n       Test if is_sameXY(unsigned int,unsigned int) const and is_sameZ(unsigned int) const are both verified.\n    **/\n    bool is_sameXYZ(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z) const {\n      return is_sameXY(size_x,size_y) && _depth==size_z;\n    }\n\n    //! Test if image width, height and depth are the same as that of another image.\n    /**\n       Test if is_sameXY(const CImg<t>&) const and is_sameZ(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameXYZ(const CImg<t>& img) const {\n      return is_sameXYZ(img._width,img._height,img._depth);\n    }\n\n    //! Test if image width, height and spectrum are equal to specified values.\n    /**\n       Test if is_sameXY(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified.\n    **/\n    bool is_sameXYC(const unsigned int size_x, const unsigned int size_y, const unsigned int size_c) const {\n      return is_sameXY(size_x,size_y) && _spectrum==size_c;\n    }\n\n    //! Test if image width, height and spectrum are the same as that of another image.\n    /**\n       Test if is_sameXY(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameXYC(const CImg<t>& img) const {\n      return is_sameXYC(img._width,img._height,img._spectrum);\n    }\n\n    //! Test if image width, depth and spectrum are equal to specified values.\n    /**\n       Test if is_sameXZ(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified.\n    **/\n    bool is_sameXZC(const unsigned int size_x, const unsigned int size_z, const unsigned int size_c) const {\n      return is_sameXZ(size_x,size_z) && _spectrum==size_c;\n    }\n\n    //! Test if image width, depth and spectrum are the same as that of another image.\n    /**\n       Test if is_sameXZ(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameXZC(const CImg<t>& img) const {\n      return is_sameXZC(img._width,img._depth,img._spectrum);\n    }\n\n    //! Test if image height, depth and spectrum are equal to specified values.\n    /**\n       Test if is_sameYZ(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified.\n    **/\n    bool is_sameYZC(const unsigned int size_y, const unsigned int size_z, const unsigned int size_c) const {\n      return is_sameYZ(size_y,size_z) && _spectrum==size_c;\n    }\n\n    //! Test if image height, depth and spectrum are the same as that of another image.\n    /**\n       Test if is_sameYZ(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameYZC(const CImg<t>& img) const {\n      return is_sameYZC(img._height,img._depth,img._spectrum);\n    }\n\n    //! Test if image width, height, depth and spectrum are equal to specified values.\n    /**\n       Test if is_sameXYZ(unsigned int,unsigned int,unsigned int) const and is_sameC(unsigned int) const are both\n       verified.\n    **/\n    bool is_sameXYZC(const unsigned int size_x, const unsigned int size_y,\n                     const unsigned int size_z, const unsigned int size_c) const {\n      return is_sameXYZ(size_x,size_y,size_z) && _spectrum==size_c;\n    }\n\n    //! Test if image width, height, depth and spectrum are the same as that of another image.\n    /**\n       Test if is_sameXYZ(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.\n    **/\n    template<typename t>\n    bool is_sameXYZC(const CImg<t>& img) const {\n      return is_sameXYZC(img._width,img._height,img._depth,img._spectrum);\n    }\n\n    //! Test if specified coordinates are inside image bounds.\n    /**\n       Return \\c true if pixel located at (\\c x,\\c y,\\c z,\\c c) is inside bounds of the image instance,\n       and \\c false otherwise.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note\n       - Return \\c true only if all these conditions are verified:\n         - The image instance is \\e not empty.\n         - <tt>0<=x<=\\ref width() - 1</tt>.\n         - <tt>0<=y<=\\ref height() - 1</tt>.\n         - <tt>0<=z<=\\ref depth() - 1</tt>.\n         - <tt>0<=c<=\\ref spectrum() - 1</tt>.\n    **/\n    bool containsXYZC(const int x, const int y=0, const int z=0, const int c=0) const {\n      return !is_empty() && x>=0 && x<width() && y>=0 && y<height() && z>=0 && z<depth() && c>=0 && c<spectrum();\n    }\n\n    //! Test if pixel value is inside image bounds and get its X,Y,Z and C-coordinates.\n    /**\n       Return \\c true, if specified reference refers to a pixel value inside bounds of the image instance,\n       and \\c false otherwise.\n       \\param pixel Reference to pixel value to test.\n       \\param[out] x X-coordinate of the pixel value, if test succeeds.\n       \\param[out] y Y-coordinate of the pixel value, if test succeeds.\n       \\param[out] z Z-coordinate of the pixel value, if test succeeds.\n       \\param[out] c C-coordinate of the pixel value, if test succeeds.\n       \\note\n       - Useful to convert an offset to a buffer value into pixel value coordinates:\n       \\code\n       const CImg<float> img(100,100,1,3);      // Construct a 100x100 RGB color image.\n       const unsigned long offset = 1249;       // Offset to the pixel (49,12,0,0).\n       unsigned int x,y,z,c;\n       if (img.contains(img[offset],x,y,z,c)) { // Convert offset to (x,y,z,c) coordinates.\n         std::printf(\"Offset %u refers to pixel located at (%u,%u,%u,%u).\\n\",\n                     offset,x,y,z,c);\n       }\n       \\endcode\n    **/\n    template<typename t>\n    bool contains(const T& pixel, t& x, t& y, t& z, t& c) const {\n      const ulongT wh = (ulongT)_width*_height, whd = wh*_depth, siz = whd*_spectrum;\n      const T *const ppixel = &pixel;\n      if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false;\n      ulongT off = (ulongT)(ppixel - _data);\n      const ulongT nc = off/whd;\n      off%=whd;\n      const ulongT nz = off/wh;\n      off%=wh;\n      const ulongT ny = off/_width, nx = off%_width;\n      x = (t)nx; y = (t)ny; z = (t)nz; c = (t)nc;\n      return true;\n    }\n\n    //! Test if pixel value is inside image bounds and get its X,Y and Z-coordinates.\n    /**\n       Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X,Y and Z-coordinates are set.\n    **/\n    template<typename t>\n    bool contains(const T& pixel, t& x, t& y, t& z) const {\n      const ulongT wh = (ulongT)_width*_height, whd = wh*_depth, siz = whd*_spectrum;\n      const T *const ppixel = &pixel;\n      if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false;\n      ulongT off = ((ulongT)(ppixel - _data))%whd;\n      const ulongT nz = off/wh;\n      off%=wh;\n      const ulongT ny = off/_width, nx = off%_width;\n      x = (t)nx; y = (t)ny; z = (t)nz;\n      return true;\n    }\n\n    //! Test if pixel value is inside image bounds and get its X and Y-coordinates.\n    /**\n       Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X and Y-coordinates are set.\n    **/\n    template<typename t>\n    bool contains(const T& pixel, t& x, t& y) const {\n      const ulongT wh = (ulongT)_width*_height, siz = wh*_depth*_spectrum;\n      const T *const ppixel = &pixel;\n      if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false;\n      ulongT off = ((unsigned int)(ppixel - _data))%wh;\n      const ulongT ny = off/_width, nx = off%_width;\n      x = (t)nx; y = (t)ny;\n      return true;\n    }\n\n    //! Test if pixel value is inside image bounds and get its X-coordinate.\n    /**\n       Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X-coordinate is set.\n    **/\n    template<typename t>\n    bool contains(const T& pixel, t& x) const {\n      const T *const ppixel = &pixel;\n      if (is_empty() || ppixel<_data || ppixel>=_data + size()) return false;\n      x = (t)(((ulongT)(ppixel - _data))%_width);\n      return true;\n    }\n\n    //! Test if pixel value is inside image bounds.\n    /**\n       Similar to contains(const T&,t&,t&,t&,t&) const, except that no pixel coordinates are set.\n    **/\n    bool contains(const T& pixel) const {\n      const T *const ppixel = &pixel;\n      return !is_empty() && ppixel>=_data && ppixel<_data + size();\n    }\n\n    //! Test if pixel buffers of instance and input images overlap.\n    /**\n       Return \\c true, if pixel buffers attached to image instance and input image \\c img overlap,\n       and \\c false otherwise.\n       \\param img Input image to compare with.\n       \\note\n       - Buffer overlapping may happen when manipulating \\e shared images.\n       - If two image buffers overlap, operating on one of the image will probably modify the other one.\n       - Most of the time, \\c CImg<T> instances are \\e non-shared and do not overlap between each others.\n       \\par Example\n       \\code\n       const CImg<float>\n         img1(\"reference.jpg\"),             // Load RGB-color image.\n         img2 = img1.get_shared_channel(1); // Get shared version of the green channel.\n       if (img1.is_overlapped(img2)) {      // Test succeeds, 'img1' and 'img2' overlaps.\n         std::printf(\"Buffers overlap!\\n\");\n       }\n       \\endcode\n    **/\n    template<typename t>\n    bool is_overlapped(const CImg<t>& img) const {\n      const ulongT csiz = size(), isiz = img.size();\n      return !((void*)(_data + csiz)<=(void*)img._data || (void*)_data>=(void*)(img._data + isiz));\n    }\n\n    //! Test if the set {\\c *this,\\c primitives,\\c colors,\\c opacities} defines a valid 3d object.\n    /**\n       Return \\c true is the 3d object represented by the set {\\c *this,\\c primitives,\\c colors,\\c opacities} defines a\n       valid 3d object, and \\c false otherwise. The vertex coordinates are defined by the instance image.\n       \\param primitives List of primitives of the 3d object.\n       \\param colors List of colors of the 3d object.\n       \\param opacities List (or image) of opacities of the 3d object.\n       \\param full_check Tells if full checking of the 3d object must be performed.\n       \\param[out] error_message C-string to contain the error message, if the test does not succeed.\n       \\note\n       - Set \\c full_checking to \\c false to speed-up the 3d object checking. In this case, only the size of\n         each 3d object component is checked.\n       - Size of the string \\c error_message should be at least 128-bytes long, to be able to contain the error message.\n    **/\n    template<typename tp, typename tc, typename to>\n    bool is_object3d(const CImgList<tp>& primitives,\n                     const CImgList<tc>& colors,\n                     const to& opacities,\n                     const bool full_check=true,\n                     char *const error_message=0) const {\n      if (error_message) *error_message = 0;\n\n      // Check consistency for the particular case of an empty 3d object.\n      if (is_empty()) {\n        if (primitives || colors || opacities) {\n          if (error_message) cimg_sprintf(error_message,\n                                          \"3d object (%u,%u) defines no vertices but %u primitives, \"\n                                          \"%u colors and %lu opacities\",\n                                          _width,primitives._width,primitives._width,\n                                          colors._width,(unsigned long)opacities.size());\n          return false;\n        }\n        return true;\n      }\n\n      // Check consistency of vertices.\n      if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions.\n        if (error_message) cimg_sprintf(error_message,\n                                        \"3d object (%u,%u) has invalid vertex dimensions (%u,%u,%u,%u)\",\n                                        _width,primitives._width,_width,_height,_depth,_spectrum);\n        return false;\n      }\n      if (colors._width>primitives._width + 1) {\n        if (error_message) cimg_sprintf(error_message,\n                                        \"3d object (%u,%u) defines %u colors\",\n                                        _width,primitives._width,colors._width);\n        return false;\n      }\n      if (opacities.size()>primitives._width) {\n        if (error_message) cimg_sprintf(error_message,\n                                        \"3d object (%u,%u) defines %lu opacities\",\n                                        _width,primitives._width,(unsigned long)opacities.size());\n        return false;\n      }\n      if (!full_check) return true;\n\n      // Check consistency of primitives.\n      cimglist_for(primitives,l) {\n        const CImg<tp>& primitive = primitives[l];\n        const unsigned int psiz = primitive.size();\n        switch (psiz) {\n        case 1 : { // Point.\n          const unsigned int i0 = (unsigned int)primitive(0);\n          if (i0>=_width) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"3d object (%u,%u) refers to invalid vertex indice %u in \"\n                                            \"point primitive [%u]\",\n                                            _width,primitives._width,i0,l);\n            return false;\n          }\n        } break;\n        case 5 : { // Sphere.\n          const unsigned int\n            i0 = (unsigned int)primitive(0),\n            i1 = (unsigned int)primitive(1);\n          if (i0>=_width || i1>=_width) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"3d object (%u,%u) refers to invalid vertex indices (%u,%u) in \"\n                                            \"sphere primitive [%u]\",\n                                            _width,primitives._width,i0,i1,l);\n            return false;\n          }\n        } break;\n        case 2 : // Segment.\n        case 6 : {\n          const unsigned int\n            i0 = (unsigned int)primitive(0),\n            i1 = (unsigned int)primitive(1);\n          if (i0>=_width || i1>=_width) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"3d object (%u,%u) refers to invalid vertex indices (%u,%u) in \"\n                                            \"segment primitive [%u]\",\n                                            _width,primitives._width,i0,i1,l);\n            return false;\n          }\n        } break;\n        case 3 : // Triangle.\n        case 9 : {\n          const unsigned int\n            i0 = (unsigned int)primitive(0),\n            i1 = (unsigned int)primitive(1),\n            i2 = (unsigned int)primitive(2);\n          if (i0>=_width || i1>=_width || i2>=_width) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in \"\n                                            \"triangle primitive [%u]\",\n                                            _width,primitives._width,i0,i1,i2,l);\n            return false;\n          }\n        } break;\n        case 4 : // Quadrangle.\n        case 12 : {\n          const unsigned int\n            i0 = (unsigned int)primitive(0),\n            i1 = (unsigned int)primitive(1),\n            i2 = (unsigned int)primitive(2),\n            i3 = (unsigned int)primitive(3);\n          if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in \"\n                                            \"quadrangle primitive [%u]\",\n                                            _width,primitives._width,i0,i1,i2,i3,l);\n            return false;\n          }\n        } break;\n        default :\n          if (error_message) cimg_sprintf(error_message,\n                                          \"3d object (%u,%u) defines an invalid primitive [%u] of size %u\",\n                                          _width,primitives._width,l,(unsigned int)psiz);\n          return false;\n        }\n      }\n\n      // Check consistency of colors.\n      cimglist_for(colors,c) {\n        const CImg<tc>& color = colors[c];\n        if (!color) {\n          if (error_message) cimg_sprintf(error_message,\n                                          \"3d object (%u,%u) defines no color for primitive [%u]\",\n                                          _width,primitives._width,c);\n          return false;\n        }\n      }\n\n      // Check consistency of light texture.\n      if (colors._width>primitives._width) {\n        const CImg<tc> &light = colors.back();\n        if (!light || light._depth>1) {\n          if (error_message) cimg_sprintf(error_message,\n                                          \"3d object (%u,%u) defines an invalid light texture (%u,%u,%u,%u)\",\n                                          _width,primitives._width,light._width,\n                                          light._height,light._depth,light._spectrum);\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    //! Test if image instance represents a valid serialization of a 3d object.\n    /**\n       Return \\c true if the image instance represents a valid serialization of a 3d object, and \\c false otherwise.\n       \\param full_check Tells if full checking of the instance must be performed.\n       \\param[out] error_message C-string to contain the error message, if the test does not succeed.\n       \\note\n       - Set \\c full_check to \\c false to speed-up the 3d object checking. In this case, only the size of\n         each 3d object component is checked.\n       - Size of the string \\c error_message should be at least 128-bytes long, to be able to contain the error message.\n    **/\n    bool is_CImg3d(const bool full_check=true, char *const error_message=0) const {\n      if (error_message) *error_message = 0;\n\n      // Check instance dimension and header.\n      if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) {\n        if (error_message) cimg_sprintf(error_message,\n                                        \"CImg3d has invalid dimensions (%u,%u,%u,%u)\",\n                                        _width,_height,_depth,_spectrum);\n        return false;\n      }\n      const T *ptrs = _data, *const ptre = end();\n      if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') ||\n          !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) {\n        if (error_message) cimg_sprintf(error_message,\n                                        \"CImg3d header not found\");\n        return false;\n      }\n      const unsigned int\n        nb_points = cimg::float2uint((float)*(ptrs++)),\n        nb_primitives = cimg::float2uint((float)*(ptrs++));\n\n      // Check consistency of number of vertices / primitives.\n      if (!full_check) {\n        const ulongT minimal_size = 8UL + 3*nb_points + 6*nb_primitives;\n        if (_data + minimal_size>ptre) {\n          if (error_message) cimg_sprintf(error_message,\n                                          \"CImg3d (%u,%u) has only %lu values, while at least %lu values were expected\",\n                                          nb_points,nb_primitives,size(),minimal_size);\n          return false;\n        }\n      }\n\n      // Check consistency of vertex data.\n      if (!nb_points) {\n        if (nb_primitives) {\n          if (error_message) cimg_sprintf(error_message,\n                                          \"CImg3d (%u,%u) defines no vertices but %u primitives\",\n                                          nb_points,nb_primitives,nb_primitives);\n          return false;\n        }\n        if (ptrs!=ptre) {\n          if (error_message) cimg_sprintf(error_message,\n                                          \"CImg3d (%u,%u) is an empty object but contains %u value%s \"\n                                          \"more than expected\",\n                                          nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?\"s\":\"\");\n          return false;\n        }\n        return true;\n      }\n      if (ptrs + 3*nb_points>ptre) {\n        if (error_message) cimg_sprintf(error_message,\n                                        \"CImg3d (%u,%u) defines only %u vertices data\",\n                                        nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3);\n        return false;\n      }\n      ptrs+=3*nb_points;\n\n      // Check consistency of primitive data.\n      if (ptrs==ptre) {\n        if (error_message) cimg_sprintf(error_message,\n                                        \"CImg3d (%u,%u) defines %u vertices but no primitive\",\n                                        nb_points,nb_primitives,nb_points);\n        return false;\n      }\n\n      if (!full_check) return true;\n\n      for (unsigned int p = 0; p<nb_primitives; ++p) {\n        const unsigned int nb_inds = (unsigned int)*(ptrs++);\n        switch (nb_inds) {\n        case 1 : { // Point.\n          const unsigned int i0 = cimg::float2uint((float)*(ptrs++));\n          if (i0>=nb_points) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive [%u]\",\n                                            nb_points,nb_primitives,i0,p);\n            return false;\n          }\n        } break;\n        case 5 : { // Sphere.\n          const unsigned int\n            i0 = cimg::float2uint((float)*(ptrs++)),\n            i1 = cimg::float2uint((float)*(ptrs++));\n          ptrs+=3;\n          if (i0>=nb_points || i1>=nb_points) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in \"\n                                            \"sphere primitive [%u]\",\n                                            nb_points,nb_primitives,i0,i1,p);\n            return false;\n          }\n        } break;\n        case 2 : case 6 : { // Segment.\n          const unsigned int\n            i0 = cimg::float2uint((float)*(ptrs++)),\n            i1 = cimg::float2uint((float)*(ptrs++));\n          if (nb_inds==6) ptrs+=4;\n          if (i0>=nb_points || i1>=nb_points) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in \"\n                                            \"segment primitive [%u]\",\n                                            nb_points,nb_primitives,i0,i1,p);\n            return false;\n          }\n        } break;\n        case 3 : case 9 : { // Triangle.\n          const unsigned int\n            i0 = cimg::float2uint((float)*(ptrs++)),\n            i1 = cimg::float2uint((float)*(ptrs++)),\n            i2 = cimg::float2uint((float)*(ptrs++));\n          if (nb_inds==9) ptrs+=6;\n          if (i0>=nb_points || i1>=nb_points || i2>=nb_points) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in \"\n                                            \"triangle primitive [%u]\",\n                                            nb_points,nb_primitives,i0,i1,i2,p);\n            return false;\n          }\n        } break;\n        case 4 : case 12 : { // Quadrangle.\n          const unsigned int\n            i0 = cimg::float2uint((float)*(ptrs++)),\n            i1 = cimg::float2uint((float)*(ptrs++)),\n            i2 = cimg::float2uint((float)*(ptrs++)),\n            i3 = cimg::float2uint((float)*(ptrs++));\n          if (nb_inds==12) ptrs+=8;\n          if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) {\n            if (error_message) cimg_sprintf(error_message,\n                                            \"CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in \"\n                                            \"quadrangle primitive [%u]\",\n                                            nb_points,nb_primitives,i0,i1,i2,i3,p);\n            return false;\n          }\n        } break;\n        default :\n          if (error_message) cimg_sprintf(error_message,\n                                          \"CImg3d (%u,%u) defines an invalid primitive [%u] of size %u\",\n                                          nb_points,nb_primitives,p,nb_inds);\n          return false;\n        }\n        if (ptrs>ptre) {\n          if (error_message) cimg_sprintf(error_message,\n                                          \"CImg3d (%u,%u) has incomplete primitive data for primitive [%u], \"\n                                          \"%u values missing\",\n                                          nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre));\n          return false;\n        }\n      }\n\n      // Check consistency of color data.\n      if (ptrs==ptre) {\n        if (error_message) cimg_sprintf(error_message,\n                                        \"CImg3d (%u,%u) defines no color/texture data\",\n                                        nb_points,nb_primitives);\n        return false;\n      }\n      for (unsigned int c = 0; c<nb_primitives; ++c) {\n        if (*(ptrs++)!=(T)-128) ptrs+=2;\n        else if ((ptrs+=3)<ptre) {\n          const unsigned int\n            w = (unsigned int)*(ptrs - 3),\n            h = (unsigned int)*(ptrs - 2),\n            s = (unsigned int)*(ptrs - 1);\n          if (!h && !s) {\n            if (w>=c) {\n              if (error_message) cimg_sprintf(error_message,\n                                              \"CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u \"\n                                              \"for primitive [%u]\",\n                                              nb_points,nb_primitives,w,c);\n              return false;\n            }\n          } else ptrs+=w*h*s;\n        }\n        if (ptrs>ptre) {\n          if (error_message) cimg_sprintf(error_message,\n                                          \"CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], \"\n                                          \"%u values missing\",\n                                          nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre));\n          return false;\n        }\n      }\n\n      // Check consistency of opacity data.\n      if (ptrs==ptre) {\n        if (error_message) cimg_sprintf(error_message,\n                                        \"CImg3d (%u,%u) defines no opacity data\",\n                                        nb_points,nb_primitives);\n        return false;\n      }\n      for (unsigned int o = 0; o<nb_primitives; ++o) {\n        if (*(ptrs++)==(T)-128 && (ptrs+=3)<ptre) {\n          const unsigned int\n            w = (unsigned int)*(ptrs - 3),\n            h = (unsigned int)*(ptrs - 2),\n            s = (unsigned int)*(ptrs - 1);\n          if (!h && !s) {\n            if (w>=o) {\n              if (error_message) cimg_sprintf(error_message,\n                                              \"CImg3d (%u,%u) refers to invalid shared opacity indice %u \"\n                                              \"for primitive [%u]\",\n                                              nb_points,nb_primitives,w,o);\n              return false;\n            }\n          } else ptrs+=w*h*s;\n        }\n        if (ptrs>ptre) {\n          if (error_message) cimg_sprintf(error_message,\n                                          \"CImg3d (%u,%u) has incomplete opacity data for primitive [%u]\",\n                                          nb_points,nb_primitives,o);\n          return false;\n        }\n      }\n\n      // Check end of data.\n      if (ptrs<ptre) {\n        if (error_message) cimg_sprintf(error_message,\n                                        \"CImg3d (%u,%u) contains %u value%s more than expected\",\n                                        nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?\"s\":\"\");\n        return false;\n      }\n      return true;\n    }\n\n    static bool _is_CImg3d(const T val, const char c) {\n      return val>=(T)c && val<(T)(c + 1);\n    }\n\n    //@}\n    //-------------------------------------\n    //\n    //! \\name Mathematical Functions\n    //@{\n    //-------------------------------------\n\n    // Define the math formula parser/compiler and expression evaluator.\n    struct _cimg_math_parser {\n      CImg<doubleT> mem;\n      CImg<intT> memtype;\n      CImgList<ulongT> _code, &code;\n      CImg<ulongT> opcode;\n      const CImg<ulongT> *p_code_begin, *p_code_end, *p_code;\n\n      CImg<charT> expr, pexpr;\n      const CImg<T>& imgin;\n      const CImgList<T>& listin;\n      CImg<T> &imgout;\n      CImgList<T>& listout;\n\n      CImg<doubleT> _img_stats, &img_stats;\n      CImgList<doubleT> _list_stats, &list_stats, _list_median, &list_median;\n      CImg<uintT> mem_img_stats;\n\n      CImg<uintT> level, variable_pos, reserved_label;\n      CImgList<charT> variable_def, function_def, function_body;\n      char *user_function;\n\n      unsigned int mempos, mem_img_median, debug_indent, init_size, result_dim;\n      bool is_parallelizable, need_input_copy;\n      double *result;\n      const char *const calling_function, *s_op, *ss_op;\n      typedef double (*mp_func)(_cimg_math_parser&);\n\n#define _cimg_mp_is_constant(arg) (memtype[arg]==1) // Is constant?\n#define _cimg_mp_is_scalar(arg) (memtype[arg]<2) // Is scalar?\n#define _cimg_mp_is_temp(arg) (!memtype[arg]) // Is temporary scalar?\n#define _cimg_mp_is_variable(arg) (memtype[arg]==-1) // Is scalar variable?\n#define _cimg_mp_is_vector(arg) (memtype[arg]>1) // Is vector?\n#define _cimg_mp_vector_size(arg) (_cimg_mp_is_scalar(arg)?0U:(unsigned int)memtype[arg] - 1) // Vector size\n#define _cimg_mp_calling_function calling_function_s()._data\n#define _cimg_mp_op(s) s_op = s; ss_op = ss\n#define _cimg_mp_check_type(arg,n_arg,mode,N) check_type(arg,n_arg,mode,N,ss,se,saved_char)\n#define _cimg_mp_check_constant(arg,n_arg,is_strict) check_constant(arg,n_arg,is_strict,ss,se,saved_char)\n#define _cimg_mp_check_matrix_square(arg,n_arg) check_matrix_square(arg,n_arg,ss,se,saved_char)\n#define _cimg_mp_check_vector0(dim) check_vector0(dim,ss,se,saved_char)\n#define _cimg_mp_check_list(is_out) check_list(is_out,ss,se,saved_char)\n#define _cimg_mp_defunc(mp) (*(mp_func)(*(mp).opcode))(mp)\n#define _cimg_mp_return(x) { *se = saved_char; s_op = previous_s_op; ss_op = previous_ss_op; return x; }\n#define _cimg_mp_constant(val) _cimg_mp_return(constant((double)(val)))\n#define _cimg_mp_scalar0(op) _cimg_mp_return(scalar0(op))\n#define _cimg_mp_scalar1(op,i1) _cimg_mp_return(scalar1(op,i1))\n#define _cimg_mp_scalar2(op,i1,i2) _cimg_mp_return(scalar2(op,i1,i2))\n#define _cimg_mp_scalar3(op,i1,i2,i3) _cimg_mp_return(scalar3(op,i1,i2,i3))\n#define _cimg_mp_scalar6(op,i1,i2,i3,i4,i5,i6) _cimg_mp_return(scalar6(op,i1,i2,i3,i4,i5,i6))\n#define _cimg_mp_scalar7(op,i1,i2,i3,i4,i5,i6,i7) _cimg_mp_return(scalar7(op,i1,i2,i3,i4,i5,i6,i7))\n#define _cimg_mp_vector1_v(op,i1) _cimg_mp_return(vector1_v(op,i1))\n#define _cimg_mp_vector2_sv(op,i1,i2) _cimg_mp_return(vector2_sv(op,i1,i2))\n#define _cimg_mp_vector2_vs(op,i1,i2) _cimg_mp_return(vector2_vs(op,i1,i2))\n#define _cimg_mp_vector2_vv(op,i1,i2) _cimg_mp_return(vector2_vv(op,i1,i2))\n#define _cimg_mp_vector3_vss(op,i1,i2,i3) _cimg_mp_return(vector3_vss(op,i1,i2,i3))\n\n      // Constructors.\n      _cimg_math_parser(const char *const expression, const char *const funcname=0,\n                        const CImg<T>& img_input=CImg<T>::const_empty(), CImg<T> *const img_output=0,\n                        const CImgList<T> *const list_input=0, CImgList<T> *const list_output=0):\n        code(_code),imgin(img_input),listin(list_input?*list_input:CImgList<T>::const_empty()),\n        imgout(img_output?*img_output:CImg<T>::empty()),listout(list_output?*list_output:CImgList<T>::empty()),\n        img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),user_function(0),\n        mem_img_median(~0U),debug_indent(0),init_size(0),result_dim(0),is_parallelizable(true),\n        need_input_copy(false),calling_function(funcname?funcname:\"cimg_math_parser\") {\n        if (!expression || !*expression)\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s: Empty expression.\",\n                                      pixel_type(),_cimg_mp_calling_function);\n        const char *_expression = expression;\n        while (*_expression && (*_expression<=' ' || *_expression==';')) ++_expression;\n        CImg<charT>::string(_expression).move_to(expr);\n        char *ps = &expr.back() - 1;\n        while (ps>expr._data && (*ps==' ' || *ps==';')) --ps;\n        *(++ps) = 0; expr._width = (unsigned int)(ps - expr._data + 1);\n\n        // Ease the retrieval of previous non-space characters afterwards.\n        pexpr.assign(expr._width);\n\n        char c, *pe = pexpr._data;\n        for (ps = expr._data, c = ' '; *ps; ++ps) {\n          if (*ps!=' ') c = *ps;\n          *(pe++) = c;\n        }\n        *pe = 0;\n\n        // Count parentheses/brackets level of expression.\n        level.assign(expr._width - 1);\n        int lv = 0;\n        unsigned int *pd = level._data;\n        for (ps = expr._data; *ps && lv>=0; ++ps)\n          *(pd++) = (unsigned int)(*ps=='('||*ps=='['?lv++:*ps==')'||*ps==']'?--lv:lv);\n        if (lv!=0) {\n          cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,\n                                      expr._data);\n        }\n\n        // Init constant values.\n        mem.assign(96);\n        memtype.assign(96);\n        double *p_mem = mem._data;\n        for (unsigned int i = 0; i<=10; ++i) *(p_mem++) = (double)i;  // mem[0-10]\n        for (unsigned int i = 1; i<=5; ++i) *(p_mem++) = -(double)i;  // mem[11-15]\n        *(p_mem++) = 0.5; // mem[16]\n        *(p_mem++) = 0; // mem[17] = thread_id\n        *(p_mem++) = (double)imgin._width; // mem[18]\n        *(p_mem++) = (double)imgin._height; // mem[19]\n        *(p_mem++) = (double)imgin._depth; // mem[20]\n        *(p_mem++) = (double)imgin._spectrum; // mem[21]\n        *(p_mem++) = (double)imgin._is_shared; // mem[22]\n        *(p_mem++) = (double)imgin._width*imgin._height; // mem[23]\n        *(p_mem++) = (double)imgin._width*imgin._height*imgin._depth; // mem[24]\n        *(p_mem++) = (double)imgin._width*imgin._height*imgin._depth*imgin._spectrum; // mem[25]\n        *(p_mem++) = cimg::PI; // mem[26]\n        *(p_mem++) = std::exp(1.0); // mem[27]\n        *(p_mem++) = cimg::type<double>::nan(); // mem[28]\n\n        // Then, [29] = x, [30] = y, [31] = z and [32] = c.\n#define _cimg_mp_x 29\n#define _cimg_mp_y 30\n#define _cimg_mp_z 31\n#define _cimg_mp_c 32\n\n        // Set value property :\n        // { -1 = variable | 0 = regular value | 1 = compile time constant | N>1 = constant ptr to vector[N-1] }.\n        std::memset(memtype._data,0,sizeof(int)*memtype._width);\n        int *p_memtype = memtype._data; for (unsigned int i = 0; i<_cimg_mp_x; ++i) *(p_memtype++) = 1;\n        memtype[17] = 0;\n\n        mempos = _cimg_mp_c + 1;\n        variable_pos.assign(8);\n        reserved_label.assign(128,1,1,1,~0U);\n        reserved_label['t'] = 17;\n        reserved_label['w'] = 18;\n        reserved_label['h'] = 19;\n        reserved_label['d'] = 20;\n        reserved_label['s'] = 21;\n        reserved_label['r'] = 22;\n        reserved_label[0] = 23; // wh\n        reserved_label[1] = 24; // whd\n        reserved_label[2] = 25; // whds\n        reserved_label[3] = 26; // pi\n        reserved_label['e'] = 27;\n        reserved_label[29] = 0; // interpolation\n        reserved_label[30] = 0; // boundary\n        reserved_label['x'] = _cimg_mp_x;\n        reserved_label['y'] = _cimg_mp_y;\n        reserved_label['z'] = _cimg_mp_z;\n        reserved_label['c'] = _cimg_mp_c;\n        // reserved_label[4-28] store also two-char variables:\n        // [4] = im, [5] = iM, [6] = ia, [7] = iv, [8] = is, [9] = ip, [10] = ic,\n        // [11] = xm, [12] = ym, [13] = zm, [14] = cm, [15] = xM, [16] = yM, [17] = zM, [18]=cM, [19]=i0...[28]=i9,\n\n        // Compile expression into a serie of opcodes.\n        s_op = \"\"; ss_op = expr._data;\n        const unsigned int ind_result = compile(expr._data,expr._data + expr._width - 1,0,0);\n        p_code_end = code.end();\n\n        // Free resources used for parsing and prepare for evaluation.\n        if (_cimg_mp_is_vector(ind_result)) result_dim = _cimg_mp_vector_size(ind_result);\n        mem.resize(mempos,1,1,1,-1);\n        result = mem._data + ind_result;\n        memtype.assign();\n        level.assign();\n        variable_pos.assign();\n        reserved_label.assign();\n        expr.assign();\n        pexpr.assign();\n        opcode.assign();\n        opcode._width = opcode._depth = opcode._spectrum = 1;\n        opcode._is_shared = true;\n\n        // Execute init() function if any specified.\n        p_code_begin = code._data + init_size;\n        if (init_size) {\n          mem[_cimg_mp_x] = mem[_cimg_mp_y] = mem[_cimg_mp_z] = mem[_cimg_mp_c] = 0;\n          for (p_code = code._data; p_code<p_code_begin; ++p_code) {\n            const CImg<ulongT> &op = *p_code;\n            opcode._data = op._data; opcode._height = op._height;\n            const ulongT target = opcode[1];\n            mem[target] = _cimg_mp_defunc(*this);\n          }\n        }\n      }\n\n      _cimg_math_parser():\n        code(_code),p_code_begin(0),p_code_end(0),\n        imgin(CImg<T>::const_empty()),listin(CImgList<T>::const_empty()),\n        imgout(CImg<T>::empty()),listout(CImgList<T>::empty()),\n        img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),debug_indent(0),\n        result_dim(0),is_parallelizable(true),need_input_copy(false),calling_function(0) {\n        mem.assign(1 + _cimg_mp_c,1,1,1,0); // Allow to skip 'is_empty?' test in operator()()\n        result = mem._data;\n      }\n\n      _cimg_math_parser(const _cimg_math_parser& mp):\n        mem(mp.mem),code(mp.code),p_code_begin(mp.p_code_begin),p_code_end(mp.p_code_end),\n        imgin(mp.imgin),listin(mp.listin),imgout(mp.imgout),listout(mp.listout),img_stats(mp.img_stats),\n        list_stats(mp.list_stats),list_median(mp.list_median),debug_indent(0),result_dim(mp.result_dim),\n        is_parallelizable(mp.is_parallelizable), need_input_copy(mp.need_input_copy),\n        result(mem._data + (mp.result - mp.mem._data)),calling_function(0) {\n#ifdef cimg_use_openmp\n        mem[17] = omp_get_thread_num();\n#endif\n        opcode._width = opcode._depth = opcode._spectrum = 1;\n        opcode._is_shared = true;\n      }\n\n      // Compilation procedure.\n      unsigned int compile(char *ss, char *se, const unsigned int depth, unsigned int *const p_ref) {\n        if (depth>256) {\n          cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s: Call stack overflow (infinite recursion?), \"\n                                      \"in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,\n                                      (ss - 4)>expr._data?\"...\":\"\",\n                                      (ss - 4)>expr._data?ss - 4:expr._data,\n                                      se<&expr.back()?\"...\":\"\");\n        }\n\n        const char *const ss0 = ss;\n        char c1, c2, c3, c4;\n\n        if (ss<se) {\n          while (*ss && (*ss<=' ' || *ss==';')) ++ss;\n          while (se>ss && (c1=*(se - 1))>0 && (c1<=' ' || c1==';')) --se;\n        }\n        if (se>ss && *(se - 1)==';') --se;\n        while (*ss=='(' && *(se - 1)==')' && std::strchr(ss,')')==se - 1) { // Detect simple content around parentheses.\n          ++ss; --se;\n        }\n        if (se<=ss || !*ss) {\n          cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s: %s%s Missing %s, in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?\":\":\"\",\n                                      *s_op=='F'?\"argument\":\"item\",\n                                      (ss_op - 4)>expr._data?\"...\":\"\",\n                                      (ss_op - 4)>expr._data?ss_op - 4:expr._data,\n                                      ss_op + std::strlen(ss_op)<&expr.back()?\"...\":\"\");\n        }\n\n        const char *const previous_s_op = s_op, *const previous_ss_op = ss_op;\n        const unsigned int depth1 = depth + 1;\n        unsigned int pos, p1, p2, p3, arg1, arg2, arg3, arg4, arg5, arg6;\n        char\n          *const se1 = se - 1, *const se2 = se - 2, *const se3 = se - 3,\n          *const ss1 = ss + 1, *const ss2 = ss + 2, *const ss3 = ss + 3, *const ss4 = ss + 4,\n          *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7, *const ss8 = ss + 8,\n          *s, *ps, *ns, *s0, *s1, *s2, *s3, sep = 0, end = 0;\n        double val, val1, val2;\n        mp_func op;\n\n        // 'p_ref' is a 'unsigned int[7]' used to return a reference to an image or vector value\n        // linked to the returned memory slot (reference that cannot be determined at compile time).\n        // p_ref[0] can be { 0 = scalar (unlinked) | 1 = vector value | 2 = image value (offset) |\n        //                   3 = image value (coordinates) | 4 = image value as a vector (offsets) |\n        //                   5 = image value as a vector (coordinates) }.\n        // Depending on p_ref[0], the remaining p_ref[k] have the following meaning:\n        // When p_ref[0]==0, p_ref is actually unlinked.\n        // When p_ref[0]==1, p_ref = [ 1, vector_ind, offset ].\n        // When p_ref[0]==2, p_ref = [ 2, image_ind (or ~0U), is_relative, offset ].\n        // When p_ref[0]==3, p_ref = [ 3, image_ind (or ~0U), is_relative, x, y, z, c ].\n        // When p_ref[0]==4, p_ref = [ 4, image_ind (or ~0U), is_relative, offset ].\n        // When p_ref[0]==5, p_ref = [ 5, image_ind (or ~0U), is_relative, x, y, z ].\n        if (p_ref) { *p_ref = 0; p_ref[1] = p_ref[2] = p_ref[3] = p_ref[4] = p_ref[5] = p_ref[6] = ~0U; }\n\n        const char saved_char = *se; *se = 0;\n        const unsigned int clevel = level[ss - expr._data], clevel1 = clevel + 1;\n        bool is_sth, is_relative;\n        CImg<uintT> ref;\n        CImgList<ulongT> _opcode;\n        CImg<charT> variable_name;\n\n        // Look for a single value or a pre-defined variable.\n        int nb = cimg_sscanf(ss,\"%lf%c%c\",&val,&(sep=0),&(end=0));\n\n#if cimg_OS==2\n        // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able\n        // to read those particular values.\n        if (!nb && (*ss=='+' || *ss=='-' || *ss=='i' || *ss=='I' || *ss=='n' || *ss=='N')) {\n          is_sth = true;\n          s = ss;\n          if (*s=='+') ++s; else if (*s=='-') { ++s; is_sth = false; }\n          if (!cimg::strcasecmp(s,\"inf\")) { val = cimg::type<double>::inf(); nb = 1; }\n          else if (!cimg::strcasecmp(s,\"nan\")) { val = cimg::type<double>::nan(); nb = 1; }\n          if (nb==1 && !is_sth) val = -val;\n        }\n#endif\n        if (nb==1) _cimg_mp_constant(val);\n        if (nb==2 && sep=='%') _cimg_mp_constant(val/100);\n\n        if (ss1==se) switch (*ss) { // One-char variable\n          case 't' : case 'w' : case 'h' : case 'd' : case 's' : case 'r' :\n          case 'x' : case 'y' : case 'z' : case 'c' : case 'e' :\n            _cimg_mp_return(reserved_label[*ss]);\n          case 'u' :\n            if (reserved_label['u']!=~0U) _cimg_mp_return(reserved_label['u']);\n            _cimg_mp_scalar2(mp_u,0,1);\n          case 'g' :\n            if (reserved_label['g']!=~0U) _cimg_mp_return(reserved_label['g']);\n            _cimg_mp_scalar0(mp_g);\n          case 'i' :\n            if (reserved_label['i']!=~0U) _cimg_mp_return(reserved_label['i']);\n            _cimg_mp_scalar0(mp_i);\n          case 'I' :\n            _cimg_mp_op(\"Variable 'I'\");\n            if (reserved_label['I']!=~0U) _cimg_mp_return(reserved_label['I']);\n            _cimg_mp_check_vector0(imgin._spectrum);\n            need_input_copy = true;\n            pos = vector(imgin._spectrum);\n            CImg<ulongT>::vector((ulongT)mp_Joff,pos,0,0).move_to(code);\n            _cimg_mp_return(pos);\n          case 'R' :\n            if (reserved_label['R']!=~0U) _cimg_mp_return(reserved_label['R']);\n            need_input_copy = true;\n            _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,0,0,0);\n          case 'G' :\n            if (reserved_label['G']!=~0U) _cimg_mp_return(reserved_label['G']);\n            need_input_copy = true;\n            _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,1,0,0);\n          case 'B' :\n            if (reserved_label['B']!=~0U) _cimg_mp_return(reserved_label['B']);\n            need_input_copy = true;\n            _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,2,0,0);\n          case 'A' :\n            if (reserved_label['A']!=~0U) _cimg_mp_return(reserved_label['A']);\n            need_input_copy = true;\n            _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,3,0,0);\n          }\n        else if (ss2==se) { // Two-chars variable\n          arg1 = arg2 = ~0U;\n          if (*ss=='w' && *ss1=='h') _cimg_mp_return(reserved_label[0]); // wh\n          if (*ss=='p' && *ss1=='i') _cimg_mp_return(reserved_label[3]); // pi\n          if (*ss=='i') {\n            if (*ss1>='0' && *ss1<='9') { // i0...i9\n              pos = 19 + *ss1 - '0';\n              if (reserved_label[pos]!=~0U) _cimg_mp_return(reserved_label[pos]);\n              need_input_copy = true;\n              _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,pos - 19,0,0);\n            }\n            switch (*ss1) {\n            case 'm' : arg1 = 4; arg2 = 0; break; // im\n            case 'M' : arg1 = 5; arg2 = 1; break; // iM\n            case 'a' : arg1 = 6; arg2 = 2; break; // ia\n            case 'v' : arg1 = 7; arg2 = 3; break; // iv\n            case 's' : arg1 = 8; arg2 = 12; break; // is\n            case 'p' : arg1 = 9; arg2 = 13; break; // is\n            case 'c' : // ic\n              if (reserved_label[10]!=~0U) _cimg_mp_return(reserved_label[10]);\n              if (mem_img_median==~0U) mem_img_median = imgin?constant(imgin.median()):0;\n              _cimg_mp_return(mem_img_median);\n              break;\n            }\n          }\n          else if (*ss1=='m') switch (*ss) {\n            case 'x' : arg1 = 11; arg2 = 4; break; // xm\n            case 'y' : arg1 = 12; arg2 = 5; break; // ym\n            case 'z' : arg1 = 13; arg2 = 6; break; // zm\n            case 'c' : arg1 = 14; arg2 = 7; break; // cm\n            }\n          else if (*ss1=='M') switch (*ss) {\n            case 'x' : arg1 = 15; arg2 = 8; break; // xM\n            case 'y' : arg1 = 16; arg2 = 9; break; // yM\n            case 'z' : arg1 = 17; arg2 = 10; break; // zM\n            case 'c' : arg1 = 18; arg2 = 11; break; // cM\n            }\n          if (arg1!=~0U) {\n            if (reserved_label[arg1]!=~0U) _cimg_mp_return(reserved_label[arg1]);\n            if (!img_stats) {\n              img_stats.assign(1,14,1,1,0).fill(imgin.get_stats(),false);\n              mem_img_stats.assign(1,14,1,1,~0U);\n            }\n            if (mem_img_stats[arg2]==~0U) mem_img_stats[arg2] = constant(img_stats[arg2]);\n            _cimg_mp_return(mem_img_stats[arg2]);\n          }\n        } else if (ss3==se) { // Three-chars variable\n          if (*ss=='w' && *ss1=='h' && *ss2=='d') _cimg_mp_return(reserved_label[1]); // whd\n        } else if (ss4==se) { // Four-chars variable\n          if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s') _cimg_mp_return(reserved_label[2]); // whds\n        }\n\n        pos = ~0U;\n        for (s0 = ss, s = ss1; s<se1; ++s)\n          if (*s==';' && level[s - expr._data]==clevel) { // Separator ';'\n            pos = compile(s0,s,depth,0);\n            s0 = s + 1;\n          }\n        if (pos!=~0U) _cimg_mp_return(compile(s0,se,depth,p_ref));\n\n        // Declare / assign variable, vector value or image value.\n        for (s = ss1, ps = ss, ns = ss2; s<se1; ++s, ++ps, ++ns)\n          if (*s=='=' && *ns!='=' && *ps!='=' && *ps!='>' && *ps!='<' && *ps!='!' &&\n              *ps!='+' && *ps!='-' && *ps!='*' && *ps!='/' && *ps!='%' &&\n              *ps!='>' && *ps!='<' && *ps!='&' && *ps!='|' && *ps!='^' &&\n              level[s - expr._data]==clevel) {\n            variable_name.assign(ss,(unsigned int)(s + 1 - ss)).back() = 0;\n            cimg::strpare(variable_name);\n            const unsigned int l_variable_name = (unsigned int)std::strlen(variable_name);\n            char *const ve1 = ss + l_variable_name - 1;\n            _cimg_mp_op(\"Operator '='\");\n\n            // Assign image value (direct).\n            if (l_variable_name>2 && (*ss=='i' || *ss=='j' || *ss=='I' || *ss=='J') && (*ss1=='(' || *ss1=='[') &&\n                (reserved_label[*ss]==~0U || *ss1=='(' || !_cimg_mp_is_vector(reserved_label[*ss]))) {\n              is_relative = *ss=='j' || *ss=='J';\n\n              if (*ss1=='[' && *ve1==']') { // i/j/I/J[_#ind,offset] = value\n                is_parallelizable = false;\n                if (*ss2=='#') { // Index specified\n                  s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                  p1 = compile(ss3,s0++,depth1,0);\n                  _cimg_mp_check_list(true);\n                } else { p1 = ~0U; s0 = ss2; }\n                arg1 = compile(s0,ve1,depth1,0); // Offset\n                arg2 = compile(s + 1,se,depth1,0); // Value to assign\n                if (_cimg_mp_is_vector(arg2)) {\n                  p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any\n                  if (p1==~0U) p2 = imgin._spectrum;\n                  else if (_cimg_mp_is_constant(p1)) {\n                    p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());\n                    p2 = listin[p3]._spectrum;\n                  }\n                  _cimg_mp_check_vector0(p2);\n                } else p2 = 0;\n                _cimg_mp_check_type(arg2,2,*ss>='i'?1:3,p2);\n\n                if (p_ref) {\n                  *p_ref = _cimg_mp_is_vector(arg2)?4:2;\n                  p_ref[1] = p1;\n                  p_ref[2] = (unsigned int)is_relative;\n                  p_ref[3] = arg1;\n                  if (_cimg_mp_is_vector(arg2))\n                    set_variable_vector(arg2); // Prevent from being used in further optimization\n                  else if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;\n                  if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1;\n                  if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;\n                }\n                if (p1!=~0U) {\n                  if (!listout) _cimg_mp_return(arg2);\n                  if (*ss>='i')\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff),\n                                        arg2,p1,arg1).move_to(code);\n                  else if (_cimg_mp_is_scalar(arg2))\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s),\n                                        arg2,p1,arg1).move_to(code);\n                  else\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),\n                                        arg2,p1,arg1).move_to(code);\n                } else {\n                  if (!imgout) _cimg_mp_return(arg2);\n                  if (*ss>='i')\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff),\n                                        arg2,arg1).move_to(code);\n                  if (_cimg_mp_is_scalar(arg2))\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s),\n                                        arg2,arg1).move_to(code);\n                  else\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),\n                                        arg2,arg1).move_to(code);\n                }\n                _cimg_mp_return(arg2);\n              }\n\n              if (*ss1=='(' && *ve1==')') { // i/j/I/J(_#ind,_x,_y,_z,_c) = value\n                is_parallelizable = false;\n                if (*ss2=='#') { // Index specified\n                  s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                  p1 = compile(ss3,s0++,depth1,0);\n                  _cimg_mp_check_list(true);\n                } else { p1 = ~0U; s0 = ss2; }\n                arg1 = is_relative?0U:(unsigned int)_cimg_mp_x;\n                arg2 = is_relative?0U:(unsigned int)_cimg_mp_y;\n                arg3 = is_relative?0U:(unsigned int)_cimg_mp_z;\n                arg4 = is_relative?0U:(unsigned int)_cimg_mp_c;\n                arg5 = compile(s + 1,se,depth1,0); // Value to assign\n                if (s0<ve1) { // X or [ X,_Y,_Z,_C ]\n                  s1 = s0; while (s1<ve1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n                  arg1 = compile(s0,s1,depth1,0);\n                  if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector\n                    p2 = _cimg_mp_vector_size(arg1); // Vector size\n                    ++arg1;\n                    if (p2>1) {\n                      arg2 = arg1 + 1;\n                      if (p2>2) {\n                        arg3 = arg2 + 1;\n                        if (p2>3) arg4 = arg3 + 1;\n                      }\n                    }\n                  } else if (s1<ve1) { // Y\n                    s2 = ++s1; while (s2<ve1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n                    arg2 = compile(s1,s2,depth1,0);\n                    if (s2<ve1) { // Z\n                      s3 = ++s2; while (s3<ve1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;\n                      arg3 = compile(s2,s3,depth1,0);\n                      if (s3<ve1) arg4 = compile(++s3,ve1,depth1,0); // C\n                    }\n                  }\n                }\n\n                if (_cimg_mp_is_vector(arg5)) {\n                  p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any\n                  if (p1==~0U) p2 = imgin._spectrum;\n                  else if (_cimg_mp_is_constant(p1)) {\n                    p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());\n                    p2 = listin[p3]._spectrum;\n                  }\n                  _cimg_mp_check_vector0(p2);\n                } else p2 = 0;\n                _cimg_mp_check_type(arg5,2,*ss>='i'?1:3,p2);\n\n                if (p_ref) {\n                  *p_ref = _cimg_mp_is_vector(arg5)?5:3;\n                  p_ref[1] = p1;\n                  p_ref[2] = (unsigned int)is_relative;\n                  p_ref[3] = arg1;\n                  p_ref[4] = arg2;\n                  p_ref[5] = arg3;\n                  p_ref[6] = arg4;\n                  if (_cimg_mp_is_vector(arg5))\n                    set_variable_vector(arg5); // Prevent from being used in further optimization\n                  else if (_cimg_mp_is_temp(arg5)) memtype[arg5] = -1;\n                  if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1;\n                  if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;\n                  if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;\n                  if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1;\n                  if (_cimg_mp_is_temp(arg4)) memtype[arg4] = -1;\n                }\n                if (p1!=~0U) {\n                  if (!listout) _cimg_mp_return(arg5);\n                  if (*ss>='i')\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),\n                                        arg5,p1,arg1,arg2,arg3,arg4).move_to(code);\n                  else if (_cimg_mp_is_scalar(arg5))\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s),\n                                        arg5,p1,arg1,arg2,arg3).move_to(code);\n                  else\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),\n                                        arg5,p1,arg1,arg2,arg3).move_to(code);\n                } else {\n                  if (!imgout) _cimg_mp_return(arg5);\n                  if (*ss>='i')\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),\n                                        arg5,arg1,arg2,arg3,arg4).move_to(code);\n                  else if (_cimg_mp_is_scalar(arg5))\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s),\n                                        arg5,arg1,arg2,arg3).move_to(code);\n                  else\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),\n                                        arg5,arg1,arg2,arg3).move_to(code);\n                }\n                _cimg_mp_return(arg5);\n              }\n            }\n\n            // Assign vector value (direct).\n            if (l_variable_name>3 && *ve1==']' && *ss!='[') {\n              s0 = ve1; while (s0>ss && *s0!='[') --s0;\n              is_sth = true; // is_valid_variable_name?\n              if (*ss>='0' && *ss<='9') is_sth = false;\n              else for (ns = ss; ns<s0; ++ns)\n                     if (!is_varchar(*ns)) { is_sth = false; break; }\n              if (is_sth && s0>ss) {\n                variable_name[s0 - ss] = 0; // Remove brackets in variable name\n                arg1 = ~0U; // Vector slot\n                arg2 = compile(++s0,ve1,depth1,0); // Index\n                arg3 = compile(s + 1,se,depth1,0); // Value to assign\n                _cimg_mp_check_type(arg3,2,1,0);\n\n                if (variable_name[1]) { // Multi-char variable\n                  cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i])) {\n                    arg1 = variable_pos[i]; break;\n                  }\n                } else arg1 = reserved_label[*variable_name]; // Single-char variable\n                if (arg1==~0U) compile(ss,s0 - 1,depth1,0); // Variable does not exist -> error\n                else { // Variable already exists\n                  if (_cimg_mp_is_scalar(arg1)) compile(ss,s,depth1,0); // Variable is not a vector -> error\n                  if (_cimg_mp_is_constant(arg2)) { // Constant index -> return corresponding variable slot directly\n                    nb = (int)mem[arg2];\n                    if (nb>=0 && nb<(int)_cimg_mp_vector_size(arg1)) {\n                      arg1+=nb + 1;\n                      CImg<ulongT>::vector((ulongT)mp_copy,arg1,arg3).move_to(code);\n                      _cimg_mp_return(arg1);\n                    }\n                    compile(ss,s,depth1,0); // Out-of-bounds reference -> error\n                  }\n\n                  // Case of non-constant index -> return assigned value + linked reference\n                  if (p_ref) {\n                    *p_ref = 1;\n                    p_ref[1] = arg1;\n                    p_ref[2] = arg2;\n                    if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1; // Prevent from being used in further optimization\n                    if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;\n                  }\n                  CImg<ulongT>::vector((ulongT)mp_vector_set_off,arg3,arg1,_cimg_mp_vector_size(arg1),arg2,arg3).\n                    move_to(code);\n                  _cimg_mp_return(arg3);\n                }\n              }\n            }\n\n            // Assign user-defined macro.\n            if (l_variable_name>2 && *ve1==')' && *ss!='(') {\n              s0 = ve1; while (s0>ss && *s0!='(') --s0;\n              is_sth = std::strncmp(variable_name,\"debug(\",6) &&\n                std::strncmp(variable_name,\"print(\",6); // is_valid_function_name?\n              if (*ss>='0' && *ss<='9') is_sth = false;\n              else for (ns = ss; ns<s0; ++ns)\n                     if (!is_varchar(*ns)) { is_sth = false; break; }\n\n              if (is_sth && s0>ss) { // Looks like a valid function declaration\n                s0 = variable_name._data + (s0 - ss);\n                *s0 = 0;\n                s1 = variable_name._data + l_variable_name - 1; // Pointer to closing parenthesis\n                CImg<charT>(variable_name._data,(unsigned int)(s0 - variable_name._data + 1)).move_to(function_def,0);\n                ++s; while (*s && *s<=' ') ++s;\n                CImg<charT>(s,(unsigned int)(se - s + 1)).move_to(function_body,0);\n\n                p1 = 1; // Indice of current parsed argument\n                for (s = s0 + 1; s<=s1; ++p1, s = ns + 1) { // Parse function arguments\n                  if (p1>24) {\n                    *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);\n                    throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                                \"CImg<%s>::%s: %s: Too much specified arguments (>24) when defining \"\n                                                \"function '%s()', in expression '%s%s%s'.\",\n                                                pixel_type(),_cimg_mp_calling_function,s_op,\n                                                variable_name._data,\n                                                (ss - 4)>expr._data?\"...\":\"\",\n                                                (ss - 4)>expr._data?ss - 4:expr._data,\n                                                se<&expr.back()?\"...\":\"\");\n                  }\n                  while (*s && *s<=' ') ++s;\n                  if (*s==')' && p1==1) break; // Function has no arguments\n\n                  s2 = s; // Start of the argument name\n                  is_sth = true; // is_valid_argument_name?\n                  if (*s>='0' && *s<='9') is_sth = false;\n                  else for (ns = s; ns<s1 && *ns!=',' && *ns>' '; ++ns)\n                         if (!is_varchar(*ns)) { is_sth = false; break; }\n                  s3 = ns; // End of the argument name\n                  while (*ns && *ns<=' ') ++ns;\n                  if (!is_sth || s2==s3 || (*ns!=',' && ns!=s1)) {\n                    *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);\n                    throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                                \"CImg<%s>::%s: %s: %s name specified for argument %u when defining \"\n                                                \"function '%s()', in expression '%s%s%s'.\",\n                                                pixel_type(),_cimg_mp_calling_function,s_op,\n                                                is_sth?\"Empty\":\"Invalid\",p1,\n                                                variable_name._data,\n                                                (ss - 4)>expr._data?\"...\":\"\",\n                                                (ss - 4)>expr._data?ss - 4:expr._data,\n                                                se<&expr.back()?\"...\":\"\");\n                  }\n                  if (ns==s1 || *ns==',') { // New argument found\n                    *s3 = 0;\n                    p2 = (unsigned int)(s3 - s2); // Argument length\n                    p3 = function_body[0]._width - p2 + 1; // Related to copy length\n                    for (ps = std::strstr(function_body[0],s2); ps; ps = std::strstr(ps,s2)) { // Replace by arg number\n                      if (!((ps>function_body[0]._data && is_varchar(*(ps - 1))) ||\n                            (ps + p2<function_body[0].end() && is_varchar(*(ps + p2))))) {\n                        *(ps++) = (char)p1;\n                        if (p2>1) {\n                          std::memmove(ps,ps + p2 - 1,function_body[0]._data + p3 - ps);\n                          function_body[0]._width-=p2 - 1;\n                        }\n                      } else ++ps;\n                    }\n                  }\n                }\n                // Store number of arguments\n                function_def[0].resize(function_def[0]._width + 1,1,1,1,0).back() = (char)(p1 - 1);\n                _cimg_mp_return(28);\n              }\n            }\n\n            // Check if the variable name could be valid. If not, this is probably an lvalue assignment.\n            is_sth = true; // is_valid_variable_name?\n            if (*variable_name>='0' && *variable_name<='9') is_sth = false;\n            else for (ns = variable_name._data; *ns; ++ns)\n                   if (!is_varchar(*ns)) { is_sth = false; break; }\n\n            // Assign variable (direct).\n            if (is_sth) {\n              if (variable_name[1] && !variable_name[2]) { // Two-chars variable\n                c1 = variable_name[0];\n                c2 = variable_name[1];\n                if (c1=='w' && c2=='h') variable_name.fill((char)0,(char)0); // wh\n                else if (c1=='p' && c2=='i') variable_name.fill(3,0); // pi\n                else if (c1=='i') {\n                  if (c2>='0' && c2<='9') variable_name.fill(19 + c2 - '0',0); // i0...i9\n                  else if (c2=='m') variable_name.fill(4,0); // im\n                  else if (c2=='M') variable_name.fill(5,0); // iM\n                  else if (c2=='a') variable_name.fill(6,0); // ia\n                  else if (c2=='v') variable_name.fill(7,0); // iv\n                  else if (c2=='s') variable_name.fill(8,0); // is\n                  else if (c2=='p') variable_name.fill(9,0); // ip\n                  else if (c2=='c') variable_name.fill(10,0); // ic\n                } else if (c2=='m') {\n                  if (c1=='x') variable_name.fill(11,0); // xm\n                  else if (c1=='y') variable_name.fill(12,0); // ym\n                  else if (c1=='z') variable_name.fill(13,0); // zm\n                  else if (c1=='c') variable_name.fill(14,0); // cm\n                } else if (c2=='M') {\n                  if (c1=='x') variable_name.fill(15,0); // xM\n                  else if (c1=='y') variable_name.fill(16,0); // yM\n                  else if (c1=='z') variable_name.fill(17,0); // zM\n                  else if (c1=='c') variable_name.fill(18,0); // cM\n                }\n              } else if (variable_name[1] && variable_name[2] && !variable_name[3]) { // Three-chars variable\n                c1 = variable_name[0];\n                c2 = variable_name[1];\n                c3 = variable_name[2];\n                if (c1=='w' && c2=='h' && c3=='d') variable_name.fill(1,0); // whd\n              } else if (variable_name[1] && variable_name[2] && variable_name[3] &&\n                         !variable_name[4]) { // Four-chars variable\n                c1 = variable_name[0];\n                c2 = variable_name[1];\n                c3 = variable_name[2];\n                c4 = variable_name[3];\n                if (c1=='w' && c2=='h' && c3=='d' && c4=='s') variable_name.fill(2,0); // whds\n              } else if (!std::strcmp(variable_name,\"interpolation\")) variable_name.fill(29,0);\n              else if (!std::strcmp(variable_name,\"boundary\")) variable_name.fill(30,0);\n\n              arg1 = ~0U;\n              arg2 = compile(s + 1,se,depth1,0);\n              if (!variable_name[1]) // One-char variable, or variable in reserved_labels\n                arg1 = reserved_label[*variable_name];\n              else // Multi-char variable name : check for existing variable with same name\n                cimglist_for(variable_def,i)\n                  if (!std::strcmp(variable_name,variable_def[i])) { arg1 = variable_pos[i]; break; }\n\n              if (arg1==~0U || arg1<=_cimg_mp_c) { // Create new variable\n                if (_cimg_mp_is_vector(arg2)) { // Vector variable\n                  arg1 = vector_copy(arg2);\n                  set_variable_vector(arg1);\n                } else { // Scalar variable\n                  arg1 = scalar1(mp_copy,arg2);\n                  memtype[arg1] = -1;\n                }\n\n                if (!variable_name[1]) reserved_label[*variable_name] = arg1;\n                else {\n                  if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0);\n                  variable_pos[variable_def._width] = arg1;\n                  variable_name.move_to(variable_def);\n                }\n\n              } else { // Variable already exists -> assign a new value\n                _cimg_mp_check_type(arg2,2,_cimg_mp_is_vector(arg1)?3:1,_cimg_mp_vector_size(arg1));\n                if (_cimg_mp_is_vector(arg1)) { // Vector\n                  if (_cimg_mp_is_vector(arg2)) // From vector\n                    CImg<ulongT>::vector((ulongT)mp_vector_copy,arg1,arg2,(ulongT)_cimg_mp_vector_size(arg1)).\n                      move_to(code);\n                  else // From scalar\n                    CImg<ulongT>::vector((ulongT)mp_vector_init,arg1,(ulongT)_cimg_mp_vector_size(arg1),arg2).\n                      move_to(code);\n                } else // Scalar\n                  CImg<ulongT>::vector((ulongT)mp_copy,arg1,arg2).move_to(code);\n              }\n              _cimg_mp_return(arg1);\n            }\n\n            // Assign lvalue (variable name was not valid).\n            is_sth = (bool)std::strchr(variable_name,'?'); // Contains_ternary_operator?\n            if (is_sth) break; // Do nothing and make ternary operator prioritary over assignment\n\n            if (l_variable_name>2 && (std::strchr(variable_name,'(') || std::strchr(variable_name,'['))) {\n              ref.assign(7);\n              arg1 = compile(ss,s,depth1,ref); // Lvalue slot\n              arg2 = compile(s + 1,se,depth1,0); // Value to assign\n\n              if (*ref==1) { // Vector value (scalar): V[k] = scalar\n                _cimg_mp_check_type(arg2,2,1,0);\n                arg3 = ref[1]; // Vector slot\n                arg4 = ref[2]; // Index\n                if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n                CImg<ulongT>::vector((ulongT)mp_vector_set_off,arg2,arg3,(ulongT)_cimg_mp_vector_size(arg3),arg4,arg2).\n                  move_to(code);\n                _cimg_mp_return(arg2);\n              }\n\n              if (*ref==2) { // Image value (scalar): i/j[_#ind,off] = scalar\n                _cimg_mp_check_type(arg2,2,1,0);\n                is_parallelizable = false;\n                p1 = ref[1]; // Index\n                is_relative = (bool)ref[2];\n                arg3 = ref[3]; // Offset\n                if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n                if (p1!=~0U) {\n                  if (!listout) _cimg_mp_return(arg2);\n                  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff),\n                                      arg2,p1,arg3).move_to(code);\n                } else {\n                  if (!imgout) _cimg_mp_return(arg2);\n                  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff),\n                                      arg2,arg3).move_to(code);\n                }\n                _cimg_mp_return(arg2);\n              }\n\n              if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) = scalar\n                _cimg_mp_check_type(arg2,2,1,0);\n                is_parallelizable = false;\n                p1 = ref[1]; // Index\n                is_relative = (bool)ref[2];\n                arg3 = ref[3]; // X\n                arg4 = ref[4]; // Y\n                arg5 = ref[5]; // Z\n                arg6 = ref[6]; // C\n                if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n                if (p1!=~0U) {\n                  if (!listout) _cimg_mp_return(arg2);\n                  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),\n                                      arg2,p1,arg3,arg4,arg5,arg6).move_to(code);\n                } else {\n                  if (!imgout) _cimg_mp_return(arg2);\n                  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),\n                                      arg2,arg3,arg4,arg5,arg6).move_to(code);\n                }\n                _cimg_mp_return(arg2);\n              }\n\n              if (*ref==4) { // Image value (vector): I/J[_#ind,off] = value\n                _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n                is_parallelizable = false;\n                p1 = ref[1]; // Index\n                is_relative = (bool)ref[2];\n                arg3 = ref[3]; // Offset\n                if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n                if (p1!=~0U) {\n                  if (!listout) _cimg_mp_return(arg2);\n                  if (_cimg_mp_is_scalar(arg2))\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s),\n                                        arg2,p1,arg3).move_to(code);\n                  else\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),\n                                        arg2,p1,arg3).move_to(code);\n                } else {\n                  if (!imgout) _cimg_mp_return(arg2);\n                  if (_cimg_mp_is_scalar(arg2))\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s),\n                                        arg2,arg3).move_to(code);\n                  else\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),\n                                        arg2,arg3).move_to(code);\n                }\n                _cimg_mp_return(arg2);\n              }\n\n              if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) = value\n                _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n                is_parallelizable = false;\n                p1 = ref[1]; // Index\n                is_relative = (bool)ref[2];\n                arg3 = ref[3]; // X\n                arg4 = ref[4]; // Y\n                arg5 = ref[5]; // Z\n                if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n                if (p1!=~0U) {\n                  if (!listout) _cimg_mp_return(arg2);\n                  if (_cimg_mp_is_scalar(arg2))\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s),\n                                        arg2,p1,arg3,arg4,arg5).move_to(code);\n                  else\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),\n                                        arg2,p1,arg3,arg4,arg5).move_to(code);\n                } else {\n                  if (!imgout) _cimg_mp_return(arg2);\n                  if (_cimg_mp_is_scalar(arg2))\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s),\n                                        arg2,arg3,arg4,arg5).move_to(code);\n                  else\n                    CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),\n                                        arg2,arg3,arg4,arg5).move_to(code);\n                }\n                _cimg_mp_return(arg2);\n              }\n\n              if (_cimg_mp_is_vector(arg1)) { // Vector variable: V = value\n                _cimg_mp_check_type(arg2,2,1,0);\n                if (_cimg_mp_is_vector(arg2)) // From vector\n                  CImg<ulongT>::vector((ulongT)mp_vector_copy,arg1,arg2,(ulongT)_cimg_mp_vector_size(arg1)).\n                    move_to(code);\n                else // From scalar\n                  CImg<ulongT>::vector((ulongT)mp_vector_init,arg1,(ulongT)_cimg_mp_vector_size(arg1),arg2).\n                    move_to(code);\n                _cimg_mp_return(arg1);\n              }\n\n              if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s = scalar\n                _cimg_mp_check_type(arg2,2,1,0);\n                CImg<ulongT>::vector((ulongT)mp_copy,arg1,arg2).move_to(code);\n                _cimg_mp_return(arg1);\n\n              }\n            }\n\n            // No assignment expressions match -> error\n            *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);\n            throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                        \"CImg<%s>::%s: %s: Invalid left-hand operand '%s', \"\n                                        \"in expression '%s%s%s'.\",\n                                        pixel_type(),_cimg_mp_calling_function,s_op,\n                                        variable_name._data,\n                                        (ss - 4)>expr._data?\"...\":\"\",\n                                        (ss - 4)>expr._data?ss - 4:expr._data,\n                                        se<&expr.back()?\"...\":\"\");\n          }\n\n        // Apply unary/binary/ternary operators. The operator precedences should be roughly the same as in C++.\n        for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1\n          if (*s=='=' && (*ps=='*' || *ps=='/' || *ps=='^') && *ns==*ps &&\n              level[s - expr._data]==clevel) { // Self-operators for complex numbers only (**=,//=,^^=)\n            _cimg_mp_op(*ps=='*'?\"Operator '**='\":*ps=='/'?\"Operator '//='\":\"Operator '^^='\");\n\n            ref.assign(7);\n            arg1 = compile(ss,ns,depth1,ref); // Vector slot\n            arg2 = compile(s + 1,se,depth1,0); // Right operand\n            if (*ps!='*') {\n              _cimg_mp_check_type(arg1,2,2,2);\n              _cimg_mp_check_type(arg2,2,2,2);\n            }\n            if (_cimg_mp_is_vector(arg2)) { // Complex **= complex or Matrix **= matrix\n              if (*ps=='*') {\n                if (_cimg_mp_vector_size(arg1)==2 && _cimg_mp_vector_size(arg2)==2)\n                  CImg<ulongT>::vector((ulongT)mp_complex_mul,arg1,arg1,arg2).move_to(code);\n                else {\n                  _cimg_mp_check_matrix_square(arg2,2);\n                  p3 = _cimg_mp_vector_size(arg1);\n                  p2 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg2));\n                  p1 = p3/p2;\n                  if (p1*p2!=p3) {\n                    *se = saved_char; cimg::strellipsize(expr,64);\n                    throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                                \"CImg<%s>::%s: %s: Types of left-hand and right-hand operands \"\n                                                \"('%s' and '%s') do not match, in expression '%s%s%s'.\",\n                                                pixel_type(),_cimg_mp_calling_function,s_op,\n                                                s_type(arg1)._data,s_type(arg2)._data,\n                                                (ss - 4)>expr._data?\"...\":\"\",\n                                                (ss - 4)>expr._data?ss - 4:expr._data,\n                                                se<&expr.back()?\"...\":\"\");\n                  }\n                  CImg<ulongT>::vector((ulongT)mp_matrix_mul,arg1,arg1,arg2,p1,p2,p2).move_to(code);\n                }\n              } else if (*ps=='/')\n                CImg<ulongT>::vector((ulongT)mp_complex_div_vv,arg1,arg1,arg2).move_to(code);\n              else\n                CImg<ulongT>::vector((ulongT)mp_complex_pow_vv,arg1,arg1,arg2).move_to(code);\n            } else { // Complex **= scalar\n              if (*ps=='*') self_vector_s(arg1,mp_self_mul,arg2);\n              else if (*ps=='/') self_vector_s(arg1,mp_self_div,arg2);\n              else CImg<ulongT>::vector((ulongT)mp_complex_pow_vs,arg1,arg1,arg2).move_to(code);\n            }\n\n            // Write computed value back in image if necessary.\n            if (*ref==4) { // Image value (vector): I/J[_#ind,off] **= value\n              is_parallelizable = false;\n              p1 = ref[1]; // Index\n              is_relative = (bool)ref[2];\n              arg3 = ref[3]; // Offset\n              if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n              if (p1!=~0U) {\n                if (!listout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),\n                                    arg1,p1,arg3).move_to(code);\n              } else {\n                if (!imgout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),\n                                    arg1,arg3).move_to(code);\n              }\n\n            } else if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) **= value\n              is_parallelizable = false;\n              p1 = ref[1]; // Index\n              is_relative = (bool)ref[2];\n              arg3 = ref[3]; // X\n              arg4 = ref[4]; // Y\n              arg5 = ref[5]; // Z\n              if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n              if (p1!=~0U) {\n                if (!listout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),\n                                    arg1,p1,arg3,arg4,arg5).move_to(code);\n              } else {\n                if (!imgout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),\n                                    arg1,arg3,arg4,arg5).move_to(code);\n              }\n            }\n\n            _cimg_mp_return(arg1);\n          }\n\n        for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1\n          if (*s=='=' && (*ps=='+' || *ps=='-' || *ps=='*' || *ps=='/' || *ps=='%' ||\n                          *ps=='&' || *ps=='^' || *ps=='|' ||\n                          (*ps=='>' && *ns=='>') || (*ps=='<' && *ns=='<')) &&\n              level[s - expr._data]==clevel) { // Self-operators (+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=)\n            switch (*ps) {\n            case '+' : op = mp_self_add; _cimg_mp_op(\"Operator '+='\"); break;\n            case '-' : op = mp_self_sub; _cimg_mp_op(\"Operator '-='\"); break;\n            case '*' : op = mp_self_mul; _cimg_mp_op(\"Operator '*='\"); break;\n            case '/' : op = mp_self_div; _cimg_mp_op(\"Operator '/='\"); break;\n            case '%' : op = mp_self_modulo; _cimg_mp_op(\"Operator '%='\"); break;\n            case '<' : op = mp_self_bitwise_left_shift; _cimg_mp_op(\"Operator '<<='\"); break;\n            case '>' : op = mp_self_bitwise_right_shift; _cimg_mp_op(\"Operator '>=='\"); break;\n            case '&' : op = mp_self_bitwise_and; _cimg_mp_op(\"Operator '&='\"); break;\n            case '|' : op = mp_self_bitwise_or; _cimg_mp_op(\"Operator '|='\"); break;\n            default : op = mp_self_pow; _cimg_mp_op(\"Operator '^='\"); break;\n            }\n            s1 = *ps=='>' || *ps=='<'?ns:ps;\n\n            ref.assign(7);\n            arg1 = compile(ss,s1,depth1,ref); // Variable slot\n            arg2 = compile(s + 1,se,depth1,0); // Value to apply\n\n            if (*ref>0 && !_cimg_mp_is_temp(arg1)) { // Apply operator on a copy if necessary.\n              if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1);\n              else arg1 = scalar1(mp_copy,arg1);\n            }\n\n            if (*ref==1) { // Vector value (scalar): V[k] += scalar\n              _cimg_mp_check_type(arg2,2,1,0);\n              arg3 = ref[1]; // Vector slot\n              arg4 = ref[2]; // Index\n              if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n              CImg<ulongT>::vector((ulongT)op,arg1,arg2).move_to(code);\n              CImg<ulongT>::vector((ulongT)mp_vector_set_off,arg1,arg3,(ulongT)_cimg_mp_vector_size(arg3),arg4,arg1).\n                move_to(code);\n              _cimg_mp_return(arg1);\n            }\n\n            if (*ref==2) { // Image value (scalar): i/j[_#ind,off] += scalar\n              _cimg_mp_check_type(arg2,2,1,0);\n              is_parallelizable = false;\n              p1 = ref[1]; // Index\n              is_relative = (bool)ref[2];\n              arg3 = ref[3]; // Offset\n              if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n              CImg<ulongT>::vector((ulongT)op,arg1,arg2).move_to(code);\n              if (p1!=~0U) {\n                if (!listout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff),\n                                    arg1,p1,arg3).move_to(code);\n              } else {\n                if (!imgout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff),\n                                    arg1,arg3).move_to(code);\n              }\n              _cimg_mp_return(arg1);\n            }\n\n            if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) += scalar\n              _cimg_mp_check_type(arg2,2,1,0);\n              is_parallelizable = false;\n              p1 = ref[1]; // Index\n              is_relative = (bool)ref[2];\n              arg3 = ref[3]; // X\n              arg4 = ref[4]; // Y\n              arg5 = ref[5]; // Z\n              arg6 = ref[6]; // C\n              if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n              CImg<ulongT>::vector((ulongT)op,arg1,arg2).move_to(code);\n              if (p1!=~0U) {\n                if (!listout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),\n                                    arg1,p1,arg3,arg4,arg5,arg6).move_to(code);\n              } else {\n                if (!imgout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),\n                                    arg1,arg3,arg4,arg5,arg6).move_to(code);\n              }\n              _cimg_mp_return(arg1);\n            }\n\n            if (*ref==4) { // Image value (vector): I/J[_#ind,off] += value\n              _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n              is_parallelizable = false;\n              p1 = ref[1]; // Index\n              is_relative = (bool)ref[2];\n              arg3 = ref[3]; // Offset\n              if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n              if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2);\n              if (p1!=~0U) {\n                if (!listout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),\n                                    arg1,p1,arg3).move_to(code);\n              } else {\n                if (!imgout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),\n                                    arg1,arg3).move_to(code);\n              }\n              _cimg_mp_return(arg1);\n            }\n\n            if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) += value\n              _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n              is_parallelizable = false;\n              p1 = ref[1]; // Index\n              is_relative = (bool)ref[2];\n              arg3 = ref[3]; // X\n              arg4 = ref[4]; // Y\n              arg5 = ref[5]; // Z\n              if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n              if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2);\n              if (p1!=~0U) {\n                if (!listout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),\n                                    arg1,p1,arg3,arg4,arg5).move_to(code);\n              } else {\n                if (!imgout) _cimg_mp_return(arg1);\n                CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),\n                                    arg1,arg3,arg4,arg5).move_to(code);\n              }\n              _cimg_mp_return(arg1);\n            }\n\n            if (_cimg_mp_is_vector(arg1)) { // Vector variable: V += value\n              _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n              if (_cimg_mp_is_vector(arg2)) self_vector_v(arg1,op,arg2); // Vector += vector\n              else self_vector_s(arg1,op,arg2); // Vector += scalar\n              _cimg_mp_return(arg1);\n            }\n\n            if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s += scalar\n              _cimg_mp_check_type(arg2,2,1,0);\n              CImg<ulongT>::vector((ulongT)op,arg1,arg2).move_to(code);\n              _cimg_mp_return(arg1);\n            }\n\n            variable_name.assign(ss,(unsigned int)(s - ss)).back() = 0;\n            *se = saved_char; cimg::strellipsize(expr,64);\n            throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                        \"CImg<%s>::%s: %s: Invalid left-hand operand '%s', \"\n                                        \"in expression '%s%s%s'.\",\n                                        pixel_type(),_cimg_mp_calling_function,s_op,\n                                        variable_name._data,\n                                        (ss - 4)>expr._data?\"...\":\"\",\n                                        (ss - 4)>expr._data?ss - 4:expr._data,\n                                        se<&expr.back()?\"...\":\"\");\n          }\n\n        for (s = ss1; s<se1; ++s)\n          if (*s=='?' && level[s - expr._data]==clevel) { // Ternary operator 'cond?expr1:expr2'\n            _cimg_mp_op(\"Operator '?:'\");\n            s1 = s + 1; while (s1<se1 && (*s1!=':' || level[s1 - expr._data]!=clevel)) ++s1;\n            arg1 = compile(ss,s,depth1,0);\n            _cimg_mp_check_type(arg1,1,1,0);\n            if (_cimg_mp_is_constant(arg1)) {\n              if ((bool)mem[arg1]) return compile(s + 1,*s1!=':'?se:s1,depth1,0);\n              else return *s1!=':'?0:compile(++s1,se,depth1,0);\n            }\n            p2 = code._width;\n            arg2 = compile(s + 1,*s1!=':'?se:s1,depth1,0);\n            p3 = code._width;\n            arg3 = *s1==':'?compile(++s1,se,depth1,0):_cimg_mp_is_vector(arg2)?vector(_cimg_mp_vector_size(arg2),0):0;\n            _cimg_mp_check_type(arg3,3,_cimg_mp_is_vector(arg2)?2:1,_cimg_mp_vector_size(arg2));\n            arg4 = _cimg_mp_is_vector(arg2)?_cimg_mp_vector_size(arg2):0; // Output vector size (or 0 if scalar)\n            if (arg4) pos = vector(arg4); else pos = scalar();\n            CImg<ulongT>::vector((ulongT)mp_if,pos,arg1,arg2,arg3,\n                                p3 - p2,code._width - p3,arg4).move_to(code,p2);\n            _cimg_mp_return(pos);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) { // Logical or ('||')\n            _cimg_mp_op(\"Operator '||'\");\n            arg1 = compile(ss,s,depth1,0);\n            p2 = code._width;\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg1,1,1,0);\n            _cimg_mp_check_type(arg2,2,1,0);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n              _cimg_mp_constant(mem[arg1] || mem[arg2]);\n            pos = scalar();\n            CImg<ulongT>::vector((ulongT)mp_logical_or,pos,arg1,arg2,code._width - p2).\n              move_to(code,p2);\n            _cimg_mp_return(pos);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) { // Logical and ('&&')\n            _cimg_mp_op(\"Operator '&&'\");\n            arg1 = compile(ss,s,depth1,0);\n            p2 = code._width;\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg1,1,1,0);\n            _cimg_mp_check_type(arg2,2,1,0);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n              _cimg_mp_constant(mem[arg1] && mem[arg2]);\n            pos = scalar();\n            CImg<ulongT>::vector((ulongT)mp_logical_and,pos,arg1,arg2,code._width - p2).\n              move_to(code,p2);\n            _cimg_mp_return(pos);\n          }\n\n        for (s = se2; s>ss; --s)\n          if (*s=='|' && level[s - expr._data]==clevel) { // Bitwise or ('|')\n            _cimg_mp_op(\"Operator '|'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_or,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_or,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_or,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n              _cimg_mp_constant((ulongT)mem[arg1] | (ulongT)mem[arg2]);\n            _cimg_mp_scalar2(mp_bitwise_or,arg1,arg2);\n          }\n\n        for (s = se2; s>ss; --s)\n          if (*s=='&' && level[s - expr._data]==clevel) { // Bitwise and ('&')\n            _cimg_mp_op(\"Operator '&'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_and,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_and,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_and,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n              _cimg_mp_constant((ulongT)mem[arg1] & (ulongT)mem[arg2]);\n            _cimg_mp_scalar2(mp_bitwise_and,arg1,arg2);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel) { // Not equal to ('!=')\n            _cimg_mp_op(\"Operator '!='\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_neq,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_neq,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_neq,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]!=mem[arg2]);\n            _cimg_mp_scalar2(mp_neq,arg1,arg2);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel) { // Equal to ('==')\n            _cimg_mp_op(\"Operator '=='\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_eq,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_eq,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_eq,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]==mem[arg2]);\n            _cimg_mp_scalar2(mp_eq,arg1,arg2);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel) { // Less or equal than ('<=')\n            _cimg_mp_op(\"Operator '<='\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lte,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lte,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lte,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]<=mem[arg2]);\n            _cimg_mp_scalar2(mp_lte,arg1,arg2);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel) { // Greater or equal than ('>=')\n            _cimg_mp_op(\"Operator '>='\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gte,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gte,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gte,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>=mem[arg2]);\n            _cimg_mp_scalar2(mp_gte,arg1,arg2);\n          }\n\n        for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps)\n          if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel) { // Less than ('<')\n            _cimg_mp_op(\"Operator '<'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lt,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lt,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lt,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]<mem[arg2]);\n            _cimg_mp_scalar2(mp_lt,arg1,arg2);\n          }\n\n        for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps)\n          if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel) { // Greather than ('>')\n            _cimg_mp_op(\"Operator '>'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gt,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gt,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gt,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>mem[arg2]);\n            _cimg_mp_scalar2(mp_gt,arg1,arg2);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel) { // Left bit shift ('<<')\n            _cimg_mp_op(\"Operator '<<'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2))\n              _cimg_mp_vector2_vv(mp_bitwise_left_shift,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2))\n              _cimg_mp_vector2_vs(mp_bitwise_left_shift,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2))\n              _cimg_mp_vector2_sv(mp_bitwise_left_shift,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n              _cimg_mp_constant((longT)mem[arg1]<<(unsigned int)mem[arg2]);\n            _cimg_mp_scalar2(mp_bitwise_left_shift,arg1,arg2);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel) { // Right bit shift ('>>')\n            _cimg_mp_op(\"Operator '>>'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2))\n              _cimg_mp_vector2_vv(mp_bitwise_right_shift,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2))\n              _cimg_mp_vector2_vs(mp_bitwise_right_shift,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2))\n              _cimg_mp_vector2_sv(mp_bitwise_right_shift,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n              _cimg_mp_constant((longT)mem[arg1]>>(unsigned int)mem[arg2]);\n            _cimg_mp_scalar2(mp_bitwise_right_shift,arg1,arg2);\n          }\n\n        for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps)\n          if (*s=='+' && (*ns!='+' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' &&\n              *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' &&\n              (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' &&\n                                                                                     *(ps - 1)<='9')))) &&\n              level[s - expr._data]==clevel) { // Addition ('+')\n            _cimg_mp_op(\"Operator '+'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_add,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_add,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_add,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] + mem[arg2]);\n            if (arg2==1) _cimg_mp_scalar1(mp_increment,arg1);\n            if (arg1==1) _cimg_mp_scalar1(mp_increment,arg2);\n            _cimg_mp_scalar2(mp_add,arg1,arg2);\n          }\n\n        for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps)\n          if (*s=='-' && (*ns!='-' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' &&\n              *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' &&\n              (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' &&\n                                                                                     *(ps - 1)<='9')))) &&\n              level[s - expr._data]==clevel) { // Subtraction ('-')\n            _cimg_mp_op(\"Operator '-'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_sub,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_sub,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_sub,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] - mem[arg2]);\n            if (arg2==1) _cimg_mp_scalar1(mp_decrement,arg1);\n            _cimg_mp_scalar2(mp_sub,arg1,arg2);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='*' && *ns=='*' && level[s - expr._data]==clevel) { // Complex/matrix multiplication ('**')\n            _cimg_mp_op(\"Operator '**'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 2,se,depth1,0);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {\n              if (_cimg_mp_vector_size(arg1)==2 && _cimg_mp_vector_size(arg2)==2) { // Complex multiplication\n                pos = vector(2);\n                CImg<ulongT>::vector((ulongT)mp_complex_mul,pos,arg1,arg2).move_to(code);\n                _cimg_mp_return(pos);\n              } else { // Matrix multiplication\n                p1 = _cimg_mp_vector_size(arg1);\n                p2 = _cimg_mp_vector_size(arg2);\n                arg4 = p1/p2;\n                if (arg4*p2!=p1) {\n                  *se = saved_char; cimg::strellipsize(expr,64);\n                  throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                              \"CImg<%s>::%s: %s: Types of left-hand and right-hand operands \"\n                                              \"('%s' and '%s') do not match, in expression '%s%s%s'.\",\n                                              pixel_type(),_cimg_mp_calling_function,s_op,\n                                              s_type(arg1)._data,s_type(arg2)._data,\n                                              (ss - 4)>expr._data?\"...\":\"\",\n                                              (ss - 4)>expr._data?ss - 4:expr._data,\n                                              se<&expr.back()?\"...\":\"\");\n                }\n                pos = vector(arg4);\n                CImg<ulongT>::vector((ulongT)mp_matrix_mul,pos,arg1,arg2,arg4,p2,1).move_to(code);\n                _cimg_mp_return(pos);\n              }\n            }\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]);\n            _cimg_mp_scalar2(mp_mul,arg1,arg2);\n          }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='/' && *ns=='/' && level[s - expr._data]==clevel) { // Complex division ('//')\n            _cimg_mp_op(\"Operator '//'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg1,1,3,2);\n            _cimg_mp_check_type(arg2,2,3,2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {\n              pos = vector(2);\n              CImg<ulongT>::vector((ulongT)mp_complex_div_vv,pos,arg1,arg2).move_to(code);\n              _cimg_mp_return(pos);\n            }\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) {\n              pos = vector(2);\n              CImg<ulongT>::vector((ulongT)mp_complex_div_sv,pos,arg1,arg2).move_to(code);\n              _cimg_mp_return(pos);\n            }\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]);\n            _cimg_mp_scalar2(mp_div,arg1,arg2);\n          }\n\n        for (s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) { // Multiplication ('*')\n            _cimg_mp_op(\"Operator '*'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_mul,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]);\n            _cimg_mp_scalar2(mp_mul,arg1,arg2);\n          }\n\n\n        for (s = se2; s>ss; --s) if (*s=='/' && level[s - expr._data]==clevel) { // Division ('/')\n            _cimg_mp_op(\"Operator '/'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_div,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_div,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]);\n            _cimg_mp_scalar2(mp_div,arg1,arg2);\n          }\n\n        for (s = se2, ns = se1; s>ss; --s, --ns)\n          if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel) { // Modulo ('%')\n            _cimg_mp_op(\"Operator '%'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_modulo,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_modulo,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_modulo,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n              _cimg_mp_constant(cimg::mod(mem[arg1],mem[arg2]));\n            _cimg_mp_scalar2(mp_modulo,arg1,arg2);\n          }\n\n        if (se1>ss) {\n          if (*ss=='+' && (*ss1!='+' || (ss2<se && *ss2>='0' && *ss2<='9'))) { // Unary plus ('+')\n            _cimg_mp_op(\"Operator '+'\");\n            _cimg_mp_return(compile(ss1,se,depth1,0));\n          }\n\n          if (*ss=='-' && (*ss1!='-' || (ss2<se && *ss2>='0' && *ss2<='9'))) { // Unary minus ('-')\n            _cimg_mp_op(\"Operator '-'\");\n            arg1 = compile(ss1,se,depth1,0);\n            if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_minus,arg1);\n            if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(-mem[arg1]);\n            _cimg_mp_scalar1(mp_minus,arg1);\n          }\n\n          if (*ss=='!') { // Logical not ('!')\n            _cimg_mp_op(\"Operator '!'\");\n            arg1 = compile(ss1,se,depth1,0);\n            if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_logical_not,arg1);\n            if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(!mem[arg1]);\n            _cimg_mp_scalar1(mp_logical_not,arg1);\n          }\n\n          if (*ss=='~') { // Bitwise not ('~')\n            _cimg_mp_op(\"Operator '~'\");\n            arg1 = compile(ss1,se,depth1,0);\n            if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bitwise_not,arg1);\n            if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(~(ulongT)mem[arg1]);\n            _cimg_mp_scalar1(mp_bitwise_not,arg1);\n          }\n        }\n\n        for (s = se3, ns = se2; s>ss; --s, --ns)\n          if (*s=='^' && *ns=='^' && level[s - expr._data]==clevel) { // Complex power ('^^')\n            _cimg_mp_op(\"Operator '^^'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 2,se,depth1,0);\n            _cimg_mp_check_type(arg1,1,3,2);\n            _cimg_mp_check_type(arg2,2,3,2);\n            pos = (_cimg_mp_is_vector(arg1) || _cimg_mp_is_vector(arg2))?vector(2):0;\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {\n              CImg<ulongT>::vector((ulongT)mp_complex_pow_vv,pos,arg1,arg2).move_to(code);\n              _cimg_mp_return(pos);\n            }\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) {\n              CImg<ulongT>::vector((ulongT)mp_complex_pow_vs,pos,arg1,arg2).move_to(code);\n              _cimg_mp_return(pos);\n            }\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) {\n              CImg<ulongT>::vector((ulongT)mp_complex_pow_sv,pos,arg1,arg2).move_to(code);\n              _cimg_mp_return(pos);\n            }\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n              _cimg_mp_constant(std::pow(mem[arg1],mem[arg2]));\n            switch (arg2) {\n            case 0 : _cimg_mp_return(1);\n            case 1 : _cimg_mp_return(arg1);\n            case 2 : _cimg_mp_scalar1(mp_sqr,arg1);\n            case 3 : _cimg_mp_scalar1(mp_pow3,arg1);\n            case 4 : _cimg_mp_scalar1(mp_pow4,arg1);\n            default : _cimg_mp_scalar2(mp_pow,arg1,arg2);\n            }\n          }\n\n        for (s = se2; s>ss; --s)\n          if (*s=='^' && level[s - expr._data]==clevel) { // Power ('^')\n            _cimg_mp_op(\"Operator '^'\");\n            arg1 = compile(ss,s,depth1,0);\n            arg2 = compile(s + 1,se,depth1,0);\n            _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_pow,arg1,arg2);\n            if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_pow,arg1,arg2);\n            if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_pow,arg1,arg2);\n            if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n              _cimg_mp_constant(std::pow(mem[arg1],mem[arg2]));\n            switch (arg2) {\n            case 0 : _cimg_mp_return(1);\n            case 1 : _cimg_mp_return(arg1);\n            case 2 : _cimg_mp_scalar1(mp_sqr,arg1);\n            case 3 : _cimg_mp_scalar1(mp_pow3,arg1);\n            case 4 : _cimg_mp_scalar1(mp_pow4,arg1);\n            default : _cimg_mp_scalar2(mp_pow,arg1,arg2);\n            }\n          }\n\n        is_sth = ss1<se1 && (*ss=='+' || *ss=='-') && *ss1==*ss; // is pre-?\n        if (is_sth || (se2>ss && (*se1=='+' || *se1=='-') && *se2==*se1)) { // Pre/post-decrement and increment\n          if ((is_sth && *ss=='+') || (!is_sth && *se1=='+')) {\n            _cimg_mp_op(\"Operator '++'\");\n            op = mp_self_increment;\n          } else {\n            _cimg_mp_op(\"Operator '--'\");\n            op = mp_self_decrement;\n          }\n          ref.assign(7);\n          arg1 = is_sth?compile(ss2,se,depth1,ref):compile(ss,se2,depth1,ref); // Variable slot\n\n          if (*ref>0 && !_cimg_mp_is_temp(arg1)) { // Apply operator on a copy if necessary.\n            if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1);\n            else arg1 = scalar1(mp_copy,arg1);\n          }\n\n          if (is_sth) pos = arg1; // Determine return indice, depending on pre/post action\n          else {\n            if (_cimg_mp_is_vector(arg1)) pos = vector_copy(arg1);\n            else pos = scalar1(mp_copy,arg1);\n          }\n\n          if (*ref==1) { // Vector value (scalar): V[k]++\n            arg3 = ref[1]; // Vector slot\n            arg4 = ref[2]; // Index\n            if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n            CImg<ulongT>::vector((ulongT)op,arg1,1).move_to(code);\n            CImg<ulongT>::vector((ulongT)mp_vector_set_off,arg1,arg3,(ulongT)_cimg_mp_vector_size(arg3),arg4,arg1).\n              move_to(code);\n            _cimg_mp_return(pos);\n          }\n\n          if (*ref==2) { // Image value (scalar): i/j[_#ind,off]++\n            is_parallelizable = false;\n            p1 = ref[1]; // Index\n            is_relative = (bool)ref[2];\n            arg3 = ref[3]; // Offset\n            if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n            CImg<ulongT>::vector((ulongT)op,arg1).move_to(code);\n            if (p1!=~0U) {\n              if (!listout) _cimg_mp_return(pos);\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff),\n                                  arg1,p1,arg3).move_to(code);\n            } else {\n              if (!imgout) _cimg_mp_return(pos);\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff),\n                                  arg1,arg3).move_to(code);\n            }\n            _cimg_mp_return(pos);\n          }\n\n          if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c)++\n            is_parallelizable = false;\n            p1 = ref[1]; // Index\n            is_relative = (bool)ref[2];\n            arg3 = ref[3]; // X\n            arg4 = ref[4]; // Y\n            arg5 = ref[5]; // Z\n            arg6 = ref[6]; // C\n            if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n            CImg<ulongT>::vector((ulongT)op,arg1).move_to(code);\n            if (p1!=~0U) {\n              if (!listout) _cimg_mp_return(pos);\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),\n                                  arg1,p1,arg3,arg4,arg5,arg6).move_to(code);\n            } else {\n              if (!imgout) _cimg_mp_return(pos);\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),\n                                  arg1,arg3,arg4,arg5,arg6).move_to(code);\n            }\n            _cimg_mp_return(pos);\n          }\n\n          if (*ref==4) { // Image value (vector): I/J[_#ind,off]++\n            is_parallelizable = false;\n            p1 = ref[1]; // Index\n            is_relative = (bool)ref[2];\n            arg3 = ref[3]; // Offset\n            if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n            self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1);\n            if (p1!=~0U) {\n              if (!listout) _cimg_mp_return(pos);\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),\n                                  arg1,p1,arg3).move_to(code);\n            } else {\n              if (!imgout) _cimg_mp_return(pos);\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),\n                                  arg1,arg3).move_to(code);\n            }\n            _cimg_mp_return(pos);\n          }\n\n          if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c)++\n            is_parallelizable = false;\n            p1 = ref[1]; // Index\n            is_relative = (bool)ref[2];\n            arg3 = ref[3]; // X\n            arg4 = ref[4]; // Y\n            arg5 = ref[5]; // Z\n            if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));\n            self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1);\n            if (p1!=~0U) {\n              if (!listout) _cimg_mp_return(pos);\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),\n                                  arg1,p1,arg3,arg4,arg5).move_to(code);\n            } else {\n              if (!imgout) _cimg_mp_return(pos);\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),\n                                  arg1,arg3,arg4,arg5).move_to(code);\n            }\n            _cimg_mp_return(pos);\n          }\n\n          if (_cimg_mp_is_vector(arg1)) { // Vector variable: V++\n            self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1);\n            _cimg_mp_return(pos);\n          }\n\n          if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s++\n            CImg<ulongT>::vector((ulongT)op,arg1).move_to(code);\n            _cimg_mp_return(pos);\n          }\n\n          if (is_sth) variable_name.assign(ss2,(unsigned int)(se - ss1));\n          else variable_name.assign(ss,(unsigned int)(se1 - ss));\n          variable_name.back() = 0;\n          *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s: %s: Invalid operand '%s', \"\n                                      \"in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,s_op,\n                                      variable_name._data,\n                                      (ss - 4)>expr._data?\"...\":\"\",\n                                      (ss - 4)>expr._data?ss - 4:expr._data,\n                                      se<&expr.back()?\"...\":\"\");\n        }\n\n        // Array-like access to vectors and  image values 'i/j[_#ind,offset,_boundary]' and 'vector[offset]'.\n        if (*se1==']' && *ss!='[') {\n          _cimg_mp_op(\"Operator '[]'\");\n          is_relative = *ss=='j' || *ss=='J';\n\n          if ((*ss=='I' || *ss=='J') && *ss1=='[' &&\n              (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a vector\n            if (*ss2=='#') { // Index specified\n              s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n              p1 = compile(ss3,s0++,depth1,0);\n              _cimg_mp_check_list(false);\n            } else { p1 = ~0U; s0 = ss2; }\n            s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n            arg1 = compile(s0,s1,depth1,0); // Offset\n            arg2 = s1<se1?compile(++s1,se1,depth1,0):~0U; // Boundary\n            if (p_ref && arg2==~0U) {\n              *p_ref = 4;\n              p_ref[1] = p1;\n              p_ref[2] = (unsigned int)is_relative;\n              p_ref[3] = arg1;\n              if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization\n              if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;\n            }\n            p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any\n            if (p1==~0U) p2 = imgin._spectrum;\n            else if (_cimg_mp_is_constant(p1)) {\n              p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());\n              p2 = listin[p3]._spectrum;\n            }\n            _cimg_mp_check_vector0(p2);\n            pos = vector(p2);\n            if (p1!=~0U) {\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_list_Joff:mp_list_Ioff),\n                                  pos,p1,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code);\n            } else {\n              need_input_copy = true;\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_Joff:mp_Ioff),\n                                  pos,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code);\n            }\n            _cimg_mp_return(pos);\n          }\n\n          if ((*ss=='i' || *ss=='j') && *ss1=='[' &&\n              (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a scalar\n            if (*ss2=='#') { // Index specified\n              s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n              p1 = compile(ss3,s0++,depth1,0);\n            } else { p1 = ~0U; s0 = ss2; }\n            s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n            arg1 = compile(s0,s1,depth1,0); // Offset\n            arg2 = s1<se1?compile(++s1,se1,depth1,0):~0U; // Boundary\n            if (p_ref && arg2==~0U) {\n              *p_ref = 2;\n              p_ref[1] = p1;\n              p_ref[2] = (unsigned int)is_relative;\n              p_ref[3] = arg1;\n              if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization\n              if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;\n            }\n            if (p1!=~0U) {\n              if (!listin) _cimg_mp_return(0);\n              pos = scalar3(is_relative?mp_list_joff:mp_list_ioff,p1,arg1,arg2==~0U?reserved_label[30]:arg2);\n            } else {\n              if (!imgin) _cimg_mp_return(0);\n              need_input_copy = true;\n              pos = scalar2(is_relative?mp_joff:mp_ioff,arg1,arg2==~0U?reserved_label[30]:arg2);\n            }\n            memtype[pos] = -1; // Create it as a variable to prevent from being used in further optimization\n            _cimg_mp_return(pos);\n          }\n\n          s0 = se1; while (s0>ss && *s0!='[') --s0;\n          if (s0>ss) { // Vector value\n            arg1 = compile(ss,s0,depth1,0);\n            s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n\n            if (s1<se1) { // Two arguments -> sub-vector extraction\n              arg2 = compile(++s0,s1,depth1,0);\n              arg3 = compile(++s1,se1,depth1,0);\n              _cimg_mp_check_constant(arg2,1,false);\n              _cimg_mp_check_constant(arg3,2,false);\n              p1 = (unsigned int)mem[arg2];\n              p2 = (unsigned int)mem[arg3];\n              p3 = _cimg_mp_vector_size(arg1);\n              if (p1>=p3 || p2>=p3) {\n                variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0;\n                *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);\n                throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                            \"CImg<%s>::%s: %s: Out-of-bounds request for sub-vector '%s[%d,%d]' \"\n                                            \"(vector '%s' has dimension %u), \"\n                                            \"in expression '%s%s%s'.\",\n                                            pixel_type(),_cimg_mp_calling_function,s_op,\n                                            variable_name._data,(int)mem[arg2],(int)mem[arg3],\n                                            variable_name._data,p3,\n                                            (ss - 4)>expr._data?\"...\":\"\",\n                                            (ss - 4)>expr._data?ss - 4:expr._data,\n                                            se<&expr.back()?\"...\":\"\");\n              }\n              if (p1>p2) cimg::swap(p1,p2);\n              (p2-=p1)++;\n              pos = vector(p2);\n              CImg<ulongT>::vector((ulongT)mp_vector_crop,pos,arg1,p1,p2).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            // One argument -> vector value reference\n            if (_cimg_mp_is_scalar(arg1)) {\n              variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0;\n              *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);\n              throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                          \"CImg<%s>::%s: %s: Array brackets used on non-vector variable '%s', \"\n                                          \"in expression '%s%s%s'.\",\n                                          pixel_type(),_cimg_mp_calling_function,s_op,\n                                          variable_name._data,\n                                          (ss - 4)>expr._data?\"...\":\"\",\n                                          (ss - 4)>expr._data?ss - 4:expr._data,\n                                          se<&expr.back()?\"...\":\"\");\n            }\n\n            arg2 = compile(++s0,se1,depth1,0);\n            if (_cimg_mp_is_constant(arg2)) { // Constant index\n              nb = (int)mem[arg2];\n              if (nb>=0 && nb<(int)_cimg_mp_vector_size(arg1)) _cimg_mp_return(arg1 + 1 + nb);\n              variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0;\n              *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);\n              throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                          \"CImg<%s>::%s: Out-of-bounds reference '%s[%d]' \"\n                                          \"(vector '%s' has dimension %u), \"\n                                          \"in expression '%s%s%s'.\",\n                                          pixel_type(),_cimg_mp_calling_function,\n                                          variable_name._data,nb,\n                                          variable_name._data,_cimg_mp_vector_size(arg1),\n                                          (ss - 4)>expr._data?\"...\":\"\",\n                                          (ss - 4)>expr._data?ss - 4:expr._data,\n                                          se<&expr.back()?\"...\":\"\");\n            }\n            if (p_ref) {\n              *p_ref = 1;\n              p_ref[1] = arg1;\n              p_ref[2] = arg2;\n              if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; // Prevent from being used in further optimization\n            }\n            _cimg_mp_scalar3(mp_vector_off,arg1,(ulongT)_cimg_mp_vector_size(arg1),arg2);\n          }\n        }\n\n        // Look for a function call, an access to image value, or a parenthesis.\n        if (*se1==')') {\n          if (*ss=='(') _cimg_mp_return(compile(ss1,se1,depth1,p_ref)); // Simple parentheses\n          is_relative = *ss=='j' || *ss=='J';\n          _cimg_mp_op(\"Operator '()'\");\n\n          // I/J(_#ind,_x,_y,_z,_interpolation,_boundary)\n          if ((*ss=='I' || *ss=='J') && *ss1=='(') { // Image value as scalar\n            if (*ss2=='#') { // Index specified\n              s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n              p1 = compile(ss3,s0++,depth1,0);\n              _cimg_mp_check_list(false);\n            } else { p1 = ~0U; s0 = ss2; }\n            arg1 = is_relative?0U:(unsigned int)_cimg_mp_x;\n            arg2 = is_relative?0U:(unsigned int)_cimg_mp_y;\n            arg3 = is_relative?0U:(unsigned int)_cimg_mp_z;\n            arg4 = arg5 = ~0U;\n            if (s0<se1) {\n              s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(s0,s1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector\n                p2 = _cimg_mp_vector_size(arg1);\n                ++arg1;\n                if (p2>1) {\n                  arg2 = arg1 + 1;\n                  if (p2>2) arg3 = arg2 + 1;\n                }\n                if (s1<se1) {\n                  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n                  arg4 = compile(s1,s2,depth1,0);\n                  arg5 = s2<se1?compile(++s2,se1,depth1,0):~0U;\n                }\n              } else if (s1<se1) {\n                s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n                arg2 = compile(s1,s2,depth1,0);\n                if (s2<se1) {\n                  s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;\n                  arg3 = compile(s2,s3,depth1,0);\n                  if (s3<se1) {\n                    s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n                    arg4 = compile(s3,s2,depth1,0);\n                    arg5 = s2<se1?compile(++s2,se1,depth1,0):~0U;\n                  }\n                }\n              }\n            }\n            if (p_ref && arg4==~0U && arg5==~0U) {\n              *p_ref = 5;\n              p_ref[1] = p1;\n              p_ref[2] = (unsigned int)is_relative;\n              p_ref[3] = arg1;\n              p_ref[4] = arg2;\n              p_ref[5] = arg3;\n              if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization\n              if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;\n              if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;\n              if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1;\n            }\n            p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any\n            if (p1==~0U) p2 = imgin._spectrum;\n            else if (_cimg_mp_is_constant(p1)) {\n              p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());\n              p2 = listin[p3]._spectrum;\n            }\n            _cimg_mp_check_vector0(p2);\n            pos = vector(p2);\n            if (p1!=~0U)\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_list_Jxyz:mp_list_Ixyz),\n                                  pos,p1,arg1,arg2,arg3,\n                                  arg4==~0U?reserved_label[29]:arg4,\n                                  arg5==~0U?reserved_label[30]:arg5).move_to(code);\n            else {\n              need_input_copy = true;\n              CImg<ulongT>::vector((ulongT)(is_relative?mp_Jxyz:mp_Ixyz),\n                                  pos,arg1,arg2,arg3,\n                                  arg4==~0U?reserved_label[29]:arg4,\n                                  arg5==~0U?reserved_label[30]:arg5).move_to(code);\n            }\n            _cimg_mp_return(pos);\n          }\n\n          // i/j(_#ind,_x,_y,_z,_c,_interpolation,_boundary)\n          if ((*ss=='i' || *ss=='j') && *ss1=='(') { // Image value as scalar\n            if (*ss2=='#') { // Index specified\n              s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n              p1 = compile(ss3,s0++,depth1,0);\n            } else { p1 = ~0U; s0 = ss2; }\n            arg1 = is_relative?0U:(unsigned int)_cimg_mp_x;\n            arg2 = is_relative?0U:(unsigned int)_cimg_mp_y;\n            arg3 = is_relative?0U:(unsigned int)_cimg_mp_z;\n            arg4 = is_relative?0U:(unsigned int)_cimg_mp_c;\n            arg5 = arg6 = ~0U;\n            if (s0<se1) {\n              s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(s0,s1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector\n                p2 = _cimg_mp_vector_size(arg1);\n                ++arg1;\n                if (p2>1) {\n                  arg2 = arg1 + 1;\n                  if (p2>2) {\n                    arg3 = arg2 + 1;\n                    if (p2>3) arg4 = arg3 + 1;\n                  }\n                }\n                if (s1<se1) {\n                  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n                  arg5 = compile(s1,s2,depth1,0);\n                  arg6 = s2<se1?compile(++s2,se1,depth1,0):~0U;\n                }\n              } else if (s1<se1) {\n                s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n                arg2 = compile(s1,s2,depth1,0);\n                if (s2<se1) {\n                  s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;\n                  arg3 = compile(s2,s3,depth1,0);\n                  if (s3<se1) {\n                    s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n                    arg4 = compile(s3,s2,depth1,0);\n                    if (s2<se1) {\n                      s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;\n                      arg5 = compile(s2,s3,depth1,0);\n                      arg6 = s3<se1?compile(++s3,se1,depth1,0):~0U;\n                    }\n                  }\n                }\n              }\n            }\n            if (p_ref && arg5==~0U && arg6==~0U) {\n              *p_ref = 3;\n              p_ref[1] = p1;\n              p_ref[2] = (unsigned int)is_relative;\n              p_ref[3] = arg1;\n              p_ref[4] = arg2;\n              p_ref[5] = arg3;\n              p_ref[6] = arg4;\n              if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization\n              if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;\n              if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;\n              if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1;\n              if (_cimg_mp_is_temp(arg4)) memtype[arg4] = -1;\n            }\n\n            if (p1!=~0U) {\n              if (!listin) _cimg_mp_return(0);\n              pos = scalar7(is_relative?mp_list_jxyzc:mp_list_ixyzc,\n                            p1,arg1,arg2,arg3,arg4,\n                            arg5==~0U?reserved_label[29]:arg5,\n                            arg6==~0U?reserved_label[30]:arg6);\n            } else {\n              if (!imgin) _cimg_mp_return(0);\n              need_input_copy = true;\n              pos = scalar6(is_relative?mp_jxyzc:mp_ixyzc,\n                            arg1,arg2,arg3,arg4,\n                            arg5==~0U?reserved_label[29]:arg5,\n                            arg6==~0U?reserved_label[30]:arg6);\n            }\n            memtype[pos] = -1; // Create it as a variable to prevent from being used in further optimization\n            _cimg_mp_return(pos);\n          }\n\n          // Mathematical functions.\n          switch (*ss) {\n          case 'a' :\n            if (!std::strncmp(ss,\"abs(\",4)) { // Absolute value\n              _cimg_mp_op(\"Function 'abs()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_abs,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::abs(mem[arg1]));\n              _cimg_mp_scalar1(mp_abs,arg1);\n            }\n\n            if (!std::strncmp(ss,\"acos(\",5)) { // Arccos\n              _cimg_mp_op(\"Function 'acos()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_acos,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::acos(mem[arg1]));\n              _cimg_mp_scalar1(mp_acos,arg1);\n            }\n\n            if (!std::strncmp(ss,\"asin(\",5)) { // Arcsin\n              _cimg_mp_op(\"Function 'asin()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_asin,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::asin(mem[arg1]));\n              _cimg_mp_scalar1(mp_asin,arg1);\n            }\n\n            if (!std::strncmp(ss,\"atan(\",5)) { // Arctan\n              _cimg_mp_op(\"Function 'atan()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_atan,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::atan(mem[arg1]));\n              _cimg_mp_scalar1(mp_atan,arg1);\n            }\n\n            if (!std::strncmp(ss,\"atan2(\",6)) { // Arctan2\n              _cimg_mp_op(\"Function 'atan2()'\");\n              s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss6,s1,depth1,0);\n              arg2 = compile(++s1,se1,depth1,0);\n              _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n              if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_atan2,arg1,arg2);\n              if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_atan2,arg1,arg2);\n              if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_atan2,arg1,arg2);\n              if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n                _cimg_mp_constant(std::atan2(mem[arg1],mem[arg2]));\n              _cimg_mp_scalar2(mp_atan2,arg1,arg2);\n            }\n            break;\n\n          case 'c' :\n            if (!std::strncmp(ss,\"cabs(\",5)) { // Complex absolute value\n              _cimg_mp_op(\"Function 'cabs()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              _cimg_mp_check_type(arg1,0,2,2);\n              _cimg_mp_scalar2(mp_hypot,arg1 + 1,arg1 + 2);\n            }\n\n            if (!std::strncmp(ss,\"carg(\",5)) { // Complex argument\n              _cimg_mp_op(\"Function 'carg()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              _cimg_mp_check_type(arg1,0,2,2);\n              _cimg_mp_scalar2(mp_atan2,arg1 + 2,arg1 + 1);\n            }\n\n            if (!std::strncmp(ss,\"cbrt(\",5)) { // Cubic root\n              _cimg_mp_op(\"Function 'cbrt()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cbrt,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::pow(mem[arg1],1.0/3));\n              _cimg_mp_scalar1(mp_cbrt,arg1);\n            }\n\n            if (!std::strncmp(ss,\"cconj(\",6)) { // Complex conjugate\n              _cimg_mp_op(\"Function 'cconj()'\");\n              arg1 = compile(ss6,se1,depth1,0);\n              _cimg_mp_check_type(arg1,0,2,2);\n              pos = vector(2);\n              CImg<ulongT>::vector((ulongT)mp_complex_conj,pos,arg1).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"cexp(\",5)) { // Complex exponential\n              _cimg_mp_op(\"Function 'cexp()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              _cimg_mp_check_type(arg1,0,2,2);\n              pos = vector(2);\n              CImg<ulongT>::vector((ulongT)mp_complex_exp,pos,arg1).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"clog(\",5)) { // Complex logarithm\n              _cimg_mp_op(\"Function 'clog()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              _cimg_mp_check_type(arg1,0,2,2);\n              pos = vector(2);\n              CImg<ulongT>::vector((ulongT)mp_complex_log,pos,arg1).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"copy(\",5)) { // Memory copy\n              _cimg_mp_op(\"Function 'copy()'\");\n              ref.assign(14);\n              s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = p1 = compile(ss5,s1,depth1,ref);\n              s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n              arg2 = compile(s1,s2,depth1,ref._data + 7);\n              arg3 = ~0U; arg4 = arg5 = 1;\n              if (s2<se1) {\n                s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;\n                arg3 = compile(s2,s3,depth1,0);\n                if (s3<se1) {\n                  s1 = ++s3; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n                  arg4 = compile(s3,s1,depth1,0);\n                  arg5 = s1<se1?compile(++s1,se1,depth1,0):1;\n                }\n              }\n              if (_cimg_mp_is_vector(arg1) && !ref[0]) ++arg1;\n              if (_cimg_mp_is_vector(arg2)) {\n                if (arg3==~0U) arg3 = _cimg_mp_vector_size(arg2);\n                if (!ref[7]) ++arg2;\n              }\n              if (arg3==~0U) arg3 = 1;\n              _cimg_mp_check_type(arg3,3,1,0);\n              _cimg_mp_check_type(arg4,4,1,0);\n              _cimg_mp_check_type(arg5,5,1,0);\n              CImg<ulongT>(1,21).move_to(code);\n              code.back().get_shared_rows(0,6).fill((ulongT)mp_memcopy,p1,arg1,arg2,arg3,arg4,arg5);\n              code.back().get_shared_rows(7,20).fill(ref);\n              _cimg_mp_return(p1);\n            }\n\n            if (!std::strncmp(ss,\"cos(\",4)) { // Cosine\n              _cimg_mp_op(\"Function 'cos()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cos,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cos(mem[arg1]));\n              _cimg_mp_scalar1(mp_cos,arg1);\n            }\n\n            if (!std::strncmp(ss,\"cosh(\",5)) { // Hyperbolic cosine\n              _cimg_mp_op(\"Function 'cosh()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cosh,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cosh(mem[arg1]));\n              _cimg_mp_scalar1(mp_cosh,arg1);\n            }\n\n            if (!std::strncmp(ss,\"crop(\",5)) { // Image crop\n              _cimg_mp_op(\"Function 'crop()'\");\n              if (*ss5=='#') { // Index specified\n                s0 = ss6; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                p1 = compile(ss6,s0++,depth1,0);\n                _cimg_mp_check_list(false);\n              } else { p1 = ~0U; s0 = ss5; need_input_copy = true; }\n              pos = 0;\n              is_sth = false; // Coordinates specified as a vector?\n              if (ss5<se1) for (s = s0; s<se; ++s, ++pos) {\n                ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&\n                               (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;\n                arg1 = compile(s,ns,depth1,0);\n                if (!pos && _cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector\n                  opcode = CImg<ulongT>::sequence((ulongT)_cimg_mp_vector_size(arg1),arg1 + 1,\n                                                 arg1 + (ulongT)_cimg_mp_vector_size(arg1));\n                  opcode.resize(1,cimg::min(opcode._height,4U),1,1,0).move_to(_opcode);\n                  is_sth = true;\n                } else {\n                  _cimg_mp_check_type(arg1,pos + 1,1,0);\n                  CImg<ulongT>::vector(arg1).move_to(_opcode);\n                }\n                s = ns;\n              }\n              (_opcode>'y').move_to(opcode);\n\n              arg1 = 0; arg2 = p1!=~0U?1:0;\n              switch (opcode._height) {\n              case 0 : case 1 :\n                CImg<ulongT>::vector(0,0,0,0,~0U,~0U,~0U,~0U,0).move_to(opcode);\n                break;\n              case 2 :\n                CImg<ulongT>::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,reserved_label[30]).move_to(opcode);\n                arg1 = arg2?3:2;\n                break;\n              case 3 :\n                CImg<ulongT>::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,opcode[2]).move_to(opcode);\n                arg1 = arg2?3:2;\n                break;\n              case 4 :\n                CImg<ulongT>::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,reserved_label[30]).\n                  move_to(opcode);\n                arg1 = (is_sth?2:1) + arg2;\n                break;\n              case 5 :\n                CImg<ulongT>::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,opcode[4]).\n                  move_to(opcode);\n                arg1 = (is_sth?2:1) + arg2;\n                break;\n              case 6 :\n                CImg<ulongT>::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U,\n                                    reserved_label[30]).move_to(opcode);\n                arg1 = (is_sth?2:4) + arg2;\n                break;\n              case 7 :\n                CImg<ulongT>::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U,\n                                    opcode[6]).move_to(opcode);\n                arg1 = (is_sth?2:4) + arg2;\n                break;\n              case 8 :\n                CImg<ulongT>::vector(*opcode,opcode[1],opcode[2],opcode[3],opcode[4],opcode[5],opcode[6],\n                                    opcode[7],reserved_label[30]).move_to(opcode);\n                arg1 = (is_sth?2:5) + arg2;\n                break;\n              case 9 :\n                arg1 = (is_sth?2:5) + arg2;\n                break;\n              default : // Error -> too much arguments\n                throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                            \"CImg<%s>::%s: %s: Too much arguments specified, \"\n                                            \"in expression '%s%s%s'.\",\n                                            pixel_type(),_cimg_mp_calling_function,s_op,\n                                            (ss - 4)>expr._data?\"...\":\"\",\n                                            (ss - 4)>expr._data?ss - 4:expr._data,\n                                            se<&expr.back()?\"...\":\"\");\n              }\n              _cimg_mp_check_type(*opcode,arg2 + 1,1,0);\n              _cimg_mp_check_type(opcode[1],arg2 + (is_sth?0:1),1,0);\n              _cimg_mp_check_type(opcode[2],arg2 + (is_sth?0:2),1,0);\n              _cimg_mp_check_type(opcode[3],arg2 + (is_sth?0:3),1,0);\n\n              if (opcode[4]!=(ulongT)~0U) {\n                _cimg_mp_check_constant(opcode[4],arg1,true);\n                opcode[4] = (ulongT)mem[opcode[4]];\n              }\n              if (opcode[5]!=(ulongT)~0U) {\n                _cimg_mp_check_constant(opcode[5],arg1 + 1,true);\n                opcode[5] = (ulongT)mem[opcode[5]];\n              }\n              if (opcode[6]!=(ulongT)~0U) {\n                _cimg_mp_check_constant(opcode[6],arg1 + 2,true);\n                opcode[6] = (ulongT)mem[opcode[6]];\n              }\n              if (opcode[7]!=(ulongT)~0U) {\n                _cimg_mp_check_constant(opcode[7],arg1 + 3,true);\n                opcode[7] = (ulongT)mem[opcode[7]];\n              }\n              _cimg_mp_check_type(opcode[8],arg1 + 4,1,0);\n\n              if (opcode[4]==(ulongT)~0U || opcode[5]==(ulongT)~0U ||\n                  opcode[6]==(ulongT)~0U || opcode[7]==(ulongT)~0U) {\n                if (p1!=~0U) {\n                  _cimg_mp_check_constant(p1,1,false);\n                  p1 = (unsigned int)cimg::mod((int)mem[p1],listin.width());\n                }\n                const CImg<T> &img = p1!=~0U?listin[p1]:imgin;\n                if (!img)\n                  throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                              \"CImg<%s>::%s: %s: Cannot crop empty image when \"\n                                              \"some xyzc-coordinates are unspecified, in expression '%s%s%s'.\",\n                                              pixel_type(),_cimg_mp_calling_function,s_op,\n                                              (ss - 4)>expr._data?\"...\":\"\",\n                                              (ss - 4)>expr._data?ss - 4:expr._data,\n                                              se<&expr.back()?\"...\":\"\");\n                if (opcode[4]==(ulongT)~0U) opcode[4] = (ulongT)img._width;\n                if (opcode[5]==(ulongT)~0U) opcode[5] = (ulongT)img._height;\n                if (opcode[6]==(ulongT)~0U) opcode[6] = (ulongT)img._depth;\n                if (opcode[7]==(ulongT)~0U) opcode[7] = (ulongT)img._spectrum;\n              }\n\n              pos = vector(opcode[4]*opcode[5]*opcode[6]*opcode[7]);\n              CImg<ulongT>::vector((ulongT)mp_crop,\n                                  pos,p1,\n                                  *opcode,opcode[1],opcode[2],opcode[3],\n                                  opcode[4],opcode[5],opcode[6],opcode[7],\n                                  opcode[8]).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"cross(\",6)) { // Cross product\n              _cimg_mp_op(\"Function 'cross()'\");\n              s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss6,s1,depth1,0);\n              arg2 = compile(++s1,se1,depth1,0);\n              _cimg_mp_check_type(arg1,1,2,3);\n              _cimg_mp_check_type(arg2,2,2,3);\n              pos = vector(3);\n              CImg<ulongT>::vector((ulongT)mp_cross,pos,arg1,arg2).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"cut(\",4)) { // Cut\n              _cimg_mp_op(\"Function 'cut()'\");\n              s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss4,s1,depth1,0);\n              s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n              arg2 = compile(++s1,s2,depth1,0);\n              arg3 = compile(++s2,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_cut,arg1,arg2,arg3);\n              if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3)) {\n                val = mem[arg1];\n                val1 = mem[arg2];\n                val2 = mem[arg3];\n                _cimg_mp_constant(val<val1?val1:val>val2?val2:val);\n              }\n              _cimg_mp_scalar3(mp_cut,arg1,arg2,arg3);\n            }\n            break;\n\n          case 'd' :\n            if (!std::strncmp(ss,\"date(\",5)) { // Date and file date\n              _cimg_mp_op(\"Function 'date()'\");\n              s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = 0;\n              is_sth = s1!=se1; // is_fdate\n              if (s1==se1 && ss5!=se1 && // Exactly one argument\n                  (cimg_sscanf(ss5,\"%u%c\",&arg1,&sep)!=2 || sep!=')')) is_sth = true;\n              if (is_sth) {\n                if (cimg_sscanf(ss5,\"%u%c\",&arg1,&sep)!=2 || sep!=',') { arg1 = 0; s1 = ss4; }\n                *se1 = 0; val = (double)cimg::fdate(++s1,arg1); *se1 = ')';\n              } else val = (double)cimg::date(arg1);\n              _cimg_mp_constant(val);\n            }\n\n            if (!std::strncmp(ss,\"debug(\",6)) { // Print debug info\n              _cimg_mp_op(\"Function 'debug()'\");\n              p1 = code._width;\n              arg1 = compile(ss6,se1,depth1,p_ref);\n              *se1 = 0;\n              ((CImg<ulongT>::vector((ulongT)mp_debug,arg1,code._width - p1),\n                CImg<ulongT>::string(ss6).unroll('y'))>'y').move_to(code,p1);\n              *se1 = ')';\n              _cimg_mp_return(arg1);\n            }\n\n            if (!std::strncmp(ss,\"det(\",4)) { // Matrix determinant\n              _cimg_mp_op(\"Function 'det()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              _cimg_mp_check_matrix_square(arg1,1);\n              p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));\n              _cimg_mp_scalar2(mp_det,arg1,p1);\n            }\n\n            if (!std::strncmp(ss,\"diag(\",5)) { // Diagonal matrix\n              _cimg_mp_op(\"Function 'diag()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              _cimg_mp_check_type(arg1,1,2,0);\n              p1 = _cimg_mp_vector_size(arg1);\n              pos = vector(p1*p1);\n              CImg<ulongT>::vector((ulongT)mp_diag,pos,arg1,p1).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"dot(\",4)) { // Dot product\n              _cimg_mp_op(\"Function 'dot()'\");\n              s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss4,s1,depth1,0);\n              arg2 = compile(++s1,se1,depth1,0);\n              _cimg_mp_check_type(arg1,1,2,0);\n              _cimg_mp_check_type(arg2,2,2,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_scalar3(mp_dot,arg1,arg2,_cimg_mp_vector_size(arg1));\n              _cimg_mp_scalar2(mp_mul,arg1,arg2);\n            }\n\n            if (!std::strncmp(ss,\"dowhile\",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // Do..while\n              _cimg_mp_op(\"Function 'dowhile()'\");\n              if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace\n              s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              p1 = code._width;\n              arg1 = compile(ss8,s1,depth1,0);\n              arg2 = s1<se1?compile(++s1,se1,depth1,0):arg1;\n              _cimg_mp_check_type(arg2,2,1,0);\n              CImg<ulongT>::vector((ulongT)mp_dowhile,arg1,arg2,code._width - p1).move_to(code,p1);\n              _cimg_mp_return(arg1);\n            }\n\n            if (!std::strncmp(ss,\"draw(\",5)) { // Draw image\n              _cimg_mp_op(\"Function 'draw()'\");\n              is_parallelizable = false;\n              if (*ss5=='#') { // Index specified\n                s0 = ss6; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                p1 = compile(ss6,s0++,depth1,0);\n                _cimg_mp_check_list(true);\n              } else { p1 = ~0U; s0 = ss5; }\n              s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(s0,s1,depth1,0);\n              arg2 = is_relative?0U:(unsigned int)_cimg_mp_x;\n              arg3 = is_relative?0U:(unsigned int)_cimg_mp_y;\n              arg4 = is_relative?0U:(unsigned int)_cimg_mp_z;\n              arg5 = is_relative?0U:(unsigned int)_cimg_mp_c;\n              if (s1<se1) {\n                s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                arg2 = compile(++s1,s0,depth1,0);\n                if (_cimg_mp_is_vector(arg2)) { // Coordinates specified as a vector\n                  p2 = _cimg_mp_vector_size(arg2);\n                  ++arg2;\n                  if (p2>1) {\n                    arg3 = arg2 + 1;\n                    if (p2>2) {\n                      arg4 = arg3 + 1;\n                      if (p2>3) arg5 = arg4 + 1;\n                    }\n                  }\n                  ++s0;\n                  is_sth = true;\n                } else {\n                  if (s0<se1) {\n                    is_sth = p1!=~0U;\n                    s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n                    arg3 = compile(++s0,s1,depth1,0);\n                    _cimg_mp_check_type(arg3,is_sth?4:3,1,0);\n                    if (s1<se1) {\n                      s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                      arg4 = compile(++s1,s0,depth1,0);\n                      _cimg_mp_check_type(arg4,is_sth?5:4,1,0);\n                      if (s0<se1) {\n                        s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n                        arg5 = compile(++s0,s1,depth1,0);\n                        _cimg_mp_check_type(arg5,is_sth?6:5,1,0);\n                        s0 = ++s1;\n                      }\n                    }\n                  }\n                  is_sth = false;\n                }\n              }\n\n              CImg<ulongT>::vector((ulongT)mp_draw,arg1,p1,arg2,arg3,arg4,arg5,0,0,0,0,1,(ulongT)-1,0,1).\n                move_to(opcode);\n\n              arg2 = arg3 = arg4 = arg5 = ~0U;\n              p2 = p1!=~0U?0:1;\n              if (s0<se1) {\n                s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n                arg2 = compile(s0,s1,depth1,0);\n                _cimg_mp_check_constant(arg2,p2 + (is_sth?3:6),true);\n                arg2 = (unsigned int)mem[arg2];\n                if (s1<se1) {\n                  s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                  arg3 = compile(++s1,s0,depth1,0);\n                  _cimg_mp_check_constant(arg3,p2 + (is_sth?4:7),true);\n                  arg3 = (unsigned int)mem[arg3];\n                  if (s0<se1) {\n                    s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n                    arg4 = compile(++s0,s1,depth1,0);\n                    _cimg_mp_check_constant(arg4,p2 + (is_sth?5:8),true);\n                    arg4 = (unsigned int)mem[arg4];\n                    if (s1<se1) {\n                      s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                      arg5 = compile(++s1,s0,depth1,0);\n                      _cimg_mp_check_constant(arg5,p2 + (is_sth?6:9),true);\n                      arg5 = (unsigned int)mem[arg5];\n                    }\n                  }\n                }\n              }\n              if (s0<s1) s0 = s1;\n              if (arg2==~0U || arg3==~0U || arg4==~0U || arg5==~0U) {\n                if (p1!=~0U) {\n                  _cimg_mp_check_constant(p1,1,false);\n                  p1 = (unsigned int)cimg::mod((int)mem[p1],listout.width());\n                }\n                const CImg<T> &img = p1!=~0U?listout[p1]:imgout;\n                if (arg2==~0U) arg2 = img._width;\n                if (arg3==~0U) arg3 = img._height;\n                if (arg4==~0U) arg4 = img._depth;\n                if (arg5==~0U) arg5 = img._spectrum;\n              }\n              if (arg2*arg3*arg4*arg5!=_cimg_mp_vector_size(arg1)) {\n                *se = saved_char; cimg::strellipsize(expr,64);\n                throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                            \"CImg<%s>::%s: %s: Type of %s argument ('%s') and specified size \"\n                                            \"(%u,%u,%u,%u) do not match, in expression '%s%s%s'.\",\n                                            pixel_type(),_cimg_mp_calling_function,s_op,\n                                            p1==~0U?\"first\":\"second\",s_type(arg1)._data,\n                                            arg2,arg3,arg4,arg5,\n                                            (ss - 4)>expr._data?\"...\":\"\",\n                                            (ss - 4)>expr._data?ss - 4:expr._data,\n                                            se<&expr.back()?\"...\":\"\");\n              }\n              opcode[7] = (ulongT)arg2;\n              opcode[8] = (ulongT)arg3;\n              opcode[9] = (ulongT)arg4;\n              opcode[10] = (ulongT)arg5;\n\n              if (s0<se1) {\n                s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n                arg6 = compile(++s0,s1,depth1,0);\n                _cimg_mp_check_type(arg6,0,1,0);\n                opcode[11] = arg6;\n                if (s1<se1) {\n                  s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                  p2 = compile(++s1,s0,depth1,0);\n                  _cimg_mp_check_type(p2,0,2,0);\n                  if (arg2*arg3*arg4%_cimg_mp_vector_size(p2)) {\n                    *se = saved_char; cimg::strellipsize(expr,64);\n                    throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                                \"CImg<%s>::%s: %s: Type of opacity mask ('%s') and specified size \"\n                                                \"(%u,%u,%u,%u) do not match, in expression '%s%s%s'.\",\n                                                pixel_type(),_cimg_mp_calling_function,s_op,\n                                                s_type(p2)._data,\n                                                arg2,arg3,arg4,arg5,\n                                                (ss - 4)>expr._data?\"...\":\"\",\n                                                (ss - 4)>expr._data?ss - 4:expr._data,\n                                                se<&expr.back()?\"...\":\"\");\n                  }\n                  opcode[12] = p2;\n                  opcode[13] = _cimg_mp_vector_size(p2)/(arg2*arg3*arg4);\n                  p3 = s0<se1?compile(++s0,se1,depth1,0):1;\n                  _cimg_mp_check_type(p3,0,1,0);\n                  opcode[14] = p3;\n                }\n              }\n              opcode.move_to(code);\n              _cimg_mp_return(arg1);\n            }\n            break;\n\n          case 'e' :\n            if (!std::strncmp(ss,\"eig(\",4)) { // Matrix eigenvalues/eigenvector\n              _cimg_mp_op(\"Function 'eig()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              _cimg_mp_check_matrix_square(arg1,1);\n              p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));\n              pos = vector((p1 + 1)*p1);\n              CImg<ulongT>::vector((ulongT)mp_eig,pos,arg1,p1).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"exp(\",4)) { // Exponential\n              _cimg_mp_op(\"Function 'exp()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_exp,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::exp(mem[arg1]));\n              _cimg_mp_scalar1(mp_exp,arg1);\n            }\n\n            if (!std::strncmp(ss,\"eye(\",4)) { // Identity matrix\n              _cimg_mp_op(\"Function 'eye()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              _cimg_mp_check_constant(arg1,1,true);\n              p1 = (unsigned int)mem[arg1];\n              pos = vector(p1*p1);\n              CImg<ulongT>::vector((ulongT)mp_eye,pos,p1).move_to(code);\n              _cimg_mp_return(pos);\n            }\n            break;\n\n          case 'f' :\n            if (*ss1=='o' && *ss2=='r' && (*ss3=='(' || (*ss3 && *ss3<=' ' && *ss4=='('))) { // For loop\n              _cimg_mp_op(\"Function 'for()'\");\n              if (*ss3<=' ') cimg::swap(*ss3,*ss4); // Allow space before opening brace\n              s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n              s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;\n              compile(ss4,s1,depth1,0);\n              p1 = code._width;\n              arg1 = compile(++s1,s2,depth1,0);\n              p2 = code._width;\n              if (s3<se1) { pos = compile(s3 + 1,se1,depth1,0); compile(++s2,s3,depth1,0); } // Body + proc\n              else pos = compile(++s2,se1,depth1,0); // Proc only\n              _cimg_mp_check_type(arg1,2,1,0);\n              arg2 = _cimg_mp_is_vector(pos)?_cimg_mp_vector_size(pos):0; // Output vector size (or 0 if scalar)\n              CImg<ulongT>::vector((ulongT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1);\n              _cimg_mp_return(pos);\n            }\n            break;\n\n          case 'g' :\n            if (!std::strncmp(ss,\"gauss(\",6)) { // Gaussian function\n              _cimg_mp_op(\"Function 'gauss()'\");\n              s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss6,s1,depth1,0);\n              arg2 = s1<se1?compile(++s1,se1,depth1,0):1;\n              _cimg_mp_check_type(arg2,2,1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(mp_gauss,arg1,arg2);\n              if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) {\n                val1 = mem[arg1];\n                val2 = mem[arg2];\n                _cimg_mp_constant(std::exp(-val1*val1/(2*val2*val2))/std::sqrt(2*val2*val2*cimg::PI));\n              }\n              _cimg_mp_scalar2(mp_gauss,arg1,arg2);\n            }\n            break;\n\n          case 'h' :\n            if (!std::strncmp(ss,\"hypot(\",6)) { // Hypothenuse\n              _cimg_mp_op(\"Function 'hypot()'\");\n              s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss6,s1,depth1,0);\n              arg2 = compile(++s1,se1,depth1,0);\n              _cimg_mp_check_type(arg1,1,1,0);\n              _cimg_mp_check_type(arg2,2,1,0);\n              if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) {\n                val1 = cimg::abs(mem[arg1]);\n                val2 = cimg::abs(mem[arg2]);\n                if (val1<val2) { val = val1; val1 = val2; } else val = val2;\n                if (val1>0) { val/=val1; _cimg_mp_constant(val1*std::sqrt(1+val*val)); }\n                _cimg_mp_constant(0);\n              }\n              _cimg_mp_scalar2(mp_hypot,arg1,arg2);\n            }\n            break;\n\n          case 'i' :\n            if (*ss1=='f' && (*ss2=='(' || (*ss2 && *ss2<=' ' && *ss3=='('))) { // If..then[..else.]\n              _cimg_mp_op(\"Function 'if()'\");\n              if (*ss2<=' ') cimg::swap(*ss2,*ss3); // Allow space before opening brace\n              s1 = ss3; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n              arg1 = compile(ss3,s1,depth1,0);\n              _cimg_mp_check_type(arg1,1,1,0);\n              if (_cimg_mp_is_constant(arg1)) {\n                if ((bool)mem[arg1]) return compile(++s1,s2,depth1,0);\n                else return s2<se1?compile(++s2,se1,depth1,0):0;\n              }\n              p2 = code._width;\n              arg2 = compile(++s1,s2,depth1,0);\n              p3 = code._width;\n              arg3 = s2<se1?compile(++s2,se1,depth1,0):_cimg_mp_is_vector(arg2)?vector(_cimg_mp_vector_size(arg2),0):0;\n              _cimg_mp_check_type(arg3,3,_cimg_mp_is_vector(arg2)?2:1,_cimg_mp_vector_size(arg2));\n              arg4 = _cimg_mp_is_vector(arg2)?_cimg_mp_vector_size(arg2):0; // Output vector size (or 0 if scalar)\n              if (arg4) pos = vector(arg4); else pos = scalar();\n              CImg<ulongT>::vector((ulongT)mp_if,pos,arg1,arg2,arg3,\n                                  p3 - p2,code._width - p3,arg4).move_to(code,p2);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"init(\",5)) { // Init\n              _cimg_mp_op(\"Function 'init()'\");\n              if (ss0!=expr._data || code.width()) { // (only allowed as the first instruction)\n                *se = saved_char; cimg::strellipsize(expr,64);\n                throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                            \"CImg<%s>::%s: %s: Init invokation not done at the \"\n                                            \"beginning of expression '%s%s%s'.\",\n                                            pixel_type(),_cimg_mp_calling_function,s_op,\n                                            (ss - 4)>expr._data?\"...\":\"\",\n                                            (ss - 4)>expr._data?ss - 4:expr._data,\n                                            se<&expr.back()?\"...\":\"\");\n              }\n              arg1 = compile(ss5,se1,depth1,p_ref);\n              init_size = code.width();\n              _cimg_mp_return(arg1);\n            }\n\n            if (!std::strncmp(ss,\"int(\",4)) { // Integer cast\n              _cimg_mp_op(\"Function 'int()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_int,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant((longT)mem[arg1]);\n              _cimg_mp_scalar1(mp_int,arg1);\n            }\n\n            if (!std::strncmp(ss,\"inv(\",4)) { // Matrix/scalar inversion\n              _cimg_mp_op(\"Function 'inv()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              _cimg_mp_check_matrix_square(arg1,1);\n              p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));\n              pos = vector(p1*p1);\n              CImg<ulongT>::vector((ulongT)mp_inv,pos,arg1,p1).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (*ss1=='s') { // Family of 'is_?()' functions\n\n              if (!std::strncmp(ss,\"isbool(\",7)) { // Is boolean?\n                _cimg_mp_op(\"Function 'isbool()'\");\n                if (ss7==se1) _cimg_mp_return(0);\n                arg1 = compile(ss7,se1,depth1,0);\n                if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isbool,arg1);\n                if (_cimg_mp_is_constant(arg1)) _cimg_mp_return(mem[arg1]==0.0 || mem[arg1]==1.0);\n                _cimg_mp_scalar1(mp_isbool,arg1);\n              }\n\n              if (!std::strncmp(ss,\"isdir(\",6)) { // Is directory?\n                _cimg_mp_op(\"Function 'isdir()'\");\n                *se1 = 0;\n                is_sth = cimg::is_directory(ss6);\n                *se1 = ')';\n                _cimg_mp_return(is_sth?1U:0U);\n              }\n\n              if (!std::strncmp(ss,\"isfile(\",7)) { // Is file?\n                _cimg_mp_op(\"Function 'isfile()'\");\n                *se1 = 0;\n                is_sth = cimg::is_file(ss7);\n                *se1 = ')';\n                _cimg_mp_return(is_sth?1U:0U);\n              }\n\n              if (!std::strncmp(ss,\"isin(\",5)) { // Is in sequence/vector?\n                if (ss5>=se1) _cimg_mp_return(0);\n                _cimg_mp_op(\"Function 'isin()'\");\n                pos = scalar();\n                CImg<ulongT>::vector((ulongT)mp_isin,pos).move_to(_opcode);\n                for (s = ss5; s<se; ++s) {\n                  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&\n                                 (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;\n                  arg1 = compile(s,ns,depth1,0);\n                  if (_cimg_mp_is_vector(arg1))\n                    CImg<ulongT>::sequence((ulongT)_cimg_mp_vector_size(arg1),arg1 + 1,\n                                          arg1 + (ulongT)_cimg_mp_vector_size(arg1)).\n                      move_to(_opcode);\n                  else CImg<ulongT>::vector(arg1).move_to(_opcode);\n                  s = ns;\n                }\n                (_opcode>'y').move_to(code);\n                _cimg_mp_return(pos);\n              }\n\n              if (!std::strncmp(ss,\"isinf(\",6)) { // Is infinite?\n                _cimg_mp_op(\"Function 'isinf()'\");\n                if (ss6==se1) _cimg_mp_return(0);\n                arg1 = compile(ss6,se1,depth1,0);\n                if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isinf,arg1);\n                if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type<double>::is_inf(mem[arg1]));\n                _cimg_mp_scalar1(mp_isinf,arg1);\n              }\n\n              if (!std::strncmp(ss,\"isint(\",6)) { // Is integer?\n                _cimg_mp_op(\"Function 'isint()'\");\n                if (ss6==se1) _cimg_mp_return(0);\n                arg1 = compile(ss6,se1,depth1,0);\n                if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isint,arg1);\n                if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)(cimg::mod(mem[arg1],1.0)==0));\n                _cimg_mp_scalar1(mp_isint,arg1);\n              }\n\n              if (!std::strncmp(ss,\"isnan(\",6)) { // Is NaN?\n                _cimg_mp_op(\"Function 'isnan()'\");\n                if (ss6==se1) _cimg_mp_return(0);\n                arg1 = compile(ss6,se1,depth1,0);\n                if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isnan,arg1);\n                if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type<double>::is_nan(mem[arg1]));\n                _cimg_mp_scalar1(mp_isnan,arg1);\n              }\n\n              if (!std::strncmp(ss,\"isval(\",6)) { // Is value?\n                _cimg_mp_op(\"Function 'isval()'\");\n                val = 0;\n                if (cimg_sscanf(ss6,\"%lf%c%c\",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1);\n                _cimg_mp_return(0);\n              }\n\n            }\n            break;\n\n          case 'l' :\n            if (!std::strncmp(ss,\"log(\",4)) { // Natural logarithm\n              _cimg_mp_op(\"Function 'log()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log(mem[arg1]));\n              _cimg_mp_scalar1(mp_log,arg1);\n            }\n\n            if (!std::strncmp(ss,\"log2(\",5)) { // Base-2 logarithm\n              _cimg_mp_op(\"Function 'log2()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log2,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::log2(mem[arg1]));\n              _cimg_mp_scalar1(mp_log2,arg1);\n            }\n\n            if (!std::strncmp(ss,\"log10(\",6)) { // Base-10 logarithm\n              _cimg_mp_op(\"Function 'log10()'\");\n              arg1 = compile(ss6,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log10,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log10(mem[arg1]));\n              _cimg_mp_scalar1(mp_log10,arg1);\n            }\n            break;\n\n          case 'm' :\n            if (!std::strncmp(ss,\"mul(\",4)) { // Matrix multiplication\n              _cimg_mp_op(\"Function 'mul()'\");\n              s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss4,s1,depth1,0);\n              s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n              arg2 = compile(++s1,s2,depth1,0);\n              arg3 = s2<se1?compile(++s2,se1,depth1,0):1;\n              _cimg_mp_check_type(arg1,1,2,0);\n              _cimg_mp_check_type(arg2,2,2,0);\n              _cimg_mp_check_constant(arg3,3,true);\n              p1 = _cimg_mp_vector_size(arg1);\n              p2 = _cimg_mp_vector_size(arg2);\n              p3 = (unsigned int)mem[arg3];\n              arg5 = p2/p3;\n              arg4 = p1/arg5;\n              if (arg4*arg5!=p1 || arg5*p3!=p2) {\n                *se = saved_char; cimg::strellipsize(expr,64);\n                throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                            \"CImg<%s>::%s: %s: Types of first and second arguments ('%s' and '%s') \"\n                                            \"do not match for third argument 'nb_colsB=%u', \"\n                                            \"in expression '%s%s%s'.\",\n                                            pixel_type(),_cimg_mp_calling_function,s_op,\n                                            s_type(arg1)._data,s_type(arg2)._data,p3,\n                                            (ss - 4)>expr._data?\"...\":\"\",\n                                            (ss - 4)>expr._data?ss - 4:expr._data,\n                                            se<&expr.back()?\"...\":\"\");\n              }\n              pos = vector(arg4*p3);\n              CImg<ulongT>::vector((ulongT)mp_matrix_mul,pos,arg1,arg2,arg4,arg5,p3).move_to(code);\n              _cimg_mp_return(pos);\n            }\n            break;\n\n          case 'n' :\n            if (!std::strncmp(ss,\"narg(\",5)) { // Number of arguments\n              _cimg_mp_op(\"Function 'narg()'\");\n              if (ss5>=se1) _cimg_mp_return(0);\n              arg1 = 0;\n              for (s = ss5; s<se; ++s) {\n                ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&\n                               (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;\n                ++arg1; s = ns;\n              }\n              _cimg_mp_constant(arg1);\n            }\n\n            if ((cimg_sscanf(ss,\"norm%u%c\",&(arg1=~0U),&sep)==2 && sep=='(') ||\n                !std::strncmp(ss,\"norminf(\",8)) { // Lp norm\n              _cimg_mp_op(\"Function 'normP()'\");\n              pos = scalar();\n              switch (arg1) {\n              case 0 : CImg<ulongT>::vector((ulongT)mp_norm0,pos).move_to(_opcode); break;\n              case 1 : CImg<ulongT>::vector((ulongT)mp_norm1,pos).move_to(_opcode); break;\n              case 2 : CImg<ulongT>::vector((ulongT)mp_norm2,pos).move_to(_opcode); break;\n              case ~0U : CImg<ulongT>::vector((ulongT)mp_norminf,pos).move_to(_opcode); break;\n              default :\n                CImg<ulongT>::vector((ulongT)mp_normp,pos,(ulongT)(arg1==~0U?-1:(int)arg1)).\n                  move_to(_opcode);\n              }\n              for (s = std::strchr(ss5,'(') + 1; s<se; ++s) {\n                ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&\n                               (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;\n                arg2 = compile(s,ns,depth1,0);\n                if (_cimg_mp_is_vector(arg2))\n                  CImg<ulongT>::sequence((ulongT)_cimg_mp_vector_size(arg2),arg2 + 1,\n                                        arg2 + (ulongT)_cimg_mp_vector_size(arg2)).\n                    move_to(_opcode);\n                else CImg<ulongT>::vector(arg2).move_to(_opcode);\n                s = ns;\n              }\n              (_opcode>'y').move_to(code);\n              _cimg_mp_return(pos);\n            }\n            break;\n\n          case 'p' :\n            if (!std::strncmp(ss,\"print(\",6)) { // Print expression\n              _cimg_mp_op(\"Function 'print()'\");\n              pos = compile(ss6,se1,depth1,p_ref);\n              *se1 = 0;\n              if (_cimg_mp_is_vector(pos)) // Vector\n                ((CImg<ulongT>::vector((ulongT)mp_vector_print,pos,(ulongT)_cimg_mp_vector_size(pos)),\n                  CImg<ulongT>::string(ss6).unroll('y'))>'y').move_to(code);\n              else // Scalar\n                ((CImg<ulongT>::vector((ulongT)mp_print,pos),\n                  CImg<ulongT>::string(ss6).unroll('y'))>'y').move_to(code);\n              *se1 = ')';\n              _cimg_mp_return(pos);\n            }\n            break;\n\n          case 'r' :\n            if (!std::strncmp(ss,\"rol(\",4) || !std::strncmp(ss,\"ror(\",4)) { // Bitwise rotation\n              _cimg_mp_op(ss[2]=='l'?\"Function 'rol()'\":\"Function 'ror()'\");\n              s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss4,s1,depth1,0);\n              arg2 = s1<se1?compile(++s1,se1,depth1,0):1;\n              _cimg_mp_check_type(arg2,2,1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(*ss2=='l'?mp_rol:mp_ror,arg1,arg2);\n              if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))\n                _cimg_mp_constant(*ss2=='l'?cimg::rol(mem[arg1],(unsigned int)mem[arg2]):\n                                  cimg::ror(mem[arg1],(unsigned int)mem[arg2]));\n              _cimg_mp_scalar2(*ss2=='l'?mp_rol:mp_ror,arg1,arg2);\n            }\n\n            if (!std::strncmp(ss,\"rot(\",4)) { // 2d/3d rotation matrix\n              _cimg_mp_op(\"Function 'rot()'\");\n              s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss4,s1,depth1,0);\n              if (s1<se1) { // 3d rotation\n                _cimg_mp_check_type(arg1,1,3,3);\n                is_sth = false; // Is coordinates as vector?\n                if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector\n                  is_sth = true;\n                  p2 = _cimg_mp_vector_size(arg1);\n                  ++arg1;\n                  arg2 = arg3 = 0;\n                  if (p2>1) {\n                    arg2 = arg1 + 1;\n                    if (p2>2) arg3 = arg2 + 1;\n                  }\n                  arg4 = compile(++s1,se1,depth1,0);\n                } else {\n                  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n                  arg2 = compile(++s1,s2,depth1,0);\n                  s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;\n                  arg3 = compile(++s2,s3,depth1,0);\n                  arg4 = compile(++s3,se1,depth1,0);\n                  _cimg_mp_check_type(arg2,2,1,0);\n                  _cimg_mp_check_type(arg3,3,1,0);\n                }\n                _cimg_mp_check_type(arg4,is_sth?2:4,1,0);\n                pos = vector(9);\n                CImg<ulongT>::vector((ulongT)mp_rot3d,pos,arg1,arg2,arg3,arg4).move_to(code);\n              } else { // 2d rotation\n                _cimg_mp_check_type(arg1,1,1,0);\n                pos = vector(4);\n                CImg<ulongT>::vector((ulongT)mp_rot2d,pos,arg1).move_to(code);\n              }\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"round(\",6)) { // Value rounding\n              _cimg_mp_op(\"Function 'round()'\");\n              s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss6,s1,depth1,0);\n              arg2 = 1;\n              arg3 = 0;\n              if (s1<se1) {\n                s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n                arg2 = compile(++s1,s2,depth1,0);\n                arg3 = s2<se1?compile(++s2,se1,depth1,0):0;\n              }\n              _cimg_mp_check_type(arg2,2,1,0);\n              _cimg_mp_check_type(arg3,3,1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_round,arg1,arg2,arg3);\n              if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3))\n                _cimg_mp_constant(cimg::round(mem[arg1],mem[arg2],(int)mem[arg3]));\n              _cimg_mp_scalar3(mp_round,arg1,arg2,arg3);\n            }\n            break;\n\n          case 's' :\n            if (!std::strncmp(ss,\"sign(\",5)) { // Sign\n              _cimg_mp_op(\"Function 'sign()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sign,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sign(mem[arg1]));\n              _cimg_mp_scalar1(mp_sign,arg1);\n            }\n\n            if (!std::strncmp(ss,\"sin(\",4)) { // Sine\n              _cimg_mp_op(\"Function 'sin()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sin,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sin(mem[arg1]));\n              _cimg_mp_scalar1(mp_sin,arg1);\n            }\n\n            if (!std::strncmp(ss,\"sinc(\",5)) { // Sine cardinal\n              _cimg_mp_op(\"Function 'sinc()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinc,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sinc(mem[arg1]));\n              _cimg_mp_scalar1(mp_sinc,arg1);\n            }\n\n            if (!std::strncmp(ss,\"single(\",7)) { // Force single thread execution\n              _cimg_mp_op(\"Function 'single()'\");\n              p1 = code._width;\n              arg1 = compile(ss7,se1,depth1,p_ref);\n              CImg<ulongT>::vector((ulongT)mp_single,arg1,code._width - p1).move_to(code,p1);\n              _cimg_mp_return(arg1);\n            }\n\n            if (!std::strncmp(ss,\"sinh(\",5)) { // Hyperbolic sine\n              _cimg_mp_op(\"Function 'sinh()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinh,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sinh(mem[arg1]));\n              _cimg_mp_scalar1(mp_sinh,arg1);\n            }\n\n            if (!std::strncmp(ss,\"size(\",5)) { // Vector size.\n              _cimg_mp_op(\"Function 'size()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              _cimg_mp_constant(_cimg_mp_is_scalar(arg1)?0:_cimg_mp_vector_size(arg1));\n            }\n\n            if (!std::strncmp(ss,\"solve(\",6)) { // Solve linear system\n              _cimg_mp_op(\"Function 'solve()'\");\n              s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss6,s1,depth1,0);\n              s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;\n              arg2 = compile(++s1,s2,depth1,0);\n              arg3 = s2<se1?compile(++s2,se1,depth1,0):1;\n              _cimg_mp_check_type(arg1,1,2,0);\n              _cimg_mp_check_type(arg2,2,2,0);\n              _cimg_mp_check_constant(arg3,3,true);\n              p1 = _cimg_mp_vector_size(arg1);\n              p2 = _cimg_mp_vector_size(arg2);\n              p3 = (unsigned int)mem[arg3];\n              arg5 = p2/p3;\n              arg4 = p1/arg5;\n              if (arg4*arg5!=p1 || arg5*p3!=p2) {\n                *se = saved_char; cimg::strellipsize(expr,64);\n                throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                            \"CImg<%s>::%s: %s: Types of first and second arguments ('%s' and '%s') \"\n                                            \"do not match for third argument 'nb_colsB=%u', \"\n                                            \"in expression '%s%s%s'.\",\n                                            pixel_type(),_cimg_mp_calling_function,s_op,\n                                            s_type(arg1)._data,s_type(arg2)._data,p3,\n                                            (ss - 4)>expr._data?\"...\":\"\",\n                                            (ss - 4)>expr._data?ss - 4:expr._data,\n                                            se<&expr.back()?\"...\":\"\");\n              }\n              pos = vector(arg4*p3);\n              CImg<ulongT>::vector((ulongT)mp_solve,pos,arg1,arg2,arg4,arg5,p3).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"sort(\",5)) { // Sort vector\n              _cimg_mp_op(\"Function 'sort()'\");\n              s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss5,s1,depth1,0);\n              arg2 = arg3 = 1;\n              if (s1<se1) {\n                s0 = ++s1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;\n                arg2 = compile(s1,s0,depth1,0);\n                arg3 = s0<se1?compile(++s0,se1,depth1,0):1;\n              }\n              _cimg_mp_check_type(arg1,1,2,0);\n              _cimg_mp_check_type(arg2,2,1,0);\n              _cimg_mp_check_constant(arg3,3,true);\n              arg3 = (unsigned int)mem[arg3];\n              p1 = _cimg_mp_vector_size(arg1);\n              if (p1%arg3) {\n                *se = saved_char; cimg::strellipsize(expr,64);\n                throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                            \"CImg<%s>::%s: %s: Invalid specified chunk size (%u) for first argument \"\n                                            \"('%s'), in expression '%s%s%s'.\",\n                                            pixel_type(),_cimg_mp_calling_function,s_op,\n                                            arg3,s_type(arg1)._data,\n                                            (ss - 4)>expr._data?\"...\":\"\",\n                                            (ss - 4)>expr._data?ss - 4:expr._data,\n                                            se<&expr.back()?\"...\":\"\");\n              }\n              pos = vector(p1);\n              CImg<ulongT>::vector((ulongT)mp_sort,pos,arg1,p1,arg2,arg3).move_to(code);\n              _cimg_mp_return(pos);\n            }\n\n            if (!std::strncmp(ss,\"sqr(\",4)) { // Square\n              _cimg_mp_op(\"Function 'sqr()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqr,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sqr(mem[arg1]));\n              _cimg_mp_scalar1(mp_sqr,arg1);\n            }\n\n            if (!std::strncmp(ss,\"sqrt(\",5)) { // Square root\n              _cimg_mp_op(\"Function 'sqrt()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqrt,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sqrt(mem[arg1]));\n              _cimg_mp_scalar1(mp_sqrt,arg1);\n            }\n            break;\n\n          case 't' :\n            if (!std::strncmp(ss,\"tan(\",4)) { // Tangent\n              _cimg_mp_op(\"Function 'tan()'\");\n              arg1 = compile(ss4,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tan,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tan(mem[arg1]));\n              _cimg_mp_scalar1(mp_tan,arg1);\n            }\n\n            if (!std::strncmp(ss,\"tanh(\",5)) { // Hyperbolic tangent\n              _cimg_mp_op(\"Function 'tanh()'\");\n              arg1 = compile(ss5,se1,depth1,0);\n              if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tanh,arg1);\n              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tanh(mem[arg1]));\n              _cimg_mp_scalar1(mp_tanh,arg1);\n            }\n\n            if (!std::strncmp(ss,\"trace(\",6)) { // Matrix trace\n              _cimg_mp_op(\"Function 'trace()'\");\n              arg1 = compile(ss6,se1,depth1,0);\n              _cimg_mp_check_matrix_square(arg1,1);\n              p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));\n              _cimg_mp_scalar2(mp_trace,arg1,p1);\n            }\n\n            if (!std::strncmp(ss,\"transp(\",7)) { // Matrix transpose\n              _cimg_mp_op(\"Function 'transp()'\");\n              s1 = ss7; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss7,s1,depth1,0);\n              arg2 = compile(++s1,se1,depth1,0);\n              _cimg_mp_check_type(arg1,1,2,0);\n              _cimg_mp_check_constant(arg2,2,true);\n              p1 = _cimg_mp_vector_size(arg1);\n              p2 = (unsigned int)mem[arg2];\n              p3 = p1/p2;\n              if (p2*p3!=p1) {\n                *se = saved_char; cimg::strellipsize(expr,64);\n                throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                            \"CImg<%s>::%s: %s: Size of first argument ('%s') does not match\"\n                                            \"for second specified argument 'nb_cols=%u', \"\n                                            \"in expression '%s%s%s'.\",\n                                            pixel_type(),_cimg_mp_calling_function,s_op,\n                                            s_type(arg1)._data,p2,\n                                            (ss - 4)>expr._data?\"...\":\"\",\n                                            (ss - 4)>expr._data?ss - 4:expr._data,\n                                            se<&expr.back()?\"...\":\"\");\n              }\n              pos = vector(p3*p2);\n              CImg<ulongT>::vector((ulongT)mp_transp,pos,arg1,p2,p3).move_to(code);\n              _cimg_mp_return(pos);\n            }\n            break;\n\n          case 'u' :\n            if (*ss1=='(') { // Random value with uniform distribution\n              _cimg_mp_op(\"Function 'u()'\");\n              if (*ss2==')') _cimg_mp_scalar2(mp_u,0,1);\n              s1 = ss2; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              arg1 = compile(ss2,s1,depth1,0);\n              if (s1<se1) arg2 = compile(++s1,se1,depth1,0); else { arg2 = arg1; arg1 = 0; }\n              _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));\n              if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_u,arg1,arg2);\n              if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_u,arg1,arg2);\n              if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_u,arg1,arg2);\n              _cimg_mp_scalar2(mp_u,arg1,arg2);\n            }\n            break;\n\n          case 'v' :\n            if ((cimg_sscanf(ss,\"vector%u%c\",&(arg1=~0U),&sep)==2 && sep=='(' && arg1>0) ||\n                !std::strncmp(ss,\"vector(\",7)) { // Vector\n              _cimg_mp_op(\"Function 'vector()'\");\n              arg2 = 0; // Number of specified values.\n              s = std::strchr(ss6,'(') + 1;\n              if (s<se1 || arg1==~0U) for (; s<se; ++s) {\n                  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&\n                                 (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;\n                  arg3 = compile(s,ns,depth1,0);\n                  if (_cimg_mp_is_vector(arg3)) {\n                    arg4 = _cimg_mp_vector_size(arg3);\n                    CImg<ulongT>::sequence(arg4,arg3 + 1,arg3 + arg4).move_to(_opcode);\n                    arg2+=arg4;\n                  } else { CImg<ulongT>::vector(arg3).move_to(_opcode); ++arg2; }\n                  s = ns;\n                }\n              if (arg1==~0U) arg1 = arg2;\n              _cimg_mp_check_vector0(arg1);\n              pos = vector(arg1);\n              _opcode.insert(CImg<ulongT>::vector((ulongT)mp_vector_init,pos,arg1),0);\n              (_opcode>'y').move_to(code);\n              _cimg_mp_return(pos);\n            }\n            break;\n\n          case 'w' :\n            if (!std::strncmp(ss,\"whiledo\",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // While...do\n              _cimg_mp_op(\"Function 'whiledo()'\");\n              if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace\n              s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;\n              p1 = code._width;\n              arg1 = compile(ss8,s1,depth1,0);\n              p2 = code._width;\n              pos = compile(++s1,se1,depth1,0);\n              _cimg_mp_check_type(arg1,1,1,0);\n              arg2 = _cimg_mp_is_vector(pos)?_cimg_mp_vector_size(pos):0; // Output vector size (or 0 if scalar)\n              CImg<ulongT>::vector((ulongT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1);\n              _cimg_mp_return(pos);\n            }\n            break;\n          }\n\n          if (!std::strncmp(ss,\"min(\",4) || !std::strncmp(ss,\"max(\",4) ||\n              !std::strncmp(ss,\"med(\",4) || !std::strncmp(ss,\"kth(\",4) ||\n              !std::strncmp(ss,\"arg(\",4) || !std::strncmp(ss,\"sum(\",4) ||\n              !std::strncmp(ss,\"std(\",4) || !std::strncmp(ss,\"var(\",4) ||\n              !std::strncmp(ss,\"prod(\",5) || !std::strncmp(ss,\"mean(\",5) ||\n              !std::strncmp(ss,\"argmin(\",7) || !std::strncmp(ss,\"argmax(\",7)) { // Multi-argument functions\n            _cimg_mp_op(*ss=='a'?(ss[3]=='('?\"Function 'arg()'\":ss[4]=='i'?\"Function 'argmin()'\":\n                                  \"Function 'argmax()'\"):\n                        *ss=='s'?(ss[1]=='u'?\"Function 'sum()'\":\"Function 'std()'\"):\n                        *ss=='k'?\"Function 'kth()'\":\n                        *ss=='p'?\"Function 'prod()'\":\n                        *ss=='v'?\"Function 'var()'\":\n                        ss[1]=='i'?\"Function 'min()'\":\n                        ss[1]=='a'?\"Function 'max()'\":\n                        ss[2]=='a'?\"Function 'mean()'\":\"Function 'med()'\");\n            pos = scalar();\n            CImg<ulongT>::vector((ulongT)(*ss=='a'?(ss[3]=='('?mp_arg:ss[4]=='i'?mp_argmin:mp_argmax):\n                                        *ss=='s'?(ss[1]=='u'?mp_sum:mp_std):\n                                        *ss=='k'?mp_kth:\n                                        *ss=='p'?mp_prod:\n                                        *ss=='v'?mp_var:\n                                        ss[1]=='i'?mp_min:\n                                        ss[1]=='a'?mp_max:\n                                        ss[2]=='a'?mp_mean:\n                                        mp_med),pos).\n              move_to(_opcode);\n            for (s = std::strchr(ss,'(') + 1; s<se; ++s) {\n              ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&\n                             (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;\n              arg2 = compile(s,ns,depth1,0);\n              if (_cimg_mp_is_vector(arg2))\n                CImg<ulongT>::sequence((ulongT)_cimg_mp_vector_size(arg2),arg2 + 1,\n                                      arg2 + (ulongT)_cimg_mp_vector_size(arg2)).\n                  move_to(_opcode);\n              else CImg<ulongT>::vector(arg2).move_to(_opcode);\n              s = ns;\n            }\n            (_opcode>'y').move_to(code);\n            _cimg_mp_return(pos);\n          }\n\n          // No corresponding built-in function -> Look for a user-defined macro.\n          s0 = strchr(ss,'(');\n          if (s0) {\n            variable_name.assign(ss,s0 - ss + 1).back() = 0;\n            cimglist_for(function_def,l) if (!std::strcmp(function_def[l],variable_name)) {\n              p2 = (unsigned int)function_def[l].back(); // Number of required arguments\n              CImg<charT> _expr = function_body[l]; // Expression to be substituted\n              p1 = 1; // Indice of current parsed argument\n              for (s = s0 + 1; s<=se1; ++p1, s = ns + 1) { // Parse function arguments\n                while (*s && *s<=' ') ++s;\n                if (*s==')' && p1==1) break; // Function has no arguments\n                if (p1>p2) { ++p1; break; }\n                ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&\n                               (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;\n\n                variable_name.assign(s,ns - s + 1).back() = 0; // Argument to write\n\n                cimg_forX(_expr,k) if (_expr[k]==(char)p1) { // Perform argument substitution\n                  _expr.resize(_expr._width + variable_name._width,1,1,1,0);\n                  _expr[k++] = '(';\n                  std::memmove(_expr._data + k + variable_name._width,_expr._data + k,\n                               _expr._width - variable_name._width - k);\n                  std::memcpy(_expr._data + k,variable_name,variable_name._width - 1);\n                  k+=variable_name._width - 1;\n                  _expr[k++] = ')';\n                }\n                *ns = 0;\n              }\n\n              if (p1!=p2+1) { // Number of specified argument do not fit\n                *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);\n                throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                            \"CImg<%s>::%s: Function '%s()': Number of specified arguments does not \"\n                                            \"match function declaration (%u argument%s required), \"\n                                            \"in expression '%s%s%s'.\",\n                                            pixel_type(),_cimg_mp_calling_function,variable_name._data,\n                                            p2,p2!=1?\"s\":\"\",\n                                            (ss - 4)>expr._data?\"...\":\"\",\n                                            (ss - 4)>expr._data?ss - 4:expr._data,\n                                            se<&expr.back()?\"...\":\"\");\n              }\n\n              // Recompute 'pexpr' and 'level' for evaluating substituted expression.\n              CImg<charT> _pexpr(_expr._width);\n              ns = _pexpr._data;\n              for (ps = _expr._data, c1 = ' '; *ps; ++ps) {\n                if (*ps!=' ') c1 = *ps;\n                *(ns++) = c1;\n              }\n              *ns = 0;\n\n              CImg<uintT> _level(_expr._width - 1);\n              unsigned int *pd = _level._data;\n              nb = 0;\n              for (ps = _expr._data; *ps && nb>=0; ++ps)\n                *(pd++) = (unsigned int)(*ps=='('||*ps=='['?nb++:*ps==')'||*ps==']'?--nb:nb);\n\n              expr.swap(_expr); pexpr.swap(_pexpr); level.swap(_level);\n              s0 = user_function;\n              user_function = function_def[l];\n              pos = compile(expr._data,expr._data + expr._width - 1,depth1,p_ref);\n              user_function = s0;\n              expr.swap(_expr); pexpr.swap(_pexpr); level.swap(_level);\n              _cimg_mp_return(pos);\n            }\n          }\n        } // if (se1==')')\n\n        // Vector specification using initializer '[ ... ]'.\n        if (*ss=='[' && *se1==']') {\n          _cimg_mp_op(\"Operator '[]'\");\n          arg1 = 0; // Number of specified values.\n          if (*ss1!=']') for (s = ss1; s<se; ++s) {\n              ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&\n                             (*ns!=']' || level[ns - expr._data]!=clevel)) ++ns;\n              arg2 = compile(s,ns,depth1,0);\n              if (_cimg_mp_is_vector(arg2)) {\n                arg3 = _cimg_mp_vector_size(arg2);\n                CImg<ulongT>::sequence(arg3,arg2 + 1,arg2 + arg3).move_to(_opcode);\n                arg1+=arg3;\n              } else { CImg<ulongT>::vector(arg2).move_to(_opcode); ++arg1; }\n              s = ns;\n            }\n          _cimg_mp_check_vector0(arg1);\n          pos = vector(arg1);\n          _opcode.insert(CImg<ulongT>::vector((ulongT)mp_vector_init,pos,arg1),0);\n          (_opcode>'y').move_to(code);\n          _cimg_mp_return(pos);\n        }\n\n        // Variables related to the input list of images.\n        if (*ss1=='#' && ss2<se) {\n          arg1 = compile(ss2,se,depth1,0);\n          p1 = (unsigned int)(listin._width && _cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0);\n          switch (*ss) {\n          case 'w' : // w#ind\n            if (!listin) _cimg_mp_return(0);\n            if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width);\n            _cimg_mp_scalar1(mp_list_width,arg1);\n          case 'h' : // h#ind\n            if (!listin) _cimg_mp_return(0);\n            if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._height);\n            _cimg_mp_scalar1(mp_list_height,arg1);\n          case 'd' : // d#ind\n            if (!listin) _cimg_mp_return(0);\n            if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._depth);\n            _cimg_mp_scalar1(mp_list_depth,arg1);\n          case 'r' : // r#ind\n            if (!listin) _cimg_mp_return(0);\n            if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._is_shared);\n            _cimg_mp_scalar1(mp_list_is_shared,arg1);\n          case 's' : // s#ind\n            if (!listin) _cimg_mp_return(0);\n            if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._spectrum);\n            _cimg_mp_scalar1(mp_list_spectrum,arg1);\n          case 'i' : // i#ind\n            if (!listin) _cimg_mp_return(0);\n            _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,_cimg_mp_c,\n                             reserved_label[29],reserved_label[30]);\n          case 'R' : // R#ind\n            if (!listin) _cimg_mp_return(0);\n            _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,0,\n                             reserved_label[29],reserved_label[30]);\n          case 'G' : // G#ind\n            if (!listin) _cimg_mp_return(0);\n            _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,1,\n                             reserved_label[29],reserved_label[30]);\n          case 'B' : // B#ind\n            if (!listin) _cimg_mp_return(0);\n            _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,2,\n                             reserved_label[29],reserved_label[30]);\n          case 'A' : // A#ind\n            if (!listin) _cimg_mp_return(0);\n            _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,3,\n                             reserved_label[29],reserved_label[30]);\n          }\n        }\n\n        if (*ss1 && *ss2=='#' && ss3<se) {\n          arg1 = compile(ss3,se,depth1,0);\n          p1 = (unsigned int)(listin._width && _cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0);\n          if (*ss=='w' && *ss1=='h') { // wh#ind\n            if (!listin) _cimg_mp_return(0);\n            if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width*listin[p1]._height);\n            _cimg_mp_scalar1(mp_list_wh,arg1);\n          }\n          arg2 = ~0U;\n\n          if (*ss=='i') {\n            if (*ss1=='c') { // ic#ind\n              if (!listin) _cimg_mp_return(0);\n              if (_cimg_mp_is_constant(arg1)) {\n                if (!list_median) list_median.assign(listin._width);\n                if (!list_median[p1]) CImg<doubleT>::vector(listin[p1].median()).move_to(list_median[p1]);\n                _cimg_mp_constant(*list_median[p1]);\n              }\n              _cimg_mp_scalar1(mp_list_median,arg1);\n            }\n            if (*ss1>='0' && *ss1<='9') { // i0#ind...i9#ind\n              if (!listin) _cimg_mp_return(0);\n              _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,*ss1 - '0',\n                               reserved_label[29],reserved_label[30]);\n            }\n            switch (*ss1) {\n            case 'm' : arg2 = 0; break; // im#ind\n            case 'M' : arg2 = 1; break; // iM#ind\n            case 'a' : arg2 = 2; break; // ia#ind\n            case 'v' : arg2 = 3; break; // iv#ind\n            case 's' : arg2 = 12; break; // is#ind\n            case 'p' : arg2 = 13; break; // ip#ind\n            }\n          } else if (*ss1=='m') switch (*ss) {\n            case 'x' : arg2 = 4; break; // xm#ind\n            case 'y' : arg2 = 5; break; // ym#ind\n            case 'z' : arg2 = 6; break; // zm#ind\n            case 'c' : arg2 = 7; break; // cm#ind\n            } else if (*ss1=='M') switch (*ss) {\n            case 'x' : arg2 = 8; break; // xM#ind\n            case 'y' : arg2 = 9; break; // yM#ind\n            case 'z' : arg2 = 10; break; // zM#ind\n            case 'c' : arg2 = 11; break; // cM#ind\n            }\n          if (arg2!=~0U) {\n            if (!listin) _cimg_mp_return(0);\n            if (_cimg_mp_is_constant(arg1)) {\n              if (!list_stats) list_stats.assign(listin._width);\n              if (!list_stats[p1]) list_stats[p1].assign(1,14,1,1,0).fill(listin[p1].get_stats(),false);\n              _cimg_mp_constant(list_stats(p1,arg2));\n            }\n            _cimg_mp_scalar2(mp_list_stats,arg1,arg2);\n          }\n        }\n\n        if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='#' && ss4<se) { // whd#ind\n          arg1 = compile(ss4,se,depth1,0);\n          if (!listin) _cimg_mp_return(0);\n          p1 = (unsigned int)(_cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0);\n          if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width*listin[p1]._height*listin[p1]._depth);\n          _cimg_mp_scalar1(mp_list_whd,arg1);\n        }\n        if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s' && *ss4=='#' && ss5<se) { // whds#ind\n          arg1 = compile(ss5,se,depth1,0);\n          if (!listin) _cimg_mp_return(0);\n          p1 = (unsigned int)(_cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0);\n          if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width*listin[p1]._height*listin[p1]._depth*\n                                                            listin[p1]._spectrum);\n          _cimg_mp_scalar1(mp_list_whds,arg1);\n        }\n\n        if (!std::strcmp(ss,\"interpolation\")) _cimg_mp_return(reserved_label[29]); // interpolation\n        if (!std::strcmp(ss,\"boundary\")) _cimg_mp_return(reserved_label[30]); // boundary\n\n        // No known item found, assuming this is an already initialized variable.\n        variable_name.assign(ss,(unsigned int)(se + 1 - ss)).back() = 0;\n        if (variable_name[1]) { // Multi-char variable\n          cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i]))\n            _cimg_mp_return(variable_pos[i]);\n        } else if (reserved_label[*variable_name]!=~0U) // Single-char variable\n          _cimg_mp_return(reserved_label[*variable_name]);\n\n        // Reached an unknown item -> error.\n        is_sth = true; // is_valid_variable_name\n        if (*variable_name>='0' && *variable_name<='9') is_sth = false;\n        else for (ns = variable_name._data; *ns; ++ns)\n               if (!is_varchar(*ns)) { is_sth = false; break; }\n\n        *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);\n        if (is_sth)\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s: Undefined variable '%s' in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,\n                                      variable_name._data,\n                                      (ss - 4)>expr._data?\"...\":\"\",\n                                      (ss - 4)>expr._data?ss - 4:expr._data,\n                                      se<&expr.back()?\"...\":\"\");\n        s0 = std::strchr(ss,'(');\n        if (s0 && *se1==')') s_op = \"function call\"; else s_op = \"item\";\n        throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                    \"CImg<%s>::%s: Unrecognized %s '%s' in expression '%s%s%s'.\",\n                                    pixel_type(),_cimg_mp_calling_function,\n                                    s_op,variable_name._data,\n                                    (ss - 4)>expr._data?\"...\":\"\",\n                                    (ss - 4)>expr._data?ss - 4:expr._data,\n                                    se<&expr.back()?\"...\":\"\");\n      }\n\n      // Evaluation procedure.\n      double operator()(const double x, const double y, const double z, const double c) {\n        mem[_cimg_mp_x] = x; mem[_cimg_mp_y] = y; mem[_cimg_mp_z] = z; mem[_cimg_mp_c] = c;\n        for (p_code = p_code_begin; p_code<p_code_end; ++p_code) {\n          const CImg<ulongT> &op = *p_code;\n          opcode._data = op._data; opcode._height = op._height;\n          const ulongT target = opcode[1];\n          mem[target] = _cimg_mp_defunc(*this);\n        }\n        return *result;\n      }\n\n      // Evaluation procedure (return output values in vector 'output').\n      template<typename t>\n      void operator()(const double x, const double y, const double z, const double c, t *const output) {\n        mem[_cimg_mp_x] = x; mem[_cimg_mp_y] = y; mem[_cimg_mp_z] = z; mem[_cimg_mp_c] = c;\n        for (p_code = p_code_begin; p_code<p_code_end; ++p_code) {\n          const CImg<ulongT> &op = *p_code;\n          opcode._data = op._data; opcode._height = op._height;\n          const ulongT target = opcode[1];\n          mem[target] = _cimg_mp_defunc(*this);\n        }\n        if (result_dim) {\n          const double *ptrs = result + 1;\n          t *ptrd = output;\n          for (unsigned int k = 0; k<result_dim; ++k) *(ptrd++) = (t)*(ptrs++);\n        } else *output = (t)*result;\n      }\n\n      // Return type of a memory element as a string.\n      CImg<charT> s_type(const unsigned int arg) const {\n        CImg<charT> res;\n        if (_cimg_mp_is_vector(arg)) { // Vector\n          CImg<charT>::string(\"vectorXXXXXXXXXXXXXXXX\").move_to(res);\n          std::sprintf(res._data + 6,\"%u\",_cimg_mp_vector_size(arg));\n        } else CImg<charT>::string(\"scalar\").move_to(res);\n        return res;\n      }\n\n      // Insert constant value in memory.\n      unsigned int constant(const double val) {\n        if (val==(double)(int)val) {\n          if (val>=0 && val<=9) return (unsigned int)val;\n          if (val<0 && val>=-5) return (unsigned int)(10 - val);\n        }\n        if (val==0.5) return 16;\n        if (cimg::type<double>::is_nan(val)) return 28;\n        if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(-200,1,1,1,0); }\n        const unsigned int pos = mempos++;\n        mem[pos] = val;\n        memtype[pos] = 1; // Set constant property\n        return pos;\n      }\n\n      // Insert code instructions for processing scalars.\n      unsigned int scalar() { // Insert new scalar in memory.\n        if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(mem._width,1,1,1,0); }\n        return mempos++;\n      }\n\n      unsigned int scalar0(const mp_func op) {\n        const unsigned int pos = scalar();\n        CImg<ulongT>::vector((ulongT)op,pos).move_to(code);\n        return pos;\n      }\n\n      unsigned int scalar1(const mp_func op, const unsigned int arg1) {\n        const unsigned int pos =\n          arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:scalar();\n        CImg<ulongT>::vector((ulongT)op,pos,arg1).move_to(code);\n        return pos;\n      }\n\n      unsigned int scalar2(const mp_func op, const unsigned int arg1, const unsigned int arg2) {\n        const unsigned int pos =\n          arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:\n          arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:scalar();\n        CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2).move_to(code);\n        return pos;\n      }\n\n      unsigned int scalar3(const mp_func op,\n                           const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) {\n        const unsigned int pos =\n          arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:\n          arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:\n          arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3:scalar();\n        CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3).move_to(code);\n        return pos;\n      }\n\n      unsigned int scalar6(const mp_func op,\n                           const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,\n                           const unsigned int arg4, const unsigned int arg5, const unsigned int arg6) {\n        const unsigned int pos =\n          arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:\n          arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:\n          arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3:\n          arg4>_cimg_mp_c && _cimg_mp_is_temp(arg4)?arg4:\n          arg5>_cimg_mp_c && _cimg_mp_is_temp(arg5)?arg5:\n          arg6>_cimg_mp_c && _cimg_mp_is_temp(arg6)?arg6:scalar();\n        CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code);\n        return pos;\n      }\n\n      unsigned int scalar7(const mp_func op,\n                           const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,\n                           const unsigned int arg4, const unsigned int arg5, const unsigned int arg6,\n                           const unsigned int arg7) {\n        const unsigned int pos =\n          arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:\n          arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:\n          arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3:\n          arg4>_cimg_mp_c && _cimg_mp_is_temp(arg4)?arg4:\n          arg5>_cimg_mp_c && _cimg_mp_is_temp(arg5)?arg5:\n          arg6>_cimg_mp_c && _cimg_mp_is_temp(arg6)?arg6:\n          arg7>_cimg_mp_c && _cimg_mp_is_temp(arg7)?arg7:scalar();\n        CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6,arg7).move_to(code);\n        return pos;\n      }\n\n      // Return a string that defines the calling function + the user-defined function scope.\n      CImg<charT> calling_function_s() const {\n        CImg<charT> res;\n        const unsigned int\n          l1 = calling_function?(unsigned int)std::strlen(calling_function):0U,\n          l2 = user_function?(unsigned int)std::strlen(user_function):0U;\n        if (l2) {\n          res.assign(l1 + l2 + 48);\n          cimg_snprintf(res,res._width,\"%s(): When substituting function '%s()'\",calling_function,user_function);\n        } else {\n          res.assign(l1 + l2 + 4);\n          cimg_snprintf(res,res._width,\"%s()\",calling_function);\n        }\n        return res;\n      }\n\n      // Return true if specified argument can be a part of an allowed  variable name.\n      bool is_varchar(const char c) const {\n        return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';\n      }\n\n      // Insert code instructions for processing vectors.\n      bool is_tmp_vector(const unsigned int arg) const {\n        unsigned int siz = _cimg_mp_vector_size(arg);\n        if (siz>8) return false;\n        const int *ptr = memtype.data(arg + 1);\n        bool is_tmp = true;\n        while (siz-->0) if (*(ptr++)) { is_tmp = false; break; }\n        return is_tmp;\n      }\n\n      void set_variable_vector(const unsigned int arg) {\n        unsigned int siz = _cimg_mp_vector_size(arg);\n        int *ptr = memtype.data(arg + 1);\n        while (siz-->0) *(ptr++) = -1;\n      }\n\n      unsigned int vector(const unsigned int siz) { // Insert new vector of specified size in memory\n        if (mempos + siz>=mem._width) {\n          mem.resize(2*mem._width + siz,1,1,1,0);\n          memtype.resize(mem._width,1,1,1,0);\n        }\n        const unsigned int pos = mempos++;\n        mem[pos] = cimg::type<double>::nan();\n        memtype[pos] = siz + 1;\n        mempos+=siz;\n        return pos;\n      }\n\n      unsigned int vector(const unsigned int siz, const double value) { // Insert new initialized vector\n        const unsigned int pos = vector(siz);\n        double *ptr = &mem[pos] + 1;\n        for (unsigned int i = 0; i<siz; ++i) *(ptr++) = value;\n        return pos;\n      }\n\n      unsigned int vector_copy(const unsigned int arg) { // Insert new copy of specified vector in memory\n        const unsigned int\n          siz = _cimg_mp_vector_size(arg),\n          pos = vector(siz);\n        CImg<ulongT>::vector((ulongT)mp_vector_copy,pos,arg,siz).move_to(code);\n        return pos;\n      }\n\n      void self_vector_s(const unsigned int pos, const mp_func op, const unsigned int arg1) {\n        const unsigned int siz = _cimg_mp_vector_size(pos);\n        if (siz>24) CImg<ulongT>::vector((ulongT)mp_self_map_vector_s,pos,siz,(ulongT)op,arg1).move_to(code);\n        else {\n          code.insert(siz);\n          for (unsigned int k = 1; k<=siz; ++k)\n            CImg<ulongT>::vector((ulongT)op,pos + k,arg1).move_to(code[code._width - 1 - siz + k]);\n        }\n      }\n\n      void self_vector_v(const unsigned int pos, const mp_func op, const unsigned int arg1) {\n        const unsigned int siz = _cimg_mp_vector_size(pos);\n        if (siz>24) CImg<ulongT>::vector((ulongT)mp_self_map_vector_v,pos,siz,(ulongT)op,arg1).move_to(code);\n        else {\n          code.insert(siz);\n          for (unsigned int k = 1; k<=siz; ++k)\n            CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]);\n        }\n      }\n\n      unsigned int vector1_v(const mp_func op, const unsigned int arg1) {\n        const unsigned int\n          siz = _cimg_mp_vector_size(arg1),\n          pos = is_tmp_vector(arg1)?arg1:vector(siz);\n        if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_v,pos,siz,(ulongT)op,arg1).move_to(code);\n        else {\n          code.insert(siz);\n          for (unsigned int k = 1; k<=siz; ++k)\n            CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]);\n        }\n        return pos;\n      }\n\n      unsigned int vector2_vv(const mp_func op, const unsigned int arg1, const unsigned int arg2) {\n        const unsigned int\n          siz = _cimg_mp_vector_size(arg1),\n          pos = is_tmp_vector(arg1)?arg1:is_tmp_vector(arg2)?arg2:vector(siz);\n        if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vv,pos,siz,(ulongT)op,arg1,arg2).move_to(code);\n        else {\n          code.insert(siz);\n          for (unsigned int k = 1; k<=siz; ++k)\n            CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k,arg2 + k).move_to(code[code._width - 1 - siz + k]);\n        }\n        return pos;\n      }\n\n      unsigned int vector2_vs(const mp_func op, const unsigned int arg1, const unsigned int arg2) {\n        const unsigned int\n          siz = _cimg_mp_vector_size(arg1),\n          pos = is_tmp_vector(arg1)?arg1:vector(siz);\n        if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vs,pos,siz,(ulongT)op,arg1,arg2).move_to(code);\n        else {\n          code.insert(siz);\n          for (unsigned int k = 1; k<=siz; ++k)\n            CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k,arg2).move_to(code[code._width - 1 - siz + k]);\n        }\n        return pos;\n      }\n\n      unsigned int vector2_sv(const mp_func op, const unsigned int arg1, const unsigned int arg2) {\n        const unsigned int\n          siz = _cimg_mp_vector_size(arg2),\n          pos = is_tmp_vector(arg2)?arg2:vector(siz);\n        if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_sv,pos,siz,(ulongT)op,arg1,arg2).move_to(code);\n        else {\n          code.insert(siz);\n          for (unsigned int k = 1; k<=siz; ++k)\n            CImg<ulongT>::vector((ulongT)op,pos + k,arg1,arg2 + k).move_to(code[code._width - 1 - siz + k]);\n        }\n        return pos;\n      }\n\n      unsigned int vector3_vss(const mp_func op, const unsigned int arg1, const unsigned int arg2,\n                               const unsigned int arg3) {\n        const unsigned int\n          siz = _cimg_mp_vector_size(arg1),\n          pos = is_tmp_vector(arg1)?arg1:vector(siz);\n        if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vss,pos,siz,(ulongT)op,arg1,arg2,arg3).move_to(code);\n        else {\n          code.insert(siz);\n          for (unsigned int k = 1; k<=siz; ++k)\n            CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k,arg2,arg3).move_to(code[code._width - 1 - siz + k]);\n        }\n        return pos;\n      }\n\n      // Check if a memory slot is a positive integer constant scalar value.\n      void check_constant(const unsigned int arg, const unsigned int n_arg,\n                          const bool is_strictly_positive,\n                          const char *const ss, char *const se, const char saved_char) {\n        _cimg_mp_check_type(arg,n_arg,1,0);\n        if (!_cimg_mp_is_constant(arg) || mem[arg]<(is_strictly_positive?1:0) || (double)(int)mem[arg]!=mem[arg]) {\n          const char *s_arg = !n_arg?\"\":n_arg==1?\"First \":n_arg==2?\"Second \":n_arg==3?\"Third \":\n            n_arg==4?\"Fourth \":n_arg==5?\"Fifth \":n_arg==6?\"Sixth \":n_arg==7?\"Seventh \":n_arg==8?\"Eighth \":\n            n_arg==9?\"Ninth \":\"One of the \";\n          *se = saved_char; cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s(): %s%s %s%s (of type '%s') is not a %spositive integer constant, \"\n                                      \"in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?\":\":\"\",\n                                      s_arg,*s_arg?\"argument\":\"Argument\",s_type(arg)._data,\n                                      is_strictly_positive?\"strictly \":\"\",\n                                      (ss - 4)>expr._data?\"...\":\"\",\n                                      (ss - 4)>expr._data?ss - 4:expr._data,\n                                      se<&expr.back()?\"...\":\"\");\n        }\n      }\n\n      // Check a matrix is square.\n      void check_matrix_square(const unsigned int arg, const unsigned int n_arg,\n                               const char *const ss, char *const se, const char saved_char) {\n        _cimg_mp_check_type(arg,n_arg,2,0);\n        const unsigned int\n          siz = _cimg_mp_vector_size(arg),\n          n = (unsigned int)std::sqrt((float)siz);\n        if (n*n!=siz) {\n          const char *s_arg;\n          if (*s_op!='F') s_arg = !n_arg?\"\":n_arg==1?\"Left-hand \":\"Right-hand \";\n          else s_arg = !n_arg?\"\":n_arg==1?\"First \":n_arg==2?\"Second \":n_arg==3?\"Third \":\"One \";\n          *se = saved_char; cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s(): %s%s %s%s (of type '%s') \"\n                                      \"cannot be considered as a square matrix, in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?\":\":\"\",\n                                      s_arg,*s_op=='F'?(*s_arg?\"argument\":\"Argument\"):(*s_arg?\"operand\":\"Operand\"),\n                                      s_type(arg)._data,\n                                      (ss - 4)>expr._data?\"...\":\"\",\n                                      (ss - 4)>expr._data?ss - 4:expr._data,\n                                      se<&expr.back()?\"...\":\"\");\n        }\n      }\n\n      // Check type compatibility for one argument.\n      // Bits of 'mode' tells what types are allowed:\n      // { 1 = scalar | 2 = vectorN }.\n      // If 'N' is not zero, it also restricts the vectors to be of size N only.\n      void check_type(const unsigned int arg, const unsigned int n_arg,\n                      const unsigned int mode, const unsigned int N,\n                      const char *const ss, char *const se, const char saved_char) {\n        const bool\n          is_scalar = _cimg_mp_is_scalar(arg),\n          is_vector = _cimg_mp_is_vector(arg) && (!N || _cimg_mp_vector_size(arg)==N);\n        bool cond = false;\n        if (mode&1) cond|=is_scalar;\n        if (mode&2) cond|=is_vector;\n        if (!cond) {\n          const char *s_arg;\n          if (*s_op!='F') s_arg = !n_arg?\"\":n_arg==1?\"Left-hand \":\"Right-hand \";\n          else s_arg = !n_arg?\"\":n_arg==1?\"First \":n_arg==2?\"Second \":n_arg==3?\"Third \":\n                 n_arg==4?\"Fourth \":n_arg==5?\"Fifth \":n_arg==6?\"Sixth \":n_arg==7?\"Seventh \":n_arg==8?\"Eighth\":\n                 n_arg==9?\"Ninth\":\"One of the \";\n          CImg<charT> sb_type(32);\n          if (mode==1) cimg_snprintf(sb_type,sb_type._width,\"'scalar'\");\n          else if (mode==2) {\n            if (N) cimg_snprintf(sb_type,sb_type._width,\"'vector%u'\",N);\n            else cimg_snprintf(sb_type,sb_type._width,\"'vector'\");\n          } else {\n            if (N) cimg_snprintf(sb_type,sb_type._width,\"'scalar' or 'vector%u'\",N);\n            else cimg_snprintf(sb_type,sb_type._width,\"'scalar' or 'vector'\");\n          }\n          *se = saved_char; cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s(): %s%s %s%s has invalid type '%s' (should be %s), \"\n                                      \"in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?\":\":\"\",\n                                      s_arg,*s_op=='F'?(*s_arg?\"argument\":\"Argument\"):(*s_arg?\"operand\":\"Operand\"),\n                                      s_type(arg)._data,sb_type._data,\n                                      (ss - 4)>expr._data?\"...\":\"\",\n                                      (ss - 4)>expr._data?ss - 4:expr._data,\n                                      se<&expr.back()?\"...\":\"\");\n        }\n      }\n\n      // Check is listin is not empty.\n      void check_list(const bool is_out,\n                      const char *const ss, char *const se, const char saved_char) {\n        if ((!is_out && !listin) || (is_out && !listout)) {\n          *se = saved_char; cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s(): %s%s Invalid call with an empty image list, \"\n                                      \"in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?\":\":\"\",\n                                      (ss - 4)>expr._data?\"...\":\"\",\n                                      (ss - 4)>expr._data?ss - 4:expr._data,\n                                      se<&expr.back()?\"...\":\"\");\n        }\n      }\n\n      // Check a vector is not 0-dimensional, or with unknown dimension at compile time.\n      void check_vector0(const unsigned int dim,\n                         const char *const ss, char *const se, const char saved_char) {\n        if (!dim) {\n          *se = saved_char; cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s(): %s%s Invalid construction of a 0-dimensional vector, \"\n                                      \"in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?\":\":\"\",\n                                      (ss - 4)>expr._data?\"...\":\"\",\n                                      (ss - 4)>expr._data?ss - 4:expr._data,\n                                      se<&expr.back()?\"...\":\"\");\n        } else if (dim==~0U) {\n          *se = saved_char; cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[_cimg_math_parser] \"\n                                      \"CImg<%s>::%s(): %s%s Invalid construction of a vector with dynamic size, \"\n                                      \"in expression '%s%s%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?\":\":\"\",\n                                      (ss - 4)>expr._data?\"...\":\"\",\n                                      (ss - 4)>expr._data?ss - 4:expr._data,\n                                      se<&expr.back()?\"...\":\"\");\n        }\n      }\n\n      // Evaluation functions, known by the parser.\n      // Defining these functions 'static' ensures that sizeof(mp_func)==sizeof(ulongT),\n      // so we can store pointers to them directly in the opcode vectors.\n#ifdef _mp_arg\n#undef _mp_arg\n#endif\n#define _mp_arg(x) mp.mem[mp.opcode[x]]\n\n      static double mp_abs(_cimg_math_parser& mp) {\n        return cimg::abs(_mp_arg(2));\n      }\n\n      static double mp_add(_cimg_math_parser& mp) {\n        return _mp_arg(2) + _mp_arg(3);\n      }\n\n      static double mp_acos(_cimg_math_parser& mp) {\n        return std::acos(_mp_arg(2));\n      }\n\n      static double mp_arg(_cimg_math_parser& mp) {\n        const int _ind = (int)_mp_arg(2);\n        const unsigned int nb_args = mp.opcode._height - 2, ind = _ind<0?_ind + nb_args:(unsigned int)_ind;\n        if (ind>=nb_args) return 0;\n        return _mp_arg(ind + 2);\n      }\n\n      static double mp_argmin(_cimg_math_parser& mp) {\n        double val = _mp_arg(2);\n        unsigned int argval = 0;\n        for (unsigned int i = 3; i<mp.opcode._height; ++i) {\n          const double _val = _mp_arg(i);\n          if (_val<val) { val = _val; argval = i - 2; }\n        }\n        return (double)argval;\n      }\n\n      static double mp_argmax(_cimg_math_parser& mp) {\n        double val = _mp_arg(2);\n        unsigned int argval = 0;\n        for (unsigned int i = 3; i<mp.opcode._height; ++i) {\n          const double _val = _mp_arg(i);\n          if (_val>val) { val = _val; argval = i - 2; }\n        }\n        return (double)argval;\n      }\n\n      static double mp_asin(_cimg_math_parser& mp) {\n        return std::asin(_mp_arg(2));\n      }\n\n      static double mp_atan(_cimg_math_parser& mp) {\n        return std::atan(_mp_arg(2));\n      }\n\n      static double mp_atan2(_cimg_math_parser& mp) {\n        return std::atan2(_mp_arg(2),_mp_arg(3));\n      }\n\n      static double mp_bitwise_and(_cimg_math_parser& mp) {\n        return (double)((ulongT)_mp_arg(2) & (ulongT)_mp_arg(3));\n      }\n\n      static double mp_bitwise_left_shift(_cimg_math_parser& mp) {\n        return (double)((longT)_mp_arg(2)<<(unsigned int)_mp_arg(3));\n      }\n\n      static double mp_bitwise_not(_cimg_math_parser& mp) {\n        return (double)~(ulongT)_mp_arg(2);\n      }\n\n      static double mp_bitwise_or(_cimg_math_parser& mp) {\n        return (double)((ulongT)_mp_arg(2) | (ulongT)_mp_arg(3));\n      }\n\n      static double mp_bitwise_right_shift(_cimg_math_parser& mp) {\n        return (double)((longT)_mp_arg(2)>>(unsigned int)_mp_arg(3));\n      }\n\n      static double mp_cbrt(_cimg_math_parser& mp) {\n        return std::pow(_mp_arg(2),1.0/3);\n      }\n\n      static double mp_complex_conj(_cimg_math_parser& mp) {\n        const double *ptrs = &_mp_arg(2) + 1;\n        double *ptrd = &_mp_arg(1) + 1;\n        *(ptrd++) = *(ptrs++);\n        *ptrd = -*(ptrs);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_complex_div_sv(_cimg_math_parser& mp) {\n        const double\n          *ptr2 = &_mp_arg(3) + 1,\n          r1 = _mp_arg(2),\n          r2 = *(ptr2++), i2 = *ptr2;\n        double *ptrd = &_mp_arg(1) + 1;\n        const double denom = r2*r2 + i2*i2;\n        *(ptrd++) = r1*r2/denom;\n        *ptrd =  -r1*i2/denom;\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_complex_div_vv(_cimg_math_parser& mp) {\n        const double\n          *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1,\n          r1 = *(ptr1++), i1 = *ptr1,\n          r2 = *(ptr2++), i2 = *ptr2;\n        double *ptrd = &_mp_arg(1) + 1;\n        const double denom = r2*r2 + i2*i2;\n        *(ptrd++) = (r1*r2 + i1*i2)/denom;\n        *ptrd = (r2*i1 - r1*i2)/denom;\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_complex_exp(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs), er = std::exp(r);\n        *(ptrd++) = er*std::cos(i);\n        *(ptrd++) = er*std::sin(i);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_complex_log(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs);\n        *(ptrd++) = std::log(std::sqrt(r*r + i*i));\n        *(ptrd++) = std::atan2(i,r);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_complex_mul(_cimg_math_parser& mp) {\n        const double\n          *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1,\n          r1 = *(ptr1++), i1 = *ptr1,\n          r2 = *(ptr2++), i2 = *ptr2;\n        double *ptrd = &_mp_arg(1) + 1;\n        *(ptrd++) = r1*r2 - i1*i2;\n        *(ptrd++) = r1*i2 + r2*i1;\n        return cimg::type<double>::nan();\n      }\n\n      static void _mp_complex_pow(const double r1, const double i1,\n                                  const double r2, const double i2,\n                                  double *ptrd) {\n        double ro, io;\n        if (cimg::abs(i2)<1e-15) { // Exponent is real\n          if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) {\n            if (cimg::abs(r2)<1e-15) { ro = 1; io = 0; }\n            else ro = io = 0;\n          } else {\n            const double\n              mod1_2 = r1*r1 + i1*i1,\n              phi1 = std::atan2(i1,r1),\n              modo = std::pow(mod1_2,0.5*r2),\n              phio = r2*phi1;\n            ro = modo*std::cos(phio);\n            io = modo*std::sin(phio);\n          }\n        } else { // Exponent is complex\n          if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) ro = io = 0;\n          const double\n            mod1_2 = r1*r1 + i1*i1,\n            phi1 = std::atan2(i1,r1),\n            modo = std::pow(mod1_2,0.5*r2)*std::exp(-i2*phi1),\n            phio = r2*phi1 + 0.5*i2*std::log(mod1_2);\n          ro = modo*std::cos(phio);\n          io = modo*std::sin(phio);\n        }\n        *(ptrd++) = ro;\n        *ptrd = io;\n      }\n\n      static double mp_complex_pow_sv(_cimg_math_parser& mp) {\n        const double val1 = _mp_arg(2), *ptr2 = &_mp_arg(3) + 1;\n        double *ptrd = &_mp_arg(1) + 1;\n        _mp_complex_pow(val1,0,ptr2[0],ptr2[1],ptrd);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_complex_pow_vs(_cimg_math_parser& mp) {\n        const double *ptr1 = &_mp_arg(2) + 1, val2 = _mp_arg(3);\n        double *ptrd = &_mp_arg(1) + 1;\n        _mp_complex_pow(ptr1[0],ptr1[1],val2,0,ptrd);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_complex_pow_vv(_cimg_math_parser& mp) {\n        const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1;\n        double *ptrd = &_mp_arg(1) + 1;\n        _mp_complex_pow(ptr1[0],ptr1[1],ptr2[0],ptr2[1],ptrd);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_cos(_cimg_math_parser& mp) {\n        return std::cos(_mp_arg(2));\n      }\n\n      static double mp_cosh(_cimg_math_parser& mp) {\n        return std::cosh(_mp_arg(2));\n      }\n\n      static double mp_crop(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6);\n        const unsigned int\n          dx = (unsigned int)mp.opcode[7],\n          dy = (unsigned int)mp.opcode[8],\n          dz = (unsigned int)mp.opcode[9],\n          dc = (unsigned int)mp.opcode[10];\n        const bool boundary_conditions = (bool)_mp_arg(11);\n        unsigned int ind = (unsigned int)mp.opcode[2];\n        if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        const CImg<T> &img = ind==~0U?mp.imgin:mp.listin[ind];\n        if (!img) std::memset(ptrd,0,dx*dy*dz*dc*sizeof(double));\n        else CImg<double>(ptrd,dx,dy,dz,dc,true) = img.get_crop(x,y,z,c,\n                                                                x + dx - 1,y + dy - 1,\n                                                                z + dz - 1,c + dc - 1,\n                                                                boundary_conditions);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_cross(_cimg_math_parser& mp) {\n        CImg<doubleT>\n          vout(&_mp_arg(1) + 1,1,3,1,1,true),\n          v1(&_mp_arg(2) + 1,1,3,1,1,true),\n          v2(&_mp_arg(3) + 1,1,3,1,1,true);\n        (vout = v1).cross(v2);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_cut(_cimg_math_parser& mp) {\n        double val = _mp_arg(2), cmin = _mp_arg(3), cmax = _mp_arg(4);\n        return val<cmin?cmin:val>cmax?cmax:val;\n      }\n\n      static double mp_debug(_cimg_math_parser& mp) {\n        CImg<charT> expr(mp.opcode._height - 3);\n        const ulongT *ptrs = mp.opcode._data + 3;\n        cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);\n        cimg::strellipsize(expr);\n        const ulongT g_target = mp.opcode[1];\n\n#ifndef cimg_use_openmp\n        const unsigned int n_thread = 0;\n#else\n        const unsigned int n_thread = omp_get_thread_num();\n#pragma omp critical\n#endif\n        {\n          std::fprintf(cimg::output(),\n                       \"\\n[_cimg_math_parser] %p[thread #%u]:%*c\"\n                       \"Start debugging expression '%s', code length %u -> mem[%u] (memsize: %u)\",\n                       (void*)&mp,n_thread,mp.debug_indent,' ',\n                       expr._data,(unsigned int)mp.opcode[2],(unsigned int)g_target,mp.mem._width);\n          std::fflush(cimg::output());\n          const CImg<ulongT> *const p_end = (++mp.p_code) + mp.opcode[2];\n          CImg<ulongT> _op;\n          mp.debug_indent+=3;\n          for ( ; mp.p_code<p_end; ++mp.p_code) {\n            const CImg<ulongT> &op = *mp.p_code;\n            mp.opcode._data = op._data; mp.opcode._height = op._height;\n\n            _op.assign(1,op._height - 1);\n            const ulongT *ptrs = op._data + 1;\n            for (ulongT *ptrd = _op._data, *const ptrde = _op._data + _op._height; ptrd<ptrde; ++ptrd)\n              *ptrd = *(ptrs++);\n\n            const ulongT target = mp.opcode[1];\n            mp.mem[target] = _cimg_mp_defunc(mp);\n            std::fprintf(cimg::output(),\n                         \"\\n[_cimg_math_parser] %p[thread #%u]:%*c\"\n                         \"Opcode %p = [ %p,%s ] -> mem[%u] = %g\",\n                         (void*)&mp,n_thread,mp.debug_indent,' ',\n                         (void*)mp.opcode._data,(void*)*mp.opcode,_op.value_string().data(),\n                         (unsigned int)target,mp.mem[target]);\n            std::fflush(cimg::output());\n          }\n          mp.debug_indent-=3;\n          std::fprintf(cimg::output(),\n                       \"\\n[_cimg_math_parser] %p[thread #%u]:%*c\"\n                       \"End debugging expression '%s' -> mem[%u] = %g (memsize: %u)\",\n                       (void*)&mp,n_thread,mp.debug_indent,' ',\n                       expr._data,(unsigned int)g_target,mp.mem[g_target],mp.mem._width);\n          std::fflush(cimg::output());\n          --mp.p_code;\n        }\n        return mp.mem[g_target];\n      }\n\n      static double mp_decrement(_cimg_math_parser& mp) {\n        return _mp_arg(2) - 1;\n      }\n\n      static double mp_det(_cimg_math_parser& mp) {\n        const double *ptrs = &_mp_arg(2) + 1;\n        const unsigned int k = (unsigned int)mp.opcode(3);\n        return CImg<double>(ptrs,k,k,1,1,true).det();\n      }\n\n      static double mp_diag(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const double *ptrs = &_mp_arg(2) + 1;\n        const unsigned int k = (unsigned int)mp.opcode(3);\n        CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptrs,1,k,1,1,true).get_diagonal();\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_div(_cimg_math_parser& mp) {\n        return _mp_arg(2)/_mp_arg(3);\n      }\n\n      static double mp_dot(_cimg_math_parser& mp) {\n        const unsigned int siz = (unsigned int)mp.opcode[4];\n        return CImg<doubleT>(&_mp_arg(2) + 1,1,siz,1,1,true).\n          dot(CImg<doubleT>(&_mp_arg(3) + 1,1,siz,1,1,true));\n      }\n\n      static double mp_dowhile(_cimg_math_parser& mp) {\n        const ulongT\n          mem_proc = mp.opcode[1],\n          mem_cond = mp.opcode[2];\n        const CImg<ulongT>\n          *const p_proc = ++mp.p_code,\n          *const p_end = p_proc + mp.opcode[3];\n        do {\n          for (mp.p_code = p_proc; mp.p_code<p_end; ++mp.p_code) { // Evaluate loop iteration + condition\n            const CImg<ulongT> &op = *mp.p_code;\n            mp.opcode._data = op._data; mp.opcode._height = op._height;\n            const ulongT target = mp.opcode[1];\n            mp.mem[target] = _cimg_mp_defunc(mp);\n          }\n        } while (mp.mem[mem_cond]);\n        --mp.p_code;\n        return mp.mem[mem_proc];\n      }\n\n      static double mp_draw(_cimg_math_parser& mp) {\n        const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6);\n        const unsigned int\n          dx = (unsigned int)mp.opcode[7],\n          dy = (unsigned int)mp.opcode[8],\n          dz = (unsigned int)mp.opcode[9],\n          dc = (unsigned int)mp.opcode[10];\n        const CImg<double> S(&_mp_arg(1) + 1,dx,dy,dz,dc,true);\n        const float opacity = (float)_mp_arg(11);\n        unsigned int ind = (unsigned int)mp.opcode[2];\n        if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];\n        if (img) {\n          if (mp.opcode[12]!=(ulongT)-1) {\n            const CImg<double> M(&_mp_arg(12) + 1,dx,dy,dz,(unsigned int)mp.opcode[13],true);\n            img.draw_image(x,y,z,c,S,M,opacity,(float)_mp_arg(14));\n          } else img.draw_image(x,y,z,c,S,opacity);\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_eig(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const double *ptr1 = &_mp_arg(2) + 1;\n        const unsigned int k = (unsigned int)mp.opcode(3);\n        CImg<double> val, vec;\n        CImg<double>(ptr1,k,k,1,1,true).symmetric_eigen(val,vec);\n        CImg<double>(ptrd,k,1,1,1,true) = val.unroll('x');\n        CImg<double>(ptrd + k,k,k,1,1,true) = vec.get_transpose();\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_eq(_cimg_math_parser& mp) {\n        return (double)(_mp_arg(2)==_mp_arg(3));\n      }\n\n      static double mp_exp(_cimg_math_parser& mp) {\n        return std::exp(_mp_arg(2));\n      }\n\n      static double mp_eye(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const unsigned int k = (unsigned int)mp.opcode(2);\n        CImg<double>(ptrd,k,k,1,1,true).identity_matrix();\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_g(_cimg_math_parser& mp) {\n        cimg::unused(mp);\n        return cimg::grand();\n      }\n\n      static double mp_gauss(_cimg_math_parser& mp) {\n        const double x = _mp_arg(2), s = _mp_arg(3);\n        return std::exp(-x*x/(2*s*s))/std::sqrt(2*s*s*cimg::PI);\n      }\n\n      static double mp_gt(_cimg_math_parser& mp) {\n        return (double)(_mp_arg(2)>_mp_arg(3));\n      }\n\n      static double mp_gte(_cimg_math_parser& mp) {\n        return (double)(_mp_arg(2)>=_mp_arg(3));\n      }\n\n      static double mp_hypot(_cimg_math_parser& mp) {\n        return cimg::hypot(_mp_arg(2),_mp_arg(3));\n      }\n\n      static double mp_i(_cimg_math_parser& mp) {\n        return (double)mp.imgin.atXYZC((int)mp.mem[_cimg_mp_x],(int)mp.mem[_cimg_mp_y],\n                                       (int)mp.mem[_cimg_mp_z],(int)mp.mem[_cimg_mp_c],0);\n      }\n\n      static double mp_if(_cimg_math_parser& mp) {\n        const bool is_cond = (bool)_mp_arg(2);\n        const ulongT\n          mem_left = mp.opcode[3],\n          mem_right = mp.opcode[4];\n        const CImg<ulongT>\n          *const p_right = ++mp.p_code + mp.opcode[5],\n          *const p_end = p_right + mp.opcode[6];\n        const unsigned int vtarget = mp.opcode[1], vsiz = mp.opcode[7];\n        if (is_cond) {\n          for ( ; mp.p_code<p_right; ++mp.p_code) {\n            const CImg<ulongT> &op = *mp.p_code;\n            mp.opcode._data = op._data; mp.opcode._height = op._height;\n            const ulongT target = mp.opcode[1];\n            mp.mem[target] = _cimg_mp_defunc(mp);\n          }\n          mp.p_code = p_end - 1;\n          if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[mem_left] + 1,sizeof(double)*vsiz);\n          return mp.mem[mem_left];\n        }\n        for (mp.p_code = p_right; mp.p_code<p_end; ++mp.p_code) {\n          const CImg<ulongT> &op = *mp.p_code;\n          mp.opcode._data = op._data; mp.opcode._height = op._height;\n          const ulongT target = mp.opcode[1];\n          mp.mem[target] = _cimg_mp_defunc(mp);\n        }\n        --mp.p_code;\n        if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[mem_right] + 1,sizeof(double)*vsiz);\n        return mp.mem[mem_right];\n      }\n\n      static double mp_increment(_cimg_math_parser& mp) {\n        return _mp_arg(2) + 1;\n      }\n\n      static double mp_int(_cimg_math_parser& mp) {\n        return (double)(longT)_mp_arg(2);\n      }\n\n      static double mp_inv(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const double *ptr1 = &_mp_arg(2) + 1;\n        const unsigned int k = (unsigned int)mp.opcode(3);\n        CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptr1,k,k,1,1,true).get_invert();\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_ioff(_cimg_math_parser& mp) {\n        const unsigned int\n          boundary_conditions = (unsigned int)_mp_arg(3);\n        const CImg<T> &img = mp.imgin;\n        const longT\n          off = (longT)_mp_arg(2),\n          whds = (longT)img.size();\n        if (off<0 || off>=whds)\n          switch (boundary_conditions) {\n          case 2 : // Periodic boundary\n            if (img) return (double)img[cimg::mod(off,whds)];\n            return 0;\n          case 1 : // Neumann boundary\n            if (img) return (double)(off<0?*img:img.back());\n            return 0;\n          default : // Dirichet boundary\n            return 0;\n          }\n        return (double)img[off];\n      }\n\n      static double mp_isbool(_cimg_math_parser& mp) {\n        const double val = _mp_arg(2);\n        return (double)(val==0.0 || val==1.0);\n      }\n\n      static double mp_isin(_cimg_math_parser& mp) {\n        const double val = _mp_arg(2);\n        for (unsigned int i = 3; i<mp.opcode._height; ++i)\n          if (val==_mp_arg(i)) return 1.0;\n        return 0.0;\n      }\n\n      static double mp_isinf(_cimg_math_parser& mp) {\n        return (double)cimg::type<double>::is_inf(_mp_arg(2));\n      }\n\n      static double mp_isint(_cimg_math_parser& mp) {\n        return (double)(cimg::mod(_mp_arg(2),1.0)==0);\n      }\n\n      static double mp_isnan(_cimg_math_parser& mp) {\n        return (double)cimg::type<double>::is_nan(_mp_arg(2));\n      }\n\n      static double mp_ixyzc(_cimg_math_parser& mp) {\n        const unsigned int\n          interpolation = (unsigned int)_mp_arg(6),\n          boundary_conditions = (unsigned int)_mp_arg(7);\n        const CImg<T> &img = mp.imgin;\n        const double\n          x = _mp_arg(2), y = _mp_arg(3),\n          z = _mp_arg(4), c = _mp_arg(5);\n        if (interpolation==0) { // Nearest neighbor interpolation\n          if (boundary_conditions==2)\n            return (double)img.atXYZC(cimg::mod((int)x,img.width()),\n                                      cimg::mod((int)y,img.height()),\n                                      cimg::mod((int)z,img.depth()),\n                                      cimg::mod((int)c,img.spectrum()));\n          if (boundary_conditions==1)\n            return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c);\n          return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0);\n        } else { // Linear interpolation\n          if (boundary_conditions==2)\n            return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()),\n                                             cimg::mod((float)y,(float)img.height()),\n                                             cimg::mod((float)z,(float)img.depth()),\n                                             cimg::mod((float)c,(float)img.spectrum()));\n          if (boundary_conditions==1)\n            return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c);\n          return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0);\n        }\n      }\n\n      static double mp_joff(_cimg_math_parser& mp) {\n        const unsigned int\n          boundary_conditions = (unsigned int)_mp_arg(3);\n        const int\n          ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],\n          oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];\n        const CImg<T> &img = mp.imgin;\n        const longT\n          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),\n          whds = (longT)img.size();\n        if (off<0 || off>=whds)\n          switch (boundary_conditions) {\n          case 2 : // Periodic boundary\n            if (img) return (double)img[cimg::mod(off,whds)];\n            return 0;\n          case 1 : // Neumann boundary\n            if (img) return (double)(off<0?*img:img.back());\n            return 0;\n          default : // Dirichet boundary\n            return 0;\n          }\n        return (double)img[off];\n      }\n\n      static double mp_jxyzc(_cimg_math_parser& mp) {\n        const unsigned int\n          interpolation = (unsigned int)_mp_arg(6),\n          boundary_conditions = (unsigned int)_mp_arg(7);\n        const CImg<T> &img = mp.imgin;\n        const double\n          ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y],\n          oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c],\n          x = ox + _mp_arg(2), y = oy + _mp_arg(3),\n          z = oz + _mp_arg(4), c = oc + _mp_arg(5);\n        if (interpolation==0) { // Nearest neighbor interpolation\n          if (boundary_conditions==2)\n            return (double)img.atXYZC(cimg::mod((int)x,img.width()),\n                                      cimg::mod((int)y,img.height()),\n                                      cimg::mod((int)z,img.depth()),\n                                      cimg::mod((int)c,img.spectrum()));\n          if (boundary_conditions==1)\n            return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c);\n          return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0);\n        } else { // Linear interpolation\n          if (boundary_conditions==2)\n            return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()),\n                                             cimg::mod((float)y,(float)img.height()),\n                                             cimg::mod((float)z,(float)img.depth()),\n                                             cimg::mod((float)c,(float)img.spectrum()));\n          if (boundary_conditions==1)\n            return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c);\n          return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0);\n        }\n      }\n\n      static double mp_kth(_cimg_math_parser& mp) {\n        CImg<doubleT> vals(mp.opcode._height - 3);\n        double *p = vals.data();\n        for (unsigned int i = 3; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i);\n        int ind = (int)cimg::round(_mp_arg(2));\n        if (ind<0) ind+=vals.width() + 1;\n        ind = cimg::max(1,cimg::min(vals.width(),ind));\n        return vals.kth_smallest(ind - 1);\n      }\n\n      static double mp_list_depth(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        return (double)mp.listin[ind]._depth;\n      }\n\n      static double mp_list_height(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        return (double)mp.listin[ind]._height;\n      }\n\n      static double mp_list_ioff(_cimg_math_parser& mp) {\n        const unsigned int\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),\n          boundary_conditions = (unsigned int)_mp_arg(4);\n        const CImg<T> &img = mp.listin[ind];\n        const longT\n          off = (longT)_mp_arg(3),\n          whds = (longT)img.size();\n        if (off<0 || off>=whds)\n          switch (boundary_conditions) {\n          case 2 : // Periodic boundary\n            if (img) return (double)img[cimg::mod(off,whds)];\n            return 0;\n          case 1 : // Neumann boundary\n            if (img) return (double)(off<0?*img:img.back());\n            return 0;\n          default : // Dirichet boundary\n            return 0;\n          }\n        return (double)img[off];\n      }\n\n      static double mp_list_is_shared(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        return (double)mp.listin[ind]._is_shared;\n      }\n\n      static double mp_list_ixyzc(_cimg_math_parser& mp) {\n        const unsigned int\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),\n          interpolation = (unsigned int)_mp_arg(7),\n          boundary_conditions = (unsigned int)_mp_arg(8);\n        const CImg<T> &img = mp.listin[ind];\n        const double\n          x = _mp_arg(3), y = _mp_arg(4),\n          z = _mp_arg(5), c = _mp_arg(6);\n        if (interpolation==0) { // Nearest neighbor interpolation\n          if (boundary_conditions==2)\n            return (double)img.atXYZC(cimg::mod((int)x,img.width()),\n                                      cimg::mod((int)y,img.height()),\n                                      cimg::mod((int)z,img.depth()),\n                                      cimg::mod((int)c,img.spectrum()));\n          if (boundary_conditions==1)\n            return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c);\n          return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0);\n        } else { // Linear interpolation\n          if (boundary_conditions==2)\n            return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()),\n                                             cimg::mod((float)y,(float)img.height()),\n                                             cimg::mod((float)z,(float)img.depth()),\n                                             cimg::mod((float)c,(float)img.spectrum()));\n          if (boundary_conditions==1)\n            return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c);\n          return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0);\n        }\n      }\n\n      static double mp_list_joff(_cimg_math_parser& mp) {\n        const unsigned int\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),\n          boundary_conditions = (unsigned int)_mp_arg(4);\n        const int\n          ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],\n          oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];\n        const CImg<T> &img = mp.listin[ind];\n        const longT\n          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3),\n          whds = (longT)img.size();\n        if (off<0 || off>=whds)\n          switch (boundary_conditions) {\n          case 2 : // Periodic boundary\n            if (img) return (double)img(ind,cimg::mod(off,whds));\n            return 0;\n          case 1 : // Neumann boundary\n            if (img) return (double)(off<0?*img:img.back());\n            return 0;\n          default : // Dirichet boundary\n            return 0;\n          }\n        return (double)img[off];\n      }\n\n      static double mp_list_jxyzc(_cimg_math_parser& mp) {\n        const unsigned int\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),\n          interpolation = (unsigned int)_mp_arg(7),\n          boundary_conditions = (unsigned int)_mp_arg(8);\n        const CImg<T> &img = mp.listin[ind];\n        const double\n          ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y],\n          oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c],\n          x = ox + _mp_arg(3), y = oy + _mp_arg(4),\n          z = oz + _mp_arg(5), c = oc + _mp_arg(6);\n        if (interpolation==0) { // Nearest neighbor interpolation\n          if (boundary_conditions==2)\n            return (double)img.atXYZC(cimg::mod((int)x,img.width()),\n                                      cimg::mod((int)y,img.height()),\n                                      cimg::mod((int)z,img.depth()),\n                                      cimg::mod((int)c,img.spectrum()));\n          if (boundary_conditions==1)\n            return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c);\n          return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0);\n        } else { // Linear interpolation\n          if (boundary_conditions==2)\n            return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()),\n                                             cimg::mod((float)y,(float)img.height()),\n                                             cimg::mod((float)z,(float)img.depth()),\n                                             cimg::mod((float)c,(float)img.spectrum()));\n          if (boundary_conditions==1)\n            return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c);\n          return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0);\n        }\n      }\n\n      static double mp_list_median(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        if (!mp.list_median) mp.list_median.assign(mp.listin._width);\n        if (!mp.list_median[ind]) CImg<doubleT>::vector(mp.listin[ind].median()).move_to(mp.list_median[ind]);\n        return *mp.list_median[ind];\n      }\n\n      static double mp_list_set_ioff(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const longT\n          off = (longT)_mp_arg(3),\n          whds = (longT)img.size();\n        const double val = _mp_arg(1);\n        if (off>=0 && off<whds) img[off] = (T)val;\n        return val;\n      }\n\n      static double mp_list_set_ixyzc(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const int\n          x = (int)_mp_arg(3), y = (int)_mp_arg(4),\n          z = (int)_mp_arg(5), c = (int)_mp_arg(6);\n        const double val = _mp_arg(1);\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() &&\n            z>=0 && z<img.depth() && c>=0 && c<img.spectrum())\n          img(x,y,z,c) = (T)val;\n        return val;\n      }\n\n      static double mp_list_set_joff(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const int\n          ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],\n          oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];\n        const longT\n          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3),\n          whds = (longT)img.size();\n        const double val = _mp_arg(1);\n        if (off>=0 && off<whds) img[off] = (T)val;\n        return val;\n      }\n\n      static double mp_list_set_jxyzc(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const double\n          ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y],\n          oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c];\n        const int\n          x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)),\n          z = (int)(oz + _mp_arg(5)), c = (int)(oc + _mp_arg(6));\n        const double val = _mp_arg(1);\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() &&\n            z>=0 && z<img.depth() && c>=0 && c<img.spectrum())\n          img(x,y,z,c) = (T)val;\n        return val;\n      }\n\n      static double mp_list_set_Ioff_s(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const longT\n          off = (longT)_mp_arg(3),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const T val = (T)_mp_arg(1);\n        if (off>=0 && off<whd) {\n          T *ptrd = &img[off];\n          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }\n        }\n        return _mp_arg(1);\n      }\n\n      static double mp_list_set_Ioff_v(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const longT\n          off = (longT)_mp_arg(3),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const double *ptrs = &_mp_arg(1) + 1;\n        if (off>=0 && off<whd) {\n          T *ptrd = &img[off];\n          cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_list_set_Ixyz_s(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5);\n        const T val = (T)_mp_arg(1);\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {\n          T *ptrd = &img(x,y,z);\n          const ulongT whd = (ulongT)img._width*img._height*img._depth;\n          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }\n        }\n        return _mp_arg(1);\n      }\n\n      static double mp_list_set_Ixyz_v(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5);\n        const double *ptrs = &_mp_arg(1) + 1;\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {\n          T *ptrd = &img(x,y,z);\n          const ulongT whd = (ulongT)img._width*img._height*img._depth;\n          cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_list_set_Joff_s(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const int\n          ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],\n          oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];\n        const longT\n          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const T val = (T)_mp_arg(1);\n        if (off>=0 && off<whd) {\n          T *ptrd = &img[off];\n          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }\n        }\n        return _mp_arg(1);\n      }\n\n      static double mp_list_set_Joff_v(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const int\n          ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],\n          oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];\n        const longT\n          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const double *ptrs = &_mp_arg(1) + 1;\n        if (off>=0 && off<whd) {\n          T *ptrd = &img[off];\n          cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_list_set_Jxyz_s(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z];\n        const int x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), z = (int)(oz + _mp_arg(5));\n        const T val = (T)_mp_arg(1);\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {\n          T *ptrd = &img(x,y,z);\n          const ulongT whd = (ulongT)img._width*img._height*img._depth;\n          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }\n        }\n        return _mp_arg(1);\n      }\n\n      static double mp_list_set_Jxyz_v(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        CImg<T> &img = mp.listout[ind];\n        const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z];\n        const int x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), z = (int)(oz + _mp_arg(5));\n        const double *ptrs = &_mp_arg(1) + 1;\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {\n          T *ptrd = &img(x,y,z);\n          const ulongT whd = (ulongT)img._width*img._height*img._depth;\n          cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_list_spectrum(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        return (double)mp.listin[ind]._spectrum;\n      }\n\n      static double mp_list_stats(_cimg_math_parser& mp) {\n        const unsigned int\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),\n          k = (unsigned int)_mp_arg(3);\n        if (!mp.list_stats) mp.list_stats.assign(mp.listin._width);\n        if (!mp.list_stats[ind]) mp.list_stats[ind].assign(1,14,1,1,0).fill(mp.listin[ind].get_stats(),false);\n        return mp.list_stats(ind,k);\n      }\n\n      static double mp_list_wh(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        return (double)mp.listin[ind]._width*mp.listin[ind]._height;\n      }\n\n      static double mp_list_whd(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth;\n      }\n\n      static double mp_list_whds(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth*mp.listin[ind]._spectrum;\n      }\n\n      static double mp_list_width(_cimg_math_parser& mp) {\n        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());\n        return (double)mp.listin[ind]._width;\n      }\n\n      static double mp_list_Ioff(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const unsigned int\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),\n          boundary_conditions = (unsigned int)_mp_arg(4);\n        const CImg<T> &img = mp.listin[ind];\n        const longT\n          off = (longT)_mp_arg(3),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const T *ptrs;\n        if (off<0 || off>=whd)\n          switch (boundary_conditions) {\n          case 2 : // Periodic boundary\n            if (!img) {\n              ptrs = &img[cimg::mod(off,whd)];\n              cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n            } else std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          case 1 : // Neumann boundary\n            if (img) {\n              ptrs = off<0?img._data:&img.back();\n              cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n            } else std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          default : // Dirichet boundary\n            std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          }\n        ptrs = &img[off];\n        cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_list_Ixyz(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const unsigned int\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),\n          interpolation = (unsigned int)_mp_arg(6),\n          boundary_conditions = (unsigned int)_mp_arg(7);\n        const CImg<T> &img = mp.listin[ind];\n        const double x = _mp_arg(3), y = _mp_arg(4), z = _mp_arg(5);\n        if (interpolation==0) { // Nearest neighbor interpolation\n          if (boundary_conditions==2)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()),\n                                            cimg::mod((int)y,img.height()),\n                                            cimg::mod((int)z,img.depth()),\n                                            c);\n          else if (boundary_conditions==1)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c);\n          else\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0);\n        } else { // Linear interpolation\n          if (boundary_conditions==2)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()),\n                                                   cimg::mod((float)y,(float)img.height()),\n                                                   cimg::mod((float)z,(float)img.depth()),c);\n          else if (boundary_conditions==1)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c);\n          else\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0);\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_list_Joff(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const unsigned int\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),\n          boundary_conditions = (unsigned int)_mp_arg(4);\n        const int\n          ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z];\n        const CImg<T> &img = mp.listin[ind];\n        const longT\n          off = img.offset(ox,oy,oz) + (longT)_mp_arg(3),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const T *ptrs;\n        if (off<0 || off>=whd)\n          switch (boundary_conditions) {\n          case 2 : // Periodic boundary\n            if (!img) {\n              ptrs = &img[cimg::mod(off,whd)];\n              cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n            } else std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          case 1 : // Neumann boundary\n            if (img) {\n              ptrs = off<0?img._data:&img.back();\n              cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n            } else std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          default : // Dirichet boundary\n            std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          }\n        ptrs = &img[off];\n        cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_list_Jxyz(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const unsigned int\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),\n          interpolation = (unsigned int)_mp_arg(6),\n          boundary_conditions = (unsigned int)_mp_arg(7);\n        const CImg<T> &img = mp.listin[ind];\n        const double\n          ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z],\n          x = ox + _mp_arg(3), y = oy + _mp_arg(4), z = oz + _mp_arg(5);\n        if (interpolation==0) { // Nearest neighbor interpolation\n          if (boundary_conditions==2)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()),\n                                            cimg::mod((int)y,img.height()),\n                                            cimg::mod((int)z,img.depth()),\n                                            c);\n          else if (boundary_conditions==1)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c);\n          else\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0);\n        } else { // Linear interpolation\n          if (boundary_conditions==2)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()),\n                                                   cimg::mod((float)y,(float)img.height()),\n                                                   cimg::mod((float)z,(float)img.depth()),c);\n          else if (boundary_conditions==1)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c);\n          else\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0);\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_log(_cimg_math_parser& mp) {\n        return std::log(_mp_arg(2));\n      }\n\n      static double mp_log10(_cimg_math_parser& mp) {\n        return std::log10(_mp_arg(2));\n      }\n\n      static double mp_log2(_cimg_math_parser& mp) {\n        return cimg::log2(_mp_arg(2));\n      }\n\n      static double mp_logical_and(_cimg_math_parser& mp) {\n        const bool val_left = (bool)_mp_arg(2);\n        const CImg<ulongT> *const p_end = ++mp.p_code + mp.opcode[4];\n        if (!val_left) { mp.p_code = p_end - 1; return 0; }\n        const ulongT mem_right = mp.opcode[3];\n        for ( ; mp.p_code<p_end; ++mp.p_code) {\n          const CImg<ulongT> &op = *mp.p_code;\n          mp.opcode._data = op._data; mp.opcode._height = op._height;\n          const ulongT target = mp.opcode[1];\n          mp.mem[target] = _cimg_mp_defunc(mp);\n        }\n        --mp.p_code;\n        return (double)(bool)mp.mem[mem_right];\n      }\n\n      static double mp_logical_not(_cimg_math_parser& mp) {\n        return (double)!_mp_arg(2);\n      }\n\n      static double mp_logical_or(_cimg_math_parser& mp) {\n        const bool val_left = (bool)_mp_arg(2);\n        const CImg<ulongT> *const p_end = ++mp.p_code + mp.opcode[4];\n        if (val_left) { mp.p_code = p_end - 1; return 1; }\n        const ulongT mem_right = mp.opcode[3];\n        for ( ; mp.p_code<p_end; ++mp.p_code) {\n          const CImg<ulongT> &op = *mp.p_code;\n          mp.opcode._data = op._data; mp.opcode._height = op._height;\n          const ulongT target = mp.opcode[1];\n          mp.mem[target] = _cimg_mp_defunc(mp);\n        }\n        --mp.p_code;\n        return (double)(bool)mp.mem[mem_right];\n      }\n\n\n      static double mp_lt(_cimg_math_parser& mp) {\n        return (double)(_mp_arg(2)<_mp_arg(3));\n      }\n\n      static double mp_lte(_cimg_math_parser& mp) {\n        return (double)(_mp_arg(2)<=_mp_arg(3));\n      }\n\n      static double mp_matrix_mul(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const double\n          *ptr1 = &_mp_arg(2) + 1,\n          *ptr2 = &_mp_arg(3) + 1;\n        const unsigned int\n          k = (unsigned int)mp.opcode(4),\n          l = (unsigned int)mp.opcode(5),\n          m = (unsigned int)mp.opcode(6);\n        CImg<double>(ptrd,m,k,1,1,true) = CImg<double>(ptr1,l,k,1,1,true)*CImg<double>(ptr2,m,l,1,1,true);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_max(_cimg_math_parser& mp) {\n        double val = _mp_arg(2);\n        for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::max(val,_mp_arg(i));\n        return val;\n      }\n\n      static double* _mp_memcopy_double(_cimg_math_parser& mp, const unsigned int ind, const ulongT *const p_ref,\n                                        const longT siz, const long inc) {\n        const longT\n          off = *p_ref?p_ref[1] + (longT)mp.mem[(longT)p_ref[2]] + 1:ind,\n          eoff = off + (siz - 1)*inc;\n        if (off<0 || eoff>=mp.mem.width())\n          throw CImgArgumentException(\"[_cimg_math_parser] CImg<%s>: 'copy()': \"\n                                      \"Out-of-bounds variable pointer \"\n                                      \"(length: %ld, increment: %ld, offset start: %ld, \"\n                                      \"offset end: %ld, offset max: %u).\",\n                                      mp.imgin.pixel_type(),siz,inc,off,eoff,mp.mem._width - 1);\n        return &mp.mem[off];\n      }\n\n      static float* _mp_memcopy_float(_cimg_math_parser& mp, const ulongT *const p_ref,\n                                      const longT siz, const long inc) {\n        const unsigned ind = p_ref[1];\n        const CImg<T> &img = ind==~0U?mp.imgin:mp.listin[cimg::mod((int)mp.mem[ind],mp.listin.width())];\n        const bool is_relative = (bool)p_ref[2];\n        int ox, oy, oz, oc;\n        longT off = 0;\n        if (is_relative) {\n          ox = (int)mp.mem[_cimg_mp_x];\n          oy = (int)mp.mem[_cimg_mp_y];\n          oz = (int)mp.mem[_cimg_mp_z];\n          oc = (int)mp.mem[_cimg_mp_c];\n          off = img.offset(ox,oy,oz,oc);\n        }\n        if ((*p_ref)%2) {\n          const int\n            x = (int)mp.mem[p_ref[3]],\n            y = (int)mp.mem[p_ref[4]],\n            z = (int)mp.mem[p_ref[5]],\n            c = *p_ref==5?0:(int)mp.mem[p_ref[6]];\n          off+=img.offset(x,y,z,c);\n        } else off+=(longT)mp.mem[p_ref[3]];\n        const longT eoff = off + (siz - 1)*inc;\n        if (off<0 || eoff>=(longT)img.size())\n          throw CImgArgumentException(\"[_cimg_math_parser] CImg<%s>: Function 'copy()': \"\n                                      \"Out-of-bounds image pointer \"\n                                      \"(length: %ld, increment: %ld, offset start: %ld, \"\n                                      \"offset end: %ld, offset max: %lu).\",\n                                      mp.imgin.pixel_type(),siz,inc,off,eoff,img.size() - 1);\n        return (float*)&img[off];\n      }\n\n      static double mp_memcopy(_cimg_math_parser& mp) {\n        longT siz = (longT)_mp_arg(4);\n        const longT inc_d = (longT)_mp_arg(5), inc_s = (longT)_mp_arg(6);\n        if (siz>0) {\n          const bool\n            is_doubled = mp.opcode[7]<=1,\n            is_doubles = mp.opcode[14]<=1;\n          if (is_doubled && is_doubles) { // (double*) <- (double*)\n            double *ptrd = _mp_memcopy_double(mp,mp.opcode[2],&mp.opcode[7],siz,inc_d);\n            const double *ptrs = _mp_memcopy_double(mp,mp.opcode[3],&mp.opcode[14],siz,inc_s);\n            if (inc_d==1 && inc_s==1) {\n              if (ptrs + siz - 1<ptrd || ptrs>ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(double));\n              else std::memmove(ptrd,ptrs,siz*sizeof(double));\n            } else {\n              if (ptrs + (siz - 1)*inc_s<ptrd || ptrs>ptrd + (siz - 1)*inc_d)\n                while (siz-->0) { *ptrd = (double)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }\n              else { // Overlapping buffers\n                CImg<double> buf(siz);\n                cimg_for(buf,ptr,double) { *ptr = *ptrs; ptrs+=inc_s; }\n                ptrs = buf;\n                while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; }\n              }\n            }\n          } else if (is_doubled && !is_doubles) { // (double*) <- (float*)\n            double *ptrd = _mp_memcopy_double(mp,mp.opcode[2],&mp.opcode[7],siz,inc_d);\n            const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[14],siz,inc_s);\n            while (siz-->0) { *ptrd = (double)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }\n          } else if (!is_doubled && is_doubles) { // (float*) <- (double*)\n            float *ptrd = _mp_memcopy_float(mp,&mp.opcode[7],siz,inc_d);\n            const double *ptrs = _mp_memcopy_double(mp,mp.opcode[3],&mp.opcode[14],siz,inc_s);\n            while (siz-->0) { *ptrd = (float)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }\n          } else { // (float*) <- (float*)\n            float *ptrd = _mp_memcopy_float(mp,&mp.opcode[7],siz,inc_d);\n            const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[14],siz,inc_s);\n            if (inc_d==1 && inc_s==1) {\n              if (ptrs + siz - 1<ptrd || ptrs>ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(float));\n              else std::memmove(ptrd,ptrs,siz*sizeof(float));\n            } else {\n              if (ptrs + (siz - 1)*inc_s<ptrd || ptrs>ptrd + (siz - 1)*inc_d)\n                while (siz-->0) { *ptrd = (float)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }\n              else { // Overlapping buffers\n                CImg<float> buf(siz);\n                cimg_for(buf,ptr,float) { *ptr = *ptrs; ptrs+=inc_s; }\n                ptrs = buf;\n                while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; }\n              }\n            }\n          }\n        }\n        return _mp_arg(1);\n      }\n\n      static double mp_min(_cimg_math_parser& mp) {\n        double val = _mp_arg(2);\n        for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::min(val,_mp_arg(i));\n        return val;\n      }\n\n      static double mp_minus(_cimg_math_parser& mp) {\n        return -_mp_arg(2);\n      }\n\n      static double mp_mean(_cimg_math_parser& mp) {\n        double val = _mp_arg(2);\n        for (unsigned int i = 3; i<mp.opcode._height; ++i) val+=_mp_arg(i);\n        return val/(mp.opcode._height - 2);\n      }\n\n      static double mp_med(_cimg_math_parser& mp) {\n        CImg<doubleT> vals(mp.opcode._height - 2);\n        double *p = vals.data();\n        for (unsigned int i = 2; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i);\n        return vals.median();\n      }\n\n      static double mp_modulo(_cimg_math_parser& mp) {\n        return cimg::mod(_mp_arg(2),_mp_arg(3));\n      }\n\n      static double mp_mul(_cimg_math_parser& mp) {\n        return _mp_arg(2)*_mp_arg(3);\n      }\n\n      static double mp_neq(_cimg_math_parser& mp) {\n        return (double)(_mp_arg(2)!=_mp_arg(3));\n      }\n\n      static double mp_norm0(_cimg_math_parser& mp) {\n        double res = 0;\n        for (unsigned int i = 2; i<mp.opcode._height; ++i)\n          res+=_mp_arg(i)==0?0:1;\n        return res;\n      }\n\n      static double mp_norm1(_cimg_math_parser& mp) {\n        double res = 0;\n        for (unsigned int i = 2; i<mp.opcode._height; ++i)\n          res+=cimg::abs(_mp_arg(i));\n        return res;\n      }\n\n      static double mp_norm2(_cimg_math_parser& mp) {\n        double res = 0;\n        for (unsigned int i = 2; i<mp.opcode._height; ++i)\n          res+=cimg::sqr(_mp_arg(i));\n        return std::sqrt(res);\n      }\n\n      static double mp_norminf(_cimg_math_parser& mp) {\n        double res = 0;\n        for (unsigned int i = 2; i<mp.opcode._height; ++i) {\n          const double val = cimg::abs(_mp_arg(i));\n          if (val>res) res = val;\n        }\n        return res;\n      }\n\n      static double mp_normp(_cimg_math_parser& mp) {\n        const double p = (double)mp.opcode[2];\n        double res = 0;\n        for (unsigned int i = 3; i<mp.opcode._height; ++i)\n          res+=std::pow(cimg::abs(_mp_arg(i)),p);\n        res = std::pow(res,1/p);\n        return res>0?res:0.0;\n      }\n\n      static double mp_pow(_cimg_math_parser& mp) {\n        const double v = _mp_arg(2), p = _mp_arg(3);\n        return std::pow(v,p);\n      }\n\n      static double mp_pow3(_cimg_math_parser& mp) {\n        const double val = _mp_arg(2);\n        return val*val*val;\n      }\n\n      static double mp_pow4(_cimg_math_parser& mp) {\n        const double val = _mp_arg(2);\n        return val*val*val*val;\n      }\n\n      static double mp_print(_cimg_math_parser& mp) {\n        cimg::mutex(6);\n        CImg<charT> expr(mp.opcode._height - 2);\n        const ulongT *ptrs = mp.opcode._data + 2;\n        cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);\n        cimg::strellipsize(expr);\n        const double val = _mp_arg(1);\n#ifdef cimg_use_openmp\n#pragma omp critical\n#endif\n        {\n          std::fprintf(cimg::output(),\"\\n[_cimg_math_parser] %s = %g\",expr._data,val);\n          std::fflush(cimg::output());\n        }\n        cimg::mutex(6,0);\n        return val;\n      }\n\n      static double mp_prod(_cimg_math_parser& mp) {\n        double val = _mp_arg(2);\n        for (unsigned int i = 3; i<mp.opcode._height; ++i) val*=_mp_arg(i);\n        return val;\n      }\n\n      static double mp_copy(_cimg_math_parser& mp) {\n        return _mp_arg(2);\n      }\n\n      static double mp_rol(_cimg_math_parser& mp) {\n        return cimg::rol(_mp_arg(2),(unsigned int)_mp_arg(3));\n      }\n\n      static double mp_ror(_cimg_math_parser& mp) {\n        return cimg::ror(_mp_arg(2),(unsigned int)_mp_arg(3));\n      }\n\n      static double mp_rot2d(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const float\n          theta = (float)_mp_arg(2),\n          ca = std::cos(theta),\n          sa = std::sin(theta);\n        *(ptrd++) = ca;\n        *(ptrd++) = -sa;\n        *(ptrd++) = sa;\n        *ptrd = ca;\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_rot3d(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const float x = (float)_mp_arg(2), y = (float)_mp_arg(3), z = (float)_mp_arg(4), theta = (float)_mp_arg(5);\n        CImg<double>(ptrd,3,3,1,1,true) = CImg<double>::rotation_matrix(x,y,z,theta);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_round(_cimg_math_parser& mp) {\n        return cimg::round(_mp_arg(2),_mp_arg(3),(int)_mp_arg(4));\n      }\n\n      static double mp_self_add(_cimg_math_parser& mp) {\n        return _mp_arg(1)+=_mp_arg(2);\n      }\n\n      static double mp_self_bitwise_and(_cimg_math_parser& mp) {\n        double &val = _mp_arg(1);\n        return val = (double)((ulongT)val & (ulongT)_mp_arg(2));\n      }\n\n      static double mp_self_bitwise_left_shift(_cimg_math_parser& mp) {\n        double &val = _mp_arg(1);\n        return val = (double)((longT)val<<(unsigned int)_mp_arg(2));\n      }\n\n      static double mp_self_bitwise_or(_cimg_math_parser& mp) {\n        double &val = _mp_arg(1);\n        return val = (double)((ulongT)val | (ulongT)_mp_arg(2));\n      }\n\n      static double mp_self_bitwise_right_shift(_cimg_math_parser& mp) {\n        double &val = _mp_arg(1);\n        return val = (double)((longT)val>>(unsigned int)_mp_arg(2));\n      }\n\n      static double mp_self_decrement(_cimg_math_parser& mp) {\n        return --_mp_arg(1);\n      }\n\n      static double mp_self_increment(_cimg_math_parser& mp) {\n        return ++_mp_arg(1);\n      }\n\n      static double mp_self_map_vector_s(_cimg_math_parser& mp) { // Vector += scalar\n        unsigned int\n          ptrd = (unsigned int)mp.opcode[1] + 1,\n          siz = (unsigned int)mp.opcode[2];\n        mp_func op = (mp_func)mp.opcode[3];\n        CImg<ulongT> l_opcode(1,3);\n        l_opcode[2] = mp.opcode[4]; // Scalar argument.\n        l_opcode.swap(mp.opcode);\n        ulongT &target = mp.opcode[1];\n        while (siz-->0) { target = ptrd++; (*op)(mp); }\n        l_opcode.swap(mp.opcode);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_self_map_vector_v(_cimg_math_parser& mp) { // Vector += vector\n        unsigned int\n          ptrd = (unsigned int)mp.opcode[1] + 1,\n          siz = (unsigned int)mp.opcode[2],\n          ptrs = (unsigned int)mp.opcode[4] + 1;\n        mp_func op = (mp_func)mp.opcode[3];\n        CImg<ulongT> l_opcode(1,4);\n        l_opcode.swap(mp.opcode);\n        ulongT &target = mp.opcode[1], &argument = mp.opcode[2];\n        while (siz-->0)  { target = ptrd++; argument = ptrs++; (*op)(mp); }\n        l_opcode.swap(mp.opcode);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_self_mul(_cimg_math_parser& mp) {\n        return _mp_arg(1)*=_mp_arg(2);\n      }\n\n      static double mp_self_div(_cimg_math_parser& mp) {\n        return _mp_arg(1)/=_mp_arg(2);\n      }\n\n      static double mp_self_modulo(_cimg_math_parser& mp) {\n        double &val = _mp_arg(1);\n        return val = cimg::mod(val,_mp_arg(2));\n      }\n\n      static double mp_self_pow(_cimg_math_parser& mp) {\n        double &val = _mp_arg(1);\n        return val = std::pow(val,_mp_arg(2));\n      }\n\n      static double mp_self_sub(_cimg_math_parser& mp) {\n        return _mp_arg(1)-=_mp_arg(2);\n      }\n\n      static double mp_set_ioff(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const longT\n          off = (longT)_mp_arg(2),\n          whds = (longT)img.size();\n        const double val = _mp_arg(1);\n        if (off>=0 && off<whds) img[off] = (T)val;\n        return val;\n      }\n\n      static double mp_set_ixyzc(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const int\n          x = (int)_mp_arg(2), y = (int)_mp_arg(3),\n          z = (int)_mp_arg(4), c = (int)_mp_arg(5);\n        const double val = _mp_arg(1);\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() &&\n            z>=0 && z<img.depth() && c>=0 && c<img.spectrum())\n          img(x,y,z,c) = (T)val;\n        return val;\n      }\n\n      static double mp_set_joff(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const int\n          ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],\n          oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];\n        const longT\n          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),\n          whds = (longT)img.size();\n        const double val = _mp_arg(1);\n        if (off>=0 && off<whds) img[off] = (T)val;\n        return val;\n      }\n\n      static double mp_set_jxyzc(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const double\n          ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y],\n          oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c];\n        const int\n          x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)),\n          z = (int)(oz + _mp_arg(4)), c = (int)(oc + _mp_arg(5));\n        const double val = _mp_arg(1);\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() &&\n            z>=0 && z<img.depth() && c>=0 && c<img.spectrum())\n          img(x,y,z,c) = (T)val;\n        return val;\n      }\n\n      static double mp_set_Ioff_s(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const longT\n          off = (longT)_mp_arg(2),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const T val = (T)_mp_arg(1);\n        if (off>=0 && off<whd) {\n          T *ptrd = &img[off];\n          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }\n        }\n        return _mp_arg(1);\n      }\n\n      static double mp_set_Ioff_v(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const longT\n          off = (longT)_mp_arg(2),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const double *ptrs = &_mp_arg(1) + 1;\n        if (off>=0 && off<whd) {\n          T *ptrd = &img[off];\n          cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_set_Ixyz_s(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const int x = (int)_mp_arg(2), y = (int)_mp_arg(3), z = (int)_mp_arg(4);\n        const T val = (T)_mp_arg(1);\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {\n          T *ptrd = &img(x,y,z);\n          const ulongT whd = (ulongT)img._width*img._height*img._depth;\n          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }\n        }\n        return _mp_arg(1);\n      }\n\n      static double mp_set_Ixyz_v(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const int x = (int)_mp_arg(2), y = (int)_mp_arg(3), z = (int)_mp_arg(4);\n        const double *ptrs = &_mp_arg(1) + 1;\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {\n          T *ptrd = &img(x,y,z);\n          const ulongT whd = (ulongT)img._width*img._height*img._depth;\n          cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_set_Joff_s(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const int\n          ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],\n          oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];\n        const longT\n          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const T val = (T)_mp_arg(1);\n        if (off>=0 && off<whd) {\n          T *ptrd = &img[off];\n          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }\n        }\n        return _mp_arg(1);\n      }\n\n      static double mp_set_Joff_v(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const int\n          ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],\n          oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];\n        const longT\n          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const double *ptrs = &_mp_arg(1) + 1;\n        if (off>=0 && off<whd) {\n          T *ptrd = &img[off];\n          cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_set_Jxyz_s(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z];\n        const int x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), z = (int)(oz + _mp_arg(4));\n        const T val = (T)_mp_arg(1);\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {\n          T *ptrd = &img(x,y,z);\n          const ulongT whd = (ulongT)img._width*img._height*img._depth;\n          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }\n        }\n        return _mp_arg(1);\n      }\n\n      static double mp_set_Jxyz_v(_cimg_math_parser& mp) {\n        CImg<T> &img = mp.imgout;\n        const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z];\n        const int x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), z = (int)(oz + _mp_arg(4));\n        const double *ptrs = &_mp_arg(1) + 1;\n        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {\n          T *ptrd = &img(x,y,z);\n          const ulongT whd = (ulongT)img._width*img._height*img._depth;\n          cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_sign(_cimg_math_parser& mp) {\n        return cimg::sign(_mp_arg(2));\n      }\n\n      static double mp_sin(_cimg_math_parser& mp) {\n        return std::sin(_mp_arg(2));\n      }\n\n      static double mp_sinc(_cimg_math_parser& mp) {\n        return cimg::sinc(_mp_arg(2));\n      }\n\n      static double mp_single(_cimg_math_parser& mp) {\n        const double res = _mp_arg(1);\n#ifdef cimg_use_openmp\n#pragma omp critical\n#endif\n        {\n          for (const CImg<ulongT> *const p_end = ++mp.p_code + mp.opcode[2];\n            mp.p_code<p_end; ++mp.p_code) { // Evaluate loop iteration + condition\n            const CImg<ulongT> &op = *mp.p_code;\n            mp.opcode._data = op._data; mp.opcode._height = op._height;\n            const ulongT target = mp.opcode[1];\n            mp.mem[target] = _cimg_mp_defunc(mp);\n          }\n        }\n        --mp.p_code;\n        return res;\n      }\n\n      static double mp_sinh(_cimg_math_parser& mp) {\n        return std::sinh(_mp_arg(2));\n      }\n\n      static double mp_solve(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const double\n          *ptr1 = &_mp_arg(2) + 1,\n          *ptr2 = &_mp_arg(3) + 1;\n        const unsigned int\n          k = (unsigned int)mp.opcode(4),\n          l = (unsigned int)mp.opcode(5),\n          m = (unsigned int)mp.opcode(6);\n        CImg<double>(ptrd,m,k,1,1,true) = CImg<double>(ptr2,m,l,1,1,true).get_solve(CImg<double>(ptr1,k,l,1,1,true));\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_sort(_cimg_math_parser& mp) {\n        double *const ptrd = &_mp_arg(1) + 1;\n        const double *const ptrs = &_mp_arg(2) + 1;\n        const unsigned int\n          siz = mp.opcode[3],\n          chunk_siz = mp.opcode[5];\n        const bool is_increasing = (bool)_mp_arg(4);\n        CImg<doubleT>(ptrd,chunk_siz,siz/chunk_siz,1,1,true) = CImg<doubleT>(ptrs,chunk_siz,siz/chunk_siz,1,1,true).\n          get_sort(is_increasing,chunk_siz>1?'y':0);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_sqr(_cimg_math_parser& mp) {\n        return cimg::sqr(_mp_arg(2));\n      }\n\n      static double mp_sqrt(_cimg_math_parser& mp) {\n        return std::sqrt(_mp_arg(2));\n      }\n\n      static double mp_std(_cimg_math_parser& mp) {\n        CImg<doubleT> vals(mp.opcode._height - 2);\n        double *p = vals.data();\n        for (unsigned int i = 2; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i);\n        return std::sqrt(vals.variance());\n      }\n\n      static double mp_sub(_cimg_math_parser& mp) {\n        return _mp_arg(2) - _mp_arg(3);\n      }\n\n      static double mp_sum(_cimg_math_parser& mp) {\n        double val = _mp_arg(2);\n        for (unsigned int i = 3; i<mp.opcode._height; ++i) val+=_mp_arg(i);\n        return val;\n      }\n\n      static double mp_tan(_cimg_math_parser& mp) {\n        return std::tan(_mp_arg(2));\n      }\n\n      static double mp_tanh(_cimg_math_parser& mp) {\n        return std::tanh(_mp_arg(2));\n      }\n\n      static double mp_trace(_cimg_math_parser& mp) {\n        const double *ptrs = &_mp_arg(2) + 1;\n        const unsigned int k = (unsigned int)mp.opcode(3);\n        return CImg<double>(ptrs,k,k,1,1,true).trace();\n      }\n\n      static double mp_transp(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const double *ptr1 = &_mp_arg(2) + 1;\n        const unsigned int\n          k = (unsigned int)mp.opcode(3),\n          l = (unsigned int)mp.opcode(4);\n        CImg<double>(ptrd,l,k,1,1,true) = CImg<double>(ptr1,k,l,1,1,true).get_transpose();\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_u(_cimg_math_parser& mp) {\n        return cimg::rand(_mp_arg(2),_mp_arg(3));\n      }\n\n      static double mp_var(_cimg_math_parser& mp) {\n        CImg<doubleT> vals(mp.opcode._height - 2);\n        double *p = vals.data();\n        for (unsigned int i = 2; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i);\n        return vals.variance();\n      }\n\n      static double mp_vector_copy(_cimg_math_parser& mp) {\n        std::memcpy(&_mp_arg(1) + 1,&_mp_arg(2) + 1,sizeof(double)*mp.opcode[3]);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_vector_crop(_cimg_math_parser& mp) {\n        double *const ptrd = &_mp_arg(1) + 1;\n        const double *const ptrs = &_mp_arg(2) + 1;\n        const unsigned int p1 = mp.opcode[3], p2 = mp.opcode[4];\n        std::memcpy(ptrd,ptrs + p1,p2*sizeof(double));\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_vector_init(_cimg_math_parser& mp) {\n        unsigned int\n          ptrs = 3U,\n          ptrd = (unsigned int)mp.opcode[1] + 1,\n          siz = (unsigned int)mp.opcode[2];\n        switch (mp.opcode._height) {\n        case 3 : std::memset(mp.mem._data + ptrd,0,siz*sizeof(double)); break; // 0 values given\n        case 4 : { const double val = _mp_arg(ptrs); while (siz-->0) mp.mem[ptrd++] = val; } break;\n        default : while (siz-->0) { mp.mem[ptrd++] = _mp_arg(ptrs++); if (ptrs>=mp.opcode._height) ptrs = 3U; }\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_vector_map_sv(_cimg_math_parser& mp) { // Operator(scalar,vector)\n        unsigned int\n          siz = (unsigned int)mp.opcode[2],\n          ptrs = (unsigned int)mp.opcode[5] + 1;\n        double *ptrd = &_mp_arg(1) + 1;\n        mp_func op = (mp_func)mp.opcode[3];\n        CImg<ulongT> l_opcode(4);\n        l_opcode[2] = mp.opcode[4]; // Scalar argument1\n        l_opcode.swap(mp.opcode);\n        ulongT &argument2 = mp.opcode[3];\n        while (siz-->0) { argument2 = ptrs++; *(ptrd++) = (*op)(mp); }\n        l_opcode.swap(mp.opcode);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_vector_map_v(_cimg_math_parser& mp) { // Operator(vector)\n        unsigned int\n          siz = (unsigned int)mp.opcode[2],\n          ptrs = (unsigned int)mp.opcode[4] + 1;\n        double *ptrd = &_mp_arg(1) + 1;\n        mp_func op = (mp_func)mp.opcode[3];\n        CImg<ulongT> l_opcode(1,3);\n        l_opcode.swap(mp.opcode);\n        ulongT &argument = mp.opcode[2];\n        while (siz-->0) { argument = ptrs++; *(ptrd++) = (*op)(mp); }\n        l_opcode.swap(mp.opcode);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_vector_map_vs(_cimg_math_parser& mp) { // Operator(vector,scalar)\n        unsigned int\n          siz = (unsigned int)mp.opcode[2],\n          ptrs = (unsigned int)mp.opcode[4] + 1;\n        double *ptrd = &_mp_arg(1) + 1;\n        mp_func op = (mp_func)mp.opcode[3];\n        CImg<ulongT> l_opcode(1,4);\n        l_opcode[3] = mp.opcode[5]; // Scalar argument2\n        l_opcode.swap(mp.opcode);\n        ulongT &argument1 = mp.opcode[2];\n        while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); }\n        l_opcode.swap(mp.opcode);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_vector_map_vss(_cimg_math_parser& mp) { // Operator(vector,scalar,scalar)\n        unsigned int\n          siz = (unsigned int)mp.opcode[2],\n          ptrs = (unsigned int)mp.opcode[4] + 1;\n        double *ptrd = &_mp_arg(1) + 1;\n        mp_func op = (mp_func)mp.opcode[3];\n        CImg<ulongT> l_opcode(1,5);\n        l_opcode[3] = mp.opcode[5]; // Scalar argument2\n        l_opcode[4] = mp.opcode[6]; // Scalar argument3\n        l_opcode.swap(mp.opcode);\n        ulongT &argument1 = mp.opcode[2];\n        while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); }\n        l_opcode.swap(mp.opcode);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_vector_map_vv(_cimg_math_parser& mp) { // Operator(vector,vector)\n        unsigned int\n          siz = (unsigned int)mp.opcode[2],\n          ptrs1 = (unsigned int)mp.opcode[4] + 1,\n          ptrs2 = (unsigned int)mp.opcode[5] + 1;\n        double *ptrd = &_mp_arg(1) + 1;\n        mp_func op = (mp_func)mp.opcode[3];\n        CImg<ulongT> l_opcode(1,4);\n        l_opcode.swap(mp.opcode);\n        ulongT &argument1 = mp.opcode[2], &argument2 = mp.opcode[3];\n        while (siz-->0) { argument1 = ptrs1++; argument2 = ptrs2++; *(ptrd++) = (*op)(mp); }\n        l_opcode.swap(mp.opcode);\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_vector_off(_cimg_math_parser& mp) {\n        const unsigned int\n          ptr = mp.opcode[2] + 1,\n          siz = (int)mp.opcode[3];\n        const int off = (int)_mp_arg(4);\n        return off>=0 && off<(int)siz?mp.mem[ptr + off]:cimg::type<double>::nan();\n      }\n\n      static double mp_vector_set_off(_cimg_math_parser& mp) {\n        const unsigned int\n          ptr = mp.opcode[2] + 1,\n          siz = mp.opcode[3];\n        const int off = (int)_mp_arg(4);\n        if (off>=0 && off<(int)siz) mp.mem[ptr + off] = _mp_arg(5);\n        return _mp_arg(5);\n      }\n\n      static double mp_vector_print(_cimg_math_parser& mp) {\n        CImg<charT> expr(mp.opcode._height - 3);\n        const ulongT *ptrs = mp.opcode._data + 3;\n        cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);\n        cimg::strellipsize(expr);\n        unsigned int\n          ptr = mp.opcode[1] + 1,\n          siz = mp.opcode[2];\n        std::fprintf(cimg::output(),\"\\n[_cimg_math_parser] %s = [\",expr._data);\n        while (siz-->0) std::fprintf(cimg::output(),\"%g%s\",mp.mem[ptr++],siz?\",\":\"\");\n        std::fputc(']',cimg::output());\n        std::fflush(cimg::output());\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_whiledo(_cimg_math_parser& mp) { // Used also by 'for()'\n        const ulongT\n          mem_proc = mp.opcode[1],\n          mem_cond = mp.opcode[2];\n        const CImg<ulongT>\n          *const p_cond = ++mp.p_code,\n          *const p_proc = p_cond + mp.opcode[3],\n          *const p_end = p_proc + mp.opcode[4];\n        const unsigned int vsiz = mp.opcode[5];\n        bool is_first_iter = true, is_cond = false;\n        do {\n          for (mp.p_code = p_cond; mp.p_code<p_proc; ++mp.p_code) { // Evaluate loop condition\n            const CImg<ulongT> &op = *mp.p_code;\n            mp.opcode._data = op._data; mp.opcode._height = op._height;\n            const ulongT target = mp.opcode[1];\n            mp.mem[target] = _cimg_mp_defunc(mp);\n          }\n          is_cond = (bool)mp.mem[mem_cond];\n          if (is_cond) { // Evaluate loop iteration\n            for ( ; mp.p_code<p_end; ++mp.p_code) {\n              const CImg<ulongT> &op = *mp.p_code;\n              mp.opcode._data = op._data; mp.opcode._height = op._height;\n              const ulongT target = mp.opcode[1];\n              mp.mem[target] = _cimg_mp_defunc(mp);\n            }\n            is_first_iter = false;\n          }\n        } while (is_cond);\n        mp.p_code = p_end - 1;\n        if (vsiz && is_first_iter) std::memset(&mp.mem[mem_proc] + 1,0,vsiz*sizeof(double));\n        return is_first_iter?0:mp.mem[mem_proc];\n      }\n\n      static double mp_Ioff(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const unsigned int\n          boundary_conditions = (unsigned int)_mp_arg(3);\n        const CImg<T> &img = mp.imgin;\n        const longT\n          off = (longT)_mp_arg(2),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const T *ptrs;\n        if (off<0 || off>=whd)\n          switch (boundary_conditions) {\n          case 2 : // Periodic boundary\n            if (!img) {\n              ptrs = &img[cimg::mod(off,whd)];\n              cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n            } else std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          case 1 : // Neumann boundary\n            if (img) {\n              ptrs = off<0?img._data:&img.back();\n              cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n            } else std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          default : // Dirichet boundary\n            std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          }\n        ptrs = &img[off];\n        cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_Ixyz(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const unsigned int\n          interpolation = (unsigned int)_mp_arg(5),\n          boundary_conditions = (unsigned int)_mp_arg(6);\n        const CImg<T> &img = mp.imgin;\n        const double x = _mp_arg(2), y = _mp_arg(3), z = _mp_arg(4);\n        if (interpolation==0) { // Nearest neighbor interpolation\n          if (boundary_conditions==2)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()),\n                                            cimg::mod((int)y,img.height()),\n                                            cimg::mod((int)z,img.depth()),\n                                            c);\n          else if (boundary_conditions==1)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c);\n          else\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0);\n        } else { // Linear interpolation\n          if (boundary_conditions==2)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()),\n                                                   cimg::mod((float)y,(float)img.height()),\n                                                   cimg::mod((float)z,(float)img.depth()),c);\n          else if (boundary_conditions==1)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c);\n          else\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0);\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_Joff(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const unsigned int\n          boundary_conditions = (unsigned int)_mp_arg(3);\n        const CImg<T> &img = mp.imgin;\n        const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z];\n        const longT\n          off = img.offset(ox,oy,oz) + (longT)_mp_arg(2),\n          whd = (longT)img.width()*img.height()*img.depth();\n        const T *ptrs;\n        if (off<0 || off>=whd)\n          switch (boundary_conditions) {\n          case 2 : // Periodic boundary\n            if (!img) {\n              ptrs = &img[cimg::mod(off,whd)];\n              cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n            } else std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          case 1 : // Neumann boundary\n            if (img) {\n              ptrs = off<0?img._data:&img.back();\n              cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n            } else std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          default : // Dirichet boundary\n            std::memset(ptrd,0,img._spectrum*sizeof(double));\n            return cimg::type<double>::nan();\n          }\n        ptrs = &img[off];\n        cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_Jxyz(_cimg_math_parser& mp) {\n        double *ptrd = &_mp_arg(1) + 1;\n        const unsigned int\n          interpolation = (unsigned int)_mp_arg(5),\n          boundary_conditions = (unsigned int)_mp_arg(6);\n        const CImg<T> &img = mp.imgin;\n        const double\n          ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z],\n          x = ox + _mp_arg(2), y = oy + _mp_arg(3), z = oz + _mp_arg(4);\n        if (interpolation==0) { // Nearest neighbor interpolation\n          if (boundary_conditions==2)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()),\n                                            cimg::mod((int)y,img.height()),\n                                            cimg::mod((int)z,img.depth()),\n                                            c);\n          else if (boundary_conditions==1)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c);\n          else\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0);\n        } else { // Linear interpolation\n          if (boundary_conditions==2)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()),\n                                                   cimg::mod((float)y,(float)img.height()),\n                                                   cimg::mod((float)z,(float)img.depth()),c);\n          else if (boundary_conditions==1)\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c);\n          else\n            cimg_forC(img,c)\n              *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0);\n        }\n        return cimg::type<double>::nan();\n      }\n\n#undef _mp_arg\n\n    }; // struct _cimg_math_parser {}\n\n    //! Compute the square value of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its square value \\f$I_{(x,y,z,c)}^2\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\");\n       (img,img.get_sqr().normalize(0,255)).display();\n       \\endcode\n       \\image html ref_sqr.jpg\n    **/\n    CImg<T>& sqr() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=524288)\n#endif\n      cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); };\n      return *this;\n    }\n\n    //! Compute the square value of each pixel value \\newinstance.\n    CImg<Tfloat> get_sqr() const {\n      return CImg<Tfloat>(*this,false).sqr();\n    }\n\n    //! Compute the square root of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its square root \\f$\\sqrt{I_{(x,y,z,c)}}\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\");\n       (img,img.get_sqrt().normalize(0,255)).display();\n       \\endcode\n       \\image html ref_sqrt.jpg\n    **/\n    CImg<T>& sqrt() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=8192)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the square root of each pixel value \\newinstance.\n    CImg<Tfloat> get_sqrt() const {\n      return CImg<Tfloat>(*this,false).sqrt();\n    }\n\n    //! Compute the exponential of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its exponential \\f$e^{I_{(x,y,z,c)}}\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& exp() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=4096)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::exp((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the exponential of each pixel value \\newinstance.\n    CImg<Tfloat> get_exp() const {\n      return CImg<Tfloat>(*this,false).exp();\n    }\n\n    //! Compute the logarithm of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its logarithm\n       \\f$\\mathrm{log}_{e}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& log() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=262144)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::log((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the logarithm of each pixel value \\newinstance.\n    CImg<Tfloat> get_log() const {\n      return CImg<Tfloat>(*this,false).log();\n    }\n\n    //! Compute the base-2 logarithm of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its base-2 logarithm\n       \\f$\\mathrm{log}_{2}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& log2() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=4096)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::log2((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the base-10 logarithm of each pixel value \\newinstance.\n    CImg<Tfloat> get_log2() const {\n      return CImg<Tfloat>(*this,false).log2();\n    }\n\n    //! Compute the base-10 logarithm of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its base-10 logarithm\n       \\f$\\mathrm{log}_{10}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& log10() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=4096)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the base-10 logarithm of each pixel value \\newinstance.\n    CImg<Tfloat> get_log10() const {\n      return CImg<Tfloat>(*this,false).log10();\n    }\n\n    //! Compute the absolute value of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its absolute value \\f$|I_{(x,y,z,c)}|\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& abs() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=524288)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = cimg::abs(*ptrd);\n      return *this;\n    }\n\n    //! Compute the absolute value of each pixel value \\newinstance.\n    CImg<Tfloat> get_abs() const {\n      return CImg<Tfloat>(*this,false).abs();\n    }\n\n    //! Compute the sign of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its sign\n       \\f$\\mathrm{sign}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The sign is set to:\n         - \\c 1 if pixel value is strictly positive.\n         - \\c -1 if pixel value is strictly negative.\n         - \\c 0 if pixel value is equal to \\c 0.\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& sign() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = cimg::sign(*ptrd);\n      return *this;\n    }\n\n    //! Compute the sign of each pixel value \\newinstance.\n    CImg<Tfloat> get_sign() const {\n      return CImg<Tfloat>(*this,false).sign();\n    }\n\n    //! Compute the cosine of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its cosine \\f$\\cos(I_{(x,y,z,c)})\\f$.\n       \\note\n       - Pixel values are regarded as being in \\e radian.\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& cos() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=8192)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the cosine of each pixel value \\newinstance.\n    CImg<Tfloat> get_cos() const {\n      return CImg<Tfloat>(*this,false).cos();\n    }\n\n    //! Compute the sine of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its sine \\f$\\sin(I_{(x,y,z,c)})\\f$.\n       \\note\n       - Pixel values are regarded as being in \\e radian.\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& sin() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=8192)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::sin((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the sine of each pixel value \\newinstance.\n    CImg<Tfloat> get_sin() const {\n      return CImg<Tfloat>(*this,false).sin();\n    }\n\n    //! Compute the sinc of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its sinc\n       \\f$\\mathrm{sinc}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - Pixel values are regarded as being exin \\e radian.\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& sinc() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=2048)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::sinc((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the sinc of each pixel value \\newinstance.\n    CImg<Tfloat> get_sinc() const {\n      return CImg<Tfloat>(*this,false).sinc();\n    }\n\n    //! Compute the tangent of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its tangent \\f$\\tan(I_{(x,y,z,c)})\\f$.\n       \\note\n       - Pixel values are regarded as being exin \\e radian.\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& tan() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=2048)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the tangent of each pixel value \\newinstance.\n    CImg<Tfloat> get_tan() const {\n      return CImg<Tfloat>(*this,false).tan();\n    }\n\n    //! Compute the hyperbolic cosine of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its hyperbolic cosine\n       \\f$\\mathrm{cosh}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& cosh() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=2048)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the hyperbolic cosine of each pixel value \\newinstance.\n    CImg<Tfloat> get_cosh() const {\n      return CImg<Tfloat>(*this,false).cosh();\n    }\n\n    //! Compute the hyperbolic sine of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its hyperbolic sine\n       \\f$\\mathrm{sinh}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& sinh() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=2048)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::sinh((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the hyperbolic sine of each pixel value \\newinstance.\n    CImg<Tfloat> get_sinh() const {\n      return CImg<Tfloat>(*this,false).sinh();\n    }\n\n    //! Compute the hyperbolic tangent of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its hyperbolic tangent\n       \\f$\\mathrm{tanh}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& tanh() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=2048)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the hyperbolic tangent of each pixel value \\newinstance.\n    CImg<Tfloat> get_tanh() const {\n      return CImg<Tfloat>(*this,false).tanh();\n    }\n\n    //! Compute the arccosine of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its arccosine\n       \\f$\\mathrm{acos}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& acos() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=8192)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the arccosine of each pixel value \\newinstance.\n    CImg<Tfloat> get_acos() const {\n      return CImg<Tfloat>(*this,false).acos();\n    }\n\n    //! Compute the arcsine of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its arcsine\n       \\f$\\mathrm{asin}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& asin() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=8192)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::asin((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the arcsine of each pixel value \\newinstance.\n    CImg<Tfloat> get_asin() const {\n      return CImg<Tfloat>(*this,false).asin();\n    }\n\n    //! Compute the arctangent of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its arctangent\n       \\f$\\mathrm{atan}(I_{(x,y,z,c)})\\f$.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n    **/\n    CImg<T>& atan() {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=8192)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd);\n      return *this;\n    }\n\n    //! Compute the arctangent of each pixel value \\newinstance.\n    CImg<Tfloat> get_atan() const {\n      return CImg<Tfloat>(*this,false).atan();\n    }\n\n    //! Compute the arctangent2 of each pixel value.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its arctangent2\n       \\f$\\mathrm{atan2}(I_{(x,y,z,c)})\\f$.\n       \\param img Image whose pixel values specify the second argument of the \\c atan2() function.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n       \\par Example\n       \\code\n       const CImg<float>\n          img_x(100,100,1,1,\"x-w/2\",false),   // Define an horizontal centered gradient, from '-width/2' to 'width/2'.\n          img_y(100,100,1,1,\"y-h/2\",false),   // Define a vertical centered gradient, from '-height/2' to 'height/2'.\n          img_atan2 = img_y.get_atan2(img_x); // Compute atan2(y,x) for each pixel value.\n       (img_x,img_y,img_atan2).display();\n       \\endcode\n    **/\n    template<typename t>\n    CImg<T>& atan2(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return atan2(+img);\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)std::atan2((double)*ptrd,(double)*(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)std::atan2((double)*ptrd,(double)*(ptrs++));\n      }\n      return *this;\n    }\n\n    //! Compute the arctangent2 of each pixel value \\newinstance.\n    template<typename t>\n    CImg<Tfloat> get_atan2(const CImg<t>& img) const {\n      return CImg<Tfloat>(*this,false).atan2(img);\n    }\n\n    //! In-place pointwise multiplication.\n    /**\n       Compute the pointwise multiplication between the image instance and the specified input image \\c img.\n       \\param img Input image, as the second operand of the multiplication.\n       \\note\n       - Similar to operator+=(const CImg<t>&), except that it performs a pointwise multiplication\n         instead of an addition.\n       - It does \\e not perform a \\e matrix multiplication. For this purpose, use operator*=(const CImg<t>&) instead.\n       \\par Example\n       \\code\n       CImg<float>\n         img(\"reference.jpg\"),\n         shade(img.width,img.height(),1,1,\"-(x-w/2)^2-(y-h/2)^2\",false);\n       shade.normalize(0,1);\n       (img,shade,img.get_mul(shade)).display();\n       \\endcode\n    **/\n    template<typename t>\n    CImg<T>& mul(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return mul(+img);\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)(*ptrd * *(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd * *(ptrs++));\n      }\n      return *this;\n    }\n\n    //! In-place pointwise multiplication \\newinstance.\n    template<typename t>\n    CImg<_cimg_Tt> get_mul(const CImg<t>& img) const {\n      return CImg<_cimg_Tt>(*this,false).mul(img);\n    }\n\n    //! In-place pointwise division.\n    /**\n       Similar to mul(const CImg<t>&), except that it performs a pointwise division instead of a multiplication.\n    **/\n    template<typename t>\n    CImg<T>& div(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return div(+img);\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)(*ptrd / *(ptrs++));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd / *(ptrs++));\n      }\n      return *this;\n    }\n\n    //! In-place pointwise division \\newinstance.\n    template<typename t>\n    CImg<_cimg_Tt> get_div(const CImg<t>& img) const {\n      return CImg<_cimg_Tt>(*this,false).div(img);\n    }\n\n    //! Raise each pixel value to a specified power.\n    /**\n       Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by its power \\f$I_{(x,y,z,c)}^p\\f$.\n       \\param p Exponent value.\n       \\note\n       - The \\inplace of this method statically casts the computed values to the pixel type \\c T.\n       - The \\newinstance returns a \\c CImg<float> image, if the pixel type \\c T is \\e not float-valued.\n       \\par Example\n       \\code\n       const CImg<float>\n         img0(\"reference.jpg\"),           // Load reference color image.\n         img1 = (img0/255).pow(1.8)*=255, // Compute gamma correction, with gamma = 1.8.\n         img2 = (img0/255).pow(0.5)*=255; // Compute gamma correction, with gamma = 0.5.\n       (img0,img1,img2).display();\n       \\endcode\n    **/\n    CImg<T>& pow(const double p) {\n      if (is_empty()) return *this;\n      if (p==-4) {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val*val)); }\n        return *this;\n      }\n      if (p==-3) {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val)); }\n        return *this;\n      }\n      if (p==-2) {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val)); }\n        return *this;\n      }\n      if (p==-1) {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/val); }\n        return *this;\n      }\n      if (p==-0.5) {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=8192)\n#endif\n        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1/std::sqrt((double)val)); }\n        return *this;\n      }\n      if (p==0) return fill(1);\n      if (p==0.5) return sqrt();\n      if (p==1) return *this;\n      if (p==2) return sqr();\n      if (p==3) {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=262144)\n#endif\n        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; }\n        return *this;\n      }\n      if (p==4) {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=131072)\n#endif\n        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; }\n        return *this;\n      }\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=1024)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p);\n      return *this;\n    }\n\n    //! Raise each pixel value to a specified power \\newinstance.\n    CImg<Tfloat> get_pow(const double p) const {\n      return CImg<Tfloat>(*this,false).pow(p);\n    }\n\n    //! Raise each pixel value to a power, specified from an expression.\n    /**\n       Similar to operator+=(const char*), except it performs a pointwise exponentiation instead of an addition.\n    **/\n    CImg<T>& pow(const char *const expression) {\n      return pow((+*this)._fill(expression,true,true,0,0,\"pow\",this));\n    }\n\n    //! Raise each pixel value to a power, specified from an expression \\newinstance.\n    CImg<Tfloat> get_pow(const char *const expression) const {\n      return CImg<Tfloat>(*this,false).pow(expression);\n    }\n\n    //! Raise each pixel value to a power, pointwisely specified from another image.\n    /**\n       Similar to operator+=(const CImg<t>& img), except that it performs an exponentiation instead of an addition.\n    **/\n    template<typename t>\n    CImg<T>& pow(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return pow(+img);\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));\n      }\n      return *this;\n    }\n\n    //! Raise each pixel value to a power, pointwisely specified from another image \\newinstance.\n    template<typename t>\n    CImg<Tfloat> get_pow(const CImg<t>& img) const {\n      return CImg<Tfloat>(*this,false).pow(img);\n    }\n\n    //! Compute the bitwise left rotation of each pixel value.\n    /**\n       Similar to operator<<=(unsigned int), except that it performs a left rotation instead of a left shift.\n    **/\n    CImg<T>& rol(const unsigned int n=1) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n);\n      return *this;\n    }\n\n    //! Compute the bitwise left rotation of each pixel value \\newinstance.\n    CImg<T> get_rol(const unsigned int n=1) const {\n      return (+*this).rol(n);\n    }\n\n    //! Compute the bitwise left rotation of each pixel value.\n    /**\n       Similar to operator<<=(const char*), except that it performs a left rotation instead of a left shift.\n    **/\n    CImg<T>& rol(const char *const expression) {\n      return rol((+*this)._fill(expression,true,true,0,0,\"rol\",this));\n    }\n\n    //! Compute the bitwise left rotation of each pixel value \\newinstance.\n    CImg<T> get_rol(const char *const expression) const {\n      return (+*this).rol(expression);\n    }\n\n    //! Compute the bitwise left rotation of each pixel value.\n    /**\n       Similar to operator<<=(const CImg<t>&), except that it performs a left rotation instead of a left shift.\n    **/\n    template<typename t>\n    CImg<T>& rol(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return rol(+img);\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)cimg::rol(*ptrd,(unsigned int)(*(ptrs++)));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)cimg::rol(*ptrd,(unsigned int)(*(ptrs++)));\n      }\n      return *this;\n    }\n\n    //! Compute the bitwise left rotation of each pixel value \\newinstance.\n    template<typename t>\n    CImg<T> get_rol(const CImg<t>& img) const {\n      return (+*this).rol(img);\n    }\n\n    //! Compute the bitwise right rotation of each pixel value.\n    /**\n       Similar to operator>>=(unsigned int), except that it performs a right rotation instead of a right shift.\n    **/\n    CImg<T>& ror(const unsigned int n=1) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n);\n      return *this;\n    }\n\n    //! Compute the bitwise right rotation of each pixel value \\newinstance.\n    CImg<T> get_ror(const unsigned int n=1) const {\n      return (+*this).ror(n);\n    }\n\n    //! Compute the bitwise right rotation of each pixel value.\n    /**\n       Similar to operator>>=(const char*), except that it performs a right rotation instead of a right shift.\n    **/\n    CImg<T>& ror(const char *const expression) {\n      return ror((+*this)._fill(expression,true,true,0,0,\"ror\",this));\n    }\n\n    //! Compute the bitwise right rotation of each pixel value \\newinstance.\n    CImg<T> get_ror(const char *const expression) const {\n      return (+*this).ror(expression);\n    }\n\n    //! Compute the bitwise right rotation of each pixel value.\n    /**\n       Similar to operator>>=(const CImg<t>&), except that it performs a right rotation instead of a right shift.\n    **/\n    template<typename t>\n    CImg<T>& ror(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return ror(+img);\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = (T)cimg::ror(*ptrd,(unsigned int)(*(ptrs++)));\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)cimg::ror(*ptrd,(unsigned int)(*(ptrs++)));\n      }\n      return *this;\n    }\n\n    //! Compute the bitwise right rotation of each pixel value \\newinstance.\n    template<typename t>\n    CImg<T> get_ror(const CImg<t>& img) const {\n      return (+*this).ror(img);\n    }\n\n    //! Pointwise min operator between instance image and a value.\n    /**\n       \\param val Value used as the reference argument of the min operator.\n       \\note Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by\n       \\f$\\mathrm{min}(I_{(x,y,z,c)},\\mathrm{val})\\f$.\n     **/\n    CImg<T>& min(const T& val) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=65536)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = cimg::min(*ptrd,val);\n      return *this;\n    }\n\n    //! Pointwise min operator between instance image and a value \\newinstance.\n    CImg<T> get_min(const T& val) const {\n      return (+*this).min(val);\n    }\n\n    //! Pointwise min operator between two images.\n    /**\n       \\param img Image used as the reference argument of the min operator.\n       \\note Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by\n       \\f$\\mathrm{min}(I_{(x,y,z,c)},\\mathrm{img}_{(x,y,z,c)})\\f$.\n     **/\n    template<typename t>\n    CImg<T>& min(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return min(+img);\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = cimg::min((T)*(ptrs++),*ptrd);\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = cimg::min((T)*(ptrs++),*ptrd);\n      }\n      return *this;\n    }\n\n    //! Pointwise min operator between two images \\newinstance.\n    template<typename t>\n    CImg<_cimg_Tt> get_min(const CImg<t>& img) const {\n      return CImg<_cimg_Tt>(*this,false).min(img);\n    }\n\n    //! Pointwise min operator between an image and an expression.\n    /**\n       \\param expression Math formula as a C-string.\n       \\note Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by\n       \\f$\\mathrm{min}(I_{(x,y,z,c)},\\mathrm{expr}_{(x,y,z,c)})\\f$.\n    **/\n    CImg<T>& min(const char *const expression) {\n      return min((+*this)._fill(expression,true,true,0,0,\"min\",this));\n    }\n\n    //! Pointwise min operator between an image and an expression \\newinstance.\n    CImg<Tfloat> get_min(const char *const expression) const {\n      return CImg<Tfloat>(*this,false).min(expression);\n    }\n\n    //! Pointwise max operator between instance image and a value.\n    /**\n       \\param val Value used as the reference argument of the max operator.\n       \\note Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by\n       \\f$\\mathrm{max}(I_{(x,y,z,c)},\\mathrm{val})\\f$.\n     **/\n    CImg<T>& max(const T& val) {\n      if (is_empty()) return *this;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=65536)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = cimg::max(*ptrd,val);\n      return *this;\n    }\n\n    //! Pointwise max operator between instance image and a value \\newinstance.\n    CImg<T> get_max(const T& val) const {\n      return (+*this).max(val);\n    }\n\n    //! Pointwise max operator between two images.\n    /**\n       \\param img Image used as the reference argument of the max operator.\n       \\note Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by\n       \\f$\\mathrm{max}(I_{(x,y,z,c)},\\mathrm{img}_{(x,y,z,c)})\\f$.\n     **/\n    template<typename t>\n    CImg<T>& max(const CImg<t>& img) {\n      const ulongT siz = size(), isiz = img.size();\n      if (siz && isiz) {\n        if (is_overlapped(img)) return max(+img);\n        T *ptrd = _data, *const ptre = _data + siz;\n        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)\n          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)\n            *ptrd = cimg::max((T)*(ptrs++),*ptrd);\n        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = cimg::max((T)*(ptrs++),*ptrd);\n      }\n      return *this;\n    }\n\n    //! Pointwise max operator between two images \\newinstance.\n    template<typename t>\n    CImg<_cimg_Tt> get_max(const CImg<t>& img) const {\n      return CImg<_cimg_Tt>(*this,false).max(img);\n    }\n\n    //! Pointwise max operator between an image and an expression.\n    /**\n       \\param expression Math formula as a C-string.\n       \\note Replace each pixel value \\f$I_{(x,y,z,c)}\\f$ of the image instance by\n       \\f$\\mathrm{max}(I_{(x,y,z,c)},\\mathrm{expr}_{(x,y,z,c)})\\f$.\n    **/\n    CImg<T>& max(const char *const expression) {\n      return max((+*this)._fill(expression,true,true,0,0,\"max\",this));\n    }\n\n    //! Pointwise max operator between an image and an expression \\newinstance.\n    CImg<Tfloat> get_max(const char *const expression) const {\n      return CImg<Tfloat>(*this,false).max(expression);\n    }\n\n    //! Return a reference to the minimum pixel value.\n    /**\n     **/\n    T& min() {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"min(): Empty instance.\",\n                                    cimg_instance);\n      T *ptr_min = _data;\n      T min_value = *ptr_min;\n      cimg_for(*this,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs);\n      return *ptr_min;\n    }\n\n    //! Return a reference to the minimum pixel value \\const.\n    const T& min() const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"min(): Empty instance.\",\n                                    cimg_instance);\n      const T *ptr_min = _data;\n      T min_value = *ptr_min;\n      cimg_for(*this,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs);\n      return *ptr_min;\n    }\n\n    //! Return a reference to the maximum pixel value.\n    /**\n     **/\n    T& max() {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"max(): Empty instance.\",\n                                    cimg_instance);\n      T *ptr_max = _data;\n      T max_value = *ptr_max;\n      cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);\n      return *ptr_max;\n    }\n\n    //! Return a reference to the maximum pixel value \\const.\n    const T& max() const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"max(): Empty instance.\",\n                                    cimg_instance);\n      const T *ptr_max = _data;\n      T max_value = *ptr_max;\n      cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);\n      return *ptr_max;\n    }\n\n    //! Return a reference to the minimum pixel value as well as the maximum pixel value.\n    /**\n       \\param[out] max_val Maximum pixel value.\n    **/\n    template<typename t>\n    T& min_max(t& max_val) {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"min_max(): Empty instance.\",\n                                    cimg_instance);\n      T *ptr_min = _data;\n      T min_value = *ptr_min, max_value = min_value;\n      cimg_for(*this,ptrs,T) {\n        const T val = *ptrs;\n        if (val<min_value) { min_value = val; ptr_min = ptrs; }\n        if (val>max_value) max_value = val;\n      }\n      max_val = (t)max_value;\n      return *ptr_min;\n    }\n\n    //! Return a reference to the minimum pixel value as well as the maximum pixel value \\const.\n    template<typename t>\n    const T& min_max(t& max_val) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"min_max(): Empty instance.\",\n                                    cimg_instance);\n      const T *ptr_min = _data;\n      T min_value = *ptr_min, max_value = min_value;\n      cimg_for(*this,ptrs,T) {\n        const T val = *ptrs;\n        if (val<min_value) { min_value = val; ptr_min = ptrs; }\n        if (val>max_value) max_value = val;\n      }\n      max_val = (t)max_value;\n      return *ptr_min;\n    }\n\n    //! Return a reference to the maximum pixel value as well as the minimum pixel value.\n    /**\n       \\param[out] min_val Minimum pixel value.\n    **/\n    template<typename t>\n    T& max_min(t& min_val) {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"max_min(): Empty instance.\",\n                                    cimg_instance);\n      T *ptr_max = _data;\n      T max_value = *ptr_max, min_value = max_value;\n      cimg_for(*this,ptrs,T) {\n        const T val = *ptrs;\n        if (val>max_value) { max_value = val; ptr_max = ptrs; }\n        if (val<min_value) min_value = val;\n      }\n      min_val = (t)min_value;\n      return *ptr_max;\n    }\n\n    //! Return a reference to the maximum pixel value as well as the minimum pixel value \\const.\n    template<typename t>\n    const T& max_min(t& min_val) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"max_min(): Empty instance.\",\n                                    cimg_instance);\n      const T *ptr_max = _data;\n      T max_value = *ptr_max, min_value = max_value;\n      cimg_for(*this,ptrs,T) {\n        const T val = *ptrs;\n        if (val>max_value) { max_value = val; ptr_max = ptrs; }\n        if (val<min_value) min_value = val;\n      }\n      min_val = (t)min_value;\n      return *ptr_max;\n    }\n\n    //! Return the kth smallest pixel value.\n    /**\n       \\param k Rank of the search smallest element.\n    **/\n    T kth_smallest(const unsigned int k) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"kth_smallest(): Empty instance.\",\n                                    cimg_instance);\n      CImg<T> arr(*this);\n      unsigned int l = 0, ir = size() - 1;\n      for ( ; ; ) {\n        if (ir<=l + 1) {\n          if (ir==l + 1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);\n          return arr[k];\n        } else {\n          const unsigned int mid = (l + ir)>>1;\n          cimg::swap(arr[mid],arr[l + 1]);\n          if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);\n          if (arr[l + 1]>arr[ir]) cimg::swap(arr[l + 1],arr[ir]);\n          if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]);\n          unsigned int i = l + 1, j = ir;\n          const T pivot = arr[l + 1];\n          for ( ; ; ) {\n            do ++i; while (arr[i]<pivot);\n            do --j; while (arr[j]>pivot);\n            if (j<i) break;\n            cimg::swap(arr[i],arr[j]);\n          }\n          arr[l + 1] = arr[j];\n          arr[j] = pivot;\n          if (j>=k) ir = j - 1;\n          if (j<=k) l = i;\n        }\n      }\n    }\n\n    //! Return the median pixel value.\n    /**\n     **/\n    T median() const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"median(): Empty instance.\",\n                                    cimg_instance);\n      const unsigned int s = size();\n      const T res = kth_smallest(s>>1);\n      return (s%2)?res:((res + kth_smallest((s>>1) - 1))/2);\n    }\n\n    //! Return the product of all the pixel values.\n    /**\n     **/\n    double product() const {\n      if (is_empty()) return 0;\n      double res = 1;\n      cimg_for(*this,ptrs,T) res*=(double)*ptrs;\n      return res;\n    }\n\n    //! Return the sum of all the pixel values.\n    /**\n     **/\n    double sum() const {\n      double res = 0;\n      cimg_for(*this,ptrs,T) res+=(double)*ptrs;\n      return res;\n    }\n\n    //! Return the average pixel value.\n    /**\n     **/\n    double mean() const {\n      double res = 0;\n      cimg_for(*this,ptrs,T) res+=(double)*ptrs;\n      return res/size();\n    }\n\n    //! Return the variance of the pixel values.\n    /**\n       \\param variance_method Method used to estimate the variance. Can be:\n       - \\c 0: Second moment, computed as\n       \\f$1/N \\sum\\limits_{k=1}^{N} (x_k - \\bar x)^2 =\n       1/N \\left( \\sum\\limits_{k=1}^N x_k^2 - \\left( \\sum\\limits_{k=1}^N x_k \\right)^2 / N \\right)\\f$\n       with \\f$ \\bar x = 1/N \\sum\\limits_{k=1}^N x_k \\f$.\n       - \\c 1: Best unbiased estimator, computed as \\f$\\frac{1}{N - 1} \\sum\\limits_{k=1}^{N} (x_k - \\bar x)^2 \\f$.\n       - \\c 2: Least median of squares.\n       - \\c 3: Least trimmed of squares.\n    **/\n    double variance(const unsigned int variance_method=1) const {\n      double foo;\n      return variance_mean(variance_method,foo);\n    }\n\n    //! Return the variance as well as the average of the pixel values.\n    /**\n       \\param variance_method Method used to estimate the variance (see variance(const unsigned int) const).\n       \\param[out] mean Average pixel value.\n    **/\n    template<typename t>\n    double variance_mean(const unsigned int variance_method, t& mean) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"variance_mean(): Empty instance.\",\n                                    cimg_instance);\n\n      double variance = 0, average = 0;\n      const ulongT siz = size();\n      switch (variance_method) {\n      case 0 : { // Least mean square (standard definition)\n        double S = 0, S2 = 0;\n        cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; }\n        variance = (S2 - S*S/siz)/siz;\n        average = S;\n      } break;\n      case 1 : { // Least mean square (robust definition)\n        double S = 0, S2 = 0;\n        cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; }\n        variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;\n        average = S;\n      } break;\n      case 2 : { // Least Median of Squares (MAD)\n        CImg<Tfloat> buf(*this,false);\n        buf.sort();\n        const ulongT siz2 = siz>>1;\n        const double med_i = (double)buf[siz2];\n        cimg_for(buf,ptrs,Tfloat) {\n          const double val = (double)*ptrs; *ptrs = (Tfloat)cimg::abs(val - med_i); average+=val;\n        }\n        buf.sort();\n        const double sig = (double)(1.4828*buf[siz2]);\n        variance = sig*sig;\n      } break;\n      default : { // Least trimmed of Squares\n        CImg<Tfloat> buf(*this,false);\n        const ulongT siz2 = siz>>1;\n        cimg_for(buf,ptrs,Tfloat) {\n          const double val = (double)*ptrs; (*ptrs)=(Tfloat)((*ptrs)*val); average+=val;\n        }\n        buf.sort();\n        double a = 0;\n        const Tfloat *ptrs = buf._data;\n        for (ulongT j = 0; j<siz2; ++j) a+=(double)*(ptrs++);\n        const double sig = (double)(2.6477*std::sqrt(a/siz2));\n        variance = sig*sig;\n      }\n      }\n      mean = (t)(average/siz);\n      return variance>0?variance:0;\n    }\n\n    //! Return estimated variance of the noise.\n    /**\n       \\param variance_method Method used to compute the variance (see variance(const unsigned int) const).\n       \\note Because of structures such as edges in images it is\n       recommanded to use a robust variance estimation. The variance of the\n       noise is estimated by computing the variance of the Laplacian \\f$(\\Delta\n       I)^2 \\f$ scaled by a factor \\f$c\\f$ insuring \\f$ c E[(\\Delta I)^2]=\n       \\sigma^2\\f$ where \\f$\\sigma\\f$ is the noise variance.\n    **/\n    double variance_noise(const unsigned int variance_method=2) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"variance_noise(): Empty instance.\",\n                                    cimg_instance);\n\n      const ulongT siz = size();\n      if (!siz || !_data) return 0;\n      if (variance_method>1) { // Compute a scaled version of the Laplacian.\n        CImg<Tdouble> tmp(*this);\n        if (_depth==1) {\n          const double cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed.\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height>=262144 && _spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            CImg_3x3(I,T);\n            cimg_for3x3(*this,x,y,0,c,I,T) {\n              tmp(x,y,c) = cste*((double)Inc + (double)Ipc + (double)Icn +\n                                 (double)Icp - 4*(double)Icc);\n            }\n          }\n        } else {\n          const double cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed.\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=262144 && _spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            CImg_3x3x3(I,T);\n            cimg_for3x3x3(*this,x,y,z,c,I,T) {\n              tmp(x,y,z,c) = cste*(\n                                   (double)Incc + (double)Ipcc + (double)Icnc + (double)Icpc +\n                                   (double)Iccn + (double)Iccp - 6*(double)Iccc);\n            }\n          }\n        }\n        return tmp.variance(variance_method);\n      }\n\n      // Version that doesn't need intermediate images.\n      double variance = 0, S = 0, S2 = 0;\n      if (_depth==1) {\n        const double cste = 1.0/std::sqrt(20.0);\n        CImg_3x3(I,T);\n        cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) {\n          const double val = cste*((double)Inc + (double)Ipc +\n                                   (double)Icn + (double)Icp - 4*(double)Icc);\n          S+=val; S2+=val*val;\n        }\n      } else {\n        const double cste = 1.0/std::sqrt(42.0);\n        CImg_3x3x3(I,T);\n        cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,T) {\n          const double val = cste *\n            ((double)Incc + (double)Ipcc + (double)Icnc +\n             (double)Icpc +\n             (double)Iccn + (double)Iccp - 6*(double)Iccc);\n          S+=val; S2+=val*val;\n        }\n      }\n      if (variance_method) variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;\n      else variance = (S2 - S*S/siz)/siz;\n      return variance>0?variance:0;\n    }\n\n    //! Compute the MSE (Mean-Squared Error) between two images.\n    /**\n       \\param img Image used as the second argument of the MSE operator.\n    **/\n    template<typename t>\n    double MSE(const CImg<t>& img) const {\n      if (img.size()!=size())\n        throw CImgArgumentException(_cimg_instance\n                                    \"MSE(): Instance and specified image (%u,%u,%u,%u,%p) have different dimensions.\",\n                                    cimg_instance,\n                                    img._width,img._height,img._depth,img._spectrum,img._data);\n      double vMSE = 0;\n      const t* ptr2 = img._data;\n      cimg_for(*this,ptr1,T) {\n        const double diff = (double)*ptr1 - (double)*(ptr2++);\n        vMSE+=diff*diff;\n      }\n      const ulongT siz = img.size();\n      if (siz) vMSE/=siz;\n      return vMSE;\n    }\n\n    //! Compute the PSNR (Peak Signal-to-Noise Ratio) between two images.\n    /**\n       \\param img Image used as the second argument of the PSNR operator.\n       \\param max_value Maximum theoretical value of the signal.\n     **/\n    template<typename t>\n    double PSNR(const CImg<t>& img, const double max_value=255) const {\n      const double vMSE = (double)std::sqrt(MSE(img));\n      return (vMSE!=0)?(double)(20*std::log10(max_value/vMSE)):(double)(cimg::type<double>::max());\n    }\n\n    //! Evaluate math formula.\n    /**\n       \\param expression Math formula, as a C-string.\n       \\param x Value of the pre-defined variable \\c x.\n       \\param y Value of the pre-defined variable \\c y.\n       \\param z Value of the pre-defined variable \\c z.\n       \\param c Value of the pre-defined variable \\c c.\n       \\param list_inputs A list of input images attached to the specified math formula.\n       \\param list_outputs A pointer to a list of output images attached to the specified math formula.\n    **/\n    double eval(const char *const expression,\n                const double x=0, const double y=0, const double z=0, const double c=0,\n                const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {\n      return _eval(this,expression,x,y,z,c,list_inputs,list_outputs);\n    }\n\n    //! Evaluate math formula \\const.\n    double eval(const char *const expression,\n                const double x=0, const double y=0, const double z=0, const double c=0,\n                const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {\n      return _eval(0,expression,x,y,z,c,list_inputs,list_outputs);\n    }\n\n    double _eval(CImg<T> *const img_output, const char *const expression,\n                 const double x, const double y, const double z, const double c,\n                 const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const {\n      if (!expression) return 0;\n      if (!expression[1]) switch (*expression) { // Single-char optimization.\n        case 'w' : return (double)_width;\n        case 'h' : return (double)_height;\n        case 'd' : return (double)_depth;\n        case 's' : return (double)_spectrum;\n        case 'r' : return (double)_is_shared;\n        }\n      _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||\n                                         *expression=='*' || *expression==':'?1:0),\"eval\",\n                           *this,img_output,list_inputs,list_outputs);\n      return mp(x,y,z,c);\n    }\n\n    //! Evaluate math formula.\n    /**\n       \\param[out] output Contains values of output vector returned by the evaluated expression\n         (or is empty if the returned type is scalar).\n       \\param expression Math formula, as a C-string.\n       \\param x Value of the pre-defined variable \\c x.\n       \\param y Value of the pre-defined variable \\c y.\n       \\param z Value of the pre-defined variable \\c z.\n       \\param c Value of the pre-defined variable \\c c.\n       \\param list_inputs A list of input images attached to the specified math formula.\n       \\param list_outputs A pointer to a list of output images attached to the specified math formula.\n    **/\n    template<typename t>\n    void eval(CImg<t> &output, const char *const expression,\n              const double x=0, const double y=0, const double z=0, const double c=0,\n              const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {\n      _eval(output,this,expression,x,y,z,c,list_inputs,list_outputs);\n    }\n\n    //! Evaluate math formula \\const.\n    template<typename t>\n    void eval(CImg<t>& output, const char *const expression,\n              const double x=0, const double y=0, const double z=0, const double c=0,\n              const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {\n      _eval(output,0,expression,x,y,z,c,list_inputs,list_outputs);\n    }\n\n    template<typename t>\n    void _eval(CImg<t>& output, CImg<T> *const img_output, const char *const expression,\n               const double x, const double y, const double z, const double c,\n               const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const {\n      if (!expression) { output.assign(1); *output = 0; }\n      if (!expression[1]) switch (*expression) { // Single-char optimization.\n        case 'w' : output.assign(1); *output = (t)_width;\n        case 'h' : output.assign(1); *output = (t)_height;\n        case 'd' : output.assign(1); *output = (t)_depth;\n        case 's' : output.assign(1); *output = (t)_spectrum;\n        case 'r' : output.assign(1); *output = (t)_is_shared;\n        }\n      _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||\n                                         *expression=='*' || *expression==':'?1:0),\"eval\",\n                           *this,img_output,list_inputs,list_outputs);\n      output.assign(1,cimg::max(1U,mp.result_dim));\n      mp(x,y,z,c,output._data);\n    }\n\n    //! Evaluate math formula on a set of variables.\n    /**\n       \\param expression Math formula, as a C-string.\n       \\param xyzc Set of values (x,y,z,c) used for the evaluation.\n    **/\n    template<typename t>\n    CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc,\n                       const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {\n      return _eval(this,expression,xyzc,list_inputs,list_outputs);\n    }\n\n    //! Evaluate math formula on a set of variables \\const.\n    template<typename t>\n    CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc,\n                       const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {\n      return _eval(0,expression,xyzc,list_inputs,list_outputs);\n    }\n\n    template<typename t>\n    CImg<doubleT> _eval(CImg<T> *const output, const char *const expression, const CImg<t>& xyzc,\n                        const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {\n      CImg<doubleT> res(1,xyzc.size()/4);\n      if (!expression) return res.fill(0);\n      _cimg_math_parser mp(expression,\"eval\",*this,output,list_inputs,list_outputs);\n#ifdef cimg_use_openmp\n#pragma omp parallel if (res._height>=512 && std::strlen(expression)>=6)\n      {\n        _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;\n#pragma omp for\n        for (unsigned int i = 0; i<res._height; ++i) {\n          const unsigned int i4 = 4*i;\n          const double\n            x = (double)xyzc[i4], y = (double)xyzc[i4 + 1],\n            z = (double)xyzc[i4 + 2], c = (double)xyzc[i4 + 3];\n          res[i] = lmp(x,y,z,c);\n        }\n      }\n#else\n      const t *ps = xyzc._data;\n      cimg_for(res,pd,double) {\n        const double x = (double)*(ps++), y = (double)*(ps++), z = (double)*(ps++), c = (double)*(ps++);\n        *pd = mp(x,y,z,c);\n      }\n#endif\n      return res;\n    }\n\n    //! Compute statistics vector from the pixel values.\n    /*\n       \\param variance_method Method used to compute the variance (see variance(const unsigned int) const).\n       \\return Statistics vector as\n         <tt>[min; max; mean; variance; xmin; ymin; zmin; cmin; xmax; ymax; zmax; cmax; sum; product]</tt>.\n    **/\n    CImg<Tdouble> get_stats(const unsigned int variance_method=1) const {\n      if (is_empty()) return CImg<doubleT>();\n      const ulongT siz = size();\n      const T *const odata = _data;\n      const T *pm = odata, *pM = odata;\n      double S = 0, S2 = 0, P = _data?1:0;\n      T m = *pm, M = m;\n      cimg_for(*this,ptrs,T) {\n        const T val = *ptrs;\n        const double _val = (double)val;\n        if (val<m) { m = val; pm = ptrs; }\n        if (val>M) { M = val; pM = ptrs; }\n        S+=_val;\n        S2+=_val*_val;\n        P*=_val;\n      }\n      const double\n        mean_value = S/siz,\n        _variance_value = variance_method==0?(S2 - S*S/siz)/siz:\n        (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0):\n         variance(variance_method)),\n        variance_value = _variance_value>0?_variance_value:0;\n      int\n        xm = 0, ym = 0, zm = 0, cm = 0,\n        xM = 0, yM = 0, zM = 0, cM = 0;\n      contains(*pm,xm,ym,zm,cm);\n      contains(*pM,xM,yM,zM,cM);\n      return CImg<Tdouble>(1,14).fill((double)m,(double)M,mean_value,variance_value,\n                                      (double)xm,(double)ym,(double)zm,(double)cm,\n                                      (double)xM,(double)yM,(double)zM,(double)cM,\n                                      S,P);\n    }\n\n    //! Compute statistics vector from the pixel values \\inplace.\n    CImg<T>& stats(const unsigned int variance_method=1) {\n      return get_stats(variance_method).move_to(*this);\n    }\n\n    //@}\n    //-------------------------------------\n    //\n    //! \\name Vector / Matrix Operations\n    //@{\n    //-------------------------------------\n\n    //! Compute norm of the image, viewed as a matrix.\n    /**\n       \\param magnitude_type Norm type. Can be:\n       - \\c -1: Linf-norm\n       - \\c 0: L2-norm\n       - \\c 1: L1-norm\n    **/\n    double magnitude(const int magnitude_type=2) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"magnitude(): Empty instance.\",\n                                    cimg_instance);\n      double res = 0;\n      switch (magnitude_type) {\n      case -1 : {\n        cimg_for(*this,ptrs,T) { const double val = (double)cimg::abs(*ptrs); if (val>res) res = val; }\n      } break;\n      case 1 : {\n        cimg_for(*this,ptrs,T) res+=(double)cimg::abs(*ptrs);\n      } break;\n      default : {\n        cimg_for(*this,ptrs,T) res+=(double)cimg::sqr(*ptrs);\n        res = (double)std::sqrt(res);\n      }\n      }\n      return res;\n    }\n\n    //! Compute the trace of the image, viewed as a matrix.\n    /**\n     **/\n    double trace() const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"trace(): Empty instance.\",\n                                    cimg_instance);\n      double res = 0;\n      cimg_forX(*this,k) res+=(double)(*this)(k,k);\n      return res;\n    }\n\n    //! Compute the determinant of the image, viewed as a matrix.\n    /**\n     **/\n    double det() const {\n      if (is_empty() || _width!=_height || _depth!=1 || _spectrum!=1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"det(): Instance is not a square matrix.\",\n                                    cimg_instance);\n\n      switch (_width) {\n      case 1 : return (double)((*this)(0,0));\n      case 2 : return (double)((*this)(0,0))*(double)((*this)(1,1)) - (double)((*this)(0,1))*(double)((*this)(1,0));\n      case 3 : {\n        const double\n          a = (double)_data[0], d = (double)_data[1], g = (double)_data[2],\n          b = (double)_data[3], e = (double)_data[4], h = (double)_data[5],\n          c = (double)_data[6], f = (double)_data[7], i = (double)_data[8];\n        return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;\n      }\n      default : {\n        CImg<Tfloat> lu(*this);\n        CImg<uintT> indx;\n        bool d;\n        lu._LU(indx,d);\n        double res = d?(double)1:(double)-1;\n        cimg_forX(lu,i) res*=lu(i,i);\n        return res;\n      }\n      }\n    }\n\n    //! Compute the dot product between instance and argument, viewed as matrices.\n    /**\n       \\param img Image used as a second argument of the dot product.\n    **/\n    template<typename t>\n    double dot(const CImg<t>& img) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"dot(): Empty instance.\",\n                                    cimg_instance);\n      if (!img)\n        throw CImgArgumentException(_cimg_instance\n                                    \"dot(): Empty specified image.\",\n                                    cimg_instance);\n\n      const ulongT nb = cimg::min(size(),img.size());\n      double res = 0;\n      for (ulongT off = 0; off<nb; ++off) res+=(double)_data[off]*(double)img[off];\n      return res;\n    }\n\n    //! Get vector-valued pixel located at specified position.\n    /**\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n    **/\n    CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {\n      CImg<T> res;\n      if (res._height!=_spectrum) res.assign(1,_spectrum);\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      const T *ptrs = data(x,y,z);\n      T *ptrd = res._data;\n      cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n      return res;\n    }\n\n    //! Get (square) matrix-valued pixel located at specified position.\n    /**\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\note - The spectrum() of the image must be a square.\n     **/\n    CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {\n      const int n = (int)std::sqrt((double)_spectrum);\n      const T *ptrs = data(x,y,z,0);\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      CImg<T> res(n,n);\n      T *ptrd = res._data;\n      cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; }\n      return res;\n    }\n\n    //! Get tensor-valued pixel located at specified position.\n    /**\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n    **/\n    CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {\n      const T *ptrs = data(x,y,z,0);\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      if (_spectrum==6)\n        return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd),*(ptrs + 3*whd),*(ptrs + 4*whd),*(ptrs + 5*whd));\n      if (_spectrum==3)\n        return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd));\n      return tensor(*ptrs);\n    }\n\n    //! Set vector-valued pixel at specified position.\n    /**\n       \\param vec Vector to put on the instance image.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n    **/\n    template<typename t>\n    CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) {\n      if (x<_width && y<_height && z<_depth) {\n        const t *ptrs = vec._data;\n        const ulongT whd = (ulongT)_width*_height*_depth;\n        T *ptrd = data(x,y,z);\n        for (unsigned int k = cimg::min((unsigned int)vec.size(),_spectrum); k; --k) {\n          *ptrd = (T)*(ptrs++); ptrd+=whd;\n        }\n      }\n      return *this;\n    }\n\n    //! Set (square) matrix-valued pixel at specified position.\n    /**\n       \\param mat Matrix to put on the instance image.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n    **/\n    template<typename t>\n    CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {\n      return set_vector_at(mat,x,y,z);\n    }\n\n    //! Set tensor-valued pixel at specified position.\n    /**\n       \\param ten Tensor to put on the instance image.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n    **/\n    template<typename t>\n    CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {\n      T *ptrd = data(x,y,z,0);\n      const ulongT siz = (ulongT)_width*_height*_depth;\n      if (ten._height==2) {\n        *ptrd = (T)ten[0]; ptrd+=siz;\n        *ptrd = (T)ten[1]; ptrd+=siz;\n        *ptrd = (T)ten[3];\n      }\n      else {\n        *ptrd = (T)ten[0]; ptrd+=siz;\n        *ptrd = (T)ten[1]; ptrd+=siz;\n        *ptrd = (T)ten[2]; ptrd+=siz;\n        *ptrd = (T)ten[4]; ptrd+=siz;\n        *ptrd = (T)ten[5]; ptrd+=siz;\n        *ptrd = (T)ten[8];\n      }\n      return *this;\n    }\n\n    //! Unroll pixel values along axis \\c y.\n    /**\n       \\note Equivalent to \\code unroll('y'); \\endcode.\n    **/\n    CImg<T>& vector() {\n      return unroll('y');\n    }\n\n    //! Unroll pixel values along axis \\c y \\newinstance.\n    CImg<T> get_vector() const {\n      return get_unroll('y');\n    }\n\n    //! Resize image to become a scalar square matrix.\n    /**\n     **/\n    CImg<T>& matrix() {\n      const ulongT siz = size();\n      switch (siz) {\n      case 1 : break;\n      case 4 : _width = _height = 2; break;\n      case 9 : _width = _height = 3; break;\n      case 16 : _width = _height = 4; break;\n      case 25 : _width = _height = 5; break;\n      case 36 : _width = _height = 6; break;\n      case 49 : _width = _height = 7; break;\n      case 64 : _width = _height = 8; break;\n      case 81 : _width = _height = 9; break;\n      case 100 : _width = _height = 10; break;\n      default : {\n        ulongT i = 11, i2 = i*i;\n        while (i2<siz) { i2+=2*i + 1; ++i; }\n        if (i2==siz) _width = _height = i;\n        else throw CImgInstanceException(_cimg_instance\n                                         \"matrix(): Invalid instance size %u (should be a square integer).\",\n                                         cimg_instance,\n                                         siz);\n      }\n      }\n      return *this;\n    }\n\n    //! Resize image to become a scalar square matrix \\newinstance.\n    CImg<T> get_matrix() const {\n      return (+*this).matrix();\n    }\n\n    //! Resize image to become a symmetric tensor.\n    /**\n     **/\n    CImg<T>& tensor() {\n      return get_tensor().move_to(*this);\n    }\n\n    //! Resize image to become a symmetric tensor \\newinstance.\n    CImg<T> get_tensor() const {\n      CImg<T> res;\n      const ulongT siz = size();\n      switch (siz) {\n      case 1 : break;\n      case 3 :\n        res.assign(2,2);\n        res(0,0) = (*this)(0);\n        res(1,0) = res(0,1) = (*this)(1);\n        res(1,1) = (*this)(2);\n        break;\n      case 6 :\n        res.assign(3,3);\n        res(0,0) = (*this)(0);\n        res(1,0) = res(0,1) = (*this)(1);\n        res(2,0) = res(0,2) = (*this)(2);\n        res(1,1) = (*this)(3);\n        res(2,1) = res(1,2) = (*this)(4);\n        res(2,2) = (*this)(5);\n        break;\n      default :\n        throw CImgInstanceException(_cimg_instance\n                                    \"tensor(): Invalid instance size (does not define a 1x1, 2x2 or 3x3 tensor).\",\n                                    cimg_instance);\n      }\n      return res;\n    }\n\n    //! Resize image to become a diagonal matrix.\n    /**\n       \\note Transform the image as a diagonal matrix so that each of its initial value becomes a diagonal coefficient.\n    **/\n    CImg<T>& diagonal() {\n      return get_diagonal().move_to(*this);\n    }\n\n    //! Resize image to become a diagonal matrix \\newinstance.\n    CImg<T> get_diagonal() const {\n      if (is_empty()) return *this;\n      CImg<T> res(size(),size(),1,1,0);\n      cimg_foroff(*this,off) res(off,off) = (*this)(off);\n      return res;\n    }\n\n    //! Replace the image by an identity matrix.\n    /**\n       \\note If the instance image is not square, it is resized to a square matrix using its maximum\n       dimension as a reference.\n    **/\n    CImg<T>& identity_matrix() {\n      return identity_matrix(cimg::max(_width,_height)).move_to(*this);\n    }\n\n    //! Replace the image by an identity matrix \\newinstance.\n    CImg<T> get_identity_matrix() const {\n      return identity_matrix(cimg::max(_width,_height));\n    }\n\n    //! Fill image with a linear sequence of values.\n    /**\n       \\param a0 Starting value of the sequence.\n       \\param a1 Ending value of the sequence.\n    **/\n    CImg<T>& sequence(const T& a0, const T& a1) {\n      if (is_empty()) return *this;\n      const unsigned int siz = size() - 1;\n      T* ptr = _data;\n      if (siz) {\n        const double delta = (double)a1 - (double)a0;\n        cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);\n      } else *ptr = a0;\n      return *this;\n    }\n\n    //! Fill image with a linear sequence of values \\newinstance.\n    CImg<T> get_sequence(const T& a0, const T& a1) const {\n      return (+*this).sequence(a0,a1);\n    }\n\n    //! Transpose the image, viewed as a matrix.\n    /**\n       \\note Equivalent to \\code permute_axes(\"yxzc\"); \\endcode\n    **/\n    CImg<T>& transpose() {\n      if (_width==1) { _width = _height; _height = 1; return *this; }\n      if (_height==1) { _height = _width; _width = 1; return *this; }\n      if (_width==_height) {\n        cimg_forYZC(*this,y,z,c) for (int x = y; x<width(); ++x) cimg::swap((*this)(x,y,z,c),(*this)(y,x,z,c));\n        return *this;\n      }\n      return get_transpose().move_to(*this);\n    }\n\n    //! Transpose the image, viewed as a matrix \\newinstance.\n    CImg<T> get_transpose() const {\n      return get_permute_axes(\"yxzc\");\n    }\n\n    //! Compute the cross product between two \\c 1x3 images, viewed as 3d vectors.\n    /**\n       \\param img Image used as the second argument of the cross product.\n       \\note The first argument of the cross product is \\c *this.\n     **/\n    template<typename t>\n    CImg<T>& cross(const CImg<t>& img) {\n      if (_width!=1 || _height<3 || img._width!=1 || img._height<3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"cross(): Instance and/or specified image (%u,%u,%u,%u,%p) are not 3d vectors.\",\n                                    cimg_instance,\n                                    img._width,img._height,img._depth,img._spectrum,img._data);\n\n      const T x = (*this)[0], y = (*this)[1], z = (*this)[2];\n      (*this)[0] = (T)(y*img[2] - z*img[1]);\n      (*this)[1] = (T)(z*img[0] - x*img[2]);\n      (*this)[2] = (T)(x*img[1] - y*img[0]);\n      return *this;\n    }\n\n    //! Compute the cross product between two \\c 1x3 images, viewed as 3d vectors \\newinstance.\n    template<typename t>\n    CImg<_cimg_Tt> get_cross(const CImg<t>& img) const {\n      return CImg<_cimg_Tt>(*this).cross(img);\n    }\n\n    //! Invert the instance image, viewed as a matrix.\n    /**\n       \\param use_LU Choose the inverting algorithm. Can be:\n       - \\c true: LU-based matrix inversion.\n       - \\c false: SVD-based matrix inversion.\n    **/\n    CImg<T>& invert(const bool use_LU=true) {\n      if (_width!=_height || _depth!=1 || _spectrum!=1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"invert(): Instance is not a square matrix.\",\n                                    cimg_instance);\n#ifdef cimg_use_lapack\n      int INFO = (int)use_LU, N = _width, LWORK = 4*N, *const IPIV = new int[N];\n      Tfloat\n        *const lapA = new Tfloat[N*N],\n        *const WORK = new Tfloat[LWORK];\n      cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l));\n      cimg::getrf(N,lapA,IPIV,INFO);\n      if (INFO)\n        cimg::warn(_cimg_instance\n                   \"invert(): LAPACK function dgetrf_() returned error code %d.\",\n                   cimg_instance,\n                   INFO);\n      else {\n        cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);\n        if (INFO)\n          cimg::warn(_cimg_instance\n                     \"invert(): LAPACK function dgetri_() returned error code %d.\",\n                     cimg_instance,\n                     INFO);\n      }\n      if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N + l]); else fill(0);\n      delete[] IPIV; delete[] lapA; delete[] WORK;\n#else\n      const double dete = _width>3?-1.0:det();\n      if (dete!=0.0 && _width==2) {\n        const double\n          a = _data[0], c = _data[1],\n          b = _data[2], d = _data[3];\n        _data[0] = (T)(d/dete); _data[1] = (T)(-c/dete);\n        _data[2] = (T)(-b/dete); _data[3] = (T)(a/dete);\n      } else if (dete!=0.0 && _width==3) {\n        const double\n          a = _data[0], d = _data[1], g = _data[2],\n          b = _data[3], e = _data[4], h = _data[5],\n          c = _data[6], f = _data[7], i = _data[8];\n        _data[0] = (T)((i*e-f*h)/dete), _data[1] = (T)((g*f-i*d)/dete), _data[2] = (T)((d*h-g*e)/dete);\n        _data[3] = (T)((h*c-i*b)/dete), _data[4] = (T)((i*a-c*g)/dete), _data[5] = (T)((g*b-a*h)/dete);\n        _data[6] = (T)((b*f-e*c)/dete), _data[7] = (T)((d*c-a*f)/dete), _data[8] = (T)((a*e-d*b)/dete);\n      } else {\n        if (use_LU) { // LU-based inverse computation\n          CImg<Tfloat> A(*this), indx, col(1,_width);\n          bool d;\n          A._LU(indx,d);\n          cimg_forX(*this,j) {\n            col.fill(0);\n            col(j) = 1;\n            col._solve(A,indx);\n            cimg_forX(*this,i) (*this)(j,i) = (T)col(i);\n          }\n        } else { // SVD-based inverse computation\n          CImg<Tfloat> U(_width,_width), S(1,_width), V(_width,_width);\n          SVD(U,S,V,false);\n          U.transpose();\n          cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];\n          S.diagonal();\n          *this = V*S*U;\n        }\n      }\n#endif\n      return *this;\n    }\n\n    //! Invert the instance image, viewed as a matrix \\newinstance.\n    CImg<Tfloat> get_invert(const bool use_LU=true) const {\n      return CImg<Tfloat>(*this,false).invert(use_LU);\n    }\n\n    //! Compute the Moore-Penrose pseudo-inverse of the instance image, viewed as a matrix.\n    /**\n    **/\n    CImg<T>& pseudoinvert() {\n      return get_pseudoinvert().move_to(*this);\n    }\n\n    //! Compute the Moore-Penrose pseudo-inverse of the instance image, viewed as a matrix \\newinstance.\n    CImg<Tfloat> get_pseudoinvert() const {\n      CImg<Tfloat> U, S, V;\n      SVD(U,S,V);\n      const Tfloat tolerance = (sizeof(Tfloat)<=4?5.96e-8f:1.11e-16f)*cimg::max(_width,_height)*S.max();\n      cimg_forX(V,x) {\n        const Tfloat s = S(x), invs = s>tolerance?1/s:(Tfloat)0;\n        cimg_forY(V,y) V(x,y)*=invs;\n      }\n      return V*U.transpose();\n    }\n\n    //! Solve a system of linear equations.\n    /**\n       \\param A Matrix of the linear system.\n       \\note Solve \\c AX=B where \\c B=*this.\n    **/\n    template<typename t>\n    CImg<T>& solve(const CImg<t>& A) {\n      if (_depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1)\n        throw CImgArgumentException(_cimg_instance\n                                    \"solve(): Instance and specified matrix (%u,%u,%u,%u,%p) have \"\n                                    \"incompatible dimensions.\",\n                                    cimg_instance,\n                                    A._width,A._height,A._depth,A._spectrum,A._data);\n      typedef _cimg_Ttfloat Ttfloat;\n      if (A._width==A._height) { // Classical linear system\n        if (_width!=1) {\n          CImg<T> res(_width,A._width);\n          cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A));\n          return res.move_to(*this);\n        }\n#ifdef cimg_use_lapack\n        char TRANS = 'N';\n        int INFO, N = _height, LWORK = 4*N, *const IPIV = new int[N];\n        Ttfloat\n          *const lapA = new Ttfloat[N*N],\n          *const lapB = new Ttfloat[N],\n          *const WORK = new Ttfloat[LWORK];\n        cimg_forXY(A,k,l) lapA[k*N + l] = (Ttfloat)(A(k,l));\n        cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));\n        cimg::getrf(N,lapA,IPIV,INFO);\n        if (INFO)\n          cimg::warn(_cimg_instance\n                     \"solve(): LAPACK library function dgetrf_() returned error code %d.\",\n                     cimg_instance,\n                     INFO);\n\n        if (!INFO) {\n          cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);\n          if (INFO)\n            cimg::warn(_cimg_instance\n                       \"solve(): LAPACK library function dgetrs_() returned error code %d.\",\n                       cimg_instance,\n                       INFO);\n        }\n        if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);\n        delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;\n#else\n        CImg<Ttfloat> lu(A,false);\n        CImg<Ttfloat> indx;\n        bool d;\n        lu._LU(indx,d);\n        _solve(lu,indx);\n#endif\n      } else { // Least-square solution for non-square systems.\n#ifdef cimg_use_lapack\n        if (_width!=1) {\n          CImg<T> res(_width,A._width);\n          cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A));\n          return res.move_to(*this);\n        }\n        char TRANS = 'N';\n        int INFO, N = A._width, M = A._height, LWORK = -1, LDA = M, LDB = M, NRHS = _width;\n        Ttfloat WORK_QUERY;\n        Ttfloat\n          * const lapA = new Ttfloat[M*N],\n          * const lapB = new Ttfloat[M*NRHS];\n        cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, &WORK_QUERY, LWORK, INFO);\n        LWORK = (int) WORK_QUERY;\n        Ttfloat *const WORK = new Ttfloat[LWORK];\n        cimg_forXY(A,k,l) lapA[k*M + l] = (Ttfloat)(A(k,l));\n        cimg_forXY(*this,k,l) lapB[k*M + l] = (Ttfloat)((*this)(k,l));\n        cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, WORK, LWORK, INFO);\n        if (INFO != 0)\n          cimg::warn(_cimg_instance\n                     \"solve(): LAPACK library function sgels() returned error code %d.\",\n                     cimg_instance,\n                     INFO);\n        assign(NRHS, N);\n        if (!INFO)\n          cimg_forXY(*this,k,l) (*this)(k,l) = (T)lapB[k*M + l];\n        else\n          assign(A.get_pseudoinvert()*(*this));\n        delete[] lapA; delete[] lapB; delete[] WORK;\n#else\n        assign(A.get_pseudoinvert()*(*this));\n#endif\n      }\n      return *this;\n    }\n\n    //! Solve a system of linear equations \\newinstance.\n    template<typename t>\n    CImg<_cimg_Ttfloat> get_solve(const CImg<t>& A) const {\n      return CImg<_cimg_Ttfloat>(*this,false).solve(A);\n    }\n\n    template<typename t, typename ti>\n    CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {\n      typedef _cimg_Ttfloat Ttfloat;\n      const int N = (int)size();\n      int ii = -1;\n      Ttfloat sum;\n      for (int i = 0; i<N; ++i) {\n        const int ip = (int)indx[i];\n        Ttfloat sum = (*this)(ip);\n        (*this)(ip) = (*this)(i);\n        if (ii>=0) for (int j = ii; j<=i - 1; ++j) sum-=A(j,i)*(*this)(j);\n        else if (sum!=0) ii = i;\n        (*this)(i) = (T)sum;\n      }\n      for (int i = N - 1; i>=0; --i) {\n        sum = (*this)(i);\n        for (int j = i + 1; j<N; ++j) sum-=A(j,i)*(*this)(j);\n        (*this)(i) = (T)(sum/A(i,i));\n      }\n      return *this;\n    }\n\n    //! Solve a tridiagonal system of linear equations.\n    /**\n       \\param A Coefficients of the tridiagonal system.\n       A is a tridiagonal matrix A = [ b0,c0,0,...; a1,b1,c1,0,... ; ... ; ...,0,aN,bN ],\n       stored as a 3 columns matrix\n       \\note Solve AX=B where \\c B=*this, using the Thomas algorithm.\n    **/\n    template<typename t>\n    CImg<T>& solve_tridiagonal(const CImg<t>& A) {\n      const unsigned int siz = (unsigned int)size();\n      if (A._width!=3 || A._height!=siz)\n        throw CImgArgumentException(_cimg_instance\n                                    \"solve_tridiagonal(): Instance and tridiagonal matrix \"\n                                    \"(%u,%u,%u,%u,%p) have incompatible dimensions.\",\n                                    cimg_instance,\n                                    A._width,A._height,A._depth,A._spectrum,A._data);\n      typedef _cimg_Ttfloat Ttfloat;\n      const Ttfloat epsilon = 1e-4f;\n      CImg<Ttfloat> B = A.get_column(1), V(*this,false);\n      for (int i = 1; i<(int)siz; ++i) {\n        const Ttfloat m = A(0,i)/(B[i - 1]?B[i - 1]:epsilon);\n        B[i] -= m*A(2,i - 1);\n        V[i] -= m*V[i - 1];\n      }\n      (*this)[siz - 1] = (T)(V[siz - 1]/(B[siz - 1]?B[siz - 1]:epsilon));\n      for (int i = (int)siz - 2; i>=0; --i) (*this)[i] = (T)((V[i] - A(2,i)*(*this)[i + 1])/(B[i]?B[i]:epsilon));\n      return *this;\n    }\n\n    //! Solve a tridiagonal system of linear equations \\newinstance.\n    template<typename t>\n    CImg<_cimg_Ttfloat> get_solve_tridiagonal(const CImg<t>& A) const {\n      return CImg<_cimg_Ttfloat>(*this,false).solve_tridiagonal(A);\n    }\n\n    //! Compute eigenvalues and eigenvectors of the instance image, viewed as a matrix.\n    /**\n       \\param[out] val Vector of the estimated eigenvalues, in decreasing order.\n       \\param[out] vec Matrix of the estimated eigenvectors, sorted by columns.\n    **/\n    template<typename t>\n    const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {\n      if (is_empty()) { val.assign(); vec.assign(); }\n      else {\n        if (_width!=_height || _depth>1 || _spectrum>1)\n          throw CImgInstanceException(_cimg_instance\n                                      \"eigen(): Instance is not a square matrix.\",\n                                      cimg_instance);\n\n        if (val.size()<(ulongT)_width) val.assign(1,_width);\n        if (vec.size()<(ulongT)_width*_width) vec.assign(_width,_width);\n        switch (_width) {\n        case 1 : { val[0] = (t)(*this)[0]; vec[0] = (t)1; } break;\n        case 2 : {\n          const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a + d;\n          double f = e*e - 4*(a*d - b*c);\n          if (f<0)\n            cimg::warn(_cimg_instance\n                       \"eigen(): Complex eigenvalues found.\",\n                       cimg_instance);\n\n          f = std::sqrt(f);\n          const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);\n          const double theta1 = std::atan2(l2-a,b), theta2 = std::atan2(l1-a,b);\n          val[0] = (t)l2;\n          val[1] = (t)l1;\n          vec(0,0) = (t)std::cos(theta1);\n          vec(0,1) = (t)std::sin(theta1);\n          vec(1,0) = (t)std::cos(theta2);\n          vec(1,1) = (t)std::sin(theta2);\n        } break;\n        default :\n          throw CImgInstanceException(_cimg_instance\n                                      \"eigen(): Eigenvalues computation of general matrices is limited \"\n                                      \"to 2x2 matrices.\",\n                                      cimg_instance);\n        }\n      }\n      return *this;\n    }\n\n    //! Compute eigenvalues and eigenvectors of the instance image, viewed as a matrix.\n    /**\n       \\return A list of two images <tt>[val; vec]</tt>, whose meaning is similar as in eigen(CImg<t>&,CImg<t>&) const.\n    **/\n    CImgList<Tfloat> get_eigen() const {\n      CImgList<Tfloat> res(2);\n      eigen(res[0],res[1]);\n      return res;\n    }\n\n    //! Compute eigenvalues and eigenvectors of the instance image, viewed as a symmetric matrix.\n    /**\n       \\param[out] val Vector of the estimated eigenvalues, in decreasing order.\n       \\param[out] vec Matrix of the estimated eigenvectors, sorted by columns.\n    **/\n    template<typename t>\n    const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {\n      if (is_empty()) { val.assign(); vec.assign(); }\n      else {\n#ifdef cimg_use_lapack\n        char JOB = 'V', UPLO = 'U';\n        int N = _width, LWORK = 4*N, INFO;\n        Tfloat\n          *const lapA = new Tfloat[N*N],\n          *const lapW = new Tfloat[N],\n          *const WORK = new Tfloat[LWORK];\n        cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l));\n        cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);\n        if (INFO)\n          cimg::warn(_cimg_instance\n                     \"symmetric_eigen(): LAPACK library function dsyev_() returned error code %d.\",\n                     cimg_instance,\n                     INFO);\n\n        val.assign(1,N);\n        vec.assign(N,N);\n        if (!INFO) {\n          cimg_forY(val,i) val(i) = (T)lapW[N - 1 -i];\n          cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N - 1 - k)*N + l]);\n        } else { val.fill(0); vec.fill(0); }\n        delete[] lapA; delete[] lapW; delete[] WORK;\n#else\n        if (_width!=_height || _depth>1 || _spectrum>1)\n          throw CImgInstanceException(_cimg_instance\n                                      \"eigen(): Instance is not a square matrix.\",\n                                      cimg_instance);\n\n        val.assign(1,_width);\n        if (vec._data) vec.assign(_width,_width);\n        if (_width<3) {\n          eigen(val,vec);\n          if (_width==2) { vec[1] = -vec[2]; vec[3] = vec[0]; } // Force orthogonality for 2x2 matrices.\n          return *this;\n        }\n        CImg<t> V(_width,_width);\n        Tfloat M = 0, m = (Tfloat)min_max(M), maxabs = cimg::max((Tfloat)1.0f,cimg::abs(m),cimg::abs(M));\n        (CImg<Tfloat>(*this,false)/=maxabs).SVD(vec,val,V,false);\n        if (maxabs!=1) val*=maxabs;\n\n        bool is_ambiguous = false;\n        float eig = 0;\n        cimg_forY(val,p) {       // check for ambiguous cases.\n          if (val[p]>eig) eig = (float)val[p];\n          t scal = 0;\n          cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);\n          if (cimg::abs(scal)<0.9f) is_ambiguous = true;\n          if (scal<0) val[p] = -val[p];\n        }\n        if (is_ambiguous) {\n          ++(eig*=2);\n          SVD(vec,val,V,false,40,eig);\n          val-=eig;\n        }\n        CImg<intT> permutations;  // sort eigenvalues in decreasing order\n        CImg<t> tmp(_width);\n        val.sort(permutations,false);\n        cimg_forY(vec,k) {\n          cimg_forY(permutations,y) tmp(y) = vec(permutations(y),k);\n          std::memcpy(vec.data(0,k),tmp._data,sizeof(t)*_width);\n        }\n#endif\n      }\n      return *this;\n    }\n\n    //! Compute eigenvalues and eigenvectors of the instance image, viewed as a symmetric matrix.\n    /**\n       \\return A list of two images <tt>[val; vec]</tt>, whose meaning are similar as in\n         symmetric_eigen(CImg<t>&,CImg<t>&) const.\n    **/\n    CImgList<Tfloat> get_symmetric_eigen() const {\n      CImgList<Tfloat> res(2);\n      symmetric_eigen(res[0],res[1]);\n      return res;\n    }\n\n    //! Sort pixel values and get sorting permutations.\n    /**\n       \\param[out] permutations Permutation map used for the sorting.\n       \\param is_increasing Tells if pixel values are sorted in an increasing (\\c true) or decreasing (\\c false) way.\n    **/\n    template<typename t>\n    CImg<T>& sort(CImg<t>& permutations, const bool is_increasing=true) {\n      permutations.assign(_width,_height,_depth,_spectrum);\n      if (is_empty()) return *this;\n      cimg_foroff(permutations,off) permutations[off] = (t)off;\n      return _quicksort(0,size() - 1,permutations,is_increasing,true);\n    }\n\n    //! Sort pixel values and get sorting permutations \\newinstance.\n    template<typename t>\n    CImg<T> get_sort(CImg<t>& permutations, const bool is_increasing=true) const {\n      return (+*this).sort(permutations,is_increasing);\n    }\n\n    //! Sort pixel values.\n    /**\n       \\param is_increasing Tells if pixel values are sorted in an increasing (\\c true) or decreasing (\\c false) way.\n       \\param axis Tells if the value sorting must be done along a specific axis. Can be:\n       - \\c 0: All pixel values are sorted, independently on their initial position.\n       - \\c 'x': Image columns are sorted, according to the first value in each column.\n       - \\c 'y': Image rows are sorted, according to the first value in each row.\n       - \\c 'z': Image slices are sorted, according to the first value in each slice.\n       - \\c 'c': Image channels are sorted, according to the first value in each channel.\n    **/\n    CImg<T>& sort(const bool is_increasing=true, const char axis=0) {\n      if (is_empty()) return *this;\n      CImg<uintT> perm;\n      switch (cimg::uncase(axis)) {\n      case 0 :\n        _quicksort(0,size() - 1,perm,is_increasing,false);\n        break;\n      case 'x' : {\n        perm.assign(_width);\n        get_crop(0,0,0,0,_width - 1,0,0,0).sort(perm,is_increasing);\n        CImg<T> img(*this,false);\n        cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(perm[x],y,z,c);\n      } break;\n      case 'y' : {\n        perm.assign(_height);\n        get_crop(0,0,0,0,0,_height - 1,0,0).sort(perm,is_increasing);\n        CImg<T> img(*this,false);\n        cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,perm[y],z,c);\n      } break;\n      case 'z' : {\n        perm.assign(_depth);\n        get_crop(0,0,0,0,0,0,_depth - 1,0).sort(perm,is_increasing);\n        CImg<T> img(*this,false);\n        cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,perm[z],c);\n      } break;\n      case 'c' : {\n        perm.assign(_spectrum);\n        get_crop(0,0,0,0,0,0,0,_spectrum - 1).sort(perm,is_increasing);\n        CImg<T> img(*this,false);\n        cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,z,perm[c]);\n      } break;\n      default :\n        throw CImgArgumentException(_cimg_instance\n                                    \"sort(): Invalid specified axis '%c' \"\n                                    \"(should be { x | y | z | c }).\",\n                                    cimg_instance,axis);\n      }\n      return *this;\n    }\n\n    //! Sort pixel values \\newinstance.\n    CImg<T> get_sort(const bool is_increasing=true, const char axis=0) const {\n      return (+*this).sort(is_increasing,axis);\n    }\n\n    template<typename t>\n    CImg<T>& _quicksort(const int indm, const int indM, CImg<t>& permutations,\n                        const bool is_increasing, const bool is_permutations) {\n      if (indm<indM) {\n        const int mid = (indm + indM)/2;\n        if (is_increasing) {\n          if ((*this)[indm]>(*this)[mid]) {\n            cimg::swap((*this)[indm],(*this)[mid]);\n            if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);\n          }\n          if ((*this)[mid]>(*this)[indM]) {\n            cimg::swap((*this)[indM],(*this)[mid]);\n            if (is_permutations) cimg::swap(permutations[indM],permutations[mid]);\n          }\n          if ((*this)[indm]>(*this)[mid]) {\n            cimg::swap((*this)[indm],(*this)[mid]);\n            if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);\n          }\n        } else {\n          if ((*this)[indm]<(*this)[mid]) {\n            cimg::swap((*this)[indm],(*this)[mid]);\n            if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);\n          }\n          if ((*this)[mid]<(*this)[indM]) {\n            cimg::swap((*this)[indM],(*this)[mid]);\n            if (is_permutations) cimg::swap(permutations[indM],permutations[mid]);\n          }\n          if ((*this)[indm]<(*this)[mid]) {\n            cimg::swap((*this)[indm],(*this)[mid]);\n            if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);\n          }\n        }\n        if (indM - indm>=3) {\n          const T pivot = (*this)[mid];\n          int i = indm, j = indM;\n          if (is_increasing) {\n            do {\n              while ((*this)[i]<pivot) ++i;\n              while ((*this)[j]>pivot) --j;\n              if (i<=j) {\n                if (is_permutations) cimg::swap(permutations[i],permutations[j]);\n                cimg::swap((*this)[i++],(*this)[j--]);\n              }\n            } while (i<=j);\n          } else {\n            do {\n              while ((*this)[i]>pivot) ++i;\n              while ((*this)[j]<pivot) --j;\n              if (i<=j) {\n                if (is_permutations) cimg::swap(permutations[i],permutations[j]);\n                cimg::swap((*this)[i++],(*this)[j--]);\n              }\n            } while (i<=j);\n          }\n          if (indm<j) _quicksort(indm,j,permutations,is_increasing,is_permutations);\n          if (i<indM) _quicksort(i,indM,permutations,is_increasing,is_permutations);\n        }\n      }\n      return *this;\n    }\n\n    //! Compute the SVD of the instance image, viewed as a general matrix.\n    /**\n       Compute the SVD decomposition \\c *this=U*S*V' where \\c U and \\c V are orthogonal matrices\n       and \\c S is a diagonal matrix. \\c V' denotes the matrix transpose of \\c V.\n       \\param[out] U First matrix of the SVD product.\n       \\param[out] S Coefficients of the second (diagonal) matrix of the SVD product.\n         These coefficients are stored as a vector.\n       \\param[out] V Third matrix of the SVD product.\n       \\param sorting Tells if the diagonal coefficients are sorted (in decreasing order).\n       \\param max_iteration Maximum number of iterations considered for the algorithm convergence.\n       \\param lambda Epsilon used for the algorithm convergence.\n       \\note The instance matrix can be computed from \\c U,\\c S and \\c V by\n       \\code\n       const CImg<> A;  // Input matrix (assumed to contain some values).\n       CImg<> U,S,V;\n       A.SVD(U,S,V)\n       \\endcode\n    **/\n    template<typename t>\n    const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V, const bool sorting=true,\n                       const unsigned int max_iteration=40, const float lambda=0) const {\n      if (is_empty()) { U.assign(); S.assign(); V.assign(); }\n      else {\n        U = *this;\n        if (lambda!=0) {\n          const unsigned int delta = cimg::min(U._width,U._height);\n          for (unsigned int i = 0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda);\n        }\n        if (S.size()<_width) S.assign(1,_width);\n        if (V._width<_width || V._height<_height) V.assign(_width,_width);\n        CImg<t> rv1(_width);\n        t anorm = 0, c, f, g = 0, h, s, scale = 0;\n        int l = 0, nm = 0;\n\n        cimg_forX(U,i) {\n          l = i + 1; rv1[i] = scale*g; g = s = scale = 0;\n          if (i<height()) {\n            for (int k = i; k<height(); ++k) scale+=cimg::abs(U(i,k));\n            if (scale) {\n              for (int k = i; k<height(); ++k) { U(i,k)/=scale; s+=U(i,k)*U(i,k); }\n              f = U(i,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i) = f-g;\n              for (int j = l; j<width(); ++j) {\n                s = 0;\n                for (int k=i; k<height(); ++k) s+=U(i,k)*U(j,k);\n                f = s/h;\n                for (int k = i; k<height(); ++k) U(j,k)+=f*U(i,k);\n              }\n              for (int k = i; k<height(); ++k) U(i,k)*=scale;\n            }\n          }\n          S[i]=scale*g;\n\n          g = s = scale = 0;\n          if (i<height() && i!=width() - 1) {\n            for (int k = l; k<width(); ++k) scale+=cimg::abs(U(k,i));\n            if (scale) {\n              for (int k = l; k<width(); ++k) { U(k,i)/= scale; s+=U(k,i)*U(k,i); }\n              f = U(l,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g;\n              for (int k = l; k<width(); ++k) rv1[k]=U(k,i)/h;\n              for (int j = l; j<height(); ++j) {\n                s = 0;\n                for (int k = l; k<width(); ++k) s+=U(k,j)*U(k,i);\n                for (int k = l; k<width(); ++k) U(k,j)+=s*rv1[k];\n              }\n              for (int k = l; k<width(); ++k) U(k,i)*=scale;\n            }\n          }\n          anorm = (t)cimg::max((float)anorm,(float)(cimg::abs(S[i]) + cimg::abs(rv1[i])));\n        }\n\n        for (int i = width() - 1; i>=0; --i) {\n          if (i<width()-1) {\n            if (g) {\n              for (int j = l; j<width(); ++j) V(i,j) =(U(j,i)/U(l,i))/g;\n              for (int j = l; j<width(); ++j) {\n                s = 0;\n                for (int k = l; k<width(); ++k) s+=U(k,i)*V(j,k);\n                for (int k = l; k<width(); ++k) V(j,k)+=s*V(i,k);\n              }\n            }\n            for (int j = l; j<width(); ++j) V(j,i) = V(i,j) = (t)0.0;\n          }\n          V(i,i) = (t)1.0; g = rv1[i]; l = i;\n        }\n\n        for (int i = cimg::min(width(),height()) - 1; i>=0; --i) {\n          l = i + 1; g = S[i];\n          for (int j = l; j<width(); ++j) U(j,i) = 0;\n          if (g) {\n            g = 1/g;\n            for (int j = l; j<width(); ++j) {\n              s = 0; for (int k = l; k<height(); ++k) s+=U(i,k)*U(j,k);\n              f = (s/U(i,i))*g;\n              for (int k = i; k<height(); ++k) U(j,k)+=f*U(i,k);\n            }\n            for (int j = i; j<height(); ++j) U(i,j)*= g;\n          } else for (int j = i; j<height(); ++j) U(i,j) = 0;\n          ++U(i,i);\n        }\n\n        for (int k = width() - 1; k>=0; --k) {\n          for (unsigned int its = 0; its<max_iteration; ++its) {\n            bool flag = true;\n            for (l = k; l>=1; --l) {\n              nm = l - 1;\n              if ((cimg::abs(rv1[l]) + anorm)==anorm) { flag = false; break; }\n              if ((cimg::abs(S[nm]) + anorm)==anorm) break;\n            }\n            if (flag) {\n              c = 0; s = 1;\n              for (int i = l; i<=k; ++i) {\n                f = s*rv1[i]; rv1[i] = c*rv1[i];\n                if ((cimg::abs(f) + anorm)==anorm) break;\n                g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;\n                cimg_forY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c + z*s; U(i,j) = z*c - y*s; }\n              }\n            }\n\n            const t z = S[k];\n            if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; }\n            nm = k - 1;\n            t x = S[l], y = S[nm];\n            g = rv1[nm]; h = rv1[k];\n            f = ((y - z)*(y + z)+(g - h)*(g + h))/cimg::max((t)1e-25,2*h*y);\n            g = (t)cimg::_pythagore(f,1.0);\n            f = ((x - z)*(x + z)+h*((y/(f + (f>=0?g:-g))) - h))/cimg::max((t)1e-25,x);\n            c = s = 1;\n            for (int j = l; j<=nm; ++j) {\n              const int i = j + 1;\n              g = rv1[i]; h = s*g; g = c*g;\n              t y = S[i];\n              t z = (t)cimg::_pythagore(f,h);\n              rv1[j] = z; c = f/cimg::max((t)1e-25,z); s = h/cimg::max((t)1e-25,z);\n              f = x*c + g*s; g = g*c - x*s; h = y*s; y*=c;\n              cimg_forX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c + z*s; V(i,jj) = z*c - x*s; }\n              z = (t)cimg::_pythagore(f,h); S[j] = z;\n              if (z) { z = 1/cimg::max((t)1e-25,z); c = f*z; s = h*z; }\n              f = c*g + s*y; x = c*y - s*g;\n              cimg_forY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c + z*s; U(i,jj) = z*c - y*s; }\n            }\n            rv1[l] = 0; rv1[k]=f; S[k]=x;\n          }\n        }\n\n        if (sorting) {\n          CImg<intT> permutations;\n          CImg<t> tmp(_width);\n          S.sort(permutations,false);\n          cimg_forY(U,k) {\n            cimg_forY(permutations,y) tmp(y) = U(permutations(y),k);\n            std::memcpy(U.data(0,k),tmp._data,sizeof(t)*_width);\n          }\n          cimg_forY(V,k) {\n            cimg_forY(permutations,y) tmp(y) = V(permutations(y),k);\n            std::memcpy(V.data(0,k),tmp._data,sizeof(t)*_width);\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Compute the SVD of the instance image, viewed as a general matrix.\n    /**\n       \\return A list of three images <tt>[U; S; V]</tt>, whose meaning is similar as in\n         SVD(CImg<t>&,CImg<t>&,CImg<t>&,bool,unsigned int,float) const.\n    **/\n    CImgList<Tfloat> get_SVD(const bool sorting=true,\n                             const unsigned int max_iteration=40, const float lambda=0) const {\n      CImgList<Tfloat> res(3);\n      SVD(res[0],res[1],res[2],sorting,max_iteration,lambda);\n      return res;\n    }\n\n    // [internal] Compute the LU decomposition of a permuted matrix.\n    template<typename t>\n    CImg<T>& _LU(CImg<t>& indx, bool& d) {\n      const int N = width();\n      int imax = 0;\n      CImg<Tfloat> vv(N);\n      indx.assign(N);\n      d = true;\n      cimg_forX(*this,i) {\n        Tfloat vmax = 0;\n        cimg_forX(*this,j) {\n          const Tfloat tmp = cimg::abs((*this)(j,i));\n          if (tmp>vmax) vmax = tmp;\n        }\n        if (vmax==0) { indx.fill(0); return fill(0); }\n        vv[i] = 1/vmax;\n      }\n      cimg_forX(*this,j) {\n        for (int i = 0; i<j; ++i) {\n          Tfloat sum=(*this)(j,i);\n          for (int k = 0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);\n          (*this)(j,i) = (T)sum;\n        }\n        Tfloat vmax = 0;\n        for (int i = j; i<width(); ++i) {\n          Tfloat sum=(*this)(j,i);\n          for (int k = 0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);\n          (*this)(j,i) = (T)sum;\n          const Tfloat tmp = vv[i]*cimg::abs(sum);\n          if (tmp>=vmax) { vmax=tmp; imax=i; }\n        }\n        if (j!=imax) {\n          cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j));\n          d =!d;\n          vv[imax] = vv[j];\n        }\n        indx[j] = (t)imax;\n        if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;\n        if (j<N) {\n          const Tfloat tmp = 1/(Tfloat)(*this)(j,j);\n          for (int i = j + 1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);\n        }\n      }\n      return *this;\n    }\n\n    //! Compute minimal path in a graph, using the Dijkstra algorithm.\n    /**\n       \\param distance An object having operator()(unsigned int i, unsigned int j) which returns distance\n         between two nodes (i,j).\n       \\param nb_nodes Number of graph nodes.\n       \\param starting_node Indice of the starting node.\n       \\param ending_node Indice of the ending node (set to ~0U to ignore ending node).\n       \\param previous_node Array that gives the previous node indice in the path to the starting node\n         (optional parameter).\n       \\return Array of distances of each node to the starting node.\n    **/\n    template<typename tf, typename t>\n    static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,\n                            const unsigned int starting_node, const unsigned int ending_node,\n                            CImg<t>& previous_node) {\n      if (starting_node>=nb_nodes)\n        throw CImgArgumentException(\"CImg<%s>::dijkstra(): Specified indice of starting node %u is higher \"\n                                    \"than number of nodes %u.\",\n                                    pixel_type(),starting_node,nb_nodes);\n      CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());\n      dist(starting_node) = 0;\n      previous_node.assign(1,nb_nodes,1,1,(t)-1);\n      previous_node(starting_node) = (t)starting_node;\n      CImg<uintT> Q(nb_nodes);\n      cimg_forX(Q,u) Q(u) = (unsigned int)u;\n      cimg::swap(Q(starting_node),Q(0));\n      unsigned int sizeQ = nb_nodes;\n      while (sizeQ) {\n        // Update neighbors from minimal vertex\n        const unsigned int umin = Q(0);\n        if (umin==ending_node) sizeQ = 0;\n        else {\n          const T dmin = dist(umin);\n          const T infty = cimg::type<T>::max();\n          for (unsigned int q = 1; q<sizeQ; ++q) {\n            const unsigned int v = Q(q);\n            const T d = (T)distance(v,umin);\n            if (d<infty) {\n              const T alt = dmin + d;\n              if (alt<dist(v)) {\n                dist(v) = alt;\n                previous_node(v) = (t)umin;\n                const T distpos = dist(Q(q));\n                for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos + 1)/2 - 1)); pos=par)\n                  cimg::swap(Q(pos),Q(par));\n              }\n            }\n          }\n          // Remove minimal vertex from queue\n          Q(0) = Q(--sizeQ);\n          const T distpos = dist(Q(0));\n          for (unsigned int pos = 0, left = 0, right = 0;\n               ((right=2*(pos + 1),(left=right - 1))<sizeQ && distpos>dist(Q(left))) ||\n                 (right<sizeQ && distpos>dist(Q(right)));) {\n            if (right<sizeQ) {\n              if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }\n              else { cimg::swap(Q(pos),Q(right)); pos = right; }\n            } else { cimg::swap(Q(pos),Q(left)); pos = left; }\n          }\n        }\n      }\n      return dist;\n    }\n\n    //! Return minimal path in a graph, using the Dijkstra algorithm.\n    template<typename tf, typename t>\n    static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,\n                            const unsigned int starting_node, const unsigned int ending_node=~0U) {\n      CImg<uintT> foo;\n      return dijkstra(distance,nb_nodes,starting_node,ending_node,foo);\n    }\n\n    //! Return minimal path in a graph, using the Dijkstra algorithm.\n    /**\n       \\param starting_node Indice of the starting node.\n       \\param ending_node Indice of the ending node.\n       \\param previous_node Array that gives the previous node indice in the path to the starting node\n         (optional parameter).\n       \\return Array of distances of each node to the starting node.\n       \\note image instance corresponds to the adjacency matrix of the graph.\n    **/\n    template<typename t>\n    CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node,\n                      CImg<t>& previous_node) {\n      return get_dijkstra(starting_node,ending_node,previous_node).move_to(*this);\n    }\n\n    //! Return minimal path in a graph, using the Dijkstra algorithm \\newinstance.\n    template<typename t>\n    CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node,\n                         CImg<t>& previous_node) const {\n      if (_width!=_height || _depth!=1 || _spectrum!=1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"dijkstra(): Instance is not a graph adjacency matrix.\",\n                                    cimg_instance);\n\n      return dijkstra(*this,_width,starting_node,ending_node,previous_node);\n    }\n\n    //! Return minimal path in a graph, using the Dijkstra algorithm.\n    CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) {\n      return get_dijkstra(starting_node,ending_node).move_to(*this);\n    }\n\n    //! Return minimal path in a graph, using the Dijkstra algorithm \\newinstance.\n    CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const {\n      CImg<uintT> foo;\n      return get_dijkstra(starting_node,ending_node,foo);\n    }\n\n    //! Return an image containing the ascii codes of the specified  string.\n    /**\n       \\param str input C-string to encode as an image.\n       \\param is_last_zero Tells if the ending \\c '0' character appear in the resulting image.\n    **/\n    static CImg<T> string(const char *const str, const bool is_last_zero=true, const bool is_shared=false) {\n      if (!str) return CImg<T>();\n      return CImg<T>(str,(unsigned int)std::strlen(str) + (is_last_zero?1:0),1,1,1,is_shared);\n    }\n\n    //! Return a \\c 1x1 image containing specified value.\n    /**\n       \\param a0 First vector value.\n    **/\n    static CImg<T> vector(const T& a0) {\n      CImg<T> r(1,1);\n      r[0] = a0;\n      return r;\n    }\n\n    //! Return a \\c 1x2 image containing specified values.\n    /**\n       \\param a0 First vector value.\n       \\param a1 Second vector value.\n    **/\n    static CImg<T> vector(const T& a0, const T& a1) {\n      CImg<T> r(1,2); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1;\n      return r;\n    }\n\n    //! Return a \\c 1x3 image containing specified values.\n    /**\n       \\param a0 First vector value.\n       \\param a1 Second vector value.\n       \\param a2 Third vector value.\n    **/\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2) {\n      CImg<T> r(1,3); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;\n      return r;\n    }\n\n    //! Return a \\c 1x4 image containing specified values.\n    /**\n       \\param a0 First vector value.\n       \\param a1 Second vector value.\n       \\param a2 Third vector value.\n       \\param a3 Fourth vector value.\n    **/\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {\n      CImg<T> r(1,4); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      return r;\n    }\n\n    //! Return a \\c 1x5 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {\n      CImg<T> r(1,5); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;\n      return r;\n    }\n\n    //! Return a \\c 1x6 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {\n      CImg<T> r(1,6); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;\n      return r;\n    }\n\n    //! Return a \\c 1x7 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6) {\n      CImg<T> r(1,7); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;\n      return r;\n    }\n\n    //! Return a \\c 1x8 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7) {\n      CImg<T> r(1,8); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      return r;\n    }\n\n    //! Return a \\c 1x9 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7,\n                          const T& a8) {\n      CImg<T> r(1,9); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      *(ptr++) = a8;\n      return r;\n    }\n\n    //! Return a \\c 1x10 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7,\n                          const T& a8, const T& a9) {\n      CImg<T> r(1,10); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      *(ptr++) = a8; *(ptr++) = a9;\n      return r;\n    }\n\n    //! Return a \\c 1x11 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7,\n                          const T& a8, const T& a9, const T& a10) {\n      CImg<T> r(1,11); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10;\n      return r;\n    }\n\n    //! Return a \\c 1x12 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7,\n                          const T& a8, const T& a9, const T& a10, const T& a11) {\n      CImg<T> r(1,12); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;\n      return r;\n    }\n\n    //! Return a \\c 1x13 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7,\n                          const T& a8, const T& a9, const T& a10, const T& a11,\n                          const T& a12) {\n      CImg<T> r(1,13); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;\n      *(ptr++) = a12;\n      return r;\n    }\n\n    //! Return a \\c 1x14 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7,\n                          const T& a8, const T& a9, const T& a10, const T& a11,\n                          const T& a12, const T& a13) {\n      CImg<T> r(1,14); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;\n      *(ptr++) = a12; *(ptr++) = a13;\n      return r;\n    }\n\n    //! Return a \\c 1x15 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7,\n                          const T& a8, const T& a9, const T& a10, const T& a11,\n                          const T& a12, const T& a13, const T& a14) {\n      CImg<T> r(1,15); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;\n      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;\n      return r;\n    }\n\n    //! Return a \\c 1x16 image containing specified values.\n    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7,\n                          const T& a8, const T& a9, const T& a10, const T& a11,\n                          const T& a12, const T& a13, const T& a14, const T& a15) {\n      CImg<T> r(1,16); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;\n      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;\n      return r;\n    }\n\n    //! Return a 1x1 matrix containing specified coefficients.\n    /**\n       \\param a0 First matrix value.\n       \\note Equivalent to vector(const T&).\n    **/\n    static CImg<T> matrix(const T& a0) {\n      return vector(a0);\n    }\n\n    //! Return a 2x2 matrix containing specified coefficients.\n    /**\n       \\param a0 First matrix value.\n       \\param a1 Second matrix value.\n       \\param a2 Third matrix value.\n       \\param a3 Fourth matrix value.\n    **/\n    static CImg<T> matrix(const T& a0, const T& a1,\n                          const T& a2, const T& a3) {\n      CImg<T> r(2,2); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1;\n      *(ptr++) = a2; *(ptr++) = a3;\n      return r;\n    }\n\n    //! Return a 3x3 matrix containing specified coefficients.\n    /**\n       \\param a0 First matrix value.\n       \\param a1 Second matrix value.\n       \\param a2 Third matrix value.\n       \\param a3 Fourth matrix value.\n       \\param a4 Fifth matrix value.\n       \\param a5 Sixth matrix value.\n       \\param a6 Seventh matrix value.\n       \\param a7 Eighth matrix value.\n       \\param a8 Nineth matrix value.\n    **/\n    static CImg<T> matrix(const T& a0, const T& a1, const T& a2,\n                          const T& a3, const T& a4, const T& a5,\n                          const T& a6, const T& a7, const T& a8) {\n      CImg<T> r(3,3); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;\n      *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;\n      *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;\n      return r;\n    }\n\n    //! Return a 4x4 matrix containing specified coefficients.\n    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,\n                          const T& a4, const T& a5, const T& a6, const T& a7,\n                          const T& a8, const T& a9, const T& a10, const T& a11,\n                          const T& a12, const T& a13, const T& a14, const T& a15) {\n      CImg<T> r(4,4); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;\n      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;\n      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;\n      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;\n      return r;\n    }\n\n    //! Return a 5x5 matrix containing specified coefficients.\n    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,\n                          const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,\n                          const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,\n                          const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,\n                          const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {\n      CImg<T> r(5,5); T *ptr = r._data;\n      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;\n      *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;\n      *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;\n      *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19;\n      *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24;\n      return r;\n    }\n\n    //! Return a 1x1 symmetric matrix containing specified coefficients.\n    /**\n       \\param a0 First matrix value.\n       \\note Equivalent to vector(const T&).\n    **/\n    static CImg<T> tensor(const T& a0) {\n      return matrix(a0);\n    }\n\n    //! Return a 2x2 symmetric matrix tensor containing specified coefficients.\n    static CImg<T> tensor(const T& a0, const T& a1, const T& a2) {\n      return matrix(a0,a1,a1,a2);\n    }\n\n    //! Return a 3x3 symmetric matrix containing specified coefficients.\n    static CImg<T> tensor(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {\n      return matrix(a0,a1,a2,a1,a3,a4,a2,a4,a5);\n    }\n\n    //! Return a 1x1 diagonal matrix containing specified coefficients.\n    static CImg<T> diagonal(const T& a0) {\n      return matrix(a0);\n    }\n\n    //! Return a 2x2 diagonal matrix containing specified coefficients.\n    static CImg<T> diagonal(const T& a0, const T& a1) {\n      return matrix(a0,0,0,a1);\n    }\n\n    //! Return a 3x3 diagonal matrix containing specified coefficients.\n    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) {\n      return matrix(a0,0,0,0,a1,0,0,0,a2);\n    }\n\n    //! Return a 4x4 diagonal matrix containing specified coefficients.\n    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {\n      return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);\n    }\n\n    //! Return a 5x5 diagonal matrix containing specified coefficients.\n    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {\n      return matrix(a0,0,0,0,0,0,a1,0,0,0,0,0,a2,0,0,0,0,0,a3,0,0,0,0,0,a4);\n    }\n\n    //! Return a NxN identity matrix.\n    /**\n       \\param N Dimension of the matrix.\n    **/\n    static CImg<T> identity_matrix(const unsigned int N) {\n      CImg<T> res(N,N,1,1,0);\n      cimg_forX(res,x) res(x,x) = 1;\n      return res;\n    }\n\n    //! Return a N-numbered sequence vector from \\p a0 to \\p a1.\n    /**\n       \\param N Size of the resulting vector.\n       \\param a0 Starting value of the sequence.\n       \\param a1 Ending value of the sequence.\n     **/\n    static CImg<T> sequence(const unsigned int N, const T& a0, const T& a1) {\n      if (N) return CImg<T>(1,N).sequence(a0,a1);\n      return CImg<T>();\n    }\n\n    //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w.\n    /**\n       \\param x X-coordinate of the rotation axis, or first quaternion coordinate.\n       \\param y Y-coordinate of the rotation axis, or second quaternion coordinate.\n       \\param z Z-coordinate of the rotation axis, or third quaternion coordinate.\n       \\param w Angle of the rotation axis, or fourth quaternion coordinate.\n       \\param is_quaternion Tell is the four arguments denotes a set { axis + angle } or a quaternion.\n     **/\n    static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w,\n                                   const bool is_quaternion=false) {\n      float X,Y,Z,W;\n      if (!is_quaternion) {\n        const float norm = (float)std::sqrt(x*x + y*y + z*z),\n          nx = norm>0?x/norm:0,\n          ny = norm>0?y/norm:0,\n          nz = norm>0?z/norm:1,\n          nw = norm>0?w:0,\n          sina = (float)std::sin(nw/2),\n          cosa = (float)std::cos(nw/2);\n        X = nx*sina;\n        Y = ny*sina;\n        Z = nz*sina;\n        W = cosa;\n      } else {\n        const float norm = (float)std::sqrt(x*x + y*y + z*z + w*w);\n        if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; }\n        else { X = Y = Z = 0; W = 1; }\n      }\n      const float xx = X*X, xy = X*Y, xz = X*Z, xw = X*W, yy = Y*Y, yz = Y*Z, yw = Y*W, zz = Z*Z, zw = Z*W;\n      return CImg<T>::matrix((T)(1 - 2*(yy + zz)), (T)(2*(xy + zw)),   (T)(2*(xz - yw)),\n                             (T)(2*(xy - zw)),   (T)(1 - 2*(xx + zz)), (T)(2*(yz + xw)),\n                             (T)(2*(xz + yw)),   (T)(2*(yz - xw)),   (T)(1 - 2*(xx + yy)));\n    }\n\n    //@}\n    //-----------------------------------\n    //\n    //! \\name Value Manipulation\n    //@{\n    //-----------------------------------\n\n    //! Fill all pixel values with specified value.\n    /**\n       \\param val Fill value.\n    **/\n    CImg<T>& fill(const T& val) {\n      if (is_empty()) return *this;\n      if (val && sizeof(T)!=1) cimg_for(*this,ptrd,T) *ptrd = val;\n      else std::memset(_data,(int)val,sizeof(T)*size());\n      return *this;\n    }\n\n    //! Fill all pixel values with specified value \\newinstance.\n    CImg<T> get_fill(const T& val) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val);\n    }\n\n    //! Fill sequentially all pixel values with specified values.\n    /**\n       \\param val0 First fill value.\n       \\param val1 Second fill value.\n    **/\n    CImg<T>& fill(const T& val0, const T& val1) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 1;\n      for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; }\n      if (ptrd!=ptre + 1) *(ptrd++) = val0;\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 2;\n      for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; }\n      ptre+=2;\n      switch (ptre - ptrd) {\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 3;\n      for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; }\n      ptre+=3;\n      switch (ptre - ptrd) {\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 4;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4;\n      }\n      ptre+=4;\n      switch (ptre - ptrd) {\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 5;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;\n      }\n      ptre+=5;\n      switch (ptre - ptrd) {\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 6;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;\n        *(ptrd++) = val6;\n      }\n      ptre+=6;\n      switch (ptre - ptrd) {\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6, const T& val7) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 7;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3;\n        *(ptrd++) = val4; *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7;\n      }\n      ptre+=7;\n      switch (ptre - ptrd) {\n      case 7 : *(--ptre) = val6;\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6, const T& val7) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6, const T& val7, const T& val8) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 8;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2;\n        *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;\n        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8;\n      }\n      ptre+=8;\n      switch (ptre - ptrd) {\n      case 8 : *(--ptre) = val7;\n      case 7 : *(--ptre) = val6;\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6, const T& val7, const T& val8) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6, const T& val7, const T& val8, const T& val9) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 9;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4;\n        *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9;\n      }\n      ptre+=9;\n      switch (ptre - ptrd) {\n      case 9 : *(--ptre) = val8;\n      case 8 : *(--ptre) = val7;\n      case 7 : *(--ptre) = val6;\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6, const T& val7, const T& val8, const T& val9) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6, const T& val7, const T& val8, const T& val9, const T& val10) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 10;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4;\n        *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9;\n        *(ptrd++) = val10;\n      }\n      ptre+=10;\n      switch (ptre - ptrd) {\n      case 10 : *(--ptre) = val9;\n      case 9 : *(--ptre) = val8;\n      case 8 : *(--ptre) = val7;\n      case 7 : *(--ptre) = val6;\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6, const T& val7, const T& val8, const T& val9, const T& val10) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 11;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;\n        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;\n      }\n      ptre+=11;\n      switch (ptre - ptrd) {\n      case 11 : *(--ptre) = val10;\n      case 10 : *(--ptre) = val9;\n      case 9 : *(--ptre) = val8;\n      case 8 : *(--ptre) = val7;\n      case 7 : *(--ptre) = val6;\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,\n                                                           val11);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,\n                  const T& val12) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 12;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;\n        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;\n        *(ptrd++) = val12;\n      }\n      ptre+=12;\n      switch (ptre - ptrd) {\n      case 12 : *(--ptre) = val11;\n      case 11 : *(--ptre) = val10;\n      case 10 : *(--ptre) = val9;\n      case 9 : *(--ptre) = val8;\n      case 8 : *(--ptre) = val7;\n      case 7 : *(--ptre) = val6;\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,\n                     const T& val12) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,\n                                                           val11,val12);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,\n                  const T& val12, const T& val13) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 13;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;\n        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;\n        *(ptrd++) = val12; *(ptrd++) = val13;\n      }\n      ptre+=13;\n      switch (ptre - ptrd) {\n      case 13 : *(--ptre) = val12;\n      case 12 : *(--ptre) = val11;\n      case 11 : *(--ptre) = val10;\n      case 10 : *(--ptre) = val9;\n      case 9 : *(--ptre) = val8;\n      case 8 : *(--ptre) = val7;\n      case 7 : *(--ptre) = val6;\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,\n                     const T& val12, const T& val13) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,\n                                                           val11,val12,val13);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,\n                  const T& val12, const T& val13, const T& val14) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 14;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;\n        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;\n        *(ptrd++) = val12; *(ptrd++) = val13; *(ptrd++) = val14;\n      }\n      ptre+=14;\n      switch (ptre - ptrd) {\n      case 14 : *(--ptre) = val13;\n      case 13 : *(--ptre) = val12;\n      case 12 : *(--ptre) = val11;\n      case 11 : *(--ptre) = val10;\n      case 10 : *(--ptre) = val9;\n      case 9 : *(--ptre) = val8;\n      case 8 : *(--ptre) = val7;\n      case 7 : *(--ptre) = val6;\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,\n                     const T& val12, const T& val13, const T& val14) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,\n                                                           val11,val12,val13,val14);\n    }\n\n    //! Fill sequentially all pixel values with specified values \\overloading.\n    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                  const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,\n                  const T& val12, const T& val13, const T& val14, const T& val15) {\n      if (is_empty()) return *this;\n      T *ptrd, *ptre = end() - 15;\n      for (ptrd = _data; ptrd<ptre; ) {\n        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;\n        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;\n        *(ptrd++) = val12; *(ptrd++) = val13; *(ptrd++) = val14; *(ptrd++) = val15;\n      }\n      ptre+=15;\n      switch (ptre - ptrd) {\n      case 15 : *(--ptre) = val14;\n      case 14 : *(--ptre) = val13;\n      case 13 : *(--ptre) = val12;\n      case 12 : *(--ptre) = val11;\n      case 11 : *(--ptre) = val10;\n      case 10 : *(--ptre) = val9;\n      case 9 : *(--ptre) = val8;\n      case 8 : *(--ptre) = val7;\n      case 7 : *(--ptre) = val6;\n      case 6 : *(--ptre) = val5;\n      case 5 : *(--ptre) = val4;\n      case 4 : *(--ptre) = val3;\n      case 3 : *(--ptre) = val2;\n      case 2 : *(--ptre) = val1;\n      case 1 : *(--ptre) = val0;\n      }\n      return *this;\n    }\n\n    //! Fill sequentially all pixel values with specified values \\newinstance.\n    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,\n                     const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,\n                     const T& val12, const T& val13, const T& val14, const T& val15) const {\n      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,\n                                                           val11,val12,val13,val14,val15);\n    }\n\n    //! Fill sequentially pixel values according to a given expression.\n    /**\n       \\param expression C-string describing a math formula, or a list of values.\n       \\param repeat_values In case a list of values is provided, tells if this list must be repeated for the filling.\n       \\param allow_formula tells if a formula is allowed or only a list of values.\n       \\param list_inputs In case of a mathematical expression, attach a list of images to the specified expression.\n       \\param list_outputs In case of a mathematical expression, attach a list of images to the specified expression.\n    **/\n    CImg<T>& fill(const char *const expression, const bool repeat_values, const bool allow_formula=true,\n                  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {\n      return _fill(expression,repeat_values,allow_formula,list_inputs,list_outputs,\"fill\",0);\n    }\n\n    CImg<T>& _fill(const char *const expression, const bool repeat_values, const bool allow_formula,\n                   const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs,\n                   const char *const calling_function, const CImg<T> *provides_copy) {\n      if (is_empty() || !expression || !*expression) return *this;\n      const unsigned int omode = cimg::exception_mode();\n      cimg::exception_mode(0);\n      CImg<charT> is_error;\n\n      if (allow_formula) try { // Try to fill values according to a formula\n          CImg<T> base = provides_copy?provides_copy->get_shared():get_shared();\n          _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||\n                                             *expression=='*' || *expression==':'?1:0),\n                               calling_function,base,this,list_inputs,list_outputs);\n          if (!provides_copy && expression && *expression!='>' && *expression!='<' && *expression!=':' &&\n              mp.need_input_copy)\n            base.assign().assign(*this); // Needs input copy\n\n          bool do_in_parallel = false;\n#ifdef cimg_use_openmp\n          cimg_openmp_if(*expression=='*' || *expression==':' ||\n                         (mp.is_parallelizable && _width>=320 && _height*_depth*_spectrum>=2 &&\n                          std::strlen(expression)>=6))\n            do_in_parallel = true;\n#endif\n          if (mp.result_dim) { // Vector-valued expression\n            const unsigned int N = cimg::min(mp.result_dim,_spectrum);\n            const ulongT whd = (ulongT)_width*_height*_depth;\n            T *ptrd = *expression=='<'?_data + _width*_height*_depth - 1:_data;\n            if (*expression=='<') {\n              CImg<doubleT> res(1,mp.result_dim);\n              cimg_rofXYZ(*this,x,y,z) {\n                mp(x,y,z,0,res._data);\n                const double *ptrs = res._data;\n                T *_ptrd = ptrd--; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; }\n              }\n            } else if (*expression=='>' || !do_in_parallel) {\n              CImg<doubleT> res(1,mp.result_dim);\n              cimg_forXYZ(*this,x,y,z) {\n                mp(x,y,z,0,res._data);\n                const double *ptrs = res._data;\n                T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; }\n              }\n            } else {\n#ifdef cimg_use_openmp\n#pragma omp parallel\n              {\n                _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;\n#pragma omp for collapse(2)\n                cimg_forYZ(*this,y,z) {\n                  CImg<doubleT> res(1,lmp.result_dim);\n                  T *ptrd = data(0,y,z,0);\n                  cimg_forX(*this,x) {\n                    lmp(x,y,z,0,res._data);\n                    const double *ptrs = res._data;\n                    T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; }\n                  }\n                }\n              }\n#endif\n            }\n\n          } else { // Scalar-valued expression\n            T *ptrd = *expression=='<'?end() - 1:_data;\n            if (*expression=='<')\n              cimg_rofXYZC(*this,x,y,z,c) *(ptrd--) = (T)mp(x,y,z,c);\n            else if (*expression=='>' || !do_in_parallel)\n              cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c);\n            else {\n#ifdef cimg_use_openmp\n#pragma omp parallel\n              {\n                _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;\n#pragma omp for collapse(3)\n                cimg_forYZC(*this,y,z,c) {\n                  T *ptrd = data(0,y,z,c);\n                  cimg_forX(*this,x) *ptrd++ = (T)lmp(x,y,z,c);\n                }\n              }\n#endif\n            }\n          }\n        } catch (CImgException& e) { CImg<charT>::string(e._message).move_to(is_error); }\n\n      // If failed, try to recognize a list of values.\n      if (!allow_formula || is_error) {\n        char *const item = new char[16384], sep = 0;\n        const char *nexpression = expression;\n        ulongT nb = 0;\n        const ulongT siz = size();\n        T *ptrd = _data;\n        for (double val = 0; *nexpression && nb<siz; ++nb) {\n          sep = 0;\n          const int err = cimg_sscanf(nexpression,\"%16383[ \\n\\t0-9.eEinfa+-]%c\",item,&sep);\n          if (err>0 && cimg_sscanf(item,\"%lf\",&val)==1 && (sep==',' || sep==';' || err==1)) {\n            nexpression+=std::strlen(item) + (err>1?1:0);\n            *(ptrd++) = (T)val;\n          } else break;\n        }\n        delete[] item;\n        cimg::exception_mode(omode);\n        if (nb<siz && (sep || *nexpression)) {\n          if (is_error) throw CImgArgumentException(\"%s\",is_error._data);\n          else throw CImgArgumentException(_cimg_instance\n                                           \"%s(): Invalid sequence of filling values '%s'.\",\n                                           cimg_instance,calling_function,expression);\n        }\n        if (repeat_values && nb && nb<siz)\n          for (T *ptrs = _data, *const ptre = _data + siz; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs;\n      }\n      cimg::exception_mode(omode);\n      return *this;\n    }\n\n    //! Fill sequentially pixel values according to a given expression \\newinstance.\n    CImg<T> get_fill(const char *const expression, const bool repeat_values, const bool allow_formula=true,\n                     const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {\n      return (+*this).fill(expression,repeat_values,allow_formula,list_inputs,list_outputs);\n    }\n\n    //! Fill sequentially pixel values according to the values found in another image.\n    /**\n       \\param values Image containing the values used for the filling.\n       \\param repeat_values In case there are less values than necessary in \\c values, tells if these values must be\n         repeated for the filling.\n    **/\n    template<typename t>\n    CImg<T>& fill(const CImg<t>& values, const bool repeat_values=true) {\n      if (is_empty() || !values) return *this;\n      T *ptrd = _data, *ptre = ptrd + size();\n      for (t *ptrs = values._data, *ptrs_end = ptrs + values.size(); ptrs<ptrs_end && ptrd<ptre; ++ptrs)\n        *(ptrd++) = (T)*ptrs;\n      if (repeat_values && ptrd<ptre) for (T *ptrs = _data; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs;\n      return *this;\n    }\n\n    //! Fill sequentially pixel values according to the values found in another image \\newinstance.\n    template<typename t>\n    CImg<T> get_fill(const CImg<t>& values, const bool repeat_values=true) const {\n      return repeat_values?CImg<T>(_width,_height,_depth,_spectrum).fill(values,repeat_values):\n        (+*this).fill(values,repeat_values);\n    }\n\n    //! Fill pixel values along the X-axis at a specified pixel position.\n    /**\n       \\param y Y-coordinate of the filled column.\n       \\param z Z-coordinate of the filled column.\n       \\param c C-coordinate of the filled column.\n       \\param a0 First fill value.\n    **/\n    CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const int a0, ...) {\n#define _cimg_fill1(x,y,z,c,off,siz,t) { \\\n    va_list ap; va_start(ap,a0); T *ptrd = data(x,y,z,c); *ptrd = (T)a0; \\\n    for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \\\n    va_end(ap); }\n      if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,int);\n      return *this;\n    }\n\n    //! Fill pixel values along the X-axis at a specified pixel position \\overloading.\n    CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const double a0, ...) {\n      if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,double);\n      return *this;\n    }\n\n    //! Fill pixel values along the Y-axis at a specified pixel position.\n    /**\n       \\param x X-coordinate of the filled row.\n       \\param z Z-coordinate of the filled row.\n       \\param c C-coordinate of the filled row.\n       \\param a0 First fill value.\n    **/\n    CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const int a0, ...) {\n      if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,int);\n      return *this;\n    }\n\n    //! Fill pixel values along the Y-axis at a specified pixel position \\overloading.\n    CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const double a0, ...) {\n      if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,double);\n      return *this;\n    }\n\n    //! Fill pixel values along the Z-axis at a specified pixel position.\n    /**\n       \\param x X-coordinate of the filled slice.\n       \\param y Y-coordinate of the filled slice.\n       \\param c C-coordinate of the filled slice.\n       \\param a0 First fill value.\n    **/\n    CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const int a0, ...) {\n      const ulongT wh = (ulongT)_width*_height;\n      if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,int);\n      return *this;\n    }\n\n    //! Fill pixel values along the Z-axis at a specified pixel position \\overloading.\n    CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const double a0, ...) {\n      const ulongT wh = (ulongT)_width*_height;\n      if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,double);\n      return *this;\n    }\n\n    //! Fill pixel values along the C-axis at a specified pixel position.\n    /**\n       \\param x X-coordinate of the filled channel.\n       \\param y Y-coordinate of the filled channel.\n       \\param z Z-coordinate of the filled channel.\n       \\param a0 First filling value.\n    **/\n    CImg<T>& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) {\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,int);\n      return *this;\n    }\n\n    //! Fill pixel values along the C-axis at a specified pixel position \\overloading.\n    CImg<T>& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) {\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,double);\n      return *this;\n    }\n\n    //! Discard specified sequence of values in the image buffer, along a specific axis.\n    /**\n       \\param values Sequence of values to discard.\n       \\param axis Axis along which the values are discarded. If set to \\c 0 (default value)\n         the method does it for all the buffer values and returns a one-column vector.\n       \\note Discarded values will change the image geometry, so the resulting image\n       is returned as a one-column vector.\n    **/\n    template<typename t>\n    CImg<T>& discard(const CImg<t>& values, const char axis=0) {\n      if (is_empty() || !values) return *this;\n      return get_discard(values,axis).move_to(*this);\n    }\n\n    template<typename t>\n    CImg<T> get_discard(const CImg<t>& values, const char axis=0) const {\n      CImg<T> res;\n      if (!values) return +*this;\n      if (is_empty()) return res;\n      const ulongT vsiz = values.size();\n      const char _axis = cimg::uncase(axis);\n      ulongT j = 0;\n      unsigned int k = 0;\n      int i0 = 0;\n      res.assign(width(),height(),depth(),spectrum());\n      switch (_axis) {\n      case 'x' : {\n        cimg_forX(*this,i) {\n          if ((*this)(i)!=(T)values[j]) {\n            if (j) --i;\n            res.draw_image(k,get_columns(i0,i));\n            k+=i - i0 + 1; i0 = i + 1; j = 0;\n          } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } }\n        }\n        if (i0<width()) { res.draw_image(k,get_columns(i0,width() - 1)); k+=width() - i0; }\n        res.resize(k,-100,-100,-100,0);\n      } break;\n      case 'y' : {\n        cimg_forY(*this,i) {\n          if ((*this)(0,i)!=(T)values[j]) {\n            if (j) --i;\n            res.draw_image(0,k,get_rows(i0,i));\n            k+=i - i0 + 1; i0 = i + 1; j = 0;\n          } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } }\n        }\n        if (i0<height()) { res.draw_image(0,k,get_rows(i0,height() - 1)); k+=height() - i0; }\n        res.resize(-100,k,-100,-100,0);\n      } break;\n      case 'z' : {\n        cimg_forZ(*this,i) {\n          if ((*this)(0,0,i)!=(T)values[j]) {\n            if (j) --i;\n            res.draw_image(0,0,k,get_slices(i0,i));\n            k+=i - i0 + 1; i0 = i + 1; j = 0;\n          } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } }\n        }\n        if (i0<depth()) { res.draw_image(0,0,k,get_slices(i0,height() - 1)); k+=depth() - i0; }\n        res.resize(-100,-100,k,-100,0);\n      } break;\n      case 'c' : {\n        cimg_forC(*this,i) {\n          if ((*this)(0,0,0,i)!=(T)values[j]) {\n            if (j) --i;\n            res.draw_image(0,0,0,k,get_channels(i0,i));\n            k+=i - i0 + 1; i0 = i + 1; j = 0;\n          } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } }\n        }\n        if (i0<spectrum()) { res.draw_image(0,0,k,get_channels(i0,height() - 1)); k+=spectrum() - i0; }\n        res.resize(-100,-100,-100,k,0);\n      } break;\n      default : {\n        res.unroll('y');\n        cimg_foroff(*this,i) {\n          if ((*this)[i]!=(T)values[j]) {\n            if (j) --i;\n            std::memcpy(res._data + k,_data + i0,(i - i0 + 1)*sizeof(T));\n            k+=i - i0 + 1; i0 = (int)i + 1; j = 0;\n          } else { ++j; if (j>=vsiz) { j = 0; i0 = (int)i + 1; }}\n        }\n        const ulongT siz = size();\n        if ((ulongT)i0<siz) { std::memcpy(res._data + k,_data + i0,(siz - i0)*sizeof(T)); k+=siz - i0; }\n        res.resize(1,k,1,1,0);\n      }\n      }\n      return res;\n    }\n\n    //! Discard neighboring duplicates in the image buffer, along the specified axis.\n    CImg<T>& discard(const char axis=0) {\n      return get_discard(axis).move_to(*this);\n    }\n\n    //! Discard neighboring duplicates in the image buffer, along the specified axis \\newinstance.\n    CImg<T> get_discard(const char axis=0) const {\n      CImg<T> res;\n      if (is_empty()) return res;\n      const char _axis = cimg::uncase(axis);\n      T current = *_data?0:(T)1;\n      int j = 0;\n      res.assign(width(),height(),depth(),spectrum());\n      switch (_axis) {\n      case 'x' : {\n        cimg_forX(*this,i)\n          if ((*this)(i)!=current) { res.draw_image(j++,get_column(i)); current = (*this)(i); }\n        res.resize(j,-100,-100,-100,0);\n      } break;\n      case 'y' : {\n        cimg_forY(*this,i)\n          if ((*this)(0,i)!=current) { res.draw_image(0,j++,get_row(i)); current = (*this)(0,i); }\n        res.resize(-100,j,-100,-100,0);\n      } break;\n      case 'z' : {\n        cimg_forZ(*this,i)\n          if ((*this)(0,0,i)!=current) { res.draw_image(0,0,j++,get_slice(i)); current = (*this)(0,0,i); }\n        res.resize(-100,-100,j,-100,0);\n      } break;\n      case 'c' : {\n        cimg_forC(*this,i)\n          if ((*this)(0,0,0,i)!=current) { res.draw_image(0,0,0,j++,get_channel(i)); current = (*this)(0,0,0,i); }\n        res.resize(-100,-100,-100,j,0);\n      } break;\n      default : {\n        res.unroll('y');\n        cimg_foroff(*this,i)\n          if ((*this)[i]!=current) res[j++] = current = (*this)[i];\n        res.resize(-100,j,-100,-100,0);\n      }\n      }\n      return res;\n    }\n\n    //! Invert endianness of all pixel values.\n    /**\n     **/\n    CImg<T>& invert_endianness() {\n      cimg::invert_endianness(_data,size());\n      return *this;\n    }\n\n    //! Invert endianness of all pixel values \\newinstance.\n    CImg<T> get_invert_endianness() const {\n      return (+*this).invert_endianness();\n    }\n\n    //! Fill image with random values in specified range.\n    /**\n       \\param val_min Minimal authorized random value.\n       \\param val_max Maximal authorized random value.\n       \\note Random variables are uniformely distributed in [val_min,val_max].\n     **/\n    CImg<T>& rand(const T& val_min, const T& val_max) {\n      const float delta = (float)val_max - (float)val_min + (cimg::type<T>::is_float()?0:1);\n      if (cimg::type<T>::is_float()) cimg_for(*this,ptrd,T) *ptrd = (T)(val_min + cimg::rand()*delta);\n      else cimg_for(*this,ptrd,T) *ptrd = cimg::min(val_max,(T)(val_min + cimg::rand()*delta));\n      return *this;\n    }\n\n    //! Fill image with random values in specified range \\newinstance.\n    CImg<T> get_rand(const T& val_min, const T& val_max) const {\n      return (+*this).rand(val_min,val_max);\n    }\n\n    //! Round pixel values.\n    /**\n       \\param y Rounding precision.\n       \\param rounding_type Rounding type. Can be:\n       - \\c -1: Backward.\n       - \\c 0: Nearest.\n       - \\c 1: Forward.\n    **/\n    CImg<T>& round(const double y=1, const int rounding_type=0) {\n      if (y>0)\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=8192)\n#endif\n        cimg_rof(*this,ptrd,T) *ptrd = cimg::round(*ptrd,y,rounding_type);\n      return *this;\n    }\n\n    //! Round pixel values \\newinstance.\n    CImg<T> get_round(const double y=1, const unsigned int rounding_type=0) const {\n      return (+*this).round(y,rounding_type);\n    }\n\n    //! Add random noise to pixel values.\n    /**\n       \\param sigma Amplitude of the random additive noise. If \\p sigma<0, it stands for a percentage of the\n         global value range.\n       \\param noise_type Type of additive noise (can be \\p 0=gaussian, \\p 1=uniform, \\p 2=Salt and Pepper,\n         \\p 3=Poisson or \\p 4=Rician).\n       \\return A reference to the modified image instance.\n       \\note\n       - For Poisson noise (\\p noise_type=3), parameter \\p sigma is ignored, as Poisson noise only depends on\n         the image value itself.\n       - Function \\p CImg<T>::get_noise() is also defined. It returns a non-shared modified copy of the image instance.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"), res = img.get_noise(40);\n       (img,res.normalize(0,255)).display();\n       \\endcode\n       \\image html ref_noise.jpg\n    **/\n    CImg<T>& noise(const double sigma, const unsigned int noise_type=0) {\n      if (is_empty()) return *this;\n      const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();\n      Tfloat nsigma = (Tfloat)sigma, m = 0, M = 0;\n      if (nsigma==0 && noise_type!=3) return *this;\n      if (nsigma<0 || noise_type==2) m = (Tfloat)min_max(M);\n      if (nsigma<0) nsigma = (Tfloat)(-nsigma*(M-m)/100.0);\n      switch (noise_type) {\n      case 0 : { // Gaussian noise\n        cimg_rof(*this,ptrd,T) {\n          Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::grand());\n          if (val>vmax) val = vmax;\n          if (val<vmin) val = vmin;\n          *ptrd = (T)val;\n        }\n      } break;\n      case 1 : { // Uniform noise\n        cimg_rof(*this,ptrd,T) {\n          Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::rand(-1,1));\n          if (val>vmax) val = vmax;\n          if (val<vmin) val = vmin;\n          *ptrd = (T)val;\n        }\n      } break;\n      case 2 : { // Salt & Pepper noise\n        if (nsigma<0) nsigma = -nsigma;\n        if (M==m) { m = 0; M = (Tfloat)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); }\n        cimg_rof(*this,ptrd,T) if (cimg::rand(100)<nsigma) *ptrd = (T)(cimg::rand()<0.5?M:m);\n      } break;\n      case 3 : { // Poisson Noise\n        cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::prand(*ptrd);\n      } break;\n      case 4 : { // Rice noise\n        const Tfloat sqrt2 = (Tfloat)std::sqrt(2.0);\n        cimg_rof(*this,ptrd,T) {\n          const Tfloat\n            val0 = (Tfloat)*ptrd/sqrt2,\n            re = (Tfloat)(val0 + nsigma*cimg::grand()),\n            im = (Tfloat)(val0 + nsigma*cimg::grand());\n          Tfloat val = (Tfloat)std::sqrt(re*re + im*im);\n          if (val>vmax) val = vmax;\n          if (val<vmin) val = vmin;\n          *ptrd = (T)val;\n        }\n      } break;\n      default :\n        throw CImgArgumentException(_cimg_instance\n                                    \"noise(): Invalid specified noise type %d \"\n                                    \"(should be { 0=gaussian | 1=uniform | 2=salt&Pepper | 3=poisson }).\",\n                                    cimg_instance,\n                                    noise_type);\n      }\n      return *this;\n    }\n\n    //! Add random noise to pixel values \\newinstance.\n    CImg<T> get_noise(const double sigma, const unsigned int noise_type=0) const {\n      return (+*this).noise(sigma,noise_type);\n    }\n\n    //! Linearly normalize pixel values.\n    /**\n       \\param min_value Minimum desired value of the resulting image.\n       \\param max_value Maximum desired value of the resulting image.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"), res = img.get_normalize(160,220);\n       (img,res).display();\n       \\endcode\n       \\image html ref_normalize2.jpg\n    **/\n    CImg<T>& normalize(const T& min_value, const T& max_value) {\n      if (is_empty()) return *this;\n      const T a = min_value<max_value?min_value:max_value, b = min_value<max_value?max_value:min_value;\n      T m, M = max_min(m);\n      const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;\n      if (m==M) return fill(min_value);\n      if (m!=a || M!=b)\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=65536)\n#endif\n        cimg_rof(*this,ptrd,T) *ptrd = (T)((*ptrd - fm)/(fM - fm)*(b - a) + a);\n      return *this;\n    }\n\n    //! Linearly normalize pixel values \\newinstance.\n    CImg<Tfloat> get_normalize(const T& min_value, const T& max_value) const {\n      return CImg<Tfloat>(*this,false).normalize((Tfloat)min_value,(Tfloat)max_value);\n    }\n\n    //! Normalize multi-valued pixels of the image instance, with respect to their L2-norm.\n    /**\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"), res = img.get_normalize();\n       (img,res.normalize(0,255)).display();\n       \\endcode\n       \\image html ref_normalize.jpg\n    **/\n    CImg<T>& normalize() {\n      const ulongT whd = (ulongT)_width*_height*_depth;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16)\n#endif\n      cimg_forYZ(*this,y,z) {\n        T *ptrd = data(0,y,z,0);\n        cimg_forX(*this,x) {\n          const T *ptrs = ptrd;\n          float n = 0;\n          cimg_forC(*this,c) { n+=cimg::sqr((float)*ptrs); ptrs+=whd; }\n          n = (float)std::sqrt(n);\n          T *_ptrd = ptrd++;\n          if (n>0) cimg_forC(*this,c) { *_ptrd = (T)(*_ptrd/n); _ptrd+=whd; }\n          else cimg_forC(*this,c) { *_ptrd = (T)0; _ptrd+=whd; }\n        }\n      }\n      return *this;\n    }\n\n    //! Normalize multi-valued pixels of the image instance, with respect to their L2-norm \\newinstance.\n    CImg<Tfloat> get_normalize() const {\n      return CImg<Tfloat>(*this,false).normalize();\n    }\n\n    //! Compute Lp-norm of each multi-valued pixel of the image instance.\n    /**\n       \\param norm_type Type of computed vector norm (can be \\p -1=Linf, or \\p>=0).\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"), res = img.get_norm();\n       (img,res.normalize(0,255)).display();\n       \\endcode\n       \\image html ref_norm.jpg\n    **/\n    CImg<T>& norm(const int norm_type=2) {\n      if (_spectrum==1 && norm_type) return abs();\n      return get_norm(norm_type).move_to(*this);\n    }\n\n    //! Compute L2-norm of each multi-valued pixel of the image instance \\newinstance.\n    CImg<Tfloat> get_norm(const int norm_type=2) const {\n      if (is_empty()) return *this;\n      if (_spectrum==1 && norm_type) return get_abs();\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      CImg<Tfloat> res(_width,_height,_depth);\n      switch (norm_type) {\n      case -1 : { // Linf-norm.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16)\n#endif\n        cimg_forYZ(*this,y,z) {\n          const ulongT off = (ulongT)offset(0,y,z);\n          const T *ptrs = _data + off;\n          Tfloat *ptrd = res._data + off;\n          cimg_forX(*this,x) {\n            Tfloat n = 0;\n            const T *_ptrs = ptrs++;\n            cimg_forC(*this,c) { const Tfloat val = (Tfloat)cimg::abs(*_ptrs); if (val>n) n = val; _ptrs+=whd; }\n            *(ptrd++) = n;\n          }\n        }\n      } break;\n      case 0 : { // L0-norm.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16)\n#endif\n        cimg_forYZ(*this,y,z) {\n          const ulongT off = (ulongT)offset(0,y,z);\n          const T *ptrs = _data + off;\n          Tfloat *ptrd = res._data + off;\n          cimg_forX(*this,x) {\n            unsigned int n = 0;\n            const T *_ptrs = ptrs++;\n            cimg_forC(*this,c) { n+=*_ptrs==0?0:1; _ptrs+=whd; }\n            *(ptrd++) = (Tfloat)n;\n          }\n        }\n      } break;\n      case 1 : { // L1-norm.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16)\n#endif\n        cimg_forYZ(*this,y,z) {\n          const ulongT off = (ulongT)offset(0,y,z);\n          const T *ptrs = _data + off;\n          Tfloat *ptrd = res._data + off;\n          cimg_forX(*this,x) {\n            Tfloat n = 0;\n            const T *_ptrs = ptrs++;\n            cimg_forC(*this,c) { n+=cimg::abs(*_ptrs); _ptrs+=whd; }\n            *(ptrd++) = n;\n          }\n        }\n      } break;\n      case 2 : { // L2-norm.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16)\n#endif\n        cimg_forYZ(*this,y,z) {\n          const ulongT off = (ulongT)offset(0,y,z);\n          const T *ptrs = _data + off;\n          Tfloat *ptrd = res._data + off;\n          cimg_forX(*this,x) {\n            Tfloat n = 0;\n            const T *_ptrs = ptrs++;\n            cimg_forC(*this,c) { n+=cimg::sqr((Tfloat)*_ptrs); _ptrs+=whd; }\n            *(ptrd++) = (Tfloat)std::sqrt((Tfloat)n);\n          }\n        }\n      } break;\n      default : { // Linf-norm.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16)\n#endif\n        cimg_forYZ(*this,y,z) {\n          const ulongT off = (ulongT)offset(0,y,z);\n          const T *ptrs = _data + off;\n          Tfloat *ptrd = res._data + off;\n          cimg_forX(*this,x) {\n            Tfloat n = 0;\n            const T *_ptrs = ptrs++;\n            cimg_forC(*this,c) { n+=std::pow(cimg::abs((Tfloat)*_ptrs),(Tfloat)norm_type); _ptrs+=whd; }\n            *(ptrd++) = (Tfloat)std::pow((Tfloat)n,1/(Tfloat)norm_type);\n          }\n        }\n      }\n      }\n      return res;\n    }\n\n    //! Cut pixel values in specified range.\n    /**\n       \\param min_value Minimum desired value of the resulting image.\n       \\param max_value Maximum desired value of the resulting image.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"), res = img.get_cut(160,220);\n       (img,res).display();\n       \\endcode\n       \\image html ref_cut.jpg\n    **/\n    CImg<T>& cut(const T& min_value, const T& max_value) {\n      if (is_empty()) return *this;\n      const T a = min_value<max_value?min_value:max_value, b = min_value<max_value?max_value:min_value;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n      cimg_rof(*this,ptrd,T) *ptrd = (*ptrd<a)?a:((*ptrd>b)?b:*ptrd);\n      return *this;\n    }\n\n    //! Cut pixel values in specified range \\newinstance.\n    CImg<T> get_cut(const T& min_value, const T& max_value) const {\n      return (+*this).cut(min_value,max_value);\n    }\n\n    //! Uniformly quantize pixel values.\n    /**\n       \\param nb_levels Number of quantization levels.\n       \\param keep_range Tells if resulting values keep the same range as the original ones.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"), res = img.get_quantize(4);\n       (img,res).display();\n       \\endcode\n       \\image html ref_quantize.jpg\n    **/\n    CImg<T>& quantize(const unsigned int nb_levels, const bool keep_range=true) {\n      if (!nb_levels)\n        throw CImgArgumentException(_cimg_instance\n                                    \"quantize(): Invalid quantization request with 0 values.\",\n                                    cimg_instance);\n\n      if (is_empty()) return *this;\n      Tfloat m, M = (Tfloat)max_min(m), range = M - m;\n      if (range>0) {\n        if (keep_range)\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n          cimg_rof(*this,ptrd,T) {\n            const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range);\n            *ptrd = (T)(m + cimg::min(val,nb_levels - 1)*range/nb_levels);\n          } else\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n          cimg_rof(*this,ptrd,T) {\n            const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range);\n            *ptrd = (T)cimg::min(val,nb_levels - 1);\n          }\n      }\n      return *this;\n    }\n\n    //! Uniformly quantize pixel values \\newinstance.\n    CImg<T> get_quantize(const unsigned int n, const bool keep_range=true) const {\n      return (+*this).quantize(n,keep_range);\n    }\n\n    //! Threshold pixel values.\n    /**\n       \\param value Threshold value\n       \\param soft_threshold Tells if soft thresholding must be applied (instead of hard one).\n       \\param strict_threshold Tells if threshold value is strict.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"), res = img.get_threshold(128);\n       (img,res.normalize(0,255)).display();\n       \\endcode\n       \\image html ref_threshold.jpg\n    **/\n    CImg<T>& threshold(const T& value, const bool soft_threshold=false, const bool strict_threshold=false) {\n      if (is_empty()) return *this;\n      if (strict_threshold) {\n        if (soft_threshold)\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n          cimg_rof(*this,ptrd,T) {\n            const T v = *ptrd;\n            *ptrd = v>value?(T)(v-value):v<-(float)value?(T)(v + value):(T)0;\n          }\n        else\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=65536)\n#endif\n          cimg_rof(*this,ptrd,T) *ptrd = *ptrd>value?(T)1:(T)0;\n      } else {\n        if (soft_threshold)\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=32768)\n#endif\n          cimg_rof(*this,ptrd,T) {\n            const T v = *ptrd;\n            *ptrd = v>=value?(T)(v-value):v<=-(float)value?(T)(v + value):(T)0;\n          }\n        else\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=65536)\n#endif\n          cimg_rof(*this,ptrd,T) *ptrd = *ptrd>=value?(T)1:(T)0;\n      }\n      return *this;\n    }\n\n    //! Threshold pixel values \\newinstance.\n    CImg<T> get_threshold(const T& value, const bool soft_threshold=false, const bool strict_threshold=false) const {\n      return (+*this).threshold(value,soft_threshold,strict_threshold);\n    }\n\n    //! Compute the histogram of pixel values.\n    /**\n       \\param nb_levels Number of desired histogram levels.\n       \\param min_value Minimum pixel value considered for the histogram computation.\n         All pixel values lower than \\p min_value will not be counted.\n       \\param max_value Maximum pixel value considered for the histogram computation.\n         All pixel values higher than \\p max_value will not be counted.\n       \\note\n       - The histogram H of an image I is the 1d function where H(x) counts the number of occurences of the value x\n         in the image I.\n       - The resulting histogram is always defined in 1d. Histograms of multi-valued images are not multi-dimensional.\n       \\par Example\n       \\code\n       const CImg<float> img = CImg<float>(\"reference.jpg\").histogram(256);\n       img.display_graph(0,3);\n       \\endcode\n       \\image html ref_histogram.jpg\n    **/\n    CImg<T>& histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) {\n      return get_histogram(nb_levels,min_value,max_value).move_to(*this);\n    }\n\n    //! Compute the histogram of pixel values \\overloading.\n    CImg<T>& histogram(const unsigned int nb_levels) {\n      return get_histogram(nb_levels).move_to(*this);\n    }\n\n    //! Compute the histogram of pixel values \\newinstance.\n    CImg<ulongT> get_histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) const {\n      if (!nb_levels || is_empty()) return CImg<ulongT>();\n      const double\n        vmin = (double)(min_value<max_value?min_value:max_value),\n        vmax = (double)(min_value<max_value?max_value:min_value);\n      CImg<ulongT> res(nb_levels,1,1,1,0);\n      cimg_rof(*this,ptrs,T) {\n        const T val = *ptrs;\n        if (val>=vmin && val<=vmax) ++res[val==vmax?nb_levels - 1:(unsigned int)((val - vmin)*nb_levels/(vmax - vmin))];\n      }\n      return res;\n    }\n\n    //! Compute the histogram of pixel values \\newinstance.\n    CImg<ulongT> get_histogram(const unsigned int nb_levels) const {\n      if (!nb_levels || is_empty()) return CImg<ulongT>();\n      T vmax = 0, vmin = min_max(vmax);\n      return get_histogram(nb_levels,vmin,vmax);\n    }\n\n    //! Equalize histogram of pixel values.\n    /**\n       \\param nb_levels Number of histogram levels used for the equalization.\n       \\param min_value Minimum pixel value considered for the histogram computation.\n         All pixel values lower than \\p min_value will not be counted.\n       \\param max_value Maximum pixel value considered for the histogram computation.\n         All pixel values higher than \\p max_value will not be counted.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"), res = img.get_equalize(256);\n       (img,res).display();\n       \\endcode\n       \\image html ref_equalize.jpg\n    **/\n    CImg<T>& equalize(const unsigned int nb_levels, const T& min_value, const T& max_value) {\n      if (!nb_levels || is_empty()) return *this;\n      const T\n        vmin = min_value<max_value?min_value:max_value,\n        vmax = min_value<max_value?max_value:min_value;\n      CImg<ulongT> hist = get_histogram(nb_levels,vmin,vmax);\n      ulongT cumul = 0;\n      cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; }\n      if (!cumul) cumul = 1;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(size()>=1048576)\n#endif\n      cimg_rof(*this,ptrd,T) {\n        const int pos = (int)((*ptrd-vmin)*(nb_levels - 1.)/(vmax-vmin));\n        if (pos>=0 && pos<(int)nb_levels) *ptrd = (T)(vmin + (vmax-vmin)*hist[pos]/cumul);\n      }\n      return *this;\n    }\n\n    //! Equalize histogram of pixel values \\overloading.\n    CImg<T>& equalize(const unsigned int nb_levels) {\n      if (!nb_levels || is_empty()) return *this;\n      T vmax = 0, vmin = min_max(vmax);\n      return equalize(nb_levels,vmin,vmax);\n    }\n\n    //! Equalize histogram of pixel values \\newinstance.\n    CImg<T> get_equalize(const unsigned int nblevels, const T& val_min, const T& val_max) const {\n      return (+*this).equalize(nblevels,val_min,val_max);\n    }\n\n    //! Equalize histogram of pixel values \\newinstance.\n    CImg<T> get_equalize(const unsigned int nblevels) const {\n      return (+*this).equalize(nblevels);\n    }\n\n    //! Index multi-valued pixels regarding to a specified colormap.\n    /**\n       \\param colormap Multi-valued colormap used as the basis for multi-valued pixel indexing.\n       \\param dithering Level of dithering (0=disable, 1=standard level).\n       \\param map_indexes Tell if the values of the resulting image are the colormap indices or the colormap vectors.\n       \\note\n       - \\p img.index(colormap,dithering,1) is equivalent to <tt>img.index(colormap,dithering,0).map(colormap)</tt>.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"), colormap(3,1,1,3, 0,128,255, 0,128,255, 0,128,255);\n       const CImg<float> res = img.get_index(colormap,1,true);\n       (img,res).display();\n       \\endcode\n       \\image html ref_index.jpg\n    **/\n    template<typename t>\n    CImg<T>& index(const CImg<t>& colormap, const float dithering=1, const bool map_indexes=false) {\n      return get_index(colormap,dithering,map_indexes).move_to(*this);\n    }\n\n    //! Index multi-valued pixels regarding to a specified colormap \\newinstance.\n    template<typename t>\n    CImg<typename CImg<t>::Tuint>\n    get_index(const CImg<t>& colormap, const float dithering=1, const bool map_indexes=true) const {\n      if (colormap._spectrum!=_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"index(): Instance and specified colormap (%u,%u,%u,%u,%p) \"\n                                    \"have incompatible dimensions.\",\n                                    cimg_instance,\n                                    colormap._width,colormap._height,colormap._depth,colormap._spectrum,colormap._data);\n\n      typedef typename CImg<t>::Tuint tuint;\n      if (is_empty()) return CImg<tuint>();\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        pwhd = (ulongT)colormap._width*colormap._height*colormap._depth;\n      CImg<tuint> res(_width,_height,_depth,map_indexes?_spectrum:1);\n      tuint *ptrd = res._data;\n      if (dithering>0) { // Dithered versions.\n        const float ndithering = (dithering<0?0:dithering>1?1:dithering)/16;\n        Tfloat valm = 0, valM = (Tfloat)max_min(valm);\n        if (valm==valM && valm>=0 && valM<=255) { valm = 0; valM = 255; }\n        CImg<Tfloat> cache = get_crop(-1,0,0,0,_width,1,0,_spectrum - 1);\n        Tfloat *cache_current = cache.data(1,0,0,0), *cache_next = cache.data(1,1,0,0);\n        const ulongT cwhd = (ulongT)cache._width*cache._height*cache._depth;\n        switch (_spectrum) {\n        case 1 : { // Optimized for scalars.\n          cimg_forYZ(*this,y,z) {\n            if (y<height() - 2) {\n              Tfloat *ptrc0 = cache_next; const T *ptrs0 = data(0,y + 1,z,0);\n              cimg_forX(*this,x) *(ptrc0++) = (Tfloat)*(ptrs0++);\n            }\n            Tfloat *ptrs0 = cache_current, *ptrsn0 = cache_next;\n            cimg_forX(*this,x) {\n              const Tfloat _val0 = (Tfloat)*ptrs0, val0 = _val0<valm?valm:_val0>valM?valM:_val0;\n              Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = colormap._data;\n              for (const t *ptrp0 = colormap._data, *ptrp_end = ptrp0 + pwhd; ptrp0<ptrp_end; ) {\n                const Tfloat pval0 = (Tfloat)*(ptrp0++) - val0, dist = pval0*pval0;\n                if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }\n              }\n              const Tfloat err0 = ((*(ptrs0++)=val0) - (Tfloat)*ptrmin0)*ndithering;\n              *ptrs0+=7*err0; *(ptrsn0 - 1)+=3*err0; *(ptrsn0++)+=5*err0; *ptrsn0+=err0;\n              if (map_indexes) *(ptrd++) = (tuint)*ptrmin0; else *(ptrd++) = (tuint)(ptrmin0 - colormap._data);\n            }\n            cimg::swap(cache_current,cache_next);\n          }\n        } break;\n        case 2 : { // Optimized for 2d vectors.\n          tuint *ptrd1 = ptrd + whd;\n          cimg_forYZ(*this,y,z) {\n            if (y<height() - 2) {\n              Tfloat *ptrc0 = cache_next, *ptrc1 = ptrc0 + cwhd;\n              const T *ptrs0 = data(0,y + 1,z,0), *ptrs1 = ptrs0 + whd;\n              cimg_forX(*this,x) { *(ptrc0++) = (Tfloat)*(ptrs0++); *(ptrc1++) = (Tfloat)*(ptrs1++); }\n            }\n            Tfloat\n              *ptrs0 = cache_current, *ptrs1 = ptrs0 + cwhd,\n              *ptrsn0 = cache_next, *ptrsn1 = ptrsn0 + cwhd;\n            cimg_forX(*this,x) {\n              const Tfloat\n                _val0 = (Tfloat)*ptrs0, val0 = _val0<valm?valm:_val0>valM?valM:_val0,\n                _val1 = (Tfloat)*ptrs1, val1 = _val1<valm?valm:_val1>valM?valM:_val1;\n              Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = colormap._data;\n              for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) {\n                const Tfloat\n                  pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1,\n                  dist = pval0*pval0 + pval1*pval1;\n                if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }\n              }\n              const t *const ptrmin1 = ptrmin0 + pwhd;\n              const Tfloat\n                err0 = ((*(ptrs0++)=val0) - (Tfloat)*ptrmin0)*ndithering,\n                err1 = ((*(ptrs1++)=val1) - (Tfloat)*ptrmin1)*ndithering;\n              *ptrs0+=7*err0; *ptrs1+=7*err1;\n              *(ptrsn0 - 1)+=3*err0; *(ptrsn1 - 1)+=3*err1;\n              *(ptrsn0++)+=5*err0; *(ptrsn1++)+=5*err1;\n              *ptrsn0+=err0; *ptrsn1+=err1;\n              if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*ptrmin1; }\n              else *(ptrd++) = (tuint)(ptrmin0 - colormap._data);\n            }\n            cimg::swap(cache_current,cache_next);\n          }\n        } break;\n        case 3 : { // Optimized for 3d vectors (colors).\n          tuint *ptrd1 = ptrd + whd, *ptrd2 = ptrd1 + whd;\n          cimg_forYZ(*this,y,z) {\n            if (y<height() - 2) {\n              Tfloat *ptrc0 = cache_next, *ptrc1 = ptrc0 + cwhd, *ptrc2 = ptrc1 + cwhd;\n              const T *ptrs0 = data(0,y + 1,z,0), *ptrs1 = ptrs0 + whd, *ptrs2 = ptrs1 + whd;\n              cimg_forX(*this,x) {\n                *(ptrc0++) = (Tfloat)*(ptrs0++); *(ptrc1++) = (Tfloat)*(ptrs1++); *(ptrc2++) = (Tfloat)*(ptrs2++);\n              }\n            }\n            Tfloat\n              *ptrs0 = cache_current, *ptrs1 = ptrs0 + cwhd, *ptrs2 = ptrs1 + cwhd,\n              *ptrsn0 = cache_next, *ptrsn1 = ptrsn0 + cwhd, *ptrsn2 = ptrsn1 + cwhd;\n            cimg_forX(*this,x) {\n              const Tfloat\n                _val0 = (Tfloat)*ptrs0, val0 = _val0<valm?valm:_val0>valM?valM:_val0,\n                _val1 = (Tfloat)*ptrs1, val1 = _val1<valm?valm:_val1>valM?valM:_val1,\n                _val2 = (Tfloat)*ptrs2, val2 = _val2<valm?valm:_val2>valM?valM:_val2;\n              Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = colormap._data;\n              for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd,\n                     *ptrp_end = ptrp1; ptrp0<ptrp_end; ) {\n                const Tfloat\n                  pval0 = (Tfloat)*(ptrp0++) - val0,\n                  pval1 = (Tfloat)*(ptrp1++) - val1,\n                  pval2 = (Tfloat)*(ptrp2++) - val2,\n                  dist = pval0*pval0 + pval1*pval1 + pval2*pval2;\n                if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }\n              }\n              const t *const ptrmin1 = ptrmin0 + pwhd, *const ptrmin2 = ptrmin1 + pwhd;\n              const Tfloat\n                err0 = ((*(ptrs0++)=val0) - (Tfloat)*ptrmin0)*ndithering,\n                err1 = ((*(ptrs1++)=val1) - (Tfloat)*ptrmin1)*ndithering,\n                err2 = ((*(ptrs2++)=val2) - (Tfloat)*ptrmin2)*ndithering;\n\n              *ptrs0+=7*err0; *ptrs1+=7*err1; *ptrs2+=7*err2;\n              *(ptrsn0 - 1)+=3*err0; *(ptrsn1 - 1)+=3*err1; *(ptrsn2 - 1)+=3*err2;\n              *(ptrsn0++)+=5*err0; *(ptrsn1++)+=5*err1; *(ptrsn2++)+=5*err2;\n              *ptrsn0+=err0; *ptrsn1+=err1; *ptrsn2+=err2;\n\n              if (map_indexes) {\n                *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*ptrmin1; *(ptrd2++) = (tuint)*ptrmin2;\n              } else *(ptrd++) = (tuint)(ptrmin0 - colormap._data);\n            }\n            cimg::swap(cache_current,cache_next);\n          }\n        } break;\n        default : // Generic version\n          cimg_forYZ(*this,y,z) {\n            if (y<height() - 2) {\n              Tfloat *ptrc = cache_next;\n              cimg_forC(*this,c) {\n                Tfloat *_ptrc = ptrc; const T *_ptrs = data(0,y + 1,z,c);\n                cimg_forX(*this,x) *(_ptrc++) = (Tfloat)*(_ptrs++);\n                ptrc+=cwhd;\n              }\n            }\n            Tfloat *ptrs = cache_current, *ptrsn = cache_next;\n            cimg_forX(*this,x) {\n              Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin = colormap._data;\n              for (const t *ptrp = colormap._data, *ptrp_end = ptrp + pwhd; ptrp<ptrp_end; ++ptrp) {\n                Tfloat dist = 0; Tfloat *_ptrs = ptrs; const t *_ptrp = ptrp;\n                cimg_forC(*this,c) {\n                  const Tfloat _val = *_ptrs, val = _val<valm?valm:_val>valM?valM:_val;\n                  dist+=cimg::sqr((*_ptrs=val) - (Tfloat)*_ptrp); _ptrs+=cwhd; _ptrp+=pwhd;\n                }\n                if (dist<distmin) { ptrmin = ptrp; distmin = dist; }\n              }\n              const t *_ptrmin = ptrmin; Tfloat *_ptrs = ptrs++, *_ptrsn = (ptrsn++) - 1;\n              cimg_forC(*this,c) {\n                const Tfloat err = (*(_ptrs++) - (Tfloat)*_ptrmin)*ndithering;\n                *_ptrs+=7*err; *(_ptrsn++)+=3*err; *(_ptrsn++)+=5*err; *_ptrsn+=err;\n                _ptrmin+=pwhd; _ptrs+=cwhd - 1; _ptrsn+=cwhd - 2;\n              }\n              if (map_indexes) {\n                tuint *_ptrd = ptrd++;\n                cimg_forC(*this,c) { *_ptrd = (tuint)*ptrmin; _ptrd+=whd; ptrmin+=pwhd; }\n              }\n              else *(ptrd++) = (tuint)(ptrmin - colormap._data);\n            }\n            cimg::swap(cache_current,cache_next);\n          }\n        }\n      } else { // Non-dithered versions\n        switch (_spectrum) {\n        case 1 : { // Optimized for scalars.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=64 && _height*_depth>=16 && pwhd>=16)\n#endif\n          cimg_forYZ(*this,y,z) {\n            tuint *ptrd = res.data(0,y,z);\n            for (const T *ptrs0 = data(0,y,z), *ptrs_end = ptrs0 + _width; ptrs0<ptrs_end; ) {\n              const Tfloat val0 = (Tfloat)*(ptrs0++);\n              Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = colormap._data;\n              for (const t *ptrp0 = colormap._data, *ptrp_end = ptrp0 + pwhd; ptrp0<ptrp_end; ) {\n                const Tfloat pval0 = (Tfloat)*(ptrp0++) - val0, dist = pval0*pval0;\n                if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }\n              }\n              if (map_indexes) *(ptrd++) = (tuint)*ptrmin0; else *(ptrd++) = (tuint)(ptrmin0 - colormap._data);\n            }\n          }\n        } break;\n        case 2 : { // Optimized for 2d vectors.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=64 && _height*_depth>=16 && pwhd>=16)\n#endif\n          cimg_forYZ(*this,y,z) {\n            tuint *ptrd = res.data(0,y,z), *ptrd1 = ptrd + whd;\n            for (const T *ptrs0 = data(0,y,z), *ptrs1 = ptrs0 + whd, *ptrs_end = ptrs0 + _width; ptrs0<ptrs_end; ) {\n              const Tfloat val0 = (Tfloat)*(ptrs0++), val1 = (Tfloat)*(ptrs1++);\n              Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = colormap._data;\n              for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) {\n                const Tfloat\n                  pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1,\n                  dist = pval0*pval0 + pval1*pval1;\n                if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }\n              }\n              if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*(ptrmin0 + pwhd); }\n              else *(ptrd++) = (tuint)(ptrmin0 - colormap._data);\n            }\n          }\n        } break;\n        case 3 : { // Optimized for 3d vectors (colors).\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=64 && _height*_depth>=16 && pwhd>=16)\n#endif\n          cimg_forYZ(*this,y,z) {\n            tuint *ptrd = res.data(0,y,z), *ptrd1 = ptrd + whd, *ptrd2 = ptrd1 + whd;\n            for (const T *ptrs0 = data(0,y,z), *ptrs1 = ptrs0 + whd, *ptrs2 = ptrs1 + whd,\n                   *ptrs_end = ptrs0 + _width; ptrs0<ptrs_end; ) {\n              const Tfloat val0 = (Tfloat)*(ptrs0++), val1 = (Tfloat)*(ptrs1++), val2 = (Tfloat)*(ptrs2++);\n              Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = colormap._data;\n              for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd,\n                     *ptrp_end = ptrp1; ptrp0<ptrp_end; ) {\n                const Tfloat\n                  pval0 = (Tfloat)*(ptrp0++) - val0,\n                  pval1 = (Tfloat)*(ptrp1++) - val1,\n                  pval2 = (Tfloat)*(ptrp2++) - val2,\n                  dist = pval0*pval0 + pval1*pval1 + pval2*pval2;\n                if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }\n              }\n              if (map_indexes) {\n                *(ptrd++) = (tuint)*ptrmin0;\n                *(ptrd1++) = (tuint)*(ptrmin0 + pwhd);\n                *(ptrd2++) = (tuint)*(ptrmin0 + 2*pwhd);\n              } else *(ptrd++) = (tuint)(ptrmin0 - colormap._data);\n            }\n          }\n        } break;\n        default : // Generic version.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=64 && _height*_depth>=16 && pwhd>=16)\n#endif\n          cimg_forYZ(*this,y,z) {\n            tuint *ptrd = res.data(0,y,z);\n            for (const T *ptrs = data(0,y,z), *ptrs_end = ptrs + _width; ptrs<ptrs_end; ++ptrs) {\n              Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin = colormap._data;\n              for (const t *ptrp = colormap._data, *ptrp_end = ptrp + pwhd; ptrp<ptrp_end; ++ptrp) {\n                Tfloat dist = 0; const T *_ptrs = ptrs; const t *_ptrp = ptrp;\n                cimg_forC(*this,c) { dist+=cimg::sqr((Tfloat)*_ptrs - (Tfloat)*_ptrp); _ptrs+=whd; _ptrp+=pwhd; }\n                if (dist<distmin) { ptrmin = ptrp; distmin = dist; }\n              }\n              if (map_indexes) {\n                tuint *_ptrd = ptrd++;\n                cimg_forC(*this,c) { *_ptrd = (tuint)*ptrmin; _ptrd+=whd; ptrmin+=pwhd; }\n              }\n              else *(ptrd++) = (tuint)(ptrmin - colormap._data);\n            }\n          }\n        }\n      }\n      return res;\n    }\n\n    //! Map predefined colormap on the scalar (indexed) image instance.\n    /**\n       \\param colormap Multi-valued colormap used for mapping the indexes.\n       \\param boundary_conditions The border condition type { 0=zero |  1=dirichlet | 2=periodic }.\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\"),\n                         colormap1(3,1,1,3, 0,128,255, 0,128,255, 0,128,255),\n                         colormap2(3,1,1,3, 255,0,0, 0,255,0, 0,0,255),\n                         res = img.get_index(colormap1,0).map(colormap2);\n       (img,res).display();\n       \\endcode\n       \\image html ref_map.jpg\n    **/\n    template<typename t>\n    CImg<T>& map(const CImg<t>& colormap, const unsigned int boundary_conditions=0) {\n      return get_map(colormap,boundary_conditions).move_to(*this);\n    }\n\n    //! Map predefined colormap on the scalar (indexed) image instance \\newinstance.\n    template<typename t>\n    CImg<t> get_map(const CImg<t>& colormap, const unsigned int boundary_conditions=0) const {\n      if (_spectrum!=1 && colormap._spectrum!=1)\n        throw CImgArgumentException(_cimg_instance\n                                    \"map(): Instance and specified colormap (%u,%u,%u,%u,%p) \"\n                                    \"have incompatible dimensions.\",\n                                    cimg_instance,\n                                    colormap._width,colormap._height,colormap._depth,colormap._spectrum,colormap._data);\n\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        pwhd = (ulongT)colormap._width*colormap._height*colormap._depth;\n      CImg<t> res(_width,_height,_depth,colormap._spectrum==1?_spectrum:colormap._spectrum);\n      switch (colormap._spectrum) {\n\n      case 1 : { // Optimized for scalars.\n        const T *ptrs = _data;\n        switch (boundary_conditions) {\n        case 2 : // Periodic boundaries.\n          cimg_for(res,ptrd,t) {\n            const ulongT ind = (ulongT)*(ptrs++);\n            *ptrd = colormap[ind%pwhd];\n          } break;\n        case 1 : // Neumann boundaries.\n          cimg_for(res,ptrd,t) {\n            const longT ind = (longT)*(ptrs++);\n            *ptrd = colormap[ind<0?0:ind>=(longT)pwhd?pwhd - 1:ind];\n          } break;\n        default : // Dirichlet boundaries.\n          cimg_for(res,ptrd,t) {\n            const ulongT ind = (ulongT)*(ptrs++);\n            *ptrd = ind<pwhd?colormap[ind]:(t)0;\n          }\n        }\n      } break;\n\n      case 2 : { // Optimized for 2d vectors.\n        switch (boundary_conditions) {\n        case 2 : { // Periodic boundaries.\n          const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd;\n          t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd;\n          for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) {\n            const ulongT _ind = (ulongT)*(ptrs++), ind = _ind%pwhd;\n            *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind];\n          }\n        } break;\n        case 1 : { // Neumann boundaries.\n          const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd;\n          t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd;\n          for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) {\n            const longT _ind = (longT)*(ptrs++), ind = _ind<0?0:_ind>=(longT)pwhd?(longT)pwhd - 1:_ind;\n            *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind];\n          }\n        } break;\n        default : { // Dirichlet boundaries.\n          const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd;\n          t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd;\n          for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) {\n            const ulongT ind = (ulongT)*(ptrs++);\n            const bool is_in = ind<pwhd;\n            *(ptrd0++) = is_in?ptrp0[ind]:(t)0; *(ptrd1++) = is_in?ptrp1[ind]:(t)0;\n          }\n        }\n        }\n      } break;\n\n      case 3 : { // Optimized for 3d vectors (colors).\n        switch (boundary_conditions) {\n        case 2 : { // Periodic boundaries.\n          const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd;\n          t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd, *ptrd2 = ptrd1 + whd;\n          for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) {\n            const ulongT _ind = (ulongT)*(ptrs++), ind = _ind%pwhd;\n            *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind]; *(ptrd2++) = ptrp2[ind];\n          }\n        } break;\n        case 1 : { // Neumann boundaries.\n          const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd;\n          t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd, *ptrd2 = ptrd1 + whd;\n          for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) {\n            const longT _ind = (longT)*(ptrs++), ind = _ind<0?0:_ind>=(longT)pwhd?(longT)pwhd - 1:_ind;\n            *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind]; *(ptrd2++) = ptrp2[ind];\n          }\n        } break;\n        default : { // Dirichlet boundaries.\n          const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd;\n          t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd, *ptrd2 = ptrd1 + whd;\n          for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) {\n            const ulongT ind = (ulongT)*(ptrs++);\n            const bool is_in = ind<pwhd;\n            *(ptrd0++) = is_in?ptrp0[ind]:(t)0; *(ptrd1++) = is_in?ptrp1[ind]:(t)0; *(ptrd2++) = is_in?ptrp2[ind]:(t)0;\n          }\n        }\n        }\n      } break;\n\n      default : { // Generic version.\n        switch (boundary_conditions) {\n        case 2 : { // Periodic boundaries.\n          t *ptrd = res._data;\n          for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) {\n            const ulongT _ind = (ulongT)*(ptrs++), ind = _ind%pwhd;\n            const t *ptrp = colormap._data + ind;\n            t *_ptrd = ptrd++; cimg_forC(res,c) { *_ptrd = *ptrp; _ptrd+=whd; ptrp+=pwhd; }\n          }\n        } break;\n        case 1 : { // Neumann boundaries.\n          t *ptrd = res._data;\n          for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) {\n            const longT _ind = (longT)*(ptrs++), ind = _ind<0?0:_ind>=(longT)pwhd?(longT)pwhd - 1:_ind;\n            const t *ptrp = colormap._data + ind;\n            t *_ptrd = ptrd++; cimg_forC(res,c) { *_ptrd = *ptrp; _ptrd+=whd; ptrp+=pwhd; }\n          }\n        } break;\n        default : { // Dirichlet boundaries.\n          t *ptrd = res._data;\n          for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) {\n            const ulongT ind = (ulongT)*(ptrs++);\n            const bool is_in = ind<pwhd;\n            if (is_in) {\n              const t *ptrp = colormap._data + ind;\n              t *_ptrd = ptrd++; cimg_forC(res,c) { *_ptrd = *ptrp; _ptrd+=whd; ptrp+=pwhd; }\n            } else {\n              t *_ptrd = ptrd++; cimg_forC(res,c) { *_ptrd = (t)0; _ptrd+=whd; }\n            }\n          }\n        }\n        }\n      }\n      }\n      return res;\n    }\n\n    //! Label connected components.\n    /**\n       \\param is_high_connectivity Boolean that choose between 4(false)- or 8(true)-connectivity\n       in 2d case, and between 6(false)- or 26(true)-connectivity in 3d case.\n       \\param tolerance Tolerance used to determine if two neighboring pixels belong to the same region.\n       \\note The algorithm of connected components computation has been primarily done\n       by A. Meijster, according to the publication:\n       'W.H. Hesselink, A. Meijster, C. Bron, \"Concurrent Determination of Connected Components.\",\n       In: Science of Computer Programming 41 (2001), pp. 173--194'.\n       The submitted code has then been modified to fit CImg coding style and constraints.\n    **/\n    CImg<T>& label(const bool is_high_connectivity=false, const Tfloat tolerance=0) {\n      return get_label(is_high_connectivity,tolerance).move_to(*this);\n    }\n\n    //! Label connected components \\newinstance.\n    CImg<ulongT> get_label(const bool is_high_connectivity=false,\n                           const Tfloat tolerance=0) const {\n      if (is_empty()) return CImg<ulongT>();\n\n      // Create neighborhood tables.\n      int dx[13], dy[13], dz[13], nb = 0;\n      dx[nb] = 1; dy[nb] = 0; dz[nb++] = 0;\n      dx[nb] = 0; dy[nb] = 1; dz[nb++] = 0;\n      if (is_high_connectivity) {\n        dx[nb] = 1; dy[nb] = 1; dz[nb++] = 0;\n        dx[nb] = 1; dy[nb] = -1; dz[nb++] = 0;\n      }\n      if (_depth>1) { // 3d version.\n        dx[nb] = 0; dy[nb] = 0; dz[nb++]=1;\n        if (is_high_connectivity) {\n          dx[nb] = 1; dy[nb] = 1; dz[nb++] = -1;\n          dx[nb] = 1; dy[nb] = 0; dz[nb++] = -1;\n          dx[nb] = 1; dy[nb] = -1; dz[nb++] = -1;\n          dx[nb] = 0; dy[nb] = 1; dz[nb++] = -1;\n\n          dx[nb] = 0; dy[nb] = 1; dz[nb++] = 1;\n          dx[nb] = 1; dy[nb] = -1; dz[nb++] = 1;\n          dx[nb] = 1; dy[nb] = 0; dz[nb++] = 1;\n          dx[nb] = 1; dy[nb] = 1; dz[nb++] = 1;\n        }\n      }\n      return _get_label(nb,dx,dy,dz,tolerance);\n    }\n\n    //! Label connected components \\overloading.\n    /**\n       \\param connectivity_mask Mask of the neighboring pixels.\n       \\param tolerance Tolerance used to determine if two neighboring pixels belong to the same region.\n    **/\n    template<typename t>\n    CImg<T>& label(const CImg<t>& connectivity_mask, const Tfloat tolerance=0) {\n      return get_label(connectivity_mask,tolerance).move_to(*this);\n    }\n\n    //! Label connected components \\newinstance.\n    template<typename t>\n    CImg<ulongT> get_label(const CImg<t>& connectivity_mask,\n                           const Tfloat tolerance=0) const {\n      int nb = 0;\n      cimg_for(connectivity_mask,ptr,t) if (*ptr) ++nb;\n      CImg<intT> dx(nb,1,1,1,0), dy(nb,1,1,1,0), dz(nb,1,1,1,0);\n      nb = 0;\n      cimg_forXYZ(connectivity_mask,x,y,z) if ((x || y || z) &&\n                                               connectivity_mask(x,y,z)) {\n        dx[nb] = x; dy[nb] = y; dz[nb++] = z;\n      }\n      return _get_label(nb,dx,dy,dz,tolerance);\n    }\n\n    CImg<ulongT> _get_label(const unsigned int nb, const int\n                            *const dx, const int *const dy, const int *const dz,\n                            const Tfloat tolerance) const {\n      CImg<ulongT> res(_width,_height,_depth,_spectrum);\n      cimg_forC(*this,c) {\n        CImg<ulongT> _res = res.get_shared_channel(c);\n\n        // Init label numbers.\n        ulongT *ptr = _res.data();\n        cimg_foroff(_res,p) *(ptr++) = p;\n\n        // For each neighbour-direction, label.\n        for (unsigned int n = 0; n<nb; ++n) {\n          const int _dx = dx[n], _dy = dy[n], _dz = dz[n];\n          if (_dx || _dy || _dz) {\n            const int\n              x0 = _dx<0?-_dx:0,\n              x1 = _dx<0?width():width() - _dx,\n              y0 = _dy<0?-_dy:0,\n              y1 = _dy<0?height():height() - _dy,\n              z0 = _dz<0?-_dz:0,\n              z1 = _dz<0?depth():depth() - _dz;\n            const longT\n              wh = (longT)width()*height(),\n              whd = (longT)width()*height()*depth(),\n              offset = _dz*wh + _dy*width() + _dx;\n            for (longT z = z0, nz = z0 + _dz, pz = z0*wh; z<z1; ++z, ++nz, pz+=wh) {\n              for (longT y = y0, ny = y0 + _dy, py = y0*width() + pz; y<y1; ++y, ++ny, py+=width()) {\n                for (longT x = x0, nx = x0 + _dx, p = x0 + py; x<x1; ++x, ++nx, ++p) {\n                  if ((Tfloat)cimg::abs((*this)(x,y,z,c,wh,whd) - (*this)(nx,ny,nz,c,wh,whd))<=tolerance) {\n                    const longT q = p + offset;\n                    ulongT x, y;\n                    for (x = (ulongT)(p<q?q:p), y = (ulongT)(p<q?p:q); x!=y && _res[x]!=x; ) {\n                      x = _res[x]; if (x<y) cimg::swap(x,y);\n                    }\n                    if (x!=y) _res[x] = (ulongT)y;\n                    for (ulongT _p = (ulongT)p; _p!=y; ) {\n                      const ulongT h = _res[_p];\n                      _res[_p] = (ulongT)y;\n                      _p = h;\n                    }\n                    for (ulongT _q = (ulongT)q; _q!=y; ) {\n                      const ulongT h = _res[_q];\n                      _res[_q] = (ulongT)y;\n                      _q = h;\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n\n        // Resolve equivalences.\n        ulongT counter = 0;\n        ptr = _res.data();\n        cimg_foroff(_res,p) { *ptr = *ptr==p?counter++:_res[*ptr]; ++ptr; }\n      }\n      return res;\n    }\n\n    // [internal] Replace possibly malicious characters for commands to be called by system() by their escaped version.\n    CImg<T>& _system_strescape() {\n#define cimg_system_strescape(c,s) case c : if (p!=ptrs) CImg<T>(ptrs,(unsigned int)(p-ptrs),1,1,1,false).\\\n      move_to(list); \\\n      CImg<T>(s,(unsigned int)std::strlen(s),1,1,1,false).move_to(list); ptrs = p + 1; break\n      CImgList<T> list;\n      const T *ptrs = _data;\n      cimg_for(*this,p,T) switch ((int)*p) {\n        cimg_system_strescape('\\\\',\"\\\\\\\\\");\n        cimg_system_strescape('\\\"',\"\\\\\\\"\");\n        cimg_system_strescape('!',\"\\\"\\\\!\\\"\");\n        cimg_system_strescape('`',\"\\\\`\");\n        cimg_system_strescape('$',\"\\\\$\");\n      }\n      if (ptrs<end()) CImg<T>(ptrs,(unsigned int)(end()-ptrs),1,1,1,false).move_to(list);\n      return (list>'x').move_to(*this);\n    }\n\n    //@}\n    //---------------------------------\n    //\n    //! \\name Color Base Management\n    //@{\n    //---------------------------------\n\n    //! Return colormap \\e \"default\", containing 256 colors entries in RGB.\n    /**\n       \\return The following \\c 256x1x1x3 colormap is returned:\n       \\image html ref_colormap_default.jpg\n    **/\n    static const CImg<Tuchar>& default_LUT256() {\n      static CImg<Tuchar> colormap;\n      cimg::mutex(8);\n      if (!colormap) {\n        colormap.assign(1,256,1,3);\n        for (unsigned int index = 0, r = 16; r<256; r+=32)\n          for (unsigned int g = 16; g<256; g+=32)\n            for (unsigned int b = 32; b<256; b+=64) {\n              colormap(0,index,0) = (Tuchar)r;\n              colormap(0,index,1) = (Tuchar)g;\n              colormap(0,index++,2) = (Tuchar)b;\n            }\n      }\n      cimg::mutex(8,0);\n      return colormap;\n    }\n\n    //! Return colormap \\e \"HSV\", containing 256 colors entries in RGB.\n    /**\n       \\return The following \\c 256x1x1x3 colormap is returned:\n       \\image html ref_colormap_hsv.jpg\n    **/\n    static const CImg<Tuchar>& HSV_LUT256() {\n      static CImg<Tuchar> colormap;\n      cimg::mutex(8);\n      if (!colormap) {\n        CImg<Tint> tmp(1,256,1,3,1);\n        tmp.get_shared_channel(0).sequence(0,359);\n        colormap = tmp.HSVtoRGB();\n      }\n      cimg::mutex(8,0);\n      return colormap;\n    }\n\n    //! Return colormap \\e \"lines\", containing 256 colors entries in RGB.\n    /**\n       \\return The following \\c 256x1x1x3 colormap is returned:\n       \\image html ref_colormap_lines.jpg\n    **/\n    static const CImg<Tuchar>& lines_LUT256() {\n      static const unsigned char pal[] = {\n        217,62,88,75,1,237,240,12,56,160,165,116,1,1,204,2,15,248,148,185,133,141,46,246,222,116,16,5,207,226,\n        17,114,247,1,214,53,238,0,95,55,233,235,109,0,17,54,33,0,90,30,3,0,94,27,19,0,68,212,166,130,0,15,7,119,\n        238,2,246,198,0,3,16,10,13,2,25,28,12,6,2,99,18,141,30,4,3,140,12,4,30,233,7,10,0,136,35,160,168,184,20,\n        233,0,1,242,83,90,56,180,44,41,0,6,19,207,5,31,214,4,35,153,180,75,21,76,16,202,218,22,17,2,136,71,74,\n        81,251,244,148,222,17,0,234,24,0,200,16,239,15,225,102,230,186,58,230,110,12,0,7,129,249,22,241,37,219,\n        1,3,254,210,3,212,113,131,197,162,123,252,90,96,209,60,0,17,0,180,249,12,112,165,43,27,229,77,40,195,12,\n        87,1,210,148,47,80,5,9,1,137,2,40,57,205,244,40,8,252,98,0,40,43,206,31,187,0,180,1,69,70,227,131,108,0,\n        223,94,228,35,248,243,4,16,0,34,24,2,9,35,73,91,12,199,51,1,249,12,103,131,20,224,2,70,32,\n        233,1,165,3,8,154,246,233,196,5,0,6,183,227,247,195,208,36,0,0,226,160,210,198,69,153,210,1,23,8,192,2,4,\n        137,1,0,52,2,249,241,129,0,0,234,7,238,71,7,32,15,157,157,252,158,2,250,6,13,30,11,162,0,199,21,11,27,224,\n        4,157,20,181,111,187,218,3,0,11,158,230,196,34,223,22,248,135,254,210,157,219,0,117,239,3,255,4,227,5,247,\n        11,4,3,188,111,11,105,195,2,0,14,1,21,219,192,0,183,191,113,241,1,12,17,248,0,48,7,19,1,254,212,0,239,246,\n        0,23,0,250,165,194,194,17,3,253,0,24,6,0,141,167,221,24,212,2,235,243,0,0,205,1,251,133,204,28,4,6,1,10,\n        141,21,74,12,236,254,228,19,1,0,214,1,186,13,13,6,13,16,27,209,6,216,11,207,251,59,32,9,155,23,19,235,143,\n        116,6,213,6,75,159,23,6,0,228,4,10,245,249,1,7,44,234,4,102,174,0,19,239,103,16,15,18,8,214,22,4,47,244,\n        255,8,0,251,173,1,212,252,250,251,252,6,0,29,29,222,233,246,5,149,0,182,180,13,151,0,203,183,0,35,149,0,\n        235,246,254,78,9,17,203,73,11,195,0,3,5,44,0,0,237,5,106,6,130,16,214,20,168,247,168,4,207,11,5,1,232,251,\n        129,210,116,231,217,223,214,27,45,38,4,177,186,249,7,215,172,16,214,27,249,230,236,2,34,216,217,0,175,30,\n        243,225,244,182,20,212,2,226,21,255,20,0,2,13,62,13,191,14,76,64,20,121,4,118,0,216,1,147,0,2,210,1,215,\n        95,210,236,225,184,46,0,248,24,11,1,9,141,250,243,9,221,233,160,11,147,2,55,8,23,12,253,9,0,54,0,231,6,3,\n        141,8,2,246,9,180,5,11,8,227,8,43,110,242,1,130,5,97,36,10,6,219,86,133,11,108,6,1,5,244,67,19,28,0,174,\n        154,16,127,149,252,188,196,196,228,244,9,249,0,0,0,37,170,32,250,0,73,255,23,3,224,234,38,195,198,0,255,87,\n        33,221,174,31,3,0,189,228,6,153,14,144,14,108,197,0,9,206,245,254,3,16,253,178,248,0,95,125,8,0,3,168,21,\n        23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };\n      static const CImg<Tuchar> colormap(pal,1,256,1,3,false);\n      return colormap;\n    }\n\n    //! Return colormap \\e \"hot\", containing 256 colors entries in RGB.\n    /**\n       \\return The following \\c 256x1x1x3 colormap is returned:\n       \\image html ref_colormap_hot.jpg\n    **/\n    static const CImg<Tuchar>& hot_LUT256() {\n      static CImg<Tuchar> colormap;\n      cimg::mutex(8);\n      if (!colormap) {\n        colormap.assign(1,4,1,3,0);\n        colormap[1] = colormap[2] = colormap[3] = colormap[6] = colormap[7] = colormap[11] = 255;\n        colormap.resize(1,256,1,3,3);\n      }\n      cimg::mutex(8,0);\n      return colormap;\n    }\n\n    //! Return colormap \\e \"cool\", containing 256 colors entries in RGB.\n    /**\n       \\return The following \\c 256x1x1x3 colormap is returned:\n       \\image html ref_colormap_cool.jpg\n    **/\n    static const CImg<Tuchar>& cool_LUT256() {\n      static CImg<Tuchar> colormap;\n      cimg::mutex(8);\n      if (!colormap) colormap.assign(1,2,1,3).fill(0,255,255,0,255,255).resize(1,256,1,3,3);\n      cimg::mutex(8,0);\n      return colormap;\n    }\n\n    //! Return colormap \\e \"jet\", containing 256 colors entries in RGB.\n    /**\n       \\return The following \\c 256x1x1x3 colormap is returned:\n       \\image html ref_colormap_jet.jpg\n    **/\n    static const CImg<Tuchar>& jet_LUT256() {\n      static CImg<Tuchar> colormap;\n      cimg::mutex(8);\n      if (!colormap) {\n        colormap.assign(1,4,1,3,0);\n        colormap[2] = colormap[3] = colormap[5] = colormap[6] = colormap[8] = colormap[9] = 255;\n        colormap.resize(1,256,1,3,3);\n      }\n      cimg::mutex(8,0);\n      return colormap;\n    }\n\n    //! Return colormap \\e \"flag\", containing 256 colors entries in RGB.\n    /**\n       \\return The following \\c 256x1x1x3 colormap is returned:\n       \\image html ref_colormap_flag.jpg\n    **/\n    static const CImg<Tuchar>& flag_LUT256() {\n      static CImg<Tuchar> colormap;\n      cimg::mutex(8);\n      if (!colormap) {\n        colormap.assign(1,4,1,3,0);\n        colormap[0] = colormap[1] = colormap[5] = colormap[9] = colormap[10] = 255;\n        colormap.resize(1,256,1,3,0,2);\n      }\n      cimg::mutex(8,0);\n      return colormap;\n    }\n\n    //! Return colormap \\e \"cube\", containing 256 colors entries in RGB.\n    /**\n       \\return The following \\c 256x1x1x3 colormap is returned:\n       \\image html ref_colormap_cube.jpg\n    **/\n    static const CImg<Tuchar>& cube_LUT256() {\n      static CImg<Tuchar> colormap;\n      cimg::mutex(8);\n      if (!colormap) {\n        colormap.assign(1,8,1,3,0);\n        colormap[1] = colormap[3] = colormap[5] = colormap[7] =\n          colormap[10] = colormap[11] = colormap[12] = colormap[13] =\n          colormap[20] = colormap[21] = colormap[22] = colormap[23] = 255;\n        colormap.resize(1,256,1,3,3);\n      }\n      cimg::mutex(8,0);\n      return colormap;\n    }\n\n    //! Convert pixel values from sRGB to RGB color spaces.\n    CImg<T>& sRGBtoRGB() {\n      cimg_for(*this,ptr,T) {\n        const Tfloat\n          sval = (Tfloat)*ptr,\n          nsval = (sval<0?0:sval>255?255:sval)/255,\n          val = (Tfloat)(nsval<=0.04045f?nsval/12.92f:std::pow((nsval + 0.055f)/(1.055f),2.4f));\n        *ptr = (T)(val*255);\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from sRGB to RGB color spaces \\newinstance.\n    CImg<Tfloat> get_sRGBtoRGB() const {\n      return CImg<Tfloat>(*this,false).sRGBtoRGB();\n    }\n\n    //! Convert pixel values from RGB to sRGB color spaces.\n    CImg<T>& RGBtosRGB() {\n      cimg_for(*this,ptr,T) {\n        const Tfloat\n          val = (Tfloat)*ptr,\n          nval = (val<0?0:val>255?255:val)/255,\n          sval = (Tfloat)(nval<=0.0031308f?nval*12.92f:1.055f*std::pow(nval,0.416667f)-0.055f);\n        *ptr = (T)(sval*255);\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from RGB to sRGB color spaces \\newinstance.\n    CImg<Tfloat> get_RGBtosRGB() const {\n      return CImg<Tfloat>(*this,false).RGBtosRGB();\n    }\n\n    //! Convert pixel values from RGB to HSV color spaces.\n    CImg<T>& RGBtoHSV() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"RGBtoHSV(): Instance is not a RGB image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          R = (Tfloat)*p1,\n          G = (Tfloat)*p2,\n          B = (Tfloat)*p3,\n          nR = (R<0?0:(R>255?255:R))/255,\n          nG = (G<0?0:(G>255?255:G))/255,\n          nB = (B<0?0:(B>255?255:B))/255,\n          m = cimg::min(nR,nG,nB),\n          M = cimg::max(nR,nG,nB);\n        Tfloat H = 0, S = 0;\n        if (M!=m) {\n          const Tfloat\n            f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),\n            i = (Tfloat)((nR==m)?3:((nG==m)?5:1));\n          H = (i-f/(M-m));\n          if (H>=6) H-=6;\n          H*=60;\n          S = (M-m)/M;\n        }\n        *(p1++) = (T)H;\n        *(p2++) = (T)S;\n        *(p3++) = (T)M;\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from RGB to HSV color spaces \\newinstance.\n    CImg<Tfloat> get_RGBtoHSV() const {\n      return CImg<Tfloat>(*this,false).RGBtoHSV();\n    }\n\n    //! Convert pixel values from HSV to RGB color spaces.\n    CImg<T>& HSVtoRGB() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"HSVtoRGB(): Instance is not a HSV image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        Tfloat\n          H = cimg::mod((Tfloat)*p1,(Tfloat)360),\n          S = (Tfloat)*p2,\n          V = (Tfloat)*p3,\n          R = 0, G = 0, B = 0;\n        if (H==0 && S==0) R = G = B = V;\n        else {\n          H/=60;\n          const int i = (int)std::floor(H);\n          const Tfloat\n            f = (i&1)?(H - i):(1 - H + i),\n            m = V*(1 - S),\n            n = V*(1 - S*f);\n          switch (i) {\n          case 6 :\n          case 0 : R = V; G = n; B = m; break;\n          case 1 : R = n; G = V; B = m; break;\n          case 2 : R = m; G = V; B = n; break;\n          case 3 : R = m; G = n; B = V; break;\n          case 4 : R = n; G = m; B = V; break;\n          case 5 : R = V; G = m; B = n; break;\n          }\n        }\n        R*=255; G*=255; B*=255;\n        *(p1++) = (T)(R<0?0:(R>255?255:R));\n        *(p2++) = (T)(G<0?0:(G>255?255:G));\n        *(p3++) = (T)(B<0?0:(B>255?255:B));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from HSV to RGB color spaces \\newinstance.\n    CImg<Tuchar> get_HSVtoRGB() const {\n      return CImg<Tuchar>(*this,false).HSVtoRGB();\n    }\n\n    //! Convert pixel values from RGB to HSL color spaces.\n    CImg<T>& RGBtoHSL() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"RGBtoHSL(): Instance is not a RGB image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          R = (Tfloat)*p1,\n          G = (Tfloat)*p2,\n          B = (Tfloat)*p3,\n          nR = (R<0?0:(R>255?255:R))/255,\n          nG = (G<0?0:(G>255?255:G))/255,\n          nB = (B<0?0:(B>255?255:B))/255,\n          m = cimg::min(nR,nG,nB),\n          M = cimg::max(nR,nG,nB),\n          L = (m + M)/2;\n        Tfloat H = 0, S = 0;\n        if (M==m) H = S = 0;\n        else {\n          const Tfloat\n            f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),\n            i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f);\n          H = (i-f/(M-m));\n          if (H>=6) H-=6;\n          H*=60;\n          S = (2*L<=1)?((M - m)/(M + m)):((M - m)/(2 - M - m));\n        }\n        *(p1++) = (T)H;\n        *(p2++) = (T)S;\n        *(p3++) = (T)L;\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from RGB to HSL color spaces \\newinstance.\n    CImg<Tfloat> get_RGBtoHSL() const {\n      return CImg< Tfloat>(*this,false).RGBtoHSL();\n    }\n\n    //! Convert pixel values from HSL to RGB color spaces.\n    CImg<T>& HSLtoRGB() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"HSLtoRGB(): Instance is not a HSL image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          H = cimg::mod((Tfloat)*p1,(Tfloat)360),\n          S = (Tfloat)*p2,\n          L = (Tfloat)*p3,\n          q = 2*L<1?L*(1 + S):(L + S - L*S),\n          p = 2*L - q,\n          h = H/360,\n          tr = h + 1.0f/3,\n          tg = h,\n          tb = h - 1.0f/3,\n          ntr = tr<0?tr + 1:(tr>1?tr - 1:tr),\n          ntg = tg<0?tg + 1:(tg>1?tg - 1:tg),\n          ntb = tb<0?tb + 1:(tb>1?tb - 1:tb),\n          R = 255*(6*ntr<1?p + (q - p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p + (q - p)*6*(2.0f/3 - ntr):p))),\n          G = 255*(6*ntg<1?p + (q - p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p + (q - p)*6*(2.0f/3 - ntg):p))),\n          B = 255*(6*ntb<1?p + (q - p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p + (q - p)*6*(2.0f/3 - ntb):p)));\n        *(p1++) = (T)(R<0?0:(R>255?255:R));\n        *(p2++) = (T)(G<0?0:(G>255?255:G));\n        *(p3++) = (T)(B<0?0:(B>255?255:B));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from HSL to RGB color spaces \\newinstance.\n    CImg<Tuchar> get_HSLtoRGB() const {\n      return CImg<Tuchar>(*this,false).HSLtoRGB();\n    }\n\n    //! Convert pixel values from RGB to HSI color spaces.\n    CImg<T>& RGBtoHSI() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"RGBtoHSI(): Instance is not a RGB image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          R = (Tfloat)*p1,\n          G = (Tfloat)*p2,\n          B = (Tfloat)*p3,\n          nR = (R<0?0:(R>255?255:R))/255,\n          nG = (G<0?0:(G>255?255:G))/255,\n          nB = (B<0?0:(B>255?255:B))/255,\n          m = cimg::min(nR,nG,nB),\n          theta = (Tfloat)(std::acos(0.5f*((nR - nG) + (nR - nB))/\n                                     std::sqrt(std::pow(nR - nG,2) + (nR - nB)*(nG - nB)))*180/cimg::PI),\n          sum = nR + nG + nB;\n        Tfloat H = 0, S = 0, I = 0;\n        if (theta>0) H = (nB<=nG)?theta:360 - theta;\n        if (sum>0) S = 1 - 3/sum*m;\n        I = sum/3;\n        *(p1++) = (T)H;\n        *(p2++) = (T)S;\n        *(p3++) = (T)I;\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from RGB to HSI color spaces \\newinstance.\n    CImg<Tfloat> get_RGBtoHSI() const {\n      return CImg<Tfloat>(*this,false).RGBtoHSI();\n    }\n\n    //! Convert pixel values from HSI to RGB color spaces.\n    CImg<T>& HSItoRGB() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"HSItoRGB(): Instance is not a HSI image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        Tfloat\n          H = cimg::mod((Tfloat)*p1,(Tfloat)360),\n          S = (Tfloat)*p2,\n          I = (Tfloat)*p3,\n          a = I*(1-S),\n          R = 0, G = 0, B = 0;\n        if (H<120) {\n          B = a;\n          R = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180)));\n          G = 3*I - (R + B);\n        } else if (H<240) {\n          H-=120;\n          R = a;\n          G = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180)));\n          B = 3*I - (R + G);\n        } else {\n          H-=240;\n          G = a;\n          B = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180)));\n          R = 3*I - (G + B);\n        }\n        R*=255; G*=255; B*=255;\n        *(p1++) = (T)(R<0?0:(R>255?255:R));\n        *(p2++) = (T)(G<0?0:(G>255?255:G));\n        *(p3++) = (T)(B<0?0:(B>255?255:B));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from HSI to RGB color spaces \\newinstance.\n    CImg<Tfloat> get_HSItoRGB() const {\n      return CImg< Tuchar>(*this,false).HSItoRGB();\n    }\n\n    //! Convert pixel values from RGB to YCbCr color spaces.\n    CImg<T>& RGBtoYCbCr() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"RGBtoYCbCr(): Instance is not a RGB image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          R = (Tfloat)*p1,\n          G = (Tfloat)*p2,\n          B = (Tfloat)*p3,\n          Y = (66*R + 129*G + 25*B + 128)/256 + 16,\n          Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,\n          Cr = (112*R - 94*G - 18*B + 128)/256 + 128;\n        *(p1++) = (T)(Y<0?0:(Y>255?255:Y));\n        *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb));\n        *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from RGB to YCbCr color spaces \\newinstance.\n    CImg<Tuchar> get_RGBtoYCbCr() const {\n      return CImg<Tuchar>(*this,false).RGBtoYCbCr();\n    }\n\n    //! Convert pixel values from RGB to YCbCr color spaces.\n    CImg<T>& YCbCrtoRGB() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"YCbCrtoRGB(): Instance is not a YCbCr image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          Y = (Tfloat)*p1 - 16,\n          Cb = (Tfloat)*p2 - 128,\n          Cr = (Tfloat)*p3 - 128,\n          R = (298*Y + 409*Cr + 128)/256,\n          G = (298*Y - 100*Cb - 208*Cr + 128)/256,\n          B = (298*Y + 516*Cb + 128)/256;\n        *(p1++) = (T)(R<0?0:(R>255?255:R));\n        *(p2++) = (T)(G<0?0:(G>255?255:G));\n        *(p3++) = (T)(B<0?0:(B>255?255:B));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from RGB to YCbCr color spaces \\newinstance.\n    CImg<Tuchar> get_YCbCrtoRGB() const {\n      return CImg<Tuchar>(*this,false).YCbCrtoRGB();\n    }\n\n    //! Convert pixel values from RGB to YUV color spaces.\n    CImg<T>& RGBtoYUV() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"RGBtoYUV(): Instance is not a RGB image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          R = (Tfloat)*p1/255,\n          G = (Tfloat)*p2/255,\n          B = (Tfloat)*p3/255,\n          Y = 0.299f*R + 0.587f*G + 0.114f*B;\n        *(p1++) = (T)Y;\n        *(p2++) = (T)(0.492f*(B-Y));\n        *(p3++) = (T)(0.877*(R-Y));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from RGB to YUV color spaces \\newinstance.\n    CImg<Tfloat> get_RGBtoYUV() const {\n      return CImg<Tfloat>(*this,false).RGBtoYUV();\n    }\n\n    //! Convert pixel values from YUV to RGB color spaces.\n    CImg<T>& YUVtoRGB() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"YUVtoRGB(): Instance is not a YUV image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          Y = (Tfloat)*p1,\n          U = (Tfloat)*p2,\n          V = (Tfloat)*p3,\n          R = (Y + 1.140f*V)*255,\n          G = (Y - 0.395f*U - 0.581f*V)*255,\n          B = (Y + 2.032f*U)*255;\n        *(p1++) = (T)(R<0?0:(R>255?255:R));\n        *(p2++) = (T)(G<0?0:(G>255?255:G));\n        *(p3++) = (T)(B<0?0:(B>255?255:B));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from YUV to RGB color spaces \\newinstance.\n    CImg<Tuchar> get_YUVtoRGB() const {\n      return CImg< Tuchar>(*this,false).YUVtoRGB();\n    }\n\n    //! Convert pixel values from RGB to CMY color spaces.\n    CImg<T>& RGBtoCMY() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"RGBtoCMY(): Instance is not a RGB image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          R = (Tfloat)*p1,\n          G = (Tfloat)*p2,\n          B = (Tfloat)*p3,\n          C = 255 - R,\n          M = 255 - G,\n          Y = 255 - B;\n        *(p1++) = (T)(C<0?0:(C>255?255:C));\n        *(p2++) = (T)(M<0?0:(M>255?255:M));\n        *(p3++) = (T)(Y<0?0:(Y>255?255:Y));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from RGB to CMY color spaces \\newinstance.\n    CImg<Tuchar> get_RGBtoCMY() const {\n      return CImg<Tfloat>(*this,false).RGBtoCMY();\n    }\n\n    //! Convert pixel values from CMY to RGB color spaces.\n    CImg<T>& CMYtoRGB() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"CMYtoRGB(): Instance is not a CMY image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          C = (Tfloat)*p1,\n          M = (Tfloat)*p2,\n          Y = (Tfloat)*p3,\n          R = 255 - C,\n          G = 255 - M,\n          B = 255 - Y;\n        *(p1++) = (T)(R<0?0:(R>255?255:R));\n        *(p2++) = (T)(G<0?0:(G>255?255:G));\n        *(p3++) = (T)(B<0?0:(B>255?255:B));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from CMY to RGB color spaces \\newinstance.\n    CImg<Tuchar> get_CMYtoRGB() const {\n      return CImg<Tuchar>(*this,false).CMYtoRGB();\n    }\n\n    //! Convert pixel values from CMY to CMYK color spaces.\n    CImg<T>& CMYtoCMYK() {\n      return get_CMYtoCMYK().move_to(*this);\n    }\n\n    //! Convert pixel values from CMY to CMYK color spaces \\newinstance.\n    CImg<Tuchar> get_CMYtoCMYK() const {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"CMYtoCMYK(): Instance is not a CMY image.\",\n                                    cimg_instance);\n\n      CImg<Tfloat> res(_width,_height,_depth,4);\n      const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2);\n      Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2), *pd4 = res.data(0,0,0,3);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        Tfloat\n          C = (Tfloat)*(ps1++),\n          M = (Tfloat)*(ps2++),\n          Y = (Tfloat)*(ps3++),\n          K = cimg::min(C,M,Y);\n        if (K>=255) C = M = Y = 0;\n        else { const Tfloat K1 = 255 - K; C = 255*(C - K)/K1; M = 255*(M - K)/K1; Y = 255*(Y - K)/K1; }\n        *(pd1++) = (Tfloat)(C<0?0:(C>255?255:C));\n        *(pd2++) = (Tfloat)(M<0?0:(M>255?255:M));\n        *(pd3++) = (Tfloat)(Y<0?0:(Y>255?255:Y));\n        *(pd4++) = (Tfloat)(K<0?0:(K>255?255:K));\n      }\n      return res;\n    }\n\n    //! Convert pixel values from CMYK to CMY color spaces.\n    CImg<T>& CMYKtoCMY() {\n      return get_CMYKtoCMY().move_to(*this);\n    }\n\n    //! Convert pixel values from CMYK to CMY color spaces \\newinstance.\n    CImg<Tfloat> get_CMYKtoCMY() const {\n      if (_spectrum!=4)\n        throw CImgInstanceException(_cimg_instance\n                                    \"CMYKtoCMY(): Instance is not a CMYK image.\",\n                                    cimg_instance);\n\n      CImg<Tfloat> res(_width,_height,_depth,3);\n      const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2), *ps4 = data(0,0,0,3);\n      Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          C = (Tfloat)*(ps1++),\n          M = (Tfloat)*(ps2++),\n          Y = (Tfloat)*(ps3++),\n          K = (Tfloat)*(ps4++),\n          K1 = 1 - K/255,\n          nC = C*K1 + K,\n          nM = M*K1 + K,\n          nY = Y*K1 + K;\n        *(pd1++) = (Tfloat)(nC<0?0:(nC>255?255:nC));\n        *(pd2++) = (Tfloat)(nM<0?0:(nM>255?255:nM));\n        *(pd3++) = (Tfloat)(nY<0?0:(nY>255?255:nY));\n      }\n      return res;\n    }\n\n    //! Convert pixel values from RGB to XYZ_709 color spaces.\n    /**\n       \\note Uses the standard D65 white point.\n    **/\n    CImg<T>& RGBtoXYZ() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"RGBtoXYZ(): Instance is not a RGB image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          R = (Tfloat)*p1/255,\n          G = (Tfloat)*p2/255,\n          B = (Tfloat)*p3/255;\n        *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B);\n        *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B);\n        *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B);\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from RGB to XYZ_709 color spaces \\newinstance.\n    CImg<Tfloat> get_RGBtoXYZ() const {\n      return CImg<Tfloat>(*this,false).RGBtoXYZ();\n    }\n\n    //! Convert pixel values from XYZ_709 to RGB color spaces.\n    CImg<T>& XYZtoRGB() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"XYZtoRGB(): Instance is not a XYZ image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          X = (Tfloat)*p1*255,\n          Y = (Tfloat)*p2*255,\n          Z = (Tfloat)*p3*255,\n          R = 3.240479f*X  - 1.537150f*Y - 0.498535f*Z,\n          G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z,\n          B = 0.055648f*X  - 0.204043f*Y + 1.057311f*Z;\n        *(p1++) = (T)(R<0?0:(R>255?255:R));\n        *(p2++) = (T)(G<0?0:(G>255?255:G));\n        *(p3++) = (T)(B<0?0:(B>255?255:B));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from XYZ_709 to RGB color spaces \\newinstance.\n    CImg<Tuchar> get_XYZtoRGB() const {\n      return CImg<Tuchar>(*this,false).XYZtoRGB();\n    }\n\n    //! Convert pixel values from XYZ_709 to Lab color spaces.\n    CImg<T>& XYZtoLab() {\n#define _cimg_Labf(x) ((x)>=0.008856f?(std::pow(x,(Tfloat)1/3)):(7.787f*(x) + 16.0f/116))\n\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"XYZtoLab(): Instance is not a XYZ image.\",\n                                    cimg_instance);\n\n      const Tfloat\n        Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),\n        Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),\n        Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          X = (Tfloat)*p1,\n          Y = (Tfloat)*p2,\n          Z = (Tfloat)*p3,\n          XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,\n          fX = (Tfloat)_cimg_Labf(XXn),\n          fY = (Tfloat)_cimg_Labf(YYn),\n          fZ = (Tfloat)_cimg_Labf(ZZn);\n        *(p1++) = (T)cimg::max(0.0f,116*fY - 16);\n        *(p2++) = (T)(500*(fX - fY));\n        *(p3++) = (T)(200*(fY - fZ));\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from XYZ_709 to Lab color spaces \\newinstance.\n    CImg<Tfloat> get_XYZtoLab() const {\n      return CImg<Tfloat>(*this,false).XYZtoLab();\n    }\n\n    //! Convert pixel values from Lab to XYZ_709 color spaces.\n    CImg<T>& LabtoXYZ() {\n#define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f))\n\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"LabtoXYZ(): Instance is not a Lab image.\",\n                                    cimg_instance);\n\n      const Tfloat\n        Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),\n        Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),\n        Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          L = (Tfloat)*p1,\n          a = (Tfloat)*p2,\n          b = (Tfloat)*p3,\n          cY = (L + 16)/116,\n          Y = (Tfloat)(Yn*_cimg_Labfi(cY)),\n          cX = a/500 + cY,\n          X = (Tfloat)(Xn*_cimg_Labfi(cX)),\n          cZ = cY - b/200,\n          Z = (Tfloat)(Zn*_cimg_Labfi(cZ));\n        *(p1++) = (T)(X);\n        *(p2++) = (T)(Y);\n        *(p3++) = (T)(Z);\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from Lab to XYZ_709 color spaces \\newinstance.\n    CImg<Tfloat> get_LabtoXYZ() const {\n      return CImg<Tfloat>(*this,false).LabtoXYZ();\n    }\n\n    //! Convert pixel values from XYZ_709 to xyY color spaces.\n    CImg<T>& XYZtoxyY() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"XYZtoxyY(): Instance is not a XYZ image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n          X = (Tfloat)*p1,\n          Y = (Tfloat)*p2,\n          Z = (Tfloat)*p3,\n          sum = X + Y + Z,\n          nsum = sum>0?sum:1;\n        *(p1++) = (T)(X/nsum);\n        *(p2++) = (T)(Y/nsum);\n        *(p3++) = (T)Y;\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from XYZ_709 to xyY color spaces \\newinstance.\n    CImg<Tfloat> get_XYZtoxyY() const {\n      return CImg<Tfloat>(*this,false).XYZtoxyY();\n    }\n\n    //! Convert pixel values from xyY pixels to XYZ_709 color spaces.\n    CImg<T>& xyYtoXYZ() {\n      if (_spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"xyYtoXYZ(): Instance is not a xyY image.\",\n                                    cimg_instance);\n\n      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);\n      for (ulongT N = (ulongT)_width*_height*_depth; N; --N) {\n        const Tfloat\n         px = (Tfloat)*p1,\n         py = (Tfloat)*p2,\n         Y = (Tfloat)*p3,\n         ny = py>0?py:1;\n        *(p1++) = (T)(px*Y/ny);\n        *(p2++) = (T)Y;\n        *(p3++) = (T)((1 - px - py)*Y/ny);\n      }\n      return *this;\n    }\n\n    //! Convert pixel values from xyY pixels to XYZ_709 color spaces \\newinstance.\n    CImg<Tfloat> get_xyYtoXYZ() const {\n      return CImg<Tfloat>(*this,false).xyYtoXYZ();\n    }\n\n    //! Convert pixel values from RGB to Lab color spaces.\n    CImg<T>& RGBtoLab() {\n      return RGBtoXYZ().XYZtoLab();\n    }\n\n    //! Convert pixel values from RGB to Lab color spaces \\newinstance.\n    CImg<Tfloat> get_RGBtoLab() const {\n      return CImg<Tfloat>(*this,false).RGBtoLab();\n    }\n\n    //! Convert pixel values from Lab to RGB color spaces.\n    CImg<T>& LabtoRGB() {\n      return LabtoXYZ().XYZtoRGB();\n    }\n\n    //! Convert pixel values from Lab to RGB color spaces \\newinstance.\n    CImg<Tuchar> get_LabtoRGB() const {\n      return CImg<Tuchar>(*this,false).LabtoRGB();\n    }\n\n    //! Convert pixel values from RGB to xyY color spaces.\n    CImg<T>& RGBtoxyY() {\n      return RGBtoXYZ().XYZtoxyY();\n    }\n\n    //! Convert pixel values from RGB to xyY color spaces \\newinstance.\n    CImg<Tfloat> get_RGBtoxyY() const {\n      return CImg<Tfloat>(*this,false).RGBtoxyY();\n    }\n\n    //! Convert pixel values from xyY to RGB color spaces.\n    CImg<T>& xyYtoRGB() {\n      return xyYtoXYZ().XYZtoRGB();\n    }\n\n    //! Convert pixel values from xyY to RGB color spaces \\newinstance.\n    CImg<Tuchar> get_xyYtoRGB() const {\n      return CImg<Tuchar>(*this,false).xyYtoRGB();\n    }\n\n    //! Convert pixel values from RGB to CMYK color spaces.\n    CImg<T>& RGBtoCMYK() {\n      return RGBtoCMY().CMYtoCMYK();\n    }\n\n    //! Convert pixel values from RGB to CMYK color spaces \\newinstance.\n    CImg<Tfloat> get_RGBtoCMYK() const {\n      return CImg<Tfloat>(*this,false).RGBtoCMYK();\n    }\n\n    //! Convert pixel values from CMYK to RGB color spaces.\n    CImg<T>& CMYKtoRGB() {\n      return CMYKtoCMY().CMYtoRGB();\n    }\n\n    //! Convert pixel values from CMYK to RGB color spaces \\newinstance.\n    CImg<Tuchar> get_CMYKtoRGB() const {\n      return CImg<Tuchar>(*this,false).CMYKtoRGB();\n    }\n\n    //@}\n    //------------------------------------------\n    //\n    //! \\name Geometric / Spatial Manipulation\n    //@{\n    //------------------------------------------\n\n    static float _cimg_lanczos(const float x) {\n      if (x<=-2 || x>=2) return 0;\n      const float a = (float)cimg::PI*x, b = 0.5f*a;\n      return (float)(x?std::sin(a)*std::sin(b)/(a*b):1);\n    }\n\n    //! Resize image to new dimensions.\n    /**\n       \\param size_x Number of columns (new size along the X-axis).\n       \\param size_y Number of rows (new size along the Y-axis).\n       \\param size_z Number of slices (new size along the Z-axis).\n       \\param size_c Number of vector-channels (new size along the C-axis).\n       \\param interpolation_type Method of interpolation:\n       - -1 = no interpolation: raw memory resizing.\n       - 0 = no interpolation: additional space is filled according to \\p boundary_conditions.\n       - 1 = nearest-neighbor interpolation.\n       - 2 = moving average interpolation.\n       - 3 = linear interpolation.\n       - 4 = grid interpolation.\n       - 5 = cubic interpolation.\n       - 6 = lanczos interpolation.\n       \\param boundary_conditions Border condition type.\n       \\param centering_x Set centering type (only if \\p interpolation_type=0).\n       \\param centering_y Set centering type (only if \\p interpolation_type=0).\n       \\param centering_z Set centering type (only if \\p interpolation_type=0).\n       \\param centering_c Set centering type (only if \\p interpolation_type=0).\n       \\note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).\n    **/\n    CImg<T>& resize(const int size_x, const int size_y=-100,\n                    const int size_z=-100, const int size_c=-100,\n                    const int interpolation_type=1, const unsigned int boundary_conditions=0,\n                    const float centering_x = 0, const float centering_y = 0,\n                    const float centering_z = 0, const float centering_c = 0) {\n      if (!size_x || !size_y || !size_z || !size_c) return assign();\n      const unsigned int\n        _sx = (unsigned int)(size_x<0?-size_x*width()/100:size_x),\n        _sy = (unsigned int)(size_y<0?-size_y*height()/100:size_y),\n        _sz = (unsigned int)(size_z<0?-size_z*depth()/100:size_z),\n        _sc = (unsigned int)(size_c<0?-size_c*spectrum()/100:size_c),\n        sx = _sx?_sx:1, sy = _sy?_sy:1, sz = _sz?_sz:1, sc = _sc?_sc:1;\n      if (sx==_width && sy==_height && sz==_depth && sc==_spectrum) return *this;\n      if (is_empty()) return assign(sx,sy,sz,sc,(T)0);\n      if (interpolation_type==-1 && sx*sy*sz*sc==size()) {\n        _width = sx; _height = sy; _depth = sz; _spectrum = sc;\n        return *this;\n      }\n      return get_resize(sx,sy,sz,sc,interpolation_type,boundary_conditions,\n                        centering_x,centering_y,centering_z,centering_c).move_to(*this);\n    }\n\n    //! Resize image to new dimensions \\newinstance.\n    CImg<T> get_resize(const int size_x, const int size_y = -100,\n                       const int size_z = -100, const int size_c = -100,\n                       const int interpolation_type=1, const unsigned int boundary_conditions=0,\n                       const float centering_x = 0, const float centering_y = 0,\n                       const float centering_z = 0, const float centering_c = 0) const {\n      if (centering_x<0 || centering_x>1 || centering_y<0 || centering_y>1 ||\n          centering_z<0 || centering_z>1 || centering_c<0 || centering_c>1)\n        throw CImgArgumentException(_cimg_instance\n                                    \"resize(): Specified centering arguments (%g,%g,%g,%g) are outside range [0,1].\",\n                                    cimg_instance,\n                                    centering_x,centering_y,centering_z,centering_c);\n\n      if (!size_x || !size_y || !size_z || !size_c) return CImg<T>();\n      const unsigned int\n        _sx = (unsigned int)(size_x<0?-size_x*width()/100:size_x),\n        _sy = (unsigned int)(size_y<0?-size_y*height()/100:size_y),\n        _sz = (unsigned int)(size_z<0?-size_z*depth()/100:size_z),\n        _sc = (unsigned int)(size_c<0?-size_c*spectrum()/100:size_c),\n        sx = _sx?_sx:1, sy = _sy?_sy:1, sz = _sz?_sz:1, sc = _sc?_sc:1;\n      if (sx==_width && sy==_height && sz==_depth && sc==_spectrum) return +*this;\n      if (is_empty()) return CImg<T>(sx,sy,sz,sc,0);\n      CImg<T> res;\n      switch (interpolation_type) {\n\n        // Raw resizing.\n        //\n      case -1 :\n        std::memcpy(res.assign(sx,sy,sz,sc,0)._data,_data,sizeof(T)*cimg::min(size(),sx*sy*sz*sc));\n        break;\n\n        // No interpolation.\n        //\n      case 0 : {\n        const int\n          xc = (int)(centering_x*((int)sx - width())),\n          yc = (int)(centering_y*((int)sy - height())),\n          zc = (int)(centering_z*((int)sz - depth())),\n          cc = (int)(centering_c*((int)sc - spectrum()));\n\n        switch (boundary_conditions) {\n        case 2 : { // Periodic boundary.\n          res.assign(sx,sy,sz,sc);\n          const int\n            x0 = ((int)xc%width()) - width(),\n            y0 = ((int)yc%height()) - height(),\n            z0 = ((int)zc%depth()) - depth(),\n            c0 = ((int)cc%spectrum()) - spectrum();\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=65536)\n#endif\n          for (int c = c0; c<(int)sc; c+=spectrum())\n            for (int z = z0; z<(int)sz; z+=depth())\n              for (int y = y0; y<(int)sy; y+=height())\n                for (int x = x0; x<(int)sx; x+=width())\n                  res.draw_image(x,y,z,c,*this);\n        } break;\n        case 1 : { // Neumann boundary.\n          res.assign(sx,sy,sz,sc).draw_image(xc,yc,zc,cc,*this);\n          CImg<T> sprite;\n          if (xc>0) {  // X-backward\n            res.get_crop(xc,yc,zc,cc,xc,yc + height() - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);\n            for (int x = xc - 1; x>=0; --x) res.draw_image(x,yc,zc,cc,sprite);\n          }\n          if (xc + width()<(int)sx) { // X-forward\n            res.get_crop(xc + width() - 1,yc,zc,cc,xc + width() - 1,yc + height() - 1,\n                         zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);\n            for (int x = xc + width(); x<(int)sx; ++x) res.draw_image(x,yc,zc,cc,sprite);\n          }\n          if (yc>0) {  // Y-backward\n            res.get_crop(0,yc,zc,cc,sx - 1,yc,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);\n            for (int y = yc - 1; y>=0; --y) res.draw_image(0,y,zc,cc,sprite);\n          }\n          if (yc + height()<(int)sy) { // Y-forward\n            res.get_crop(0,yc + height() - 1,zc,cc,sx - 1,yc + height() - 1,\n                         zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);\n            for (int y = yc + height(); y<(int)sy; ++y) res.draw_image(0,y,zc,cc,sprite);\n          }\n          if (zc>0) {  // Z-backward\n            res.get_crop(0,0,zc,cc,sx - 1,sy - 1,zc,cc + spectrum() - 1).move_to(sprite);\n            for (int z = zc - 1; z>=0; --z) res.draw_image(0,0,z,cc,sprite);\n          }\n          if (zc + depth()<(int)sz) { // Z-forward\n            res.get_crop(0,0,zc  +depth() - 1,cc,sx - 1,sy - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);\n            for (int z = zc + depth(); z<(int)sz; ++z) res.draw_image(0,0,z,cc,sprite);\n          }\n          if (cc>0) {  // C-backward\n            res.get_crop(0,0,0,cc,sx - 1,sy - 1,sz - 1,cc).move_to(sprite);\n            for (int c = cc - 1; c>=0; --c) res.draw_image(0,0,0,c,sprite);\n          }\n          if (cc + spectrum()<(int)sc) { // C-forward\n            res.get_crop(0,0,0,cc + spectrum() - 1,sx - 1,sy - 1,sz - 1,cc + spectrum() - 1).move_to(sprite);\n            for (int c = cc + spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite);\n          }\n        } break;\n        default : // Dirichlet boundary.\n          res.assign(sx,sy,sz,sc,0).draw_image(xc,yc,zc,cc,*this);\n        }\n        break;\n      } break;\n\n        // Nearest neighbor interpolation.\n        //\n      case 1 : {\n        res.assign(sx,sy,sz,sc);\n        CImg<ulongT> off_x(sx), off_y(sy + 1), off_z(sz + 1), off_c(sc + 1);\n        const ulongT\n          wh = (ulongT)_width*_height,\n          whd = (ulongT)_width*_height*_depth,\n          sxy = (ulongT)sx*sy,\n          sxyz = (ulongT)sx*sy*sz;\n        if (sx==_width) off_x.fill(1);\n        else {\n          ulongT *poff_x = off_x._data, curr = 0;\n          cimg_forX(res,x) {\n            const ulongT old = curr;\n            curr = (ulongT)((x + 1.0)*_width/sx);\n            *(poff_x++) = curr - old;\n          }\n        }\n        if (sy==_height) off_y.fill(_width);\n        else {\n          ulongT *poff_y = off_y._data, curr = 0;\n          cimg_forY(res,y) {\n            const ulongT old = curr;\n            curr = (ulongT)((y + 1.0)*_height/sy);\n            *(poff_y++) = _width*(curr - old);\n          }\n          *poff_y = 0;\n        }\n        if (sz==_depth) off_z.fill(wh);\n        else {\n          ulongT *poff_z = off_z._data, curr = 0;\n          cimg_forZ(res,z) {\n            const ulongT old = curr;\n            curr = (ulongT)((z + 1.0)*_depth/sz);\n            *(poff_z++) = wh*(curr - old);\n          }\n          *poff_z = 0;\n        }\n        if (sc==_spectrum) off_c.fill(whd);\n        else {\n          ulongT *poff_c = off_c._data, curr = 0;\n          cimg_forC(res,c) {\n            const ulongT old = curr;\n            curr = (ulongT)((c + 1.0)*_spectrum/sc);\n            *(poff_c++) = whd*(curr - old);\n          }\n          *poff_c = 0;\n        }\n\n        T *ptrd = res._data;\n        const T* ptrc = _data;\n        const ulongT *poff_c = off_c._data;\n        for (unsigned int c = 0; c<sc; ) {\n          const T *ptrz = ptrc;\n          const ulongT *poff_z = off_z._data;\n          for (unsigned int z = 0; z<sz; ) {\n            const T *ptry = ptrz;\n            const ulongT *poff_y = off_y._data;\n            for (unsigned int y = 0; y<sy; ) {\n              const T *ptrx = ptry;\n              const ulongT *poff_x = off_x._data;\n              cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poff_x++); }\n              ++y;\n              ulongT dy = *(poff_y++);\n              for ( ; !dy && y<dy; std::memcpy(ptrd,ptrd - sx,sizeof(T)*sx), ++y, ptrd+=sx, dy = *(poff_y++)) {}\n              ptry+=dy;\n            }\n            ++z;\n            ulongT dz = *(poff_z++);\n            for ( ; !dz && z<dz; std::memcpy(ptrd,ptrd-sxy,sizeof(T)*sxy), ++z, ptrd+=sxy, dz = *(poff_z++)) {}\n            ptrz+=dz;\n          }\n          ++c;\n          ulongT dc = *(poff_c++);\n          for ( ; !dc && c<dc; std::memcpy(ptrd,ptrd-sxyz,sizeof(T)*sxyz), ++c, ptrd+=sxyz, dc = *(poff_c++)) {}\n          ptrc+=dc;\n        }\n      } break;\n\n        // Moving average.\n        //\n      case 2 : {\n        bool instance_first = true;\n        if (sx!=_width) {\n          CImg<Tfloat> tmp(sx,_height,_depth,_spectrum,0);\n          for (unsigned int a = _width*sx, b = _width, c = sx, s = 0, t = 0; a; ) {\n            const unsigned int d = cimg::min(b,c);\n            a-=d; b-=d; c-=d;\n            cimg_forYZC(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d;\n            if (!b) {\n              cimg_forYZC(tmp,y,z,v) tmp(t,y,z,v)/=_width;\n              ++t;\n              b = _width;\n            }\n            if (!c) { ++s; c = sx; }\n          }\n          tmp.move_to(res);\n          instance_first = false;\n        }\n        if (sy!=_height) {\n          CImg<Tfloat> tmp(sx,sy,_depth,_spectrum,0);\n          for (unsigned int a = _height*sy, b = _height, c = sy, s = 0, t = 0; a; ) {\n            const unsigned int d = cimg::min(b,c);\n            a-=d; b-=d; c-=d;\n            if (instance_first)\n              cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d;\n            else\n              cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d;\n            if (!b) {\n              cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)/=_height;\n              ++t;\n              b = _height;\n            }\n            if (!c) { ++s; c = sy; }\n          }\n          tmp.move_to(res);\n          instance_first = false;\n        }\n        if (sz!=_depth) {\n          CImg<Tfloat> tmp(sx,sy,sz,_spectrum,0);\n          for (unsigned int a = _depth*sz, b = _depth, c = sz, s = 0, t = 0; a; ) {\n            const unsigned int d = cimg::min(b,c);\n            a-=d; b-=d; c-=d;\n            if (instance_first)\n              cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d;\n            else\n              cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d;\n            if (!b) {\n              cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)/=_depth;\n              ++t;\n              b = _depth;\n            }\n            if (!c) { ++s; c = sz; }\n          }\n          tmp.move_to(res);\n          instance_first = false;\n        }\n        if (sc!=_spectrum) {\n          CImg<Tfloat> tmp(sx,sy,sz,sc,0);\n          for (unsigned int a = _spectrum*sc, b = _spectrum, c = sc, s = 0, t = 0; a; ) {\n            const unsigned int d = cimg::min(b,c);\n            a-=d; b-=d; c-=d;\n            if (instance_first)\n              cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d;\n            else\n              cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d;\n            if (!b) {\n              cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=_spectrum;\n              ++t;\n              b = _spectrum;\n            }\n            if (!c) { ++s; c = sc; }\n          }\n          tmp.move_to(res);\n          instance_first = false;\n        }\n      } break;\n\n        // Linear interpolation.\n        //\n      case 3 : {\n        CImg<uintT> off(cimg::max(sx,sy,sz,sc));\n        CImg<floatT> foff(off._width);\n        CImg<T> resx, resy, resz, resc;\n\n        if (sx!=_width) {\n          if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);\n          else {\n            if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);\n            else {\n              const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx;\n              resx.assign(sx,_height,_depth,_spectrum);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forX(resx,x) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fx;\n                *(poff++) = (unsigned int)curr - (unsigned int)old;\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resx.size()>=65536)\n#endif\n              cimg_forYZC(resx,y,z,c) {\n                const T *ptrs = data(0,y,z,c), *const ptrsmax = ptrs + _width - 1;\n                T *ptrd = resx.data(0,y,z,c);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forX(resx,x) {\n                  const float alpha = *(pfoff++);\n                  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + 1):val1;\n                  *(ptrd++) = (T)((1 - alpha)*val1 + alpha*val2);\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n        } else resx.assign(*this,true);\n\n        if (sy!=_height) {\n          if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy);\n          else {\n            if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy);\n            else {\n              const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0):\n                (float)_height/sy;\n              resy.assign(sx,sy,_depth,_spectrum);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forY(resy,y) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fy;\n                *(poff++) = sx*((unsigned int)curr-(unsigned int)old);\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resy.size()>=65536)\n#endif\n              cimg_forXZC(resy,x,z,c) {\n                const T *ptrs = resx.data(x,0,z,c), *const ptrsmax = ptrs + (_height - 1)*sx;\n                T *ptrd = resy.data(x,0,z,c);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forY(resy,y) {\n                  const float alpha = *(pfoff++);\n                  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + sx):val1;\n                  *ptrd = (T)((1 - alpha)*val1 + alpha*val2);\n                  ptrd+=sx;\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n          resx.assign();\n        } else resy.assign(resx,true);\n\n        if (sz!=_depth) {\n          if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz);\n          else {\n            if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz);\n            else {\n              const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz;\n              const unsigned int sxy = sx*sy;\n              resz.assign(sx,sy,sz,_spectrum);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forZ(resz,z) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fz;\n                *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resz.size()>=65536)\n#endif\n              cimg_forXYC(resz,x,y,c) {\n                const T *ptrs = resy.data(x,y,0,c), *const ptrsmax = ptrs + (_depth - 1)*sxy;\n                T *ptrd = resz.data(x,y,0,c);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forZ(resz,z) {\n                  const float alpha = *(pfoff++);\n                  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + sxy):val1;\n                  *ptrd = (T)((1 - alpha)*val1 + alpha*val2);\n                  ptrd+=sxy;\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n          resy.assign();\n        } else resz.assign(resy,true);\n\n        if (sc!=_spectrum) {\n          if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc);\n          else {\n            if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc);\n            else {\n              const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0):\n                (float)_spectrum/sc;\n              const unsigned int sxyz = sx*sy*sz;\n              resc.assign(sx,sy,sz,sc);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forC(resc,c) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fc;\n                *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resc.size()>=65536)\n#endif\n              cimg_forXYZ(resc,x,y,z) {\n                const T *ptrs = resz.data(x,y,z,0), *const ptrsmax = ptrs + (_spectrum - 1)*sxyz;\n                T *ptrd = resc.data(x,y,z,0);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forC(resc,c) {\n                  const float alpha = *(pfoff++);\n                  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + sxyz):val1;\n                  *ptrd = (T)((1 - alpha)*val1 + alpha*val2);\n                  ptrd+=sxyz;\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n          resz.assign();\n        } else resc.assign(resz,true);\n        return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc;\n      } break;\n\n        // Grid interpolation.\n        //\n      case 4 : {\n        CImg<T> resx, resy, resz, resc;\n        if (sx!=_width) {\n          if (sx<_width) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);\n          else {\n            resx.assign(sx,_height,_depth,_spectrum,0);\n            const int dx = (int)(2*sx), dy = 2*width();\n            int err = (int)(dy + centering_x*(sx*dy/width() - dy)), xs = 0;\n            cimg_forX(resx,x) if ((err-=dy)<=0) {\n              cimg_forYZC(resx,y,z,c) resx(x,y,z,c) = (*this)(xs,y,z,c);\n              ++xs;\n              err+=dx;\n            }\n          }\n        } else resx.assign(*this,true);\n\n        if (sy!=_height) {\n          if (sy<_height) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy);\n          else {\n            resy.assign(sx,sy,_depth,_spectrum,0);\n            const int dx = (int)(2*sy), dy = 2*height();\n            int err = (int)(dy + centering_y*(sy*dy/height() - dy)), ys = 0;\n            cimg_forY(resy,y) if ((err-=dy)<=0) {\n              cimg_forXZC(resy,x,z,c) resy(x,y,z,c) = resx(x,ys,z,c);\n              ++ys;\n              err+=dx;\n            }\n          }\n          resx.assign();\n        } else resy.assign(resx,true);\n\n        if (sz!=_depth) {\n          if (sz<_depth) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz);\n          else {\n            resz.assign(sx,sy,sz,_spectrum,0);\n            const int dx = (int)(2*sz), dy = 2*depth();\n            int err = (int)(dy + centering_z*(sz*dy/depth() - dy)), zs = 0;\n            cimg_forZ(resz,z) if ((err-=dy)<=0) {\n              cimg_forXYC(resz,x,y,c) resz(x,y,z,c) = resy(x,y,zs,c);\n              ++zs;\n              err+=dx;\n            }\n          }\n          resy.assign();\n        } else resz.assign(resy,true);\n\n        if (sc!=_spectrum) {\n          if (sc<_spectrum) resz.get_resize(sx,sy,sz,sc,1).move_to(resc);\n          else {\n            resc.assign(sx,sy,sz,sc,0);\n            const int dx = (int)(2*sc), dy = 2*spectrum();\n            int err = (int)(dy + centering_c*(sc*dy/spectrum() - dy)), cs = 0;\n            cimg_forC(resc,c) if ((err-=dy)<=0) {\n              cimg_forXYZ(resc,x,y,z) resc(x,y,z,c) = resz(x,y,z,cs);\n              ++cs;\n              err+=dx;\n            }\n          }\n          resz.assign();\n        } else resc.assign(resz,true);\n\n        return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc;\n      } break;\n\n        // Cubic interpolation.\n        //\n      case 5 : {\n        const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();\n        CImg<uintT> off(cimg::max(sx,sy,sz,sc));\n        CImg<floatT> foff(off._width);\n        CImg<T> resx, resy, resz, resc;\n\n        if (sx!=_width) {\n          if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);\n          else {\n            if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);\n            else {\n              const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx;\n              resx.assign(sx,_height,_depth,_spectrum);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forX(resx,x) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fx;\n                *(poff++) = (unsigned int)curr - (unsigned int)old;\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resx.size()>=65536)\n#endif\n              cimg_forYZC(resx,y,z,c) {\n                const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_width - 2);\n                T *ptrd = resx.data(0,y,z,c);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forX(resx,x) {\n                  const float t = *(pfoff++);\n                  const Tfloat\n                    val1 = (Tfloat)*ptrs,\n                    val0 = ptrs>ptrs0?(Tfloat)*(ptrs - 1):val1,\n                    val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + 1):val1,\n                    val3 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2):val2,\n                    val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +\n                                       t*t*t*(-val0 + 3*val1 - 3*val2 + val3));\n                  *(ptrd++) = (T)(val<vmin?vmin:val>vmax?vmax:val);\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n        } else resx.assign(*this,true);\n\n        if (sy!=_height) {\n          if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy);\n          else {\n            if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy);\n            else {\n              const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0):\n                (float)_height/sy;\n              resy.assign(sx,sy,_depth,_spectrum);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forY(resy,y) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fy;\n                *(poff++) = sx*((unsigned int)curr - (unsigned int)old);\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resy.size()>=65536)\n#endif\n              cimg_forXZC(resy,x,z,c) {\n                const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_height - 2)*sx;\n                T *ptrd = resy.data(x,0,z,c);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forY(resy,y) {\n                  const float t = *(pfoff++);\n                  const Tfloat\n                    val1 = (Tfloat)*ptrs,\n                    val0 = ptrs>ptrs0?(Tfloat)*(ptrs - sx):val1,\n                    val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sx):val1,\n                    val3 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sx):val2,\n                    val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +\n                                       t*t*t*(-val0 + 3*val1 - 3*val2 + val3));\n                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);\n                  ptrd+=sx;\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n          resx.assign();\n        } else resy.assign(resx,true);\n\n        if (sz!=_depth) {\n          if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz);\n          else {\n            if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz);\n            else {\n              const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz;\n              const unsigned int sxy = sx*sy;\n              resz.assign(sx,sy,sz,_spectrum);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forZ(resz,z) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fz;\n                *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resz.size()>=65536)\n#endif\n              cimg_forXYC(resz,x,y,c) {\n                const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_depth - 2)*sxy;\n                T *ptrd = resz.data(x,y,0,c);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forZ(resz,z) {\n                  const float t = *(pfoff++);\n                  const Tfloat\n                    val1 = (Tfloat)*ptrs,\n                    val0 = ptrs>ptrs0?(Tfloat)*(ptrs - sxy):val1,\n                    val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxy):val1,\n                    val3 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sxy):val2,\n                    val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +\n                                       t*t*t*(-val0 + 3*val1 - 3*val2 + val3));\n                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);\n                  ptrd+=sxy;\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n          resy.assign();\n        } else resz.assign(resy,true);\n\n        if (sc!=_spectrum) {\n          if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc);\n          else {\n            if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc);\n            else {\n              const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0):\n                (float)_spectrum/sc;\n              const unsigned int sxyz = sx*sy*sz;\n              resc.assign(sx,sy,sz,sc);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forC(resc,c) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fc;\n                *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resc.size()>=65536)\n#endif\n              cimg_forXYZ(resc,x,y,z) {\n                const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmax = ptrs + (_spectrum - 2)*sxyz;\n                T *ptrd = resc.data(x,y,z,0);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forC(resc,c) {\n                  const float t = *(pfoff++);\n                  const Tfloat\n                    val1 = (Tfloat)*ptrs,\n                    val0 = ptrs>ptrs0?(Tfloat)*(ptrs - sxyz):val1,\n                    val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxyz):val1,\n                    val3 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sxyz):val2,\n                    val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +\n                                       t*t*t*(-val0 + 3*val1 - 3*val2 + val3));\n                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);\n                  ptrd+=sxyz;\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n          resz.assign();\n        } else resc.assign(resz,true);\n\n        return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc;\n      } break;\n\n        // Lanczos interpolation.\n        //\n      case 6 : {\n        const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();\n        CImg<uintT> off(cimg::max(sx,sy,sz,sc));\n        CImg<floatT> foff(off._width);\n        CImg<T> resx, resy, resz, resc;\n\n        if (sx!=_width) {\n          if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);\n          else {\n            if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);\n            else {\n              const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx;\n              resx.assign(sx,_height,_depth,_spectrum);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forX(resx,x) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fx;\n                *(poff++) = (unsigned int)curr - (unsigned int)old;\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resx.size()>=65536)\n#endif\n              cimg_forYZC(resx,y,z,c) {\n                const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + 1,\n                  *const ptrsmax = ptrs0 + (_width - 2);\n                T *ptrd = resx.data(0,y,z,c);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forX(resx,x) {\n                  const float\n                    t = *(pfoff++),\n                    w0 = _cimg_lanczos(t + 2),\n                    w1 = _cimg_lanczos(t + 1),\n                    w2 = _cimg_lanczos(t),\n                    w3 = _cimg_lanczos(t - 1),\n                    w4 = _cimg_lanczos(t - 2);\n                  const Tfloat\n                    val2 = (Tfloat)*ptrs,\n                    val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - 1):val2,\n                    val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2):val1,\n                    val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + 1):val2,\n                    val4 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2):val3,\n                    val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);\n                  *(ptrd++) = (T)(val<vmin?vmin:val>vmax?vmax:val);\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n        } else resx.assign(*this,true);\n\n        if (sy!=_height) {\n          if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy);\n          else {\n            if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy);\n            else {\n              const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0):\n                (float)_height/sy;\n              resy.assign(sx,sy,_depth,_spectrum);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forY(resy,y) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fy;\n                *(poff++) = sx*((unsigned int)curr - (unsigned int)old);\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resy.size()>=65536)\n#endif\n              cimg_forXZC(resy,x,z,c) {\n                const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sx,\n                  *const ptrsmax = ptrs0 + (_height - 2)*sx;\n                T *ptrd = resy.data(x,0,z,c);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forY(resy,y) {\n                  const float\n                    t = *(pfoff++),\n                    w0 = _cimg_lanczos(t + 2),\n                    w1 = _cimg_lanczos(t + 1),\n                    w2 = _cimg_lanczos(t),\n                    w3 = _cimg_lanczos(t - 1),\n                    w4 = _cimg_lanczos(t - 2);\n                  const Tfloat\n                    val2 = (Tfloat)*ptrs,\n                    val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - sx):val2,\n                    val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sx):val1,\n                    val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sx):val2,\n                    val4 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sx):val3,\n                    val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);\n                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);\n                  ptrd+=sx;\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n          resx.assign();\n        } else resy.assign(resx,true);\n\n        if (sz!=_depth) {\n          if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz);\n          else {\n            if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz);\n            else {\n              const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz;\n              const unsigned int sxy = sx*sy;\n              resz.assign(sx,sy,sz,_spectrum);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forZ(resz,z) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fz;\n                *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resz.size()>=65536)\n#endif\n              cimg_forXYC(resz,x,y,c) {\n                const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxy,\n                  *const ptrsmax = ptrs0 + (_depth - 2)*sxy;\n                T *ptrd = resz.data(x,y,0,c);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forZ(resz,z) {\n                  const float\n                    t = *(pfoff++),\n                    w0 = _cimg_lanczos(t + 2),\n                    w1 = _cimg_lanczos(t + 1),\n                    w2 = _cimg_lanczos(t),\n                    w3 = _cimg_lanczos(t - 1),\n                    w4 = _cimg_lanczos(t - 2);\n                  const Tfloat\n                    val2 = (Tfloat)*ptrs,\n                    val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - sxy):val2,\n                    val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sxy):val1,\n                    val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxy):val2,\n                    val4 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sxy):val3,\n                    val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);\n                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);\n                  ptrd+=sxy;\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n          resy.assign();\n        } else resz.assign(resy,true);\n\n        if (sc!=_spectrum) {\n          if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc);\n          else {\n            if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc);\n            else {\n              const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0):\n                (float)_spectrum/sc;\n              const unsigned int sxyz = sx*sy*sz;\n              resc.assign(sx,sy,sz,sc);\n              float curr = 0, old = 0;\n              unsigned int *poff = off._data;\n              float *pfoff = foff._data;\n              cimg_forC(resc,c) {\n                *(pfoff++) = curr - (unsigned int)curr;\n                old = curr;\n                curr+=fc;\n                *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);\n              }\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (resc.size()>=65536)\n#endif\n              cimg_forXYZ(resc,x,y,z) {\n                const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxyz,\n                  *const ptrsmax = ptrs + (_spectrum - 2)*sxyz;\n                T *ptrd = resc.data(x,y,z,0);\n                const unsigned int *poff = off._data;\n                const float *pfoff = foff._data;\n                cimg_forC(resc,c) {\n                  const float\n                    t = *(pfoff++),\n                    w0 = _cimg_lanczos(t + 2),\n                    w1 = _cimg_lanczos(t + 1),\n                    w2 = _cimg_lanczos(t),\n                    w3 = _cimg_lanczos(t - 1),\n                    w4 = _cimg_lanczos(t - 2);\n                  const Tfloat\n                    val2 = (Tfloat)*ptrs,\n                    val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - sxyz):val2,\n                    val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sxyz):val1,\n                    val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxyz):val2,\n                    val4 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sxyz):val3,\n                    val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);\n                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);\n                  ptrd+=sxyz;\n                  ptrs+=*(poff++);\n                }\n              }\n            }\n          }\n          resz.assign();\n        } else resc.assign(resz,true);\n\n        return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc;\n      } break;\n\n        // Unknow interpolation.\n        //\n      default :\n        throw CImgArgumentException(_cimg_instance\n                                    \"resize(): Invalid specified interpolation %d \"\n                                    \"(should be { -1=raw | 0=none | 1=nearest | 2=average | 3=linear | 4=grid | \"\n                                    \"5=cubic | 6=lanczos }).\",\n                                    cimg_instance,\n                                    interpolation_type);\n      }\n      return res;\n    }\n\n    //! Resize image to dimensions of another image.\n    /**\n       \\param src Reference image used for dimensions.\n       \\param interpolation_type Interpolation method.\n       \\param boundary_conditions Boundary conditions.\n       \\param centering_x Set centering type (only if \\p interpolation_type=0).\n       \\param centering_y Set centering type (only if \\p interpolation_type=0).\n       \\param centering_z Set centering type (only if \\p interpolation_type=0).\n       \\param centering_c Set centering type (only if \\p interpolation_type=0).\n     **/\n    template<typename t>\n    CImg<T>& resize(const CImg<t>& src,\n                    const int interpolation_type=1, const unsigned int boundary_conditions=0,\n                    const float centering_x = 0, const float centering_y = 0,\n                    const float centering_z = 0, const float centering_c = 0) {\n      return resize(src._width,src._height,src._depth,src._spectrum,interpolation_type,boundary_conditions,\n                    centering_x,centering_y,centering_z,centering_c);\n    }\n\n    //! Resize image to dimensions of another image \\newinstance.\n    template<typename t>\n    CImg<T> get_resize(const CImg<t>& src,\n                       const int interpolation_type=1, const unsigned int boundary_conditions=0,\n                       const float centering_x = 0, const float centering_y = 0,\n                       const float centering_z = 0, const float centering_c = 0) const {\n      return get_resize(src._width,src._height,src._depth,src._spectrum,interpolation_type,boundary_conditions,\n                        centering_x,centering_y,centering_z,centering_c);\n    }\n\n    //! Resize image to dimensions of a display window.\n    /**\n       \\param disp Reference display window used for dimensions.\n       \\param interpolation_type Interpolation method.\n       \\param boundary_conditions Boundary conditions.\n       \\param centering_x Set centering type (only if \\p interpolation_type=0).\n       \\param centering_y Set centering type (only if \\p interpolation_type=0).\n       \\param centering_z Set centering type (only if \\p interpolation_type=0).\n       \\param centering_c Set centering type (only if \\p interpolation_type=0).\n     **/\n    CImg<T>& resize(const CImgDisplay& disp,\n                    const int interpolation_type=1, const unsigned int boundary_conditions=0,\n                    const float centering_x = 0, const float centering_y = 0,\n                    const float centering_z = 0, const float centering_c = 0) {\n      return resize(disp.width(),disp.height(),_depth,_spectrum,interpolation_type,boundary_conditions,\n                    centering_x,centering_y,centering_z,centering_c);\n    }\n\n    //! Resize image to dimensions of a display window \\newinstance.\n    CImg<T> get_resize(const CImgDisplay& disp,\n                       const int interpolation_type=1, const unsigned int boundary_conditions=0,\n                       const float centering_x = 0, const float centering_y = 0,\n                       const float centering_z = 0, const float centering_c = 0) const {\n      return get_resize(disp.width(),disp.height(),_depth,_spectrum,interpolation_type,boundary_conditions,\n                        centering_x,centering_y,centering_z,centering_c);\n    }\n\n    //! Resize image to half-size along XY axes, using an optimized filter.\n    CImg<T>& resize_halfXY() {\n      return get_resize_halfXY().move_to(*this);\n    }\n\n    //! Resize image to half-size along XY axes, using an optimized filter \\newinstance.\n    CImg<T> get_resize_halfXY() const {\n      if (is_empty()) return *this;\n      static const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,\n                                      0.1231940459f,  0.1935127547f, 0.1231940459f,\n                                      0.07842776544f, 0.1231940459f, 0.07842776544f };\n      CImg<T> I(9), res(_width/2,_height/2,_depth,_spectrum);\n      T *ptrd = res._data;\n      cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T)\n        if (x%2 && y%2) *(ptrd++) = (T)\n                          (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +\n                           I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +\n                           I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);\n      return res;\n    }\n\n    //! Resize image to double-size, using the Scale2X algorithm.\n    /**\n       \\note Use anisotropic upscaling algorithm\n       <a href=\"http://scale2x.sourceforge.net/algorithm.html\">described here</a>.\n    **/\n    CImg<T>& resize_doubleXY() {\n      return get_resize_doubleXY().move_to(*this);\n    }\n\n    //! Resize image to double-size, using the Scale2X algorithm \\newinstance.\n    CImg<T> get_resize_doubleXY() const {\n#define _cimg_gs2x_for3(bound,i) \\\n for (int i = 0, _p1##i = 0, \\\n      _n1##i = 1>=(bound)?(int)(bound) - 1:1; \\\n      _n1##i<(int)(bound) || i==--_n1##i; \\\n      _p1##i = i++, ++_n1##i, ptrd1+=(res)._width, ptrd2+=(res)._width)\n\n#define _cimg_gs2x_for3x3(img,x,y,z,c,I,T) \\\n  _cimg_gs2x_for3((img)._height,y) for (int x = 0, \\\n   _p1##x = 0, \\\n   _n1##x = (int)( \\\n   (I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[3] = I[4] = (T)(img)(0,y,z,c)), \\\n   (I[7] = (T)(img)(0,_n1##y,z,c)),     \\\n   1>=(img)._width?(img).width() - 1:1); \\\n   (_n1##x<(img).width() && ( \\\n   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[5] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \\\n   x==--_n1##x; \\\n   I[1] = I[2], \\\n   I[3] = I[4], I[4] = I[5], \\\n   I[7] = I[8], \\\n   _p1##x = x++, ++_n1##x)\n\n      if (is_empty()) return *this;\n      CImg<T> res(_width<<1,_height<<1,_depth,_spectrum);\n      CImg_3x3(I,T);\n      cimg_forZC(*this,z,c) {\n        T\n          *ptrd1 = res.data(0,0,z,c),\n          *ptrd2 = ptrd1 + res._width;\n        _cimg_gs2x_for3x3(*this,x,y,z,c,I,T) {\n          if (Icp!=Icn && Ipc!=Inc) {\n            *(ptrd1++) = Ipc==Icp?Ipc:Icc;\n            *(ptrd1++) = Icp==Inc?Inc:Icc;\n            *(ptrd2++) = Ipc==Icn?Ipc:Icc;\n            *(ptrd2++) = Icn==Inc?Inc:Icc;\n          } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; }\n        }\n      }\n      return res;\n    }\n\n    //! Resize image to triple-size, using the Scale3X algorithm.\n    /**\n       \\note Use anisotropic upscaling algorithm\n       <a href=\"http://scale2x.sourceforge.net/algorithm.html\">described here</a>.\n    **/\n    CImg<T>& resize_tripleXY() {\n      return get_resize_tripleXY().move_to(*this);\n    }\n\n    //! Resize image to triple-size, using the Scale3X algorithm \\newinstance.\n    CImg<T> get_resize_tripleXY() const {\n#define _cimg_gs3x_for3(bound,i) \\\n for (int i = 0, _p1##i = 0, \\\n      _n1##i = 1>=(bound)?(int)(bound) - 1:1; \\\n      _n1##i<(int)(bound) || i==--_n1##i; \\\n      _p1##i = i++, ++_n1##i, ptrd1+=2*(res)._width, ptrd2+=2*(res)._width, ptrd3+=2*(res)._width)\n\n#define _cimg_gs3x_for3x3(img,x,y,z,c,I,T) \\\n  _cimg_gs3x_for3((img)._height,y) for (int x = 0, \\\n   _p1##x = 0, \\\n   _n1##x = (int)( \\\n   (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \\\n   (I[3] = I[4] = (T)(img)(0,y,z,c)), \\\n   (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)),      \\\n   1>=(img)._width?(img).width() - 1:1); \\\n   (_n1##x<(img).width() && ( \\\n   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \\\n   (I[5] = (T)(img)(_n1##x,y,z,c)), \\\n   (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \\\n   x==--_n1##x; \\\n   I[0] = I[1], I[1] = I[2], \\\n   I[3] = I[4], I[4] = I[5], \\\n   I[6] = I[7], I[7] = I[8], \\\n   _p1##x = x++, ++_n1##x)\n\n      if (is_empty()) return *this;\n      CImg<T> res(3*_width,3*_height,_depth,_spectrum);\n      CImg_3x3(I,T);\n      cimg_forZC(*this,z,c) {\n        T\n          *ptrd1 = res.data(0,0,z,c),\n          *ptrd2 = ptrd1 + res._width,\n          *ptrd3 = ptrd2 + res._width;\n        _cimg_gs3x_for3x3(*this,x,y,z,c,I,T) {\n          if (Icp != Icn && Ipc != Inc) {\n            *(ptrd1++) = Ipc==Icp?Ipc:Icc;\n            *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc;\n            *(ptrd1++) = Icp==Inc?Inc:Icc;\n            *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc;\n            *(ptrd2++) = Icc;\n            *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc;\n            *(ptrd3++) = Ipc==Icn?Ipc:Icc;\n            *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc;\n            *(ptrd3++) = Icn==Inc?Inc:Icc;\n          } else {\n            *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc;\n            *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc;\n            *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc;\n          }\n        }\n      }\n      return res;\n    }\n\n    //! Mirror image content along specified axis.\n    /**\n       \\param axis Mirror axis\n    **/\n    CImg<T>& mirror(const char axis) {\n      if (is_empty()) return *this;\n      T *pf, *pb, *buf = 0;\n      switch (cimg::uncase(axis)) {\n      case 'x' : {\n        pf = _data; pb = data(_width - 1);\n        const unsigned int width2 = _width/2;\n        for (unsigned int yzv = 0; yzv<_height*_depth*_spectrum; ++yzv) {\n          for (unsigned int x = 0; x<width2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; }\n          pf+=_width - width2;\n          pb+=_width + width2;\n        }\n      } break;\n      case 'y' : {\n        buf = new T[_width];\n        pf = _data; pb = data(0,_height - 1);\n        const unsigned int height2 = _height/2;\n        for (unsigned int zv = 0; zv<_depth*_spectrum; ++zv) {\n          for (unsigned int y = 0; y<height2; ++y) {\n            std::memcpy(buf,pf,_width*sizeof(T));\n            std::memcpy(pf,pb,_width*sizeof(T));\n            std::memcpy(pb,buf,_width*sizeof(T));\n            pf+=_width;\n            pb-=_width;\n          }\n          pf+=(ulongT)_width*(_height - height2);\n          pb+=(ulongT)_width*(_height + height2);\n        }\n      } break;\n      case 'z' : {\n        buf = new T[(ulongT)_width*_height];\n        pf = _data; pb = data(0,0,_depth - 1);\n        const unsigned int depth2 = _depth/2;\n        cimg_forC(*this,c) {\n          for (unsigned int z = 0; z<depth2; ++z) {\n            std::memcpy(buf,pf,_width*_height*sizeof(T));\n            std::memcpy(pf,pb,_width*_height*sizeof(T));\n            std::memcpy(pb,buf,_width*_height*sizeof(T));\n            pf+=(ulongT)_width*_height;\n            pb-=(ulongT)_width*_height;\n          }\n          pf+=(ulongT)_width*_height*(_depth - depth2);\n          pb+=(ulongT)_width*_height*(_depth + depth2);\n        }\n      } break;\n      case 'c' : {\n        buf = new T[(ulongT)_width*_height*_depth];\n        pf = _data; pb = data(0,0,0,_spectrum - 1);\n        const unsigned int _spectrum2 = _spectrum/2;\n        for (unsigned int v = 0; v<_spectrum2; ++v) {\n          std::memcpy(buf,pf,_width*_height*_depth*sizeof(T));\n          std::memcpy(pf,pb,_width*_height*_depth*sizeof(T));\n          std::memcpy(pb,buf,_width*_height*_depth*sizeof(T));\n          pf+=(ulongT)_width*_height*_depth;\n          pb-=(ulongT)_width*_height*_depth;\n        }\n      } break;\n      default :\n        throw CImgArgumentException(_cimg_instance\n                                    \"mirror(): Invalid specified axis '%c'.\",\n                                    cimg_instance,\n                                    axis);\n      }\n      delete[] buf;\n      return *this;\n    }\n\n    //! Mirror image content along specified axis \\newinstance.\n    CImg<T> get_mirror(const char axis) const {\n      return (+*this).mirror(axis);\n    }\n\n    //! Mirror image content along specified axes.\n    /**\n       \\param axes Mirror axes, as a C-string.\n       \\note \\c axes may contains multiple characters, e.g. \\c \"xyz\"\n    **/\n    CImg<T>& mirror(const char *const axes) {\n      for (const char *s = axes; *s; ++s) mirror(*s);\n      return *this;\n    }\n\n    //! Mirror image content along specified axes \\newinstance.\n    CImg<T> get_mirror(const char *const axes) const {\n      return (+*this).mirror(axes);\n    }\n\n    //! Shift image content.\n    /**\n       \\param delta_x Amount of displacement along the X-axis.\n       \\param delta_y Amount of displacement along the Y-axis.\n       \\param delta_z Amount of displacement along the Z-axis.\n       \\param delta_c Amount of displacement along the C-axis.\n       \\param boundary_conditions Border condition.\n\n       - \\c boundary_conditions can be:\n          - 0: Zero border condition (Dirichlet).\n          - 1: Nearest neighbors (Neumann).\n          - 2: Repeat Pattern (Fourier style).\n    **/\n    CImg<T>& shift(const int delta_x, const int delta_y=0, const int delta_z=0, const int delta_c=0,\n                   const int boundary_conditions=0) {\n      if (is_empty()) return *this;\n      if (delta_x) // Shift along X-axis\n        switch (boundary_conditions) {\n        case 0 :\n          if (cimg::abs(delta_x)>=width()) return fill(0);\n          if (delta_x<0) cimg_forYZC(*this,y,z,c) {\n            std::memmove(data(0,y,z,c),data(-delta_x,y,z,c),(_width + delta_x)*sizeof(T));\n            std::memset(data(_width + delta_x,y,z,c),0,-delta_x*sizeof(T));\n          } else cimg_forYZC(*this,y,z,c) {\n            std::memmove(data(delta_x,y,z,c),data(0,y,z,c),(_width-delta_x)*sizeof(T));\n            std::memset(data(0,y,z,c),0,delta_x*sizeof(T));\n          }\n          break;\n        case 1 :\n          if (delta_x<0) {\n            const int ndelta_x = (-delta_x>=width())?width() - 1:-delta_x;\n            if (!ndelta_x) return *this;\n            cimg_forYZC(*this,y,z,c) {\n              std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T));\n              T *ptrd = data(_width - 1,y,z,c);\n              const T val = *ptrd;\n              for (int l = 0; l<ndelta_x - 1; ++l) *(--ptrd) = val;\n            }\n          } else {\n            const int ndelta_x = (delta_x>=width())?width() - 1:delta_x;\n            if (!ndelta_x) return *this;\n            cimg_forYZC(*this,y,z,c) {\n              std::memmove(data(ndelta_x,y,z,c),data(0,y,z,c),(_width-ndelta_x)*sizeof(T));\n              T *ptrd = data(0,y,z,c);\n              const T val = *ptrd;\n              for (int l = 0; l<ndelta_x - 1; ++l) *(++ptrd) = val;\n            }\n          }\n          break;\n        default : {\n          const int ml = cimg::mod(-delta_x,width()), ndelta_x = (ml<=width()/2)?ml:(ml-width());\n          if (!ndelta_x) return *this;\n          T *const buf = new T[(unsigned int)cimg::abs(ndelta_x)];\n          if (ndelta_x>0) cimg_forYZC(*this,y,z,c) {\n            std::memcpy(buf,data(0,y,z,c),ndelta_x*sizeof(T));\n            std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T));\n            std::memcpy(data(_width-ndelta_x,y,z,c),buf,ndelta_x*sizeof(T));\n          } else cimg_forYZC(*this,y,z,c) {\n            std::memcpy(buf,data(_width + ndelta_x,y,z,c),-ndelta_x*sizeof(T));\n            std::memmove(data(-ndelta_x,y,z,c),data(0,y,z,c),(_width + ndelta_x)*sizeof(T));\n            std::memcpy(data(0,y,z,c),buf,-ndelta_x*sizeof(T));\n          }\n          delete[] buf;\n        }\n        }\n\n      if (delta_y) // Shift along Y-axis\n        switch (boundary_conditions) {\n        case 0 :\n          if (cimg::abs(delta_y)>=height()) return fill(0);\n          if (delta_y<0) cimg_forZC(*this,z,c) {\n            std::memmove(data(0,0,z,c),data(0,-delta_y,z,c),_width*(_height + delta_y)*sizeof(T));\n            std::memset(data(0,_height + delta_y,z,c),0,-delta_y*_width*sizeof(T));\n          } else cimg_forZC(*this,z,c) {\n            std::memmove(data(0,delta_y,z,c),data(0,0,z,c),_width*(_height-delta_y)*sizeof(T));\n            std::memset(data(0,0,z,c),0,delta_y*_width*sizeof(T));\n          }\n          break;\n        case 1 :\n          if (delta_y<0) {\n            const int ndelta_y = (-delta_y>=height())?height() - 1:-delta_y;\n            if (!ndelta_y) return *this;\n            cimg_forZC(*this,z,c) {\n              std::memmove(data(0,0,z,c),data(0,ndelta_y,z,c),_width*(_height-ndelta_y)*sizeof(T));\n              T *ptrd = data(0,_height-ndelta_y,z,c), *ptrs = data(0,_height - 1,z,c);\n              for (int l = 0; l<ndelta_y - 1; ++l) { std::memcpy(ptrd,ptrs,_width*sizeof(T)); ptrd+=_width; }\n            }\n          } else {\n            const int ndelta_y = (delta_y>=height())?height() - 1:delta_y;\n            if (!ndelta_y) return *this;\n            cimg_forZC(*this,z,c) {\n              std::memmove(data(0,ndelta_y,z,c),data(0,0,z,c),_width*(_height-ndelta_y)*sizeof(T));\n              T *ptrd = data(0,1,z,c), *ptrs = data(0,0,z,c);\n              for (int l = 0; l<ndelta_y - 1; ++l) { std::memcpy(ptrd,ptrs,_width*sizeof(T)); ptrd+=_width; }\n            }\n          }\n          break;\n        default : {\n          const int ml = cimg::mod(-delta_y,height()), ndelta_y = (ml<=height()/2)?ml:(ml-height());\n          if (!ndelta_y) return *this;\n          T *const buf = new T[(size_t)_width*cimg::abs(ndelta_y)];\n          if (ndelta_y>0) cimg_forZC(*this,z,c) {\n            std::memcpy(buf,data(0,0,z,c),_width*ndelta_y*sizeof(T));\n            std::memmove(data(0,0,z,c),data(0,ndelta_y,z,c),_width*(_height-ndelta_y)*sizeof(T));\n            std::memcpy(data(0,_height-ndelta_y,z,c),buf,_width*ndelta_y*sizeof(T));\n          } else cimg_forZC(*this,z,c) {\n            std::memcpy(buf,data(0,_height + ndelta_y,z,c),-ndelta_y*_width*sizeof(T));\n            std::memmove(data(0,-ndelta_y,z,c),data(0,0,z,c),_width*(_height + ndelta_y)*sizeof(T));\n            std::memcpy(data(0,0,z,c),buf,-ndelta_y*_width*sizeof(T));\n          }\n          delete[] buf;\n        }\n        }\n\n      if (delta_z) // Shift along Z-axis\n        switch (boundary_conditions) {\n        case 0 :\n          if (cimg::abs(delta_z)>=depth()) return fill(0);\n          if (delta_z<0) cimg_forC(*this,c) {\n            std::memmove(data(0,0,0,c),data(0,0,-delta_z,c),_width*_height*(_depth + delta_z)*sizeof(T));\n            std::memset(data(0,0,_depth + delta_z,c),0,_width*_height*(-delta_z)*sizeof(T));\n          } else cimg_forC(*this,c) {\n            std::memmove(data(0,0,delta_z,c),data(0,0,0,c),_width*_height*(_depth-delta_z)*sizeof(T));\n            std::memset(data(0,0,0,c),0,delta_z*_width*_height*sizeof(T));\n          }\n          break;\n        case 1 :\n          if (delta_z<0) {\n            const int ndelta_z = (-delta_z>=depth())?depth() - 1:-delta_z;\n            if (!ndelta_z) return *this;\n            cimg_forC(*this,c) {\n              std::memmove(data(0,0,0,c),data(0,0,ndelta_z,c),_width*_height*(_depth-ndelta_z)*sizeof(T));\n              T *ptrd = data(0,0,_depth-ndelta_z,c), *ptrs = data(0,0,_depth - 1,c);\n              for (int l = 0; l<ndelta_z - 1; ++l) {\n                std::memcpy(ptrd,ptrs,_width*_height*sizeof(T)); ptrd+=(ulongT)_width*_height;\n              }\n            }\n          } else {\n            const int ndelta_z = (delta_z>=depth())?depth() - 1:delta_z;\n            if (!ndelta_z) return *this;\n            cimg_forC(*this,c) {\n              std::memmove(data(0,0,ndelta_z,c),data(0,0,0,c),_width*_height*(_depth-ndelta_z)*sizeof(T));\n              T *ptrd = data(0,0,1,c), *ptrs = data(0,0,0,c);\n              for (int l = 0; l<ndelta_z - 1; ++l) {\n                std::memcpy(ptrd,ptrs,_width*_height*sizeof(T)); ptrd+=(ulongT)_width*_height;\n              }\n            }\n          }\n          break;\n        default : {\n          const int ml = cimg::mod(-delta_z,depth()), ndelta_z = (ml<=depth()/2)?ml:(ml-depth());\n          if (!ndelta_z) return *this;\n          T *const buf = new T[(size_t)_width*_height*cimg::abs(ndelta_z)];\n          if (ndelta_z>0) cimg_forC(*this,c) {\n            std::memcpy(buf,data(0,0,0,c),_width*_height*ndelta_z*sizeof(T));\n            std::memmove(data(0,0,0,c),data(0,0,ndelta_z,c),_width*_height*(_depth-ndelta_z)*sizeof(T));\n            std::memcpy(data(0,0,_depth-ndelta_z,c),buf,_width*_height*ndelta_z*sizeof(T));\n          } else cimg_forC(*this,c) {\n            std::memcpy(buf,data(0,0,_depth + ndelta_z,c),-ndelta_z*_width*_height*sizeof(T));\n            std::memmove(data(0,0,-ndelta_z,c),data(0,0,0,c),_width*_height*(_depth + ndelta_z)*sizeof(T));\n            std::memcpy(data(0,0,0,c),buf,-ndelta_z*_width*_height*sizeof(T));\n          }\n          delete[] buf;\n        }\n        }\n\n      if (delta_c) // Shift along C-axis\n        switch (boundary_conditions) {\n        case 0 :\n          if (cimg::abs(delta_c)>=spectrum()) return fill(0);\n          if (delta_c<0) {\n            std::memmove(_data,data(0,0,0,-delta_c),_width*_height*_depth*(_spectrum + delta_c)*sizeof(T));\n            std::memset(data(0,0,0,_spectrum + delta_c),0,_width*_height*_depth*(-delta_c)*sizeof(T));\n          } else {\n            std::memmove(data(0,0,0,delta_c),_data,_width*_height*_depth*(_spectrum-delta_c)*sizeof(T));\n            std::memset(_data,0,delta_c*_width*_height*_depth*sizeof(T));\n          }\n          break;\n        case 1 :\n          if (delta_c<0) {\n            const int ndelta_c = (-delta_c>=spectrum())?spectrum() - 1:-delta_c;\n            if (!ndelta_c) return *this;\n            std::memmove(_data,data(0,0,0,ndelta_c),_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T));\n            T *ptrd = data(0,0,0,_spectrum-ndelta_c), *ptrs = data(0,0,0,_spectrum - 1);\n            for (int l = 0; l<ndelta_c - 1; ++l) {\n              std::memcpy(ptrd,ptrs,_width*_height*_depth*sizeof(T)); ptrd+=(ulongT)_width*_height*_depth;\n            }\n          } else {\n            const int ndelta_c = (delta_c>=spectrum())?spectrum() - 1:delta_c;\n            if (!ndelta_c) return *this;\n            std::memmove(data(0,0,0,ndelta_c),_data,_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T));\n            T *ptrd = data(0,0,0,1);\n            for (int l = 0; l<ndelta_c - 1; ++l) {\n              std::memcpy(ptrd,_data,_width*_height*_depth*sizeof(T)); ptrd+=(ulongT)_width*_height*_depth;\n            }\n          }\n          break;\n        default : {\n          const int ml = cimg::mod(-delta_c,spectrum()), ndelta_c = (ml<=spectrum()/2)?ml:(ml-spectrum());\n          if (!ndelta_c) return *this;\n          T *const buf = new T[(size_t)_width*_height*_depth*cimg::abs(ndelta_c)];\n          if (ndelta_c>0) {\n            std::memcpy(buf,_data,_width*_height*_depth*ndelta_c*sizeof(T));\n            std::memmove(_data,data(0,0,0,ndelta_c),_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T));\n            std::memcpy(data(0,0,0,_spectrum-ndelta_c),buf,_width*_height*_depth*ndelta_c*sizeof(T));\n          } else {\n            std::memcpy(buf,data(0,0,0,_spectrum + ndelta_c),-ndelta_c*_width*_height*_depth*sizeof(T));\n            std::memmove(data(0,0,0,-ndelta_c),_data,_width*_height*_depth*(_spectrum + ndelta_c)*sizeof(T));\n            std::memcpy(_data,buf,-ndelta_c*_width*_height*_depth*sizeof(T));\n          }\n          delete[] buf;\n        }\n        }\n      return *this;\n    }\n\n    //! Shift image content \\newinstance.\n    CImg<T> get_shift(const int delta_x, const int delta_y=0, const int delta_z=0, const int delta_c=0,\n                          const int boundary_conditions=0) const {\n      return (+*this).shift(delta_x,delta_y,delta_z,delta_c,boundary_conditions);\n    }\n\n    //! Permute axes order.\n    /**\n       \\param order Axes permutations, as a C-string of 4 characters.\n       This function permutes image content regarding the specified axes permutation.\n    **/\n    CImg<T>& permute_axes(const char *const order) {\n      return get_permute_axes(order).move_to(*this);\n    }\n\n    //! Permute axes order \\newinstance.\n    CImg<T> get_permute_axes(const char *const order) const {\n      const T foo = (T)0;\n      return _get_permute_axes(order,foo);\n    }\n\n    template<typename t>\n    CImg<t> _get_permute_axes(const char *const permut, const t&) const {\n      if (is_empty() || !permut) return CImg<t>(*this,false);\n      CImg<t> res;\n      const T* ptrs = _data;\n      if (!cimg::strncasecmp(permut,\"xyzc\",4)) return +*this;\n      if (!cimg::strncasecmp(permut,\"xycz\",4)) {\n        res.assign(_width,_height,_spectrum,_depth);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(x,y,c,z,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"xzyc\",4)) {\n        res.assign(_width,_depth,_height,_spectrum);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(x,z,y,c,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"xzcy\",4)) {\n        res.assign(_width,_depth,_spectrum,_height);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(x,z,c,y,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"xcyz\",4)) {\n        res.assign(_width,_spectrum,_height,_depth);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(x,c,y,z,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"xczy\",4)) {\n        res.assign(_width,_spectrum,_depth,_height);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(x,c,z,y,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"yxzc\",4)) {\n        res.assign(_height,_width,_depth,_spectrum);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(y,x,z,c,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"yxcz\",4)) {\n        res.assign(_height,_width,_spectrum,_depth);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(y,x,c,z,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"yzxc\",4)) {\n        res.assign(_height,_depth,_width,_spectrum);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(y,z,x,c,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"yzcx\",4)) {\n        res.assign(_height,_depth,_spectrum,_width);\n        switch (_width) {\n        case 1 : {\n          t *ptr_r = res.data(0,0,0,0);\n          for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) {\n            *(ptr_r++) = (t)*(ptrs++);\n          }\n        } break;\n        case 2 : {\n          t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1);\n          for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) {\n            *(ptr_r++) = (t)*(ptrs++); *(ptr_g++) = (t)*(ptrs++);\n          }\n        } break;\n        case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB\n          t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), *ptr_b = res.data(0,0,0,2);\n          for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) {\n            *(ptr_r++) = (t)*(ptrs++); *(ptr_g++) = (t)*(ptrs++); *(ptr_b++) = (t)*(ptrs++);\n          }\n        } break;\n        case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA\n          t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), *ptr_b = res.data(0,0,0,2), *ptr_a = res.data(0,0,0,3);\n          for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) {\n            *(ptr_r++) = (t)*(ptrs++); *(ptr_g++) = (t)*(ptrs++); *(ptr_b++) = (t)*(ptrs++); *(ptr_a++) = (t)*(ptrs++);\n          }\n        } break;\n        default : {\n          const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n          cimg_forXYZC(*this,x,y,z,c) res(y,z,c,x,wh,whd) = *(ptrs++);\n          return res;\n        }\n        }\n      }\n      if (!cimg::strncasecmp(permut,\"ycxz\",4)) {\n        res.assign(_height,_spectrum,_width,_depth);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(y,c,x,z,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"yczx\",4)) {\n        res.assign(_height,_spectrum,_depth,_width);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(y,c,z,x,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"zxyc\",4)) {\n        res.assign(_depth,_width,_height,_spectrum);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(z,x,y,c,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"zxcy\",4)) {\n        res.assign(_depth,_width,_spectrum,_height);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(z,x,c,y,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"zyxc\",4)) {\n        res.assign(_depth,_height,_width,_spectrum);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(z,y,x,c,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"zycx\",4)) {\n        res.assign(_depth,_height,_spectrum,_width);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(z,y,c,x,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"zcxy\",4)) {\n        res.assign(_depth,_spectrum,_width,_height);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(z,c,x,y,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"zcyx\",4)) {\n        res.assign(_depth,_spectrum,_height,_width);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(z,c,y,x,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"cxyz\",4)) {\n        res.assign(_spectrum,_width,_height,_depth);\n        switch (_spectrum) {\n        case 1 : {\n          const T *ptr_r = data(0,0,0,0);\n          t *ptrd = res._data;\n          for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) *(ptrd++) = (t)*(ptr_r++);\n        } break;\n        case 2 : {\n          const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1);\n          t *ptrd = res._data;\n          for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) {\n            *(ptrd++) = (t)*(ptr_r++); *(ptrd++) = (t)*(ptr_g++);\n          }\n        } break;\n        case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB\n          const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2);\n          t *ptrd = res._data;\n          for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) {\n            *(ptrd++) = (t)*(ptr_r++); *(ptrd++) = (t)*(ptr_g++); *(ptrd++) = (t)*(ptr_b++);\n          }\n        } break;\n        case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA\n          const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3);\n          t *ptrd = res._data;\n          for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) {\n            *(ptrd++) = (t)*(ptr_r++); *(ptrd++) = (t)*(ptr_g++); *(ptrd++) = (t)*(ptr_b++); *(ptrd++) = (t)*(ptr_a++);\n          }\n        } break;\n        default : {\n          const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n          cimg_forXYZC(*this,x,y,z,c) res(c,x,y,z,wh,whd) = (t)*(ptrs++);\n        }\n        }\n      }\n      if (!cimg::strncasecmp(permut,\"cxzy\",4)) {\n        res.assign(_spectrum,_width,_depth,_height);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(c,x,z,y,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"cyxz\",4)) {\n        res.assign(_spectrum,_height,_width,_depth);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(c,y,x,z,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"cyzx\",4)) {\n        res.assign(_spectrum,_height,_depth,_width);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(c,y,z,x,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"czxy\",4)) {\n        res.assign(_spectrum,_depth,_width,_height);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(c,z,x,y,wh,whd) = (t)*(ptrs++);\n      }\n      if (!cimg::strncasecmp(permut,\"czyx\",4)) {\n        res.assign(_spectrum,_depth,_height,_width);\n        const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth;\n        cimg_forXYZC(*this,x,y,z,c) res(c,z,y,x,wh,whd) = (t)*(ptrs++);\n      }\n      if (!res)\n        throw CImgArgumentException(_cimg_instance\n                                    \"permute_axes(): Invalid specified permutation '%s'.\",\n                                    cimg_instance,\n                                    permut);\n      return res;\n    }\n\n    //! Unroll pixel values along specified axis.\n    /**\n       \\param axis Unroll axis (can be \\c 'x', \\c 'y', \\c 'z' or c 'c').\n    **/\n    CImg<T>& unroll(const char axis) {\n      const unsigned int siz = (unsigned int)size();\n      if (siz) switch (cimg::uncase(axis)) {\n      case 'x' : _width = siz; _height = _depth = _spectrum = 1; break;\n      case 'y' : _height = siz; _width = _depth = _spectrum = 1; break;\n      case 'z' : _depth = siz; _width = _height = _spectrum = 1; break;\n      default : _spectrum = siz; _width = _height = _depth = 1;\n      }\n      return *this;\n    }\n\n    //! Unroll pixel values along specified axis \\newinstance.\n    CImg<T> get_unroll(const char axis) const {\n      return (+*this).unroll(axis);\n    }\n\n    //! Rotate image with arbitrary angle.\n    /**\n       \\param angle Rotation angle, in degrees.\n       \\param interpolation Type of interpolation. Can be <tt>{ 0=nearest | 1=linear | 2=cubic }</tt>.\n       \\param boundary Boundary conditions. Can be <tt>{  0=dirichlet | 1=neumann | 2=periodic }</tt>.\n       \\note Most of the time, size of the image is modified.\n    **/\n    CImg<T>& rotate(const float angle, const unsigned int interpolation=1,\n                    const unsigned int boundary_conditions=0) {\n      const float nangle = cimg::mod(angle,360.0f);\n      if (nangle==0.0f) return *this;\n      return get_rotate(angle,interpolation,boundary_conditions).move_to(*this);\n    }\n\n    //! Rotate image with arbitrary angle \\newinstance.\n    CImg<T> get_rotate(const float angle, const unsigned int interpolation=1,\n                       const unsigned int boundary_conditions=0) const {\n      if (is_empty()) return *this;\n      CImg<T> res;\n      const float nangle = cimg::mod(angle,360.0f);\n      if (boundary_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // Optimized version for orthogonal angles.\n        const int wm1 = width() - 1, hm1 = height() - 1;\n        const int iangle = (int)nangle/90;\n        switch (iangle) {\n        case 1 : { // 90 deg.\n          res.assign(_height,_width,_depth,_spectrum);\n          T *ptrd = res._data;\n          cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(y,hm1-x,z,c);\n        } break;\n        case 2 : { // 180 deg.\n          res.assign(_width,_height,_depth,_spectrum);\n          T *ptrd = res._data;\n          cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(wm1-x,hm1-y,z,c);\n        } break;\n        case 3 : { // 270 deg.\n          res.assign(_height,_width,_depth,_spectrum);\n          T *ptrd = res._data;\n          cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(wm1-y,x,z,c);\n        } break;\n        default : // 0 deg.\n          return *this;\n        }\n      } else { // Generic angle.\n        const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();\n        const float\n          rad = (float)(nangle*cimg::PI/180.0),\n          ca = (float)std::cos(rad),\n          sa = (float)std::sin(rad),\n          ux = cimg::abs(_width*ca), uy = cimg::abs(_width*sa),\n          vx = cimg::abs(_height*sa), vy = cimg::abs(_height*ca),\n          w2 = 0.5f*_width, h2 = 0.5f*_height,\n          dw2 = 0.5f*(ux + vx), dh2 = 0.5f*(uy + vy);\n        res.assign((int)(ux + vx),(int)(uy + vy),_depth,_spectrum);\n        switch (boundary_conditions) {\n        case 0 : { // Dirichlet boundaries.\n          switch (interpolation) {\n          case 2 : { // Cubic interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n            cimg_forXYZC(res,x,y,z,c) {\n              const Tfloat val = cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c,0);\n              res(x,y,z,c) = (T)(val<vmin?vmin:val>vmax?vmax:val);\n            }\n          } break;\n          case 1 : { // Linear interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n            cimg_forXYZC(res,x,y,z,c)\n              res(x,y,z,c) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c,0);\n          } break;\n          default : { // Nearest-neighbor interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n            cimg_forXYZC(res,x,y,z,c)\n              res(x,y,z,c) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,c,0);\n          }\n          }\n        } break;\n        case 1 : { // Neumann boundaries.\n          switch (interpolation) {\n          case 2 : { // Cubic interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n            cimg_forXYZC(res,x,y,z,c) {\n              const Tfloat val = _cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c);\n              res(x,y,z,c) = (T)(val<vmin?vmin:val>vmax?vmax:val);\n            }\n          } break;\n          case 1 : { // Linear interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n            cimg_forXYZC(res,x,y,z,c)\n              res(x,y,z,c) = (T)_linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c);\n          } break;\n          default : { // Nearest-neighbor interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n            cimg_forXYZC(res,x,y,z,c)\n              res(x,y,z,c) = _atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,c);\n          }\n          }\n        } break;\n        case 2 : { // Periodic boundaries.\n          switch (interpolation) {\n          case 2 : { // Cubic interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n            cimg_forXYZC(res,x,y,z,c) {\n              const Tfloat val = _cubic_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)width()),\n                                             cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)height()),z,c);\n              res(x,y,z,c) = (T)(val<vmin?vmin:val>vmax?vmax:val);\n            }\n          } break;\n          case 1 : { // Linear interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n            cimg_forXYZC(res,x,y,z,c)\n              res(x,y,z,c) = (T)_linear_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)width()),\n                                             cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)height()),z,c);\n          } break;\n          default : { // Nearest-neighbor interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n            cimg_forXYZC(res,x,y,z,c)\n              res(x,y,z,c) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),width()),\n                                     cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),height()),z,c);\n          }\n          }\n        } break;\n        default :\n          throw CImgArgumentException(_cimg_instance\n                                      \"rotate(): Invalid specified border conditions %d \"\n                                      \"(should be { 0=dirichlet | 1=neumann | 2=periodic }).\",\n                                      cimg_instance,\n                                      boundary_conditions);\n        }\n      }\n      return res;\n    }\n\n    //! Rotate image with arbitrary angle, around a center point.\n    /**\n       \\param angle Rotation angle, in degrees.\n       \\param cx X-coordinate of the rotation center.\n       \\param cy Y-coordinate of the rotation center.\n       \\param zoom Zoom factor.\n       \\param boundary_conditions Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann | 2=periodic }</tt>.\n       \\param interpolation_type Type of interpolation. Can be <tt>{ 0=nearest | 1=linear | 2=cubic }</tt>.\n    **/\n    CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom,\n                    const unsigned int interpolation=1, const unsigned int boundary_conditions=0) {\n      return get_rotate(angle,cx,cy,zoom,interpolation,boundary_conditions).move_to(*this);\n    }\n\n    //! Rotate image with arbitrary angle, around a center point \\newinstance.\n    CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom,\n                       const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const {\n      if (interpolation>2)\n        throw CImgArgumentException(_cimg_instance\n                                    \"rotate(): Invalid specified interpolation type %d \"\n                                    \"(should be { 0=none | 1=linear | 2=cubic }).\",\n                                    cimg_instance,\n                                    interpolation);\n      if (is_empty()) return *this;\n      CImg<T> res(_width,_height,_depth,_spectrum);\n      const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();\n      const float\n        rad = (float)((angle*cimg::PI)/180.0),\n        ca = (float)std::cos(rad)/zoom,\n        sa = (float)std::sin(rad)/zoom;\n      switch (boundary_conditions) {\n      case 0 : {\n        switch (interpolation) {\n        case 2 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n          cimg_forXYZC(res,x,y,z,c) {\n            const Tfloat val = cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c,0);\n            res(x,y,z,c) = (T)(val<vmin?vmin:val>vmax?vmax:val);\n          }\n        } break;\n        case 1 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n          cimg_forXYZC(res,x,y,z,c)\n            res(x,y,z,c) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c,0);\n        } break;\n        default : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n          cimg_forXYZC(res,x,y,z,c)\n            res(x,y,z,c) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,c,0);\n        }\n        }\n      } break;\n      case 1 : {\n        switch (interpolation) {\n        case 2 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n          cimg_forXYZC(res,x,y,z,c) {\n            const Tfloat val = _cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c);\n            res(x,y,z,c) = (T)(val<vmin?vmin:val>vmax?vmax:val);\n          }\n        } break;\n        case 1 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n          cimg_forXYZC(res,x,y,z,c)\n            res(x,y,z,c) = (T)_linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c);\n        } break;\n        default : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n          cimg_forXYZC(res,x,y,z,c)\n            res(x,y,z,c) = _atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,c);\n        }\n        }\n      } break;\n      case 2 : {\n        switch (interpolation) {\n        case 2 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n          cimg_forXYZC(res,x,y,z,c) {\n            const Tfloat val = _cubic_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)width()),\n                                           cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)height()),z,c);\n            res(x,y,z,c) = (T)(val<vmin?vmin:val>vmax?vmax:val);\n          }\n        } break;\n        case 1 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n          cimg_forXYZC(res,x,y,z,c)\n            res(x,y,z,c) = (T)_linear_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)width()),\n                                           cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)height()),z,c);\n        } break;\n        default : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=2048)\n#endif\n          cimg_forXYZC(res,x,y,z,c)\n            res(x,y,z,c) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),width()),\n                                    cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),height()),z,c);\n        }\n        }\n      } break;\n      default :\n        throw CImgArgumentException(_cimg_instance\n                                    \"rotate(): Invalid specified border conditions %d \"\n                                    \"(should be { 0=dirichlet | 1=neumann | 2=periodic }).\",\n                                    cimg_instance,\n                                    boundary_conditions);\n      }\n      return res;\n    }\n\n    //! Warp image content by a warping field.\n    /**\n       \\param warp Warping field.\n       \\param mode Can be { 0=backward-absolute | 1=backward-relative | 2=forward-absolute | 3=foward-relative }\n       \\param is_relative Tells if warping field gives absolute or relative warping coordinates.\n       \\param interpolation Can be <tt>{ 0=nearest | 1=linear | 2=cubic }</tt>.\n       \\param boundary_conditions Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann | 2=periodic }</tt>.\n    **/\n    template<typename t>\n    CImg<T>& warp(const CImg<t>& warp, const unsigned int mode=0,\n                  const unsigned int interpolation=1, const unsigned int boundary_conditions=0) {\n      return get_warp(warp,mode,interpolation,boundary_conditions).move_to(*this);\n    }\n\n    //! Warp image content by a warping field \\newinstance\n    template<typename t>\n    CImg<T> get_warp(const CImg<t>& warp, const unsigned int mode=0,\n                     const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const {\n      if (is_empty() || !warp) return *this;\n      if (mode && !is_sameXYZ(warp))\n        throw CImgArgumentException(_cimg_instance\n                                    \"warp(): Instance and specified relative warping field (%u,%u,%u,%u,%p) \"\n                                    \"have different XYZ dimensions.\",\n                                    cimg_instance,\n                                    warp._width,warp._height,warp._depth,warp._spectrum,warp._data);\n\n      CImg<T> res(warp._width,warp._height,warp._depth,_spectrum);\n\n      if (warp._spectrum==1) { // 1d warping.\n        if (mode>=3) { // Forward-relative warp.\n          res.fill(0);\n          if (interpolation>=1) // Linear interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) res.set_linear_atX(*(ptrs++),x + (float)*(ptrs0++),y,z,c);\n            }\n          else // Nearest-neighbor interpolation.\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) {\n                const int X = x + (int)*(ptrs0++);\n                if (X>=0 && X<width()) res(X,y,z,c) = *(ptrs++);\n              }\n            }\n        } else if (mode==2) { // Forward-absolute warp.\n          res.fill(0);\n          if (interpolation>=1) // Linear interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) res.set_linear_atX(*(ptrs++),(float)*(ptrs0++),y,z,c);\n            }\n          else // Nearest-neighbor interpolation.\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) {\n                const int X = (int)*(ptrs0++);\n                if (X>=0 && X<width()) res(X,y,z,c) = *(ptrs++);\n              }\n            }\n        } else if (mode==1) { // Backward-relative warp.\n          if (interpolation==2) { // Cubic interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atX(cimg::mod(x - (float)*(ptrs0++),(float)_width),y,z,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atX(x - (float)*(ptrs0++),y,z,c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)cubic_atX(x - (float)*(ptrs0++),y,z,c,0);\n              }\n          } else if (interpolation==1) { // Linear interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atX(cimg::mod(x - (float)*(ptrs0++),(float)_width),y,z,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atX(x - (float)*(ptrs0++),y,z,c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)linear_atX(x - (float)*(ptrs0++),y,z,c,0);\n              }\n          } else { // Nearest-neighbor interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod(x - (int)*(ptrs0++),(int)_width),y,z,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = _atX(x - (int)*(ptrs0++),y,z,c);\n              }\n            else // Dirichlet boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = atX(x - (int)*(ptrs0++),y,z,c,0);\n              }\n          }\n        } else { // Backward-absolute warp.\n          if (interpolation==2) { // Cubic interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atX(cimg::mod((float)*(ptrs0++),(float)_width),0,0,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atX((float)*(ptrs0++),0,0,c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)cubic_atX((float)*(ptrs0++),0,0,c,0);\n              }\n          } else if (interpolation==1) { // Linear interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atX(cimg::mod((float)*(ptrs0++),(float)_width),0,0,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atX((float)*(ptrs0++),0,0,c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)linear_atX((float)*(ptrs0++),0,0,c,0);\n              }\n          } else { // Nearest-neighbor interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width),0,0,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = _atX((int)*(ptrs0++),0,0,c);\n              }\n            else // Dirichlet boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = atX((int)*(ptrs0++),0,0,c,0);\n              }\n          }\n        }\n\n      } else if (warp._spectrum==2) { // 2d warping.\n        if (mode>=3) { // Forward-relative warp.\n          res.fill(0);\n          if (interpolation>=1) // Linear interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++),z,c);\n            }\n          else // Nearest-neighbor interpolation.\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) {\n                const int X = x + (int)*(ptrs0++), Y = y + (int)*(ptrs1++);\n                if (X>=0 && X<width() && Y>=0 && Y<height()) res(X,Y,z,c) = *(ptrs++);\n              }\n            }\n        } else if (mode==2) { // Forward-absolute warp.\n          res.fill(0);\n          if (interpolation>=1) // Linear interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),z,c);\n            }\n          else // Nearest-neighbor interpolation.\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) {\n                const int X = (int)*(ptrs0++), Y = (int)*(ptrs1++);\n                if (X>=0 && X<width() && Y>=0 && Y<height()) res(X,Y,z,c) = *(ptrs++);\n              }\n            }\n        } else if (mode==1) { // Backward-relative warp.\n          if (interpolation==2) { // Cubic interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXY(cimg::mod(x - (float)*(ptrs0++),(float)_width),\n                                                            cimg::mod(y - (float)*(ptrs1++),(float)_height),z,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)cubic_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c,0);\n              }\n          } else if (interpolation==1) { // Linear interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY(cimg::mod(x - (float)*(ptrs0++),(float)_width),\n                                                             cimg::mod(y - (float)*(ptrs1++),(float)_height),z,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)linear_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c,0);\n              }\n          } else { // Nearest-neighbor interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod(x - (int)*(ptrs0++),(int)_width),\n                                                     cimg::mod(y - (int)*(ptrs1++),(int)_height),z,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = _atXY(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z,c);\n              }\n            else // Dirichlet boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = atXY(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z,c,0);\n              }\n          }\n        } else { // Backward-absolute warp.\n          if (interpolation==2) { // Cubic interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXY(cimg::mod((float)*(ptrs0++),(float)_width),\n                                                            cimg::mod((float)*(ptrs1++),(float)_height),0,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)cubic_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c,0);\n              }\n          } else if (interpolation==1) { // Linear interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY(cimg::mod((float)*(ptrs0++),(float)_width),\n                                                             cimg::mod((float)*(ptrs1++),(float)_height),0,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)linear_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c,0);\n              }\n          } else { // Nearest-neighbor interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width),\n                                                     cimg::mod((int)*(ptrs1++),(int)_height),0,c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = _atXY((int)*(ptrs0++),(int)*(ptrs1++),0,c);\n              }\n            else // Dirichlet boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = atXY((int)*(ptrs0++),(int)*(ptrs1++),0,c,0);\n              }\n          }\n        }\n\n      } else { // 3d warping.\n        if (mode>=3) { // Forward-relative warp.\n          res.fill(0);\n          if (interpolation>=1) // Linear interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n              const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++),\n                                                    z + (float)*(ptrs2++),c);\n            }\n          else // Nearest-neighbor interpolation.\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n              const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) {\n                const int X = x + (int)*(ptrs0++), Y = y + (int)*(ptrs1++), Z = z + (int)*(ptrs2++);\n                if (X>=0 && X<width() && Y>=0 && Y<height() && Z>=0 && Z<depth()) res(X,Y,Z,c) = *(ptrs++);\n              }\n            }\n        } else if (mode==2) { // Forward-absolute warp.\n          res.fill(0);\n          if (interpolation>=1) // Linear interpolation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n              const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c);\n            }\n          else // Nearest-neighbor interpolation.\n            cimg_forYZC(res,y,z,c) {\n              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n              const T *ptrs = data(0,y,z,c);\n              cimg_forX(res,x) {\n                const int X = (int)*(ptrs0++), Y = (int)*(ptrs1++), Z = (int)*(ptrs2++);\n                if (X>=0 && X<width() && Y>=0 && Y<height() && Z>=0 && Z<depth()) res(X,Y,Z,c) = *(ptrs++);\n              }\n            }\n        } else if (mode==1) { // Backward-relative warp.\n          if (interpolation==2) { // Cubic interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXYZ(cimg::mod(x - (float)*(ptrs0++),(float)_width),\n                                                             cimg::mod(y - (float)*(ptrs1++),(float)_height),\n                                                             cimg::mod(z - (float)*(ptrs2++),(float)_depth),c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x)\n                  *(ptrd++) = (T)_cubic_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x)\n                  *(ptrd++) = (T)cubic_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c,0);\n              }\n          } else if (interpolation==1) { // Linear interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ(cimg::mod(x - (float)*(ptrs0++),(float)_width),\n                                                              cimg::mod(y - (float)*(ptrs1++),(float)_height),\n                                                              cimg::mod(z - (float)*(ptrs2++),(float)_depth),c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x)\n                  *(ptrd++) = (T)_linear_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x)\n                  *(ptrd++) = (T)linear_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c,0);\n              }\n          } else { // Nearest neighbor interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod(x - (int)*(ptrs0++),(int)_width),\n                                                     cimg::mod(y - (int)*(ptrs1++),(int)_height),\n                                                     cimg::mod(z - (int)*(ptrs2++),(int)_depth),c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = _atXYZ(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z - (int)*(ptrs2++),c);\n              }\n            else // Dirichlet boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = atXYZ(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z - (int)*(ptrs2++),c,0);\n              }\n          }\n        } else { // Backward-absolute warp.\n          if (interpolation==2) { // Cubic interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXYZ(cimg::mod((float)*(ptrs0++),(float)_width),\n                                                             cimg::mod((float)*(ptrs1++),(float)_height),\n                                                             cimg::mod((float)*(ptrs2++),(float)_depth),c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=4096)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)cubic_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c,0);\n              }\n          } else if (interpolation==1) { // Linear interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ(cimg::mod((float)*(ptrs0++),(float)_width),\n                                                              cimg::mod((float)*(ptrs1++),(float)_height),\n                                                              cimg::mod((float)*(ptrs2++),(float)_depth),c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c);\n              }\n            else // Dirichlet boundaries.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (res.size()>=1048576)\n#endif\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (T)linear_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c,0);\n              }\n          } else { // Nearest-neighbor interpolation.\n            if (boundary_conditions==2) // Periodic boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width),\n                                                     cimg::mod((int)*(ptrs1++),(int)_height),\n                                                     cimg::mod((int)*(ptrs2++),(int)_depth),c);\n              }\n            else if (boundary_conditions==1) // Neumann boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = _atXYZ((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),c);\n              }\n            else // Dirichlet boundaries.\n              cimg_forYZC(res,y,z,c) {\n                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);\n                T *ptrd = res.data(0,y,z,c);\n                cimg_forX(res,x) *(ptrd++) = atXYZ((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),c,0);\n              }\n          }\n        }\n      }\n      return res;\n    }\n\n    //! Generate a 2d representation of a 3d image, with XY,XZ and YZ views.\n    /**\n       \\param x0 X-coordinate of the projection point.\n       \\param y0 Y-coordinate of the projection point.\n       \\param z0 Z-coordinate of the projection point.\n    **/\n    CImg<T> get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0) const {\n      if (is_empty() || _depth<2) return +*this;\n      const unsigned int\n        _x0 = (x0>=_width)?_width - 1:x0,\n        _y0 = (y0>=_height)?_height - 1:y0,\n        _z0 = (z0>=_depth)?_depth - 1:z0;\n      const CImg<T>\n        img_xy = get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1),\n        img_zy = get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1).permute_axes(\"xzyc\").\n        resize(_depth,_height,1,-100,-1),\n        img_xz = get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1).resize(_width,_depth,1,-100,-1);\n      return CImg<T>(_width + _depth,_height + _depth,1,_spectrum,cimg::min(img_xy.min(),img_zy.min(),img_xz.min())).\n        draw_image(0,0,img_xy).draw_image(img_xy._width,0,img_zy).\n        draw_image(0,img_xy._height,img_xz);\n    }\n\n    //! Construct a 2d representation of a 3d image, with XY,XZ and YZ views \\inplace.\n    CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0) {\n      if (_depth<2) return *this;\n      return get_projections2d(x0,y0,z0).move_to(*this);\n    }\n\n    //! Crop image region.\n    /**\n       \\param x0 = X-coordinate of the upper-left crop rectangle corner.\n       \\param y0 = Y-coordinate of the upper-left crop rectangle corner.\n       \\param z0 = Z-coordinate of the upper-left crop rectangle corner.\n       \\param c0 = C-coordinate of the upper-left crop rectangle corner.\n       \\param x1 = X-coordinate of the lower-right crop rectangle corner.\n       \\param y1 = Y-coordinate of the lower-right crop rectangle corner.\n       \\param z1 = Z-coordinate of the lower-right crop rectangle corner.\n       \\param c1 = C-coordinate of the lower-right crop rectangle corner.\n       \\param boundary_conditions = Dirichlet (false) or Neumann border conditions.\n    **/\n    CImg<T>& crop(const int x0, const int y0, const int z0, const int c0,\n                  const int x1, const int y1, const int z1, const int c1,\n                  const bool boundary_conditions=false) {\n      return get_crop(x0,y0,z0,c0,x1,y1,z1,c1,boundary_conditions).move_to(*this);\n    }\n\n    //! Crop image region \\newinstance.\n    CImg<T> get_crop(const int x0, const int y0, const int z0, const int c0,\n                     const int x1, const int y1, const int z1, const int c1,\n                     const bool boundary_conditions=false) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"crop(): Empty instance.\",\n                                    cimg_instance);\n      const int\n        nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,\n        ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,\n        nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,\n        nc0 = c0<c1?c0:c1, nc1 = c0^c1^nc0;\n      CImg<T> res(1U + nx1 - nx0,1U + ny1 - ny0,1U + nz1 - nz0,1U + nc1 - nc0);\n      if (nx0<0 || nx1>=width() || ny0<0 || ny1>=height() || nz0<0 || nz1>=depth() || nc0<0 || nc1>=spectrum()) {\n        if (boundary_conditions) cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = _atXYZC(nx0 + x,ny0 + y,nz0 + z,nc0 + c);\n        else res.fill(0).draw_image(-nx0,-ny0,-nz0,-nc0,*this);\n      } else res.draw_image(-nx0,-ny0,-nz0,-nc0,*this);\n      return res;\n    }\n\n    //! Crop image region \\overloading.\n    CImg<T>& crop(const int x0, const int y0, const int z0,\n                  const int x1, const int y1, const int z1,\n                  const bool boundary_conditions=false) {\n      return crop(x0,y0,z0,0,x1,y1,z1,_spectrum - 1,boundary_conditions);\n    }\n\n    //! Crop image region \\newinstance.\n    CImg<T> get_crop(const int x0, const int y0, const int z0,\n                     const int x1, const int y1, const int z1,\n                     const bool boundary_conditions=false) const {\n      return get_crop(x0,y0,z0,0,x1,y1,z1,_spectrum - 1,boundary_conditions);\n    }\n\n    //! Crop image region \\overloading.\n    CImg<T>& crop(const int x0, const int y0,\n                  const int x1, const int y1,\n                  const bool boundary_conditions=false) {\n      return crop(x0,y0,0,0,x1,y1,_depth - 1,_spectrum - 1,boundary_conditions);\n    }\n\n    //! Crop image region \\newinstance.\n    CImg<T> get_crop(const int x0, const int y0,\n                     const int x1, const int y1,\n                     const bool boundary_conditions=false) const {\n      return get_crop(x0,y0,0,0,x1,y1,_depth - 1,_spectrum - 1,boundary_conditions);\n    }\n\n    //! Crop image region \\overloading.\n    CImg<T>& crop(const int x0, const int x1, const bool boundary_conditions=false) {\n      return crop(x0,0,0,0,x1,_height - 1,_depth - 1,_spectrum - 1,boundary_conditions);\n    }\n\n    //! Crop image region \\newinstance.\n    CImg<T> get_crop(const int x0, const int x1, const bool boundary_conditions=false) const {\n      return get_crop(x0,0,0,0,x1,_height - 1,_depth - 1,_spectrum - 1,boundary_conditions);\n    }\n\n    //! Autocrop image region, regarding the specified background value.\n    CImg<T>& autocrop(const T& value, const char *const axes=\"czyx\") {\n      if (is_empty()) return *this;\n      for (const char *s = axes; *s; ++s) {\n        const char axis = cimg::uncase(*s);\n        const CImg<intT> coords = _autocrop(value,axis);\n        if (coords[0]==-1 && coords[1]==-1) return assign(); // Image has only 'value' pixels.\n        else switch (axis) {\n        case 'x' : {\n          const int x0 = coords[0], x1 = coords[1];\n          if (x0>=0 && x1>=0) crop(x0,x1);\n        } break;\n        case 'y' : {\n          const int y0 = coords[0], y1 = coords[1];\n          if (y0>=0 && y1>=0) crop(0,y0,_width - 1,y1);\n        } break;\n        case 'z' : {\n          const int z0 = coords[0], z1 = coords[1];\n          if (z0>=0 && z1>=0) crop(0,0,z0,_width - 1,_height - 1,z1);\n        } break;\n        default : {\n          const int c0 = coords[0], c1 = coords[1];\n          if (c0>=0 && c1>=0) crop(0,0,0,c0,_width - 1,_height - 1,_depth - 1,c1);\n        }\n        }\n      }\n      return *this;\n    }\n\n    //! Autocrop image region, regarding the specified background value \\newinstance.\n    CImg<T> get_autocrop(const T& value, const char *const axes=\"czyx\") const {\n      return (+*this).autocrop(value,axes);\n    }\n\n    //! Autocrop image region, regarding the specified background color.\n    /**\n       \\param color Color used for the crop. If \\c 0, color is guessed.\n       \\param axes Axes used for the crop.\n    **/\n    CImg<T>& autocrop(const T *const color=0, const char *const axes=\"zyx\") {\n      if (is_empty()) return *this;\n      if (!color) { // Guess color.\n        const CImg<T> col1 = get_vector_at(0,0,0);\n        const unsigned int w = _width, h = _height, d = _depth, s = _spectrum;\n        autocrop(col1,axes);\n        if (_width==w && _height==h && _depth==d && _spectrum==s) {\n          const CImg<T> col2 = get_vector_at(w - 1,h - 1,d - 1);\n          autocrop(col2,axes);\n        }\n        return *this;\n      }\n      for (const char *s = axes; *s; ++s) {\n        const char axis = cimg::uncase(*s);\n        switch (axis) {\n        case 'x' : {\n          int x0 = width(), x1 = -1;\n          cimg_forC(*this,c) {\n            const CImg<intT> coords = get_shared_channel(c)._autocrop(color[c],'x');\n            const int nx0 = coords[0], nx1 = coords[1];\n            if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); }\n          }\n          if (x0==width() && x1==-1) return assign(); else crop(x0,x1);\n        } break;\n        case 'y' : {\n          int y0 = height(), y1 = -1;\n          cimg_forC(*this,c) {\n            const CImg<intT> coords = get_shared_channel(c)._autocrop(color[c],'y');\n            const int ny0 = coords[0], ny1 = coords[1];\n            if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); }\n          }\n          if (y0==height() && y1==-1) return assign(); else crop(0,y0,_width - 1,y1);\n        } break;\n        default : {\n          int z0 = depth(), z1 = -1;\n          cimg_forC(*this,c) {\n            const CImg<intT> coords = get_shared_channel(c)._autocrop(color[c],'z');\n            const int nz0 = coords[0], nz1 = coords[1];\n            if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); }\n          }\n          if (z0==depth() && z1==-1) return assign(); else crop(0,0,z0,_width - 1,_height - 1,z1);\n        }\n        }\n      }\n      return *this;\n    }\n\n    //! Autocrop image region, regarding the specified background color \\newinstance.\n    CImg<T> get_autocrop(const T *const color=0, const char *const axes=\"zyx\") const {\n      return (+*this).autocrop(color,axes);\n    }\n\n    //! Autocrop image region, regarding the specified background color \\overloading.\n    template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char *const axes=\"zyx\") {\n      return get_autocrop(color,axes).move_to(*this);\n    }\n\n    //! Autocrop image region, regarding the specified background color \\newinstance.\n    template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char *const axes=\"zyx\") const {\n      return get_autocrop(color._data,axes);\n    }\n\n    CImg<intT> _autocrop(const T& value, const char axis) const {\n      CImg<intT> res;\n      switch (cimg::uncase(axis)) {\n      case 'x' : {\n        int x0 = -1, x1 = -1;\n        cimg_forX(*this,x) cimg_forYZC(*this,y,z,c)\n          if ((*this)(x,y,z,c)!=value) { x0 = x; x = width(); y = height(); z = depth(); c = spectrum(); }\n        if (x0>=0) {\n          for (int x = width() - 1; x>=0; --x) cimg_forYZC(*this,y,z,c)\n            if ((*this)(x,y,z,c)!=value) { x1 = x; x = 0; y = height(); z = depth(); c = spectrum(); }\n        }\n        res = CImg<intT>::vector(x0,x1);\n      } break;\n      case 'y' : {\n        int y0 = -1, y1 = -1;\n        cimg_forY(*this,y) cimg_forXZC(*this,x,z,c)\n          if ((*this)(x,y,z,c)!=value) { y0 = y; x = width(); y = height(); z = depth(); c = spectrum(); }\n        if (y0>=0) {\n          for (int y = height() - 1; y>=0; --y) cimg_forXZC(*this,x,z,c)\n            if ((*this)(x,y,z,c)!=value) { y1 = y; x = width(); y = 0; z = depth(); c = spectrum(); }\n        }\n        res = CImg<intT>::vector(y0,y1);\n      } break;\n      case 'z' : {\n        int z0 = -1, z1 = -1;\n        cimg_forZ(*this,z) cimg_forXYC(*this,x,y,c)\n          if ((*this)(x,y,z,c)!=value) { z0 = z; x = width(); y = height(); z = depth(); c = spectrum(); }\n        if (z0>=0) {\n          for (int z = depth() - 1; z>=0; --z) cimg_forXYC(*this,x,y,c)\n            if ((*this)(x,y,z,c)!=value) { z1 = z; x = width(); y = height(); z = 0; c = spectrum(); }\n        }\n        res = CImg<intT>::vector(z0,z1);\n      } break;\n      default : {\n        int c0 = -1, c1 = -1;\n        cimg_forC(*this,c) cimg_forXYZ(*this,x,y,z)\n          if ((*this)(x,y,z,c)!=value) { c0 = c; x = width(); y = height(); z = depth(); c = spectrum(); }\n        if (c0>=0) {\n          for (int c = spectrum() - 1; c>=0; --c) cimg_forXYZ(*this,x,y,z)\n            if ((*this)(x,y,z,c)!=value) { c1 = c; x = width(); y = height(); z = depth(); c = 0; }\n        }\n        res = CImg<intT>::vector(c0,c1);\n      }\n      }\n      return res;\n    }\n\n    //! Return specified image column.\n    /**\n       \\param x0 Image column.\n    **/\n    CImg<T> get_column(const int x0) const {\n      return get_columns(x0,x0);\n    }\n\n    //! Return specified image column \\inplace.\n    CImg<T>& column(const int x0) {\n      return columns(x0,x0);\n    }\n\n    //! Return specified range of image columns.\n    /**\n       \\param x0 Starting image column.\n       \\param x1 Ending image column.\n    **/\n    CImg<T>& columns(const int x0, const int x1) {\n      return get_columns(x0,x1).move_to(*this);\n    }\n\n    //! Return specified range of image columns \\inplace.\n    CImg<T> get_columns(const int x0, const int x1) const {\n      return get_crop(x0,0,0,0,x1,height() - 1,depth() - 1,spectrum() - 1);\n    }\n\n    //! Return specified image row.\n    CImg<T> get_row(const int y0) const {\n      return get_rows(y0,y0);\n    }\n\n    //! Return specified image row \\inplace.\n    /**\n       \\param y0 Image row.\n    **/\n    CImg<T>& row(const int y0) {\n      return rows(y0,y0);\n    }\n\n    //! Return specified range of image rows.\n    /**\n       \\param y0 Starting image row.\n       \\param y1 Ending image row.\n    **/\n    CImg<T> get_rows(const int y0, const int y1) const {\n      return get_crop(0,y0,0,0,width() - 1,y1,depth() - 1,spectrum() - 1);\n    }\n\n    //! Return specified range of image rows \\inplace.\n    CImg<T>& rows(const int y0, const int y1) {\n      return get_rows(y0,y1).move_to(*this);\n    }\n\n    //! Return specified image slice.\n    /**\n       \\param z0 Image slice.\n    **/\n    CImg<T> get_slice(const int z0) const {\n      return get_slices(z0,z0);\n    }\n\n    //! Return specified image slice \\inplace.\n    CImg<T>& slice(const int z0) {\n      return slices(z0,z0);\n    }\n\n    //! Return specified range of image slices.\n    /**\n       \\param z0 Starting image slice.\n       \\param z1 Ending image slice.\n    **/\n    CImg<T> get_slices(const int z0, const int z1) const {\n      return get_crop(0,0,z0,0,width() - 1,height() - 1,z1,spectrum() - 1);\n    }\n\n    //! Return specified range of image slices \\inplace.\n    CImg<T>& slices(const int z0, const int z1) {\n      return get_slices(z0,z1).move_to(*this);\n    }\n\n    //! Return specified image channel.\n    /**\n       \\param c0 Image channel.\n    **/\n    CImg<T> get_channel(const int c0) const {\n      return get_channels(c0,c0);\n    }\n\n    //! Return specified image channel \\inplace.\n    CImg<T>& channel(const int c0) {\n      return channels(c0,c0);\n    }\n\n    //! Return specified range of image channels.\n    /**\n       \\param c0 Starting image channel.\n       \\param c1 Ending image channel.\n    **/\n    CImg<T> get_channels(const int c0, const int c1) const {\n      return get_crop(0,0,0,c0,width() - 1,height() - 1,depth() - 1,c1);\n    }\n\n    //! Return specified range of image channels \\inplace.\n    CImg<T>& channels(const int c0, const int c1) {\n      return get_channels(c0,c1).move_to(*this);\n    }\n\n    //! Return stream line of a 2d or 3d vector field.\n    CImg<floatT> get_streamline(const float x, const float y, const float z,\n                                const float L=256, const float dl=0.1f,\n                                const unsigned int interpolation_type=2, const bool is_backward_tracking=false,\n                                const bool is_oriented_only=false) const {\n      if (_spectrum!=2 && _spectrum!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"streamline(): Instance is not a 2d or 3d vector field.\",\n                                    cimg_instance);\n      if (_spectrum==2) {\n        if (is_oriented_only) {\n          typename CImg<T>::_functor4d_streamline2d_oriented func(*this);\n          return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true,\n                            0,0,0,_width - 1.0f,_height - 1.0f,0.0f);\n        } else {\n          typename CImg<T>::_functor4d_streamline2d_directed func(*this);\n          return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false,\n                            0,0,0,_width - 1.0f,_height - 1.0f,0.0f);\n        }\n      }\n      if (is_oriented_only) {\n        typename CImg<T>::_functor4d_streamline3d_oriented func(*this);\n        return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true,\n                          0,0,0,_width - 1.0f,_height - 1.0f,_depth - 1.0f);\n      }\n      typename CImg<T>::_functor4d_streamline3d_directed func(*this);\n      return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false,\n                        0,0,0,_width - 1.0f,_height - 1.0f,_depth - 1.0f);\n    }\n\n    //! Return stream line of a 3d vector field.\n    /**\n       \\param func Vector field function.\n       \\param x X-coordinate of the starting point of the streamline.\n       \\param y Y-coordinate of the starting point of the streamline.\n       \\param z Z-coordinate of the starting point of the streamline.\n       \\param L Streamline length.\n       \\param dl Streamline length increment.\n       \\param interpolation_type Type of interpolation.\n         Can be <tt>{ 0=nearest int | 1=linear | 2=2nd-order RK | 3=4th-order RK. }</tt>.\n       \\param is_backward_tracking Tells if the streamline is estimated forward or backward.\n       \\param is_oriented_only Tells if the direction of the vectors must be ignored.\n       \\param x0 X-coordinate of the first bounding-box vertex.\n       \\param y0 Y-coordinate of the first bounding-box vertex.\n       \\param z0 Z-coordinate of the first bounding-box vertex.\n       \\param x1 X-coordinate of the second bounding-box vertex.\n       \\param y1 Y-coordinate of the second bounding-box vertex.\n       \\param z1 Z-coordinate of the second bounding-box vertex.\n    **/\n    template<typename tfunc>\n    static CImg<floatT> streamline(const tfunc& func,\n                                   const float x, const float y, const float z,\n                                   const float L=256, const float dl=0.1f,\n                                   const unsigned int interpolation_type=2, const bool is_backward_tracking=false,\n                                   const bool is_oriented_only=false,\n                                   const float x0=0, const float y0=0, const float z0=0,\n                                   const float x1=0, const float y1=0, const float z1=0) {\n      if (dl<=0)\n        throw CImgArgumentException(\"CImg<%s>::streamline(): Invalid specified integration length %g \"\n                                    \"(should be >0).\",\n                                    pixel_type(),\n                                    dl);\n\n      const bool is_bounded = (x0!=x1 || y0!=y1 || z0!=z1);\n      if (L<=0 || (is_bounded && (x<x0 || x>x1 || y<y0 || y>y1 || z<z0 || z>z1))) return CImg<floatT>();\n      const unsigned int size_L = (unsigned int)cimg::round(L/dl + 1);\n      CImg<floatT> coordinates(size_L,3);\n      const float dl2 = dl/2;\n      float\n        *ptr_x = coordinates.data(0,0),\n        *ptr_y = coordinates.data(0,1),\n        *ptr_z = coordinates.data(0,2),\n        pu = (float)(dl*func(x,y,z,0)),\n        pv = (float)(dl*func(x,y,z,1)),\n        pw = (float)(dl*func(x,y,z,2)),\n        X = x, Y = y, Z = z;\n\n      switch (interpolation_type) {\n      case 0 : { // Nearest integer interpolation.\n        cimg_forX(coordinates,l) {\n          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;\n          const int\n            xi = (int)(X>0?X + 0.5f:X - 0.5f),\n            yi = (int)(Y>0?Y + 0.5f:Y - 0.5f),\n            zi = (int)(Z>0?Z + 0.5f:Z - 0.5f);\n          float\n            u = (float)(dl*func((float)xi,(float)yi,(float)zi,0)),\n            v = (float)(dl*func((float)xi,(float)yi,(float)zi,1)),\n            w = (float)(dl*func((float)xi,(float)yi,(float)zi,2));\n          if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }\n          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }\n          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;\n        }\n      } break;\n      case 1 : { // First-order interpolation.\n        cimg_forX(coordinates,l) {\n          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;\n          float\n            u = (float)(dl*func(X,Y,Z,0)),\n            v = (float)(dl*func(X,Y,Z,1)),\n            w = (float)(dl*func(X,Y,Z,2));\n          if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }\n          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }\n          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;\n        }\n      } break;\n      case 2 : { // Second order interpolation.\n        cimg_forX(coordinates,l) {\n          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;\n          float\n            u0 = (float)(dl2*func(X,Y,Z,0)),\n            v0 = (float)(dl2*func(X,Y,Z,1)),\n            w0 = (float)(dl2*func(X,Y,Z,2));\n          if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; }\n          float\n            u = (float)(dl*func(X + u0,Y + v0,Z + w0,0)),\n            v = (float)(dl*func(X + u0,Y + v0,Z + w0,1)),\n            w = (float)(dl*func(X + u0,Y + v0,Z + w0,2));\n          if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }\n          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }\n          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;\n        }\n      } break;\n      default : { // Fourth order interpolation.\n        cimg_forX(coordinates,x) {\n          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;\n          float\n            u0 = (float)(dl2*func(X,Y,Z,0)),\n            v0 = (float)(dl2*func(X,Y,Z,1)),\n            w0 = (float)(dl2*func(X,Y,Z,2));\n          if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; }\n          float\n            u1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,0)),\n            v1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,1)),\n            w1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,2));\n          if (is_oriented_only && u1*pu + v1*pv + w1*pw<0) { u1 = -u1; v1 = -v1; w1 = -w1; }\n          float\n            u2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,0)),\n            v2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,1)),\n            w2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,2));\n          if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u2 = -u2; v2 = -v2; w2 = -w2; }\n          float\n            u3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,0)),\n            v3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,1)),\n            w3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,2));\n          if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u3 = -u3; v3 = -v3; w3 = -w3; }\n          const float\n            u = (u0 + u3)/3 + (u1 + u2)/1.5f,\n            v = (v0 + v3)/3 + (v1 + v2)/1.5f,\n            w = (w0 + w3)/3 + (w1 + w2)/1.5f;\n          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }\n          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;\n        }\n      }\n      }\n      if (ptr_x!=coordinates.data(0,1)) coordinates.resize((int)(ptr_x-coordinates.data()),3,1,1,0);\n      return coordinates;\n    }\n\n    //! Return stream line of a 3d vector field \\overloading.\n    static CImg<floatT> streamline(const char *const expression,\n                                   const float x, const float y, const float z,\n                                   const float L=256, const float dl=0.1f,\n                                   const unsigned int interpolation_type=2, const bool is_backward_tracking=true,\n                                   const bool is_oriented_only=false,\n                                   const float x0=0, const float y0=0, const float z0=0,\n                                   const float x1=0, const float y1=0, const float z1=0) {\n      _functor4d_streamline_expr func(expression);\n      return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,is_oriented_only,x0,y0,z0,x1,y1,z1);\n    }\n\n    struct _functor4d_streamline2d_directed {\n      const CImg<T>& ref;\n      _functor4d_streamline2d_directed(const CImg<T>& pref):ref(pref) {}\n      float operator()(const float x, const float y, const float z, const unsigned int c) const {\n        return c<2?(float)ref._linear_atXY(x,y,(int)z,c):0;\n      }\n    };\n\n    struct _functor4d_streamline3d_directed {\n      const CImg<T>& ref;\n      _functor4d_streamline3d_directed(const CImg<T>& pref):ref(pref) {}\n      float operator()(const float x, const float y, const float z, const unsigned int c) const {\n        return (float)ref._linear_atXYZ(x,y,z,c);\n      }\n    };\n\n    struct _functor4d_streamline2d_oriented {\n      const CImg<T>& ref;\n      CImg<floatT> *pI;\n      _functor4d_streamline2d_oriented(const CImg<T>& pref):ref(pref),pI(0) { pI = new CImg<floatT>(2,2,1,2); }\n      ~_functor4d_streamline2d_oriented() { delete pI; }\n      float operator()(const float x, const float y, const float z, const unsigned int c) const {\n#define _cimg_vecalign2d(i,j) \\\n        if (I(i,j,0)*I(0,0,0) + I(i,j,1)*I(0,0,1)<0) { I(i,j,0) = -I(i,j,0); I(i,j,1) = -I(i,j,1); }\n        int\n          xi = (int)x - (x>=0?0:1), nxi = xi + 1,\n          yi = (int)y - (y>=0?0:1), nyi = yi + 1,\n          zi = (int)z;\n        const float\n          dx = x - xi,\n          dy = y - yi;\n        if (c==0) {\n          CImg<floatT>& I = *pI;\n          if (xi<0) xi = 0; if (nxi<0) nxi = 0;\n          if (xi>=ref.width()) xi = ref.width() - 1; if (nxi>=ref.width()) nxi = ref.width() - 1;\n          if (yi<0) yi = 0; if (nyi<0) nyi = 0;\n          if (yi>=ref.height()) yi = ref.height() - 1; if (nyi>=ref.height()) nyi = ref.height() - 1;\n          I(0,0,0) = (float)ref(xi,yi,zi,0);   I(0,0,1) = (float)ref(xi,yi,zi,1);\n          I(1,0,0) = (float)ref(nxi,yi,zi,0);  I(1,0,1) = (float)ref(nxi,yi,zi,1);\n          I(1,1,0) = (float)ref(nxi,nyi,zi,0); I(1,1,1) = (float)ref(nxi,nyi,zi,1);\n          I(0,1,0) = (float)ref(xi,nyi,zi,0);  I(0,1,1) = (float)ref(xi,nyi,zi,1);\n          _cimg_vecalign2d(1,0); _cimg_vecalign2d(1,1); _cimg_vecalign2d(0,1);\n        }\n        return c<2?(float)pI->_linear_atXY(dx,dy,0,c):0;\n      }\n    };\n\n    struct _functor4d_streamline3d_oriented {\n      const CImg<T>& ref;\n      CImg<floatT> *pI;\n      _functor4d_streamline3d_oriented(const CImg<T>& pref):ref(pref),pI(0) { pI = new CImg<floatT>(2,2,2,3); }\n      ~_functor4d_streamline3d_oriented() { delete pI; }\n      float operator()(const float x, const float y, const float z, const unsigned int c) const {\n#define _cimg_vecalign3d(i,j,k) if (I(i,j,k,0)*I(0,0,0,0) + I(i,j,k,1)*I(0,0,0,1) + I(i,j,k,2)*I(0,0,0,2)<0) { \\\n  I(i,j,k,0) = -I(i,j,k,0); I(i,j,k,1) = -I(i,j,k,1); I(i,j,k,2) = -I(i,j,k,2); }\n        int\n          xi = (int)x - (x>=0?0:1), nxi = xi + 1,\n          yi = (int)y - (y>=0?0:1), nyi = yi + 1,\n          zi = (int)z - (z>=0?0:1), nzi = zi + 1;\n        const float\n          dx = x - xi,\n          dy = y - yi,\n          dz = z - zi;\n        if (c==0) {\n          CImg<floatT>& I = *pI;\n          if (xi<0) xi = 0; if (nxi<0) nxi = 0;\n          if (xi>=ref.width()) xi = ref.width() - 1; if (nxi>=ref.width()) nxi = ref.width() - 1;\n          if (yi<0) yi = 0; if (nyi<0) nyi = 0;\n          if (yi>=ref.height()) yi = ref.height() - 1; if (nyi>=ref.height()) nyi = ref.height() - 1;\n          if (zi<0) zi = 0; if (nzi<0) nzi = 0;\n          if (zi>=ref.depth()) zi = ref.depth() - 1; if (nzi>=ref.depth()) nzi = ref.depth() - 1;\n          I(0,0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,0,1) = (float)ref(xi,yi,zi,1);\n          I(0,0,0,2) = (float)ref(xi,yi,zi,2); I(1,0,0,0) = (float)ref(nxi,yi,zi,0);\n          I(1,0,0,1) = (float)ref(nxi,yi,zi,1); I(1,0,0,2) = (float)ref(nxi,yi,zi,2);\n          I(1,1,0,0) = (float)ref(nxi,nyi,zi,0); I(1,1,0,1) = (float)ref(nxi,nyi,zi,1);\n          I(1,1,0,2) = (float)ref(nxi,nyi,zi,2); I(0,1,0,0) = (float)ref(xi,nyi,zi,0);\n          I(0,1,0,1) = (float)ref(xi,nyi,zi,1); I(0,1,0,2) = (float)ref(xi,nyi,zi,2);\n          I(0,0,1,0) = (float)ref(xi,yi,nzi,0); I(0,0,1,1) = (float)ref(xi,yi,nzi,1);\n          I(0,0,1,2) = (float)ref(xi,yi,nzi,2); I(1,0,1,0) = (float)ref(nxi,yi,nzi,0);\n          I(1,0,1,1) = (float)ref(nxi,yi,nzi,1);  I(1,0,1,2) = (float)ref(nxi,yi,nzi,2);\n          I(1,1,1,0) = (float)ref(nxi,nyi,nzi,0); I(1,1,1,1) = (float)ref(nxi,nyi,nzi,1);\n          I(1,1,1,2) = (float)ref(nxi,nyi,nzi,2); I(0,1,1,0) = (float)ref(xi,nyi,nzi,0);\n          I(0,1,1,1) = (float)ref(xi,nyi,nzi,1);  I(0,1,1,2) = (float)ref(xi,nyi,nzi,2);\n          _cimg_vecalign3d(1,0,0); _cimg_vecalign3d(1,1,0); _cimg_vecalign3d(0,1,0);\n          _cimg_vecalign3d(0,0,1); _cimg_vecalign3d(1,0,1); _cimg_vecalign3d(1,1,1); _cimg_vecalign3d(0,1,1);\n        }\n        return (float)pI->_linear_atXYZ(dx,dy,dz,c);\n      }\n    };\n\n    struct _functor4d_streamline_expr {\n      _cimg_math_parser *mp;\n      ~_functor4d_streamline_expr() { delete mp; }\n      _functor4d_streamline_expr(const char *const expr):mp(0) {\n        mp = new _cimg_math_parser(expr,\"streamline\",CImg<T>::const_empty(),0);\n      }\n      float operator()(const float x, const float y, const float z, const unsigned int c) const {\n        return (float)(*mp)(x,y,z,c);\n      }\n    };\n\n    //! Return a shared-memory image referencing a range of pixels of the image instance.\n    /**\n       \\param x0 X-coordinate of the starting pixel.\n       \\param x1 X-coordinate of the ending pixel.\n       \\param y0 Y-coordinate.\n       \\param z0 Z-coordinate.\n       \\param c0 C-coordinate.\n     **/\n    CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,\n                              const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) {\n      const unsigned int\n        beg = (unsigned int)offset(x0,y0,z0,c0),\n        end = (unsigned int)offset(x1,y0,z0,c0);\n      if (beg>end || beg>=size() || end>=size())\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_shared_points(): Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).\",\n                                    cimg_instance,\n                                    x0,x1,y0,z0,c0);\n\n      return CImg<T>(_data + beg,x1 - x0 + 1,1,1,1,true);\n    }\n\n    //! Return a shared-memory image referencing a range of pixels of the image instance \\const.\n    const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,\n                                    const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) const {\n      const unsigned int\n        beg = (unsigned int)offset(x0,y0,z0,c0),\n        end = (unsigned int)offset(x1,y0,z0,c0);\n      if (beg>end || beg>=size() || end>=size())\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_shared_points(): Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).\",\n                                    cimg_instance,\n                                    x0,x1,y0,z0,c0);\n\n      return CImg<T>(_data + beg,x1 - x0 + 1,1,1,1,true);\n    }\n\n    //! Return a shared-memory image referencing a range of rows of the image instance.\n    /**\n       \\param y0 Y-coordinate of the starting row.\n       \\param y1 Y-coordinate of the ending row.\n       \\param z0 Z-coordinate.\n       \\param c0 C-coordinate.\n    **/\n    CImg<T> get_shared_rows(const unsigned int y0, const unsigned int y1,\n                             const unsigned int z0=0, const unsigned int c0=0) {\n      const unsigned int\n        beg = (unsigned int)offset(0,y0,z0,c0),\n        end = (unsigned int)offset(0,y1,z0,c0);\n      if (beg>end || beg>=size() || end>=size())\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_shared_rows(): Invalid request of a shared-memory subset \"\n                                    \"(0->%u,%u->%u,%u,%u).\",\n                                    cimg_instance,\n                                    _width - 1,y0,y1,z0,c0);\n\n      return CImg<T>(_data + beg,_width,y1 - y0 + 1,1,1,true);\n    }\n\n    //! Return a shared-memory image referencing a range of rows of the image instance \\const.\n    const CImg<T> get_shared_rows(const unsigned int y0, const unsigned int y1,\n                                   const unsigned int z0=0, const unsigned int c0=0) const {\n      const unsigned int\n        beg = (unsigned int)offset(0,y0,z0,c0),\n        end = (unsigned int)offset(0,y1,z0,c0);\n      if (beg>end || beg>=size() || end>=size())\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_shared_rows(): Invalid request of a shared-memory subset \"\n                                    \"(0->%u,%u->%u,%u,%u).\",\n                                    cimg_instance,\n                                    _width - 1,y0,y1,z0,c0);\n\n      return CImg<T>(_data + beg,_width,y1 - y0 + 1,1,1,true);\n    }\n\n    //! Return a shared-memory image referencing one row of the image instance.\n    /**\n       \\param y0 Y-coordinate.\n       \\param z0 Z-coordinate.\n       \\param c0 C-coordinate.\n    **/\n    CImg<T> get_shared_row(const unsigned int y0, const unsigned int z0=0, const unsigned int c0=0) {\n      return get_shared_rows(y0,y0,z0,c0);\n    }\n\n    //! Return a shared-memory image referencing one row of the image instance \\const.\n    const CImg<T> get_shared_row(const unsigned int y0, const unsigned int z0=0, const unsigned int c0=0) const {\n      return get_shared_rows(y0,y0,z0,c0);\n    }\n\n    //! Return a shared memory image referencing a range of slices of the image instance.\n    /**\n       \\param z0 Z-coordinate of the starting slice.\n       \\param z1 Z-coordinate of the ending slice.\n       \\param c0 C-coordinate.\n    **/\n    CImg<T> get_shared_slices(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) {\n      const unsigned int\n        beg = (unsigned int)offset(0,0,z0,c0),\n        end = (unsigned int)offset(0,0,z1,c0);\n      if (beg>end || beg>=size() || end>=size())\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_shared_slices(): Invalid request of a shared-memory subset \"\n                                    \"(0->%u,0->%u,%u->%u,%u).\",\n                                    cimg_instance,\n                                    _width - 1,_height - 1,z0,z1,c0);\n\n      return CImg<T>(_data + beg,_width,_height,z1 - z0 + 1,1,true);\n    }\n\n    //! Return a shared memory image referencing a range of slices of the image instance \\const.\n    const CImg<T> get_shared_slices(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) const {\n      const unsigned int\n        beg = (unsigned int)offset(0,0,z0,c0),\n        end = (unsigned int)offset(0,0,z1,c0);\n      if (beg>end || beg>=size() || end>=size())\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_shared_slices(): Invalid request of a shared-memory subset \"\n                                    \"(0->%u,0->%u,%u->%u,%u).\",\n                                    cimg_instance,\n                                    _width - 1,_height - 1,z0,z1,c0);\n\n      return CImg<T>(_data + beg,_width,_height,z1 - z0 + 1,1,true);\n    }\n\n    //! Return a shared-memory image referencing one slice of the image instance.\n    /**\n       \\param z0 Z-coordinate.\n       \\param c0 C-coordinate.\n    **/\n    CImg<T> get_shared_slice(const unsigned int z0, const unsigned int c0=0) {\n      return get_shared_slices(z0,z0,c0);\n    }\n\n    //! Return a shared-memory image referencing one slice of the image instance \\const.\n    const CImg<T> get_shared_slice(const unsigned int z0, const unsigned int c0=0) const {\n      return get_shared_slices(z0,z0,c0);\n    }\n\n    //! Return a shared-memory image referencing a range of channels of the image instance.\n    /**\n       \\param c0 C-coordinate of the starting channel.\n       \\param c1 C-coordinate of the ending channel.\n    **/\n    CImg<T> get_shared_channels(const unsigned int c0, const unsigned int c1) {\n      const unsigned int\n        beg = (unsigned int)offset(0,0,0,c0),\n        end = (unsigned int)offset(0,0,0,c1);\n      if (beg>end || beg>=size() || end>=size())\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_shared_channels(): Invalid request of a shared-memory subset \"\n                                    \"(0->%u,0->%u,0->%u,%u->%u).\",\n                                    cimg_instance,\n                                    _width - 1,_height - 1,_depth - 1,c0,c1);\n\n      return CImg<T>(_data + beg,_width,_height,_depth,c1 - c0 + 1,true);\n    }\n\n    //! Return a shared-memory image referencing a range of channels of the image instance \\const.\n    const CImg<T> get_shared_channels(const unsigned int c0, const unsigned int c1) const {\n      const unsigned int\n        beg = (unsigned int)offset(0,0,0,c0),\n        end = (unsigned int)offset(0,0,0,c1);\n      if (beg>end || beg>=size() || end>=size())\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_shared_channels(): Invalid request of a shared-memory subset \"\n                                    \"(0->%u,0->%u,0->%u,%u->%u).\",\n                                    cimg_instance,\n                                    _width - 1,_height - 1,_depth - 1,c0,c1);\n\n      return CImg<T>(_data + beg,_width,_height,_depth,c1 - c0 + 1,true);\n    }\n\n    //! Return a shared-memory image referencing one channel of the image instance.\n    /**\n       \\param c0 C-coordinate.\n    **/\n    CImg<T> get_shared_channel(const unsigned int c0) {\n      return get_shared_channels(c0,c0);\n    }\n\n    //! Return a shared-memory image referencing one channel of the image instance \\const.\n    const CImg<T> get_shared_channel(const unsigned int c0) const {\n      return get_shared_channels(c0,c0);\n    }\n\n    //! Return a shared-memory version of the image instance.\n    CImg<T> get_shared() {\n      return CImg<T>(_data,_width,_height,_depth,_spectrum,true);\n    }\n\n    //! Return a shared-memory version of the image instance \\const.\n    const CImg<T> get_shared() const {\n      return CImg<T>(_data,_width,_height,_depth,_spectrum,true);\n    }\n\n    //! Split image into a list along specified axis.\n    /**\n       \\param axis Splitting axis. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n       \\param nb Number of splitted parts.\n       \\note\n       - If \\c nb==0, instance image is splitted into blocs of egal values along the specified axis.\n       - If \\c nb<=0, instance image is splitted into blocs of -\\c nb pixel wide.\n       - If \\c nb>0, instance image is splitted into \\c nb blocs.\n    **/\n    CImgList<T> get_split(const char axis, const int nb=-1) const {\n      CImgList<T> res;\n      if (is_empty()) return res;\n      const char _axis = cimg::uncase(axis);\n\n      if (nb<0) { // Split by bloc size.\n        const unsigned int dp = (unsigned int)(nb?-nb:1);\n        switch (_axis) {\n        case 'x': {\n          if (_width>dp) {\n            res.assign(_width/dp + (_width%dp?1:0),1,1);\n            const unsigned int pe = _width - dp;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(res._width>=128 && _height*_depth*_spectrum>=128)\n#endif\n            for (unsigned int p = 0; p<pe; p+=dp)\n              get_crop(p,0,0,0,p + dp - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]);\n            get_crop((res._width - 1)*dp,0,0,0,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back());\n          } else res.assign(*this);\n        } break;\n        case 'y': {\n          if (_height>dp) {\n            res.assign(_height/dp + (_height%dp?1:0),1,1);\n            const unsigned int pe = _height - dp;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_depth*_spectrum>=128)\n#endif\n            for (unsigned int p = 0; p<pe; p+=dp)\n              get_crop(0,p,0,0,_width - 1,p + dp - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]);\n            get_crop(0,(res._width - 1)*dp,0,0,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back());\n          } else res.assign(*this);\n        } break;\n        case 'z': {\n          if (_depth>dp) {\n            res.assign(_depth/dp + (_depth%dp?1:0),1,1);\n            const unsigned int pe = _depth - dp;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_height*_spectrum>=128)\n#endif\n            for (unsigned int p = 0; p<pe; p+=dp)\n              get_crop(0,0,p,0,_width - 1,_height - 1,p + dp - 1,_spectrum - 1).move_to(res[p/dp]);\n            get_crop(0,0,(res._width - 1)*dp,0,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back());\n          } else res.assign(*this);\n        } break;\n        case 'c' : {\n          if (_spectrum>dp) {\n            res.assign(_spectrum/dp + (_spectrum%dp?1:0),1,1);\n            const unsigned int pe = _spectrum - dp;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_height*_depth>=128)\n#endif\n            for (unsigned int p = 0; p<pe; p+=dp)\n              get_crop(0,0,0,p,_width - 1,_height - 1,_depth - 1,p + dp - 1).move_to(res[p/dp]);\n            get_crop(0,0,0,(res._width - 1)*dp,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back());\n          } else res.assign(*this);\n        }\n        }\n      } else if (nb>0) { // Split by number of (non-homogeneous) blocs.\n        const unsigned int siz = _axis=='x'?_width:_axis=='y'?_height:_axis=='z'?_depth:_axis=='c'?_spectrum:0;\n        if ((unsigned int)nb>siz)\n          throw CImgArgumentException(_cimg_instance\n                                      \"get_split(): Instance cannot be split along %c-axis into %u blocs.\",\n                                      cimg_instance,\n                                      axis,nb);\n        if (nb==1) res.assign(*this);\n        else {\n          int err = (int)siz;\n          unsigned int _p = 0;\n          switch (_axis) {\n          case 'x' : {\n            cimg_forX(*this,p) if ((err-=nb)<=0) {\n              get_crop(_p,0,0,0,p,_height - 1,_depth - 1,_spectrum - 1).move_to(res);\n              err+=(int)siz;\n              _p = p + 1U;\n            }\n          } break;\n          case 'y' : {\n            cimg_forY(*this,p) if ((err-=nb)<=0) {\n              get_crop(0,_p,0,0,_width - 1,p,_depth - 1,_spectrum - 1).move_to(res);\n              err+=(int)siz;\n              _p = p + 1U;\n            }\n          } break;\n          case 'z' : {\n            cimg_forZ(*this,p) if ((err-=nb)<=0) {\n              get_crop(0,0,_p,0,_width - 1,_height - 1,p,_spectrum - 1).move_to(res);\n              err+=(int)siz;\n              _p = p + 1U;\n            }\n          } break;\n          case 'c' : {\n            cimg_forC(*this,p) if ((err-=nb)<=0) {\n              get_crop(0,0,0,_p,_width - 1,_height - 1,_depth - 1,p).move_to(res);\n              err+=(int)siz;\n              _p = p + 1U;\n            }\n          }\n          }\n        }\n      } else { // Split by egal values according to specified axis.\n        T current = *_data;\n        switch (_axis) {\n        case 'x' : {\n          int i0 = 0;\n          cimg_forX(*this,i)\n            if ((*this)(i)!=current) { get_columns(i0,i - 1).move_to(res); i0 = i; current = (*this)(i); }\n          get_columns(i0,width() - 1).move_to(res);\n        } break;\n        case 'y' : {\n          int i0 = 0;\n          cimg_forY(*this,i)\n            if ((*this)(0,i)!=current) { get_rows(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,i); }\n          get_rows(i0,height() - 1).move_to(res);\n        } break;\n        case 'z' : {\n          int i0 = 0;\n          cimg_forZ(*this,i)\n            if ((*this)(0,0,i)!=current) { get_slices(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,i); }\n          get_slices(i0,depth() - 1).move_to(res);\n        } break;\n        case 'c' : {\n          int i0 = 0;\n          cimg_forC(*this,i)\n            if ((*this)(0,0,0,i)!=current) { get_channels(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,0,i); }\n          get_channels(i0,spectrum() - 1).move_to(res);\n        } break;\n        default : {\n          longT i0 = 0;\n          cimg_foroff(*this,i)\n            if ((*this)[i]!=current) { CImg<T>(_data + i0,1,i - i0).move_to(res); i0 = (longT)i; current = (*this)[i]; }\n          CImg<T>(_data + i0,1,size() - i0).move_to(res);\n        }\n        }\n      }\n      return res;\n    }\n\n    //! Split image into a list of sub-images, according to a specified splitting value sequence and optionnally axis.\n    /**\n       \\param values Splitting value sequence.\n       \\param axis Axis along which the splitting is performed. Can be '0' to ignore axis.\n       \\param keep_values Tells if the splitting sequence must be kept in the splitted blocs.\n     **/\n    template<typename t>\n    CImgList<T> get_split(const CImg<t>& values, const char axis=0, const bool keep_values=true) const {\n      CImgList<T> res;\n      if (is_empty()) return res;\n      const ulongT vsiz = values.size();\n      const char _axis = cimg::uncase(axis);\n      if (!vsiz) return CImgList<T>(*this);\n      if (vsiz==1) { // Split according to a single value.\n        const T value = *values;\n        switch (_axis) {\n        case 'x' : {\n          unsigned int i0 = 0, i = 0;\n          do {\n            while (i<_width && (*this)(i)==value) ++i;\n            if (i>i0) { if (keep_values) get_columns(i0,i - 1).move_to(res); i0 = i; }\n            while (i<_width && (*this)(i)!=value) ++i;\n            if (i>i0) { get_columns(i0,i - 1).move_to(res); i0 = i; }\n          } while (i<_width);\n        } break;\n        case 'y' : {\n          unsigned int i0 = 0, i = 0;\n          do {\n            while (i<_height && (*this)(0,i)==value) ++i;\n            if (i>i0) { if (keep_values) get_rows(i0,i - 1).move_to(res); i0 = i; }\n            while (i<_height && (*this)(0,i)!=value) ++i;\n            if (i>i0) { get_rows(i0,i - 1).move_to(res); i0 = i; }\n          } while (i<_height);\n        } break;\n        case 'z' : {\n          unsigned int i0 = 0, i = 0;\n          do {\n            while (i<_depth && (*this)(0,0,i)==value) ++i;\n            if (i>i0) { if (keep_values) get_slices(i0,i - 1).move_to(res); i0 = i; }\n            while (i<_depth && (*this)(0,0,i)!=value) ++i;\n            if (i>i0) { get_slices(i0,i - 1).move_to(res); i0 = i; }\n          } while (i<_depth);\n        } break;\n        case 'c' : {\n          unsigned int i0 = 0, i = 0;\n          do {\n            while (i<_spectrum && (*this)(0,0,0,i)==value) ++i;\n            if (i>i0) { if (keep_values) get_channels(i0,i - 1).move_to(res); i0 = i; }\n            while (i<_spectrum && (*this)(0,0,0,i)!=value) ++i;\n            if (i>i0) { get_channels(i0,i - 1).move_to(res); i0 = i; }\n          } while (i<_spectrum);\n        } break;\n        default : {\n          const ulongT siz = size();\n          ulongT i0 = 0, i = 0;\n          do {\n            while (i<siz && (*this)[i]==value) ++i;\n            if (i>i0) { if (keep_values) CImg<T>(_data + i0,1,i - i0).move_to(res); i0 = i; }\n            while (i<siz && (*this)[i]!=value) ++i;\n            if (i>i0) { CImg<T>(_data + i0,1,i - i0).move_to(res); i0 = i; }\n          } while (i<siz);\n        }\n        }\n      } else { // Split according to multiple values.\n        ulongT j = 0;\n        switch (_axis) {\n        case 'x' : {\n          unsigned int i0 = 0, i1 = 0, i = 0;\n          do {\n            if ((*this)(i)==*values) {\n              i1 = i; j = 0;\n              while (i<_width && (*this)(i)==values[j]) { ++i; if (++j>=vsiz) j = 0; }\n              i-=j;\n              if (i>i1) {\n                if (i1>i0) get_columns(i0,i1 - 1).move_to(res);\n                if (keep_values) get_columns(i1,i - 1).move_to(res);\n                i0 = i;\n              } else ++i;\n            } else ++i;\n          } while (i<_width);\n          if (i0<_width) get_columns(i0,width() - 1).move_to(res);\n        } break;\n        case 'y' : {\n          unsigned int i0 = 0, i1 = 0, i = 0;\n          do {\n            if ((*this)(0,i)==*values) {\n              i1 = i; j = 0;\n              while (i<_height && (*this)(0,i)==values[j]) { ++i; if (++j>=vsiz) j = 0; }\n              i-=j;\n              if (i>i1) {\n                if (i1>i0) get_rows(i0,i1 - 1).move_to(res);\n                if (keep_values) get_rows(i1,i - 1).move_to(res);\n                i0 = i;\n              } else ++i;\n            } else ++i;\n          } while (i<_height);\n          if (i0<_height) get_rows(i0,height() - 1).move_to(res);\n        } break;\n        case 'z' : {\n          unsigned int i0 = 0, i1 = 0, i = 0;\n          do {\n            if ((*this)(0,0,i)==*values) {\n              i1 = i; j = 0;\n              while (i<_depth && (*this)(0,0,i)==values[j]) { ++i; if (++j>=vsiz) j = 0; }\n              i-=j;\n              if (i>i1) {\n                if (i1>i0) get_slices(i0,i1 - 1).move_to(res);\n                if (keep_values) get_slices(i1,i - 1).move_to(res);\n                i0 = i;\n              } else ++i;\n            } else ++i;\n          } while (i<_depth);\n          if (i0<_depth) get_slices(i0,depth() - 1).move_to(res);\n        } break;\n        case 'c' : {\n          unsigned int i0 = 0, i1 = 0, i = 0;\n          do {\n            if ((*this)(0,0,0,i)==*values) {\n              i1 = i; j = 0;\n              while (i<_spectrum && (*this)(0,0,0,i)==values[j]) { ++i; if (++j>=vsiz) j = 0; }\n              i-=j;\n              if (i>i1) {\n                if (i1>i0) get_channels(i0,i1 - 1).move_to(res);\n                if (keep_values) get_channels(i1,i - 1).move_to(res);\n                i0 = i;\n              } else ++i;\n            } else ++i;\n          } while (i<_spectrum);\n          if (i0<_spectrum) get_channels(i0,spectrum() - 1).move_to(res);\n        } break;\n        default : {\n          ulongT i0 = 0, i1 = 0, i = 0;\n          const ulongT siz = size();\n          do {\n            if ((*this)[i]==*values) {\n              i1 = i; j = 0;\n              while (i<siz && (*this)[i]==values[j]) { ++i; if (++j>=vsiz) j = 0; }\n              i-=j;\n              if (i>i1) {\n                if (i1>i0) CImg<T>(_data + i0,1,i1 - i0).move_to(res);\n                if (keep_values) CImg<T>(_data + i1,1,i - i1).move_to(res);\n                i0 = i;\n              } else ++i;\n            } else ++i;\n          } while (i<siz);\n          if (i0<siz) CImg<T>(_data + i0,1,siz - i0).move_to(res);\n        } break;\n        }\n      }\n      return res;\n    }\n\n    //! Append two images along specified axis.\n    /**\n       \\param img Image to append with instance image.\n       \\param axis Appending axis. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n       \\param align Append alignment in \\c [0,1].\n    **/\n    template<typename t>\n    CImg<T>& append(const CImg<t>& img, const char axis='x', const float align=0) {\n      if (is_empty()) return assign(img,false);\n      if (!img) return *this;\n      return CImgList<T>(*this,true).insert(img).get_append(axis,align).move_to(*this);\n    }\n\n    //! Append two images along specified axis \\specialization.\n    CImg<T>& append(const CImg<T>& img, const char axis='x', const float align=0) {\n      if (is_empty()) return assign(img,false);\n      if (!img) return *this;\n      return CImgList<T>(*this,img,true).get_append(axis,align).move_to(*this);\n    }\n\n    //! Append two images along specified axis \\const.\n    template<typename t>\n    CImg<_cimg_Tt> get_append(const CImg<T>& img, const char axis='x', const float align=0) const {\n      if (is_empty()) return +img;\n      if (!img) return +*this;\n      return CImgList<_cimg_Tt>(*this,true).insert(img).get_append(axis,align);\n    }\n\n    //! Append two images along specified axis \\specialization.\n    CImg<T> get_append(const CImg<T>& img, const char axis='x', const float align=0) const {\n      if (is_empty()) return +img;\n      if (!img) return +*this;\n      return CImgList<T>(*this,img,true).get_append(axis,align);\n    }\n\n    //@}\n    //---------------------------------------\n    //\n    //! \\name Filtering / Transforms\n    //@{\n    //---------------------------------------\n\n    //! Correlate image by a mask.\n    /**\n       \\param mask = the correlation kernel.\n       \\param boundary_conditions = the border condition type (0=zero, 1=dirichlet)\n       \\param is_normalized = enable local normalization.\n       \\note\n       - The correlation of the image instance \\p *this by the mask \\p mask is defined to be:\n       res(x,y,z) = sum_{i,j,k} (*this)(x + i,y + j,z + k)*mask(i,j,k).\n    **/\n    template<typename t>\n    CImg<T>& correlate(const CImg<t>& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) {\n      if (is_empty() || !mask) return *this;\n      return get_correlate(mask,boundary_conditions,is_normalized).move_to(*this);\n    }\n\n    //! Correlate image by a mask \\newinstance.\n    template<typename t>\n    CImg<_cimg_Ttfloat> get_correlate(const CImg<t>& mask, const unsigned int boundary_conditions=1,\n                                      const bool is_normalized=false) const {\n      if (is_empty() || !mask) return *this;\n      typedef _cimg_Ttfloat Ttfloat;\n      CImg<Ttfloat> res(_width,_height,_depth,cimg::max(_spectrum,mask._spectrum));\n      if (boundary_conditions && mask._width==mask._height &&\n          ((mask._depth==1 && mask._width<=5) || (mask._depth==mask._width && mask._width<=3))) {\n        // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with boundary_conditions=1)\n        Ttfloat *ptrd = res._data;\n        CImg<T> I;\n        switch (mask._depth) {\n        case 3 : {\n          I.assign(27);\n          cimg_forC(res,c) {\n            cimg_test_abort();\n            const CImg<T> _img = get_shared_channel(c%_spectrum);\n            const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n            if (is_normalized) {\n              const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M;\n              cimg_for3x3x3(_img,x,y,z,0,I,T) {\n                const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] +\n                                     I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +\n                                     I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] +\n                                     I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +\n                                     I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +\n                                     I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +\n                                     I[18]*I[18] + I[19]*I[19] + I[20]*I[20] +\n                                     I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +\n                                     I[24]*I[24] + I[25]*I[25] + I[26]*I[26]);\n                *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] +\n                                         I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] +\n                                         I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] +\n                                         I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] +\n                                         I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] +\n                                         I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] +\n                                         I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] +\n                                         I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] +\n                                         I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26])/std::sqrt(N):0);\n              }\n            } else cimg_for3x3x3(_img,x,y,z,0,I,T)\n                     *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] +\n                                           I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] +\n                                           I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] +\n                                           I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] +\n                                           I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] +\n                                           I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] +\n                                           I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] +\n                                           I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] +\n                                           I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26]);\n          }\n        } break;\n        case 2 : {\n          I.assign(8);\n          cimg_forC(res,c) {\n            cimg_test_abort();\n            const CImg<T> _img = get_shared_channel(c%_spectrum);\n            const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n            if (is_normalized) {\n              const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M;\n              cimg_for2x2x2(_img,x,y,z,0,I,T) {\n                const Ttfloat N = M*(I[0]*I[0] + I[1]*I[1] +\n                                     I[2]*I[2] + I[3]*I[3] +\n                                     I[4]*I[4] + I[5]*I[5] +\n                                     I[6]*I[6] + I[7]*I[7]);\n                *(ptrd++) = (Ttfloat)(N?(I[0]*_mask[0] + I[1]*_mask[1] +\n                                         I[2]*_mask[2] + I[3]*_mask[3] +\n                                         I[4]*_mask[4] + I[5]*_mask[5] +\n                                         I[6]*_mask[6] + I[7]*_mask[7])/std::sqrt(N):0);\n              }\n            } else cimg_for2x2x2(_img,x,y,z,0,I,T)\n                     *(ptrd++) = (Ttfloat)(I[0]*_mask[0] + I[1]*_mask[1] +\n                                           I[2]*_mask[2] + I[3]*_mask[3] +\n                                           I[4]*_mask[4] + I[5]*_mask[5] +\n                                           I[6]*_mask[6] + I[7]*_mask[7]);\n          }\n        } break;\n        default :\n        case 1 :\n          switch (mask._width) {\n          case 6 : {\n            I.assign(36);\n            cimg_forC(res,c) {\n              cimg_test_abort();\n              const CImg<T> _img = get_shared_channel(c%_spectrum);\n              const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n              if (is_normalized) {\n                const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M;\n                cimg_forZ(_img,z) cimg_for6x6(_img,x,y,z,0,I,T) {\n                  const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +\n                                       I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +\n                                       I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +\n                                       I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +\n                                       I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24] +\n                                       I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] +\n                                       I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] +\n                                       I[35]*I[35]);\n                  *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] +\n                                           I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] +\n                                           I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] +\n                                           I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] +\n                                           I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] +\n                                           I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] +\n                                           I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26] + I[27]*_mask[27] +\n                                           I[28]*_mask[28] + I[29]*_mask[29] + I[30]*_mask[30] + I[31]*_mask[31] +\n                                           I[32]*_mask[32] + I[33]*_mask[33] + I[34]*_mask[34] + I[35]*_mask[35])/\n                                        std::sqrt(N):0);\n                }\n              } else cimg_forZ(_img,z) cimg_for6x6(_img,x,y,z,0,I,T)\n                       *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] +\n                                             I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] +\n                                             I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] +\n                                             I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] +\n                                             I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] +\n                                             I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] +\n                                             I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26] + I[27]*_mask[27] +\n                                             I[28]*_mask[28] + I[29]*_mask[29] + I[30]*_mask[30] + I[31]*_mask[31] +\n                                             I[32]*_mask[32] + I[33]*_mask[33] + I[34]*_mask[34] + I[35]*_mask[35]);\n            }\n          } break;\n          case 5 : {\n            I.assign(25);\n            cimg_forC(res,c) {\n              cimg_test_abort();\n              const CImg<T> _img = get_shared_channel(c%_spectrum);\n              const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n              if (is_normalized) {\n                const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M;\n                cimg_forZ(_img,z) cimg_for5x5(_img,x,y,z,0,I,T) {\n                  const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +\n                                       I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +\n                                       I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +\n                                       I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +\n                                       I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]);\n                  *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] +\n                                           I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] +\n                                           I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] +\n                                           I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] +\n                                           I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] +\n                                           I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] +\n                                           I[24]*_mask[24])/std::sqrt(N):0);\n                }\n              } else cimg_forZ(_img,z) cimg_for5x5(_img,x,y,z,0,I,T)\n                       *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] +\n                                             I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] +\n                                             I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] +\n                                             I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] +\n                                             I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] +\n                                             I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] +\n                                             I[24]*_mask[24]);\n            }\n          } break;\n          case 4 : {\n            I.assign(16);\n            cimg_forC(res,c) {\n              cimg_test_abort();\n              const CImg<T> _img = get_shared_channel(c%_spectrum);\n              const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n              if (is_normalized) {\n                const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M;\n                cimg_forZ(_img,z) cimg_for4x4(_img,x,y,z,0,I,T) {\n                  const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] +\n                                       I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] +\n                                       I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +\n                                       I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]);\n                  *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] +\n                                           I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] +\n                                           I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] +\n                                           I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15])/\n                                        std::sqrt(N):0);\n                }\n              } else cimg_forZ(_img,z) cimg_for4x4(_img,x,y,z,0,I,T)\n                       *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] +\n                                             I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] +\n                                             I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] +\n                                             I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15]);\n            }\n          } break;\n          case 3 : {\n            I.assign(9);\n            cimg_forC(res,c) {\n              cimg_test_abort();\n              const CImg<T> _img = get_shared_channel(c%_spectrum);\n              const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n              if (is_normalized) {\n                const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M;\n                cimg_forZ(_img,z) cimg_for3x3(_img,x,y,z,0,I,T) {\n                  const Ttfloat N = M*(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] +\n                                       I[3]*I[3] + I[4]*I[4] + I[5]*I[5] +\n                                       I[6]*I[6] + I[7]*I[7] + I[8]*I[8]);\n                  *(ptrd++) = (Ttfloat)(N?(I[0]*_mask[0] + I[1]*_mask[1] + I[2]*_mask[2] +\n                                           I[3]*_mask[3] + I[4]*_mask[4] + I[5]*_mask[5] +\n                                           I[6]*_mask[6] + I[7]*_mask[7] + I[8]*_mask[8])/std::sqrt(N):0);\n                }\n              } else cimg_forZ(_img,z) cimg_for3x3(_img,x,y,z,0,I,T)\n                       *(ptrd++) = (Ttfloat)(I[0]*_mask[0] + I[1]*_mask[1] + I[2]*_mask[2] +\n                                             I[3]*_mask[3] + I[4]*_mask[4] + I[5]*_mask[5] +\n                                             I[6]*_mask[6] + I[7]*_mask[7] + I[8]*_mask[8]);\n            }\n          } break;\n          case 2 : {\n            I.assign(4);\n            cimg_forC(res,c) {\n              cimg_test_abort();\n              const CImg<T> _img = get_shared_channel(c%_spectrum);\n              const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n              if (is_normalized) {\n                const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M;\n                cimg_forZ(_img,z) cimg_for2x2(_img,x,y,z,0,I,T) {\n                  const Ttfloat N = M*(I[0]*I[0] + I[1]*I[1] +\n                                       I[2]*I[2] + I[3]*I[3]);\n                  *(ptrd++) = (Ttfloat)(N?(I[0]*_mask[0] + I[1]*_mask[1] +\n                                           I[2]*_mask[2] + I[3]*_mask[3])/std::sqrt(N):0);\n                }\n              } else cimg_forZ(_img,z) cimg_for2x2(_img,x,y,z,0,I,T)\n                       *(ptrd++) = (Ttfloat)(I[0]*_mask[0] + I[1]*_mask[1] +\n                                             I[2]*_mask[2] + I[3]*_mask[3]);\n            }\n          } break;\n          case 1 :\n            if (is_normalized) res.fill(1);\n            else cimg_forC(res,c) {\n                cimg_test_abort();\n                const CImg<T> _img = get_shared_channel(c%_spectrum);\n                const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n                res.get_shared_channel(c).assign(_img)*=_mask[0];\n              }\n            break;\n          }\n        }\n      } else { // Generic version for other masks and boundary conditions.\n        const int\n          mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2,\n          mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2),\n          mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(res._spectrum>=2)\n#endif\n        cimg_forC(res,c) {\n          cimg_test_abort();\n          const CImg<T> _img = get_shared_channel(c%_spectrum);\n          const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n          if (is_normalized) { // Normalized correlation.\n            const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width*_height*_depth>=32768)\n#endif\n            for (int z = mz1; z<mze; ++z)\n              for (int y = my1; y<mye; ++y)\n                for (int x = mx1; x<mxe; ++x) {\n                  Ttfloat val = 0, N = 0;\n                  for (int zm = -mz1; zm<=mz2; ++zm)\n                    for (int ym = -my1; ym<=my2; ++ym)\n                      for (int xm = -mx1; xm<=mx2; ++xm) {\n                        const Ttfloat _val = (Ttfloat)_img(x + xm,y + ym,z + zm);\n                        val+=_val*_mask(mx1 + xm,my1 + ym,mz1 + zm);\n                        N+=_val*_val;\n                      }\n                  N*=M;\n                  res(x,y,z,c) = (Ttfloat)(N?val/std::sqrt(N):0);\n                }\n            if (boundary_conditions)\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n              cimg_forYZ(res,y,z)\n                for (int x = 0; x<width();\n                     (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                  Ttfloat val = 0, N = 0;\n                  for (int zm = -mz1; zm<=mz2; ++zm)\n                    for (int ym = -my1; ym<=my2; ++ym)\n                      for (int xm = -mx1; xm<=mx2; ++xm) {\n                        const Ttfloat _val = (Ttfloat)_img._atXYZ(x + xm,y + ym,z + zm);\n                        val+=_val*_mask(mx1 + xm,my1 + ym,mz1 + zm);\n                        N+=_val*_val;\n                      }\n                  N*=M;\n                  res(x,y,z,c) = (Ttfloat)(N?val/std::sqrt(N):0);\n                }\n            else\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n              cimg_forYZ(res,y,z)\n                for (int x = 0; x<width();\n                     (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                  Ttfloat val = 0, N = 0;\n                  for (int zm = -mz1; zm<=mz2; ++zm)\n                    for (int ym = -my1; ym<=my2; ++ym)\n                      for (int xm = -mx1; xm<=mx2; ++xm) {\n                        const Ttfloat _val = (Ttfloat)_img.atXYZ(x + xm,y + ym,z + zm,0,0);\n                        val+=_val*_mask(mx1 + xm,my1 + ym,mz1 + zm);\n                        N+=_val*_val;\n                      }\n                  N*=M;\n                  res(x,y,z,c) = (Ttfloat)(N?val/std::sqrt(N):0);\n                }\n          } else { // Classical correlation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width*_height*_depth>=32768)\n#endif\n            for (int z = mz1; z<mze; ++z)\n              for (int y = my1; y<mye; ++y)\n                for (int x = mx1; x<mxe; ++x) {\n                  Ttfloat val = 0;\n                  for (int zm = -mz1; zm<=mz2; ++zm)\n                    for (int ym = -my1; ym<=my2; ++ym)\n                      for (int xm = -mx1; xm<=mx2; ++xm)\n                        val+=_img(x + xm,y + ym,z + zm)*_mask(mx1 + xm,my1 + ym,mz1 + zm);\n                  res(x,y,z,c) = (Ttfloat)val;\n                }\n            if (boundary_conditions)\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n              cimg_forYZ(res,y,z)\n                for (int x = 0; x<width();\n                     (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                  Ttfloat val = 0;\n                  for (int zm = -mz1; zm<=mz2; ++zm)\n                    for (int ym = -my1; ym<=my2; ++ym)\n                      for (int xm = -mx1; xm<=mx2; ++xm)\n                        val+=_img._atXYZ(x + xm,y + ym,z + zm)*_mask(mx1 + xm,my1 + ym,mz1 + zm);\n                  res(x,y,z,c) = (Ttfloat)val;\n                }\n            else\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n              cimg_forYZ(res,y,z)\n                for (int x = 0; x<width();\n                     (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                  Ttfloat val = 0;\n                  for (int zm = -mz1; zm<=mz2; ++zm)\n                    for (int ym = -my1; ym<=my2; ++ym)\n                      for (int xm = -mx1; xm<=mx2; ++xm)\n                        val+=_img.atXYZ(x + xm,y + ym,z + zm,0,0)*_mask(mx1 + xm,my1 + ym,mz1 + zm);\n                  res(x,y,z,c) = (Ttfloat)val;\n                }\n          }\n        }\n      }\n      return res;\n    }\n\n    //! Convolve image by a mask.\n    /**\n       \\param mask = the correlation kernel.\n       \\param boundary_conditions = the border condition type (0=zero, 1=dirichlet)\n       \\param is_normalized = enable local normalization.\n       \\note\n       - The result \\p res of the convolution of an image \\p img by a mask \\p mask is defined to be:\n       res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k)\n    **/\n    template<typename t>\n    CImg<T>& convolve(const CImg<t>& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) {\n      if (is_empty() || !mask) return *this;\n      return get_convolve(mask,boundary_conditions,is_normalized).move_to(*this);\n    }\n\n    //! Cumulate image values, optionally along specified axis.\n    /**\n       \\param axis Cumulation axis. Set it to 0 to cumulate all values globally without taking axes into account.\n    **/\n    CImg<T>& cumulate(const char axis=0) {\n      switch (cimg::uncase(axis)) {\n      case 'x' :\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=512 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forYZC(*this,y,z,c) {\n          T *ptrd = data(0,y,z,c);\n          Tlong cumul = 0;\n          cimg_forX(*this,x) { cumul+=(Tlong)*ptrd; *(ptrd++) = (T)cumul; }\n        }\n        break;\n      case 'y' : {\n        const ulongT w = (ulongT)_width;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_height>=512 && _width*_depth*_spectrum>=16)\n#endif\n        cimg_forXZC(*this,x,z,c) {\n          T *ptrd = data(x,0,z,c);\n          Tlong cumul = 0;\n          cimg_forY(*this,y) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=w; }\n        }\n      } break;\n      case 'z' : {\n        const ulongT wh = (ulongT)_width*_height;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_depth>=512 && _width*_depth*_spectrum>=16)\n#endif\n        cimg_forXYC(*this,x,y,c) {\n          T *ptrd = data(x,y,0,c);\n          Tlong cumul = 0;\n          cimg_forZ(*this,z) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=wh; }\n        }\n      } break;\n      case 'c' : {\n        const ulongT whd = (ulongT)_width*_height*_depth;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_spectrum>=512 && _width*_height*_depth>=16)\n#endif\n        cimg_forXYZ(*this,x,y,z) {\n          T *ptrd = data(x,y,z,0);\n          Tlong cumul = 0;\n          cimg_forC(*this,c) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=whd; }\n        }\n      } break;\n      default : { // Global cumulation.\n        Tlong cumul = 0;\n        cimg_for(*this,ptrd,T) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; }\n      }\n      }\n      return *this;\n    }\n\n    //! Cumulate image values, optionally along specified axis \\newinstance.\n    CImg<Tlong> get_cumulate(const char axis=0) const {\n      return CImg<Tlong>(*this,false).cumulate(axis);\n    }\n\n    //! Cumulate image values, along specified axes.\n    /**\n       \\param axes Cumulation axes, as a C-string.\n       \\note \\c axes may contains multiple characters, e.g. \\c \"xyz\"\n    **/\n    CImg<T>& cumulate(const char *const axes) {\n      for (const char *s = axes; *s; ++s) cumulate(*s);\n      return *this;\n    }\n\n    //! Cumulate image values, along specified axes \\newintance.\n    CImg<Tlong> get_cumulate(const char *const axes) const {\n      return CImg<Tlong>(*this,false).cumulate(axes);\n    }\n\n    //! Convolve image by a mask \\newinstance.\n    template<typename t>\n    CImg<_cimg_Ttfloat> get_convolve(const CImg<t>& mask, const unsigned int boundary_conditions=1,\n                                     const bool is_normalized=false) const {\n      if (is_empty() || !mask) return *this;\n      return get_correlate(CImg<t>(mask._data,mask.size(),1,1,1,true).get_mirror('x').\n                           resize(mask,-1),boundary_conditions,is_normalized);\n    }\n\n    //! Erode image by a structuring element.\n    /**\n       \\param mask Structuring element.\n       \\param boundary_conditions Boundary conditions.\n       \\param is_normalized Tells if the erosion is locally normalized.\n    **/\n    template<typename t>\n    CImg<T>& erode(const CImg<t>& mask, const unsigned int boundary_conditions=1,\n                   const bool is_normalized=false) {\n      if (is_empty() || !mask) return *this;\n      return get_erode(mask,boundary_conditions,is_normalized).move_to(*this);\n    }\n\n    //! Erode image by a structuring element \\newinstance.\n    template<typename t>\n    CImg<_cimg_Tt> get_erode(const CImg<t>& mask, const unsigned int boundary_conditions=1,\n                             const bool is_normalized=false) const {\n      if (is_empty() || !mask) return *this;\n      typedef _cimg_Tt Tt;\n      CImg<Tt> res(_width,_height,_depth,cimg::max(_spectrum,mask._spectrum));\n      const int\n        mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2,\n        mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2),\n        mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_spectrum>=2)\n#endif\n      cimg_forC(*this,c) {\n        cimg_test_abort();\n        const CImg<T> _img = get_shared_channel(c%_spectrum);\n        const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n        if (is_normalized) { // Normalized erosion.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width*_height*_depth>=32768)\n#endif\n          for (int z = mz1; z<mze; ++z)\n            for (int y = my1; y<mye; ++y)\n              for (int x = mx1; x<mxe; ++x) {\n                Tt min_val = cimg::type<Tt>::max();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm);\n                      const Tt cval = (Tt)(_img(x + xm,y + ym,z + zm) + mval);\n                      if (mval && cval<min_val) min_val = cval;\n                    }\n                res(x,y,z,c) = min_val;\n              }\n          if (boundary_conditions)\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n            cimg_forYZ(res,y,z)\n              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                Tt min_val = cimg::type<Tt>::max();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm);\n                      const Tt cval = (Tt)(_img._atXYZ(x + xm,y + ym,z + zm) + mval);\n                      if (mval && cval<min_val) min_val = cval;\n                    }\n                res(x,y,z,c) = min_val;\n              }\n          else\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n            cimg_forYZ(res,y,z)\n              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                Tt min_val = cimg::type<Tt>::max();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm);\n                      const Tt cval = (Tt)(_img.atXYZ(x + xm,y + ym,z + zm,0,0) + mval);\n                      if (mval && cval<min_val) min_val = cval;\n                    }\n                res(x,y,z,c) = min_val;\n              }\n\n        } else { // Classical erosion.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width*_height*_depth>=32768)\n#endif\n          for (int z = mz1; z<mze; ++z)\n            for (int y = my1; y<mye; ++y)\n              for (int x = mx1; x<mxe; ++x) {\n                Tt min_val = cimg::type<Tt>::max();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const Tt cval = (Tt)_img(x + xm,y + ym,z + zm);\n                      if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval<min_val) min_val = cval;\n                    }\n                res(x,y,z,c) = min_val;\n              }\n          if (boundary_conditions)\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n            cimg_forYZ(res,y,z)\n              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                Tt min_val = cimg::type<Tt>::max();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const T cval = (Tt)_img._atXYZ(x + xm,y + ym,z + zm);\n                      if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval<min_val) min_val = cval;\n                    }\n                res(x,y,z,c) = min_val;\n              }\n          else\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n            cimg_forYZ(res,y,z)\n              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                Tt min_val = cimg::type<Tt>::max();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const T cval = (Tt)_img.atXYZ(x + xm,y + ym,z + zm,0,0);\n                      if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval<min_val) min_val = cval;\n                    }\n                res(x,y,z,c) = min_val;\n              }\n        }\n      }\n      return res;\n    }\n\n    //! Erode image by a rectangular structuring element of specified size.\n    /**\n       \\param sx Width of the structuring element.\n       \\param sy Height of the structuring element.\n       \\param sz Depth of the structuring element.\n    **/\n    CImg<T>& erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) {\n      if (is_empty() || (sx==1 && sy==1 && sz==1)) return *this;\n      if (sx>1 && _width>1) { // Along X-axis.\n        const int L = width(), off = 1, s = (int)sx, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2;\n        CImg<T> buf(L);\n#ifdef cimg_use_opemp\n#pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288)\n#endif\n        cimg_forYZC(*this,y,z,c) {\n          T *const ptrdb = buf._data, *ptrd = buf._data, *const ptrde = buf._data + L - 1;\n          const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;\n          T cur = *ptrs; ptrs+=off; bool is_first = true;\n          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {\n            const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }}\n          *(ptrd++) = cur;\n          if (ptrs>=ptrse) {\n            T *pd = data(0,y,z,c); cur = cimg::min(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; }\n          } else {\n            for (int p = s1; p>0 && ptrd<=ptrde; --p) {\n              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; }\n              *(ptrd++) = cur;\n            }\n            for (int p = L - s - 1; p>0; --p) {\n              const T val = *ptrs; ptrs+=off;\n              if (is_first) {\n                const T *nptrs = ptrs - off; cur = val;\n                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; }\n                nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false;\n              } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }\n              *(ptrd++) = cur;\n            }\n            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;\n            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {\n              const T val = *ptrs; ptrs-=off; if (val<cur) cur = val;\n            }\n            *(ptrd--) = cur;\n            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {\n              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur;\n            }\n            T *pd = data(0,y,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }\n          }\n        }\n      }\n\n      if (sy>1 && _height>1) { // Along Y-axis.\n        const int L = height(), off = width(), s = (int)sy, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1,\n          s2 = _s2>L?L:_s2;\n        CImg<T> buf(L);\n#ifdef cimg_use_opemp\n#pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288)\n#endif\n        cimg_forXZC(*this,x,z,c) {\n          T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1;\n          const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;\n          T cur = *ptrs; ptrs+=off; bool is_first = true;\n          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {\n            const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }\n          }\n          *(ptrd++) = cur;\n          if (ptrs>=ptrse) {\n            T *pd = data(x,0,z,c); cur = cimg::min(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; }\n          } else {\n            for (int p = s1; p>0 && ptrd<=ptrde; --p) {\n              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; }\n              *(ptrd++) = cur;\n            }\n            for (int p = L - s - 1; p>0; --p) {\n              const T val = *ptrs; ptrs+=off;\n              if (is_first) {\n                const T *nptrs = ptrs - off; cur = val;\n                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; }\n                nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false;\n              } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }\n              *(ptrd++) = cur;\n            }\n            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;\n            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {\n              const T val = *ptrs; ptrs-=off; if (val<cur) cur = val;\n            }\n            *(ptrd--) = cur;\n            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {\n              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur;\n            }\n            T *pd = data(x,0,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }\n          }\n        }\n      }\n\n      if (sz>1 && _depth>1) { // Along Z-axis.\n        const int L = depth(), off = width()*height(), s = (int)sz, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1,\n          s2 = _s2>L?L:_s2;\n        CImg<T> buf(L);\n#ifdef cimg_use_opemp\n#pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288)\n#endif\n        cimg_forXYC(*this,x,y,c) {\n          T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1;\n          const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;\n          T cur = *ptrs; ptrs+=off; bool is_first = true;\n          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {\n            const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }\n          }\n          *(ptrd++) = cur;\n          if (ptrs>=ptrse) {\n            T *pd = data(x,y,0,c); cur = cimg::min(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; }\n          } else {\n            for (int p = s1; p>0 && ptrd<=ptrde; --p) {\n              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; }\n              *(ptrd++) = cur;\n            }\n            for (int p = L - s - 1; p>0; --p) {\n              const T val = *ptrs; ptrs+=off;\n              if (is_first) {\n                const T *nptrs = ptrs - off; cur = val;\n                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; }\n                nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false;\n              } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }\n              *(ptrd++) = cur;\n            }\n            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;\n            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {\n              const T val = *ptrs; ptrs-=off; if (val<cur) cur = val;\n            }\n            *(ptrd--) = cur;\n            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {\n              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur;\n            }\n            T *pd = data(x,y,0,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Erode image by a rectangular structuring element of specified size \\newinstance.\n    CImg<T> get_erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const {\n      return (+*this).erode(sx,sy,sz);\n    }\n\n    //! Erode the image by a square structuring element of specified size.\n    /**\n       \\param s Size of the structuring element.\n    **/\n    CImg<T>& erode(const unsigned int s) {\n      return erode(s,s,s);\n    }\n\n    //! Erode the image by a square structuring element of specified size \\newinstance.\n    CImg<T> get_erode(const unsigned int s) const {\n      return (+*this).erode(s);\n    }\n\n    //! Dilate image by a structuring element.\n    /**\n       \\param mask Structuring element.\n       \\param boundary_conditions Boundary conditions.\n       \\param is_normalized Tells if the erosion is locally normalized.\n    **/\n    template<typename t>\n    CImg<T>& dilate(const CImg<t>& mask, const unsigned int boundary_conditions=1,\n                    const bool is_normalized=false) {\n      if (is_empty() || !mask) return *this;\n      return get_dilate(mask,boundary_conditions,is_normalized).move_to(*this);\n    }\n\n    //! Dilate image by a structuring element \\newinstance.\n    template<typename t>\n    CImg<_cimg_Tt> get_dilate(const CImg<t>& mask, const unsigned int boundary_conditions=1,\n                              const bool is_normalized=false) const {\n      if (is_empty() || !mask) return *this;\n      typedef _cimg_Tt Tt;\n      CImg<Tt> res(_width,_height,_depth,_spectrum);\n      const int\n        mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2,\n        mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2),\n        mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_spectrum>=2)\n#endif\n      cimg_forC(*this,c) {\n        cimg_test_abort();\n        const CImg<T> _img = get_shared_channel(c%_spectrum);\n        const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);\n        if (is_normalized) { // Normalized dilation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width*_height*_depth>=32768)\n#endif\n          for (int z = mz1; z<mze; ++z)\n            for (int y = my1; y<mye; ++y)\n              for (int x = mx1; x<mxe; ++x) {\n                Tt max_val = cimg::type<Tt>::min();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm);\n                      const Tt cval = (Tt)(_img(x + xm,y + ym,z + zm) - mval);\n                      if (mval && cval>max_val) max_val = cval;\n                    }\n                res(x,y,z,c) = max_val;\n              }\n          if (boundary_conditions)\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n            cimg_forYZ(res,y,z)\n              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                Tt max_val = cimg::type<Tt>::min();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm);\n                      const Tt cval = (Tt)(_img._atXYZ(x + xm,y + ym,z + zm) - mval);\n                      if (mval && cval>max_val) max_val = cval;\n                    }\n                res(x,y,z,c) = max_val;\n              }\n          else\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n            cimg_forYZ(*this,y,z)\n              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                Tt max_val = cimg::type<Tt>::min();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm);\n                      const Tt cval = (Tt)(_img.atXYZ(x + xm,y + ym,z + zm,0,0) - mval);\n                      if (mval && cval>max_val) max_val = cval;\n                    }\n                res(x,y,z,c) = max_val;\n              }\n        } else { // Classical dilation.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth>=128)\n#endif\n          for (int z = mz1; z<mze; ++z)\n            for (int y = my1; y<mye; ++y)\n              for (int x = mx1; x<mxe; ++x) {\n                Tt max_val = cimg::type<Tt>::min();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const Tt cval = (Tt)_img(x + xm,y + ym,z + zm);\n                      if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval>max_val) max_val = cval;\n                    }\n                res(x,y,z,c) = max_val;\n              }\n          if (boundary_conditions)\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n            cimg_forYZ(res,y,z)\n              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                Tt max_val = cimg::type<Tt>::min();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const T cval = (Tt)_img._atXYZ(x + xm,y + ym,z + zm);\n                      if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval>max_val) max_val = cval;\n                    }\n                res(x,y,z,c) = max_val;\n              }\n          else\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128)\n#endif\n            cimg_forYZ(res,y,z)\n              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {\n                Tt max_val = cimg::type<Tt>::min();\n                for (int zm = -mz1; zm<=mz2; ++zm)\n                  for (int ym = -my1; ym<=my2; ++ym)\n                    for (int xm = -mx1; xm<=mx2; ++xm) {\n                      const T cval = (Tt)_img.atXYZ(x + xm,y + ym,z + zm,0,0);\n                      if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval>max_val) max_val = cval;\n                    }\n                res(x,y,z,c) = max_val;\n              }\n        }\n      }\n      return res;\n    }\n\n    //! Dilate image by a rectangular structuring element of specified size.\n    /**\n       \\param sx Width of the structuring element.\n       \\param sy Height of the structuring element.\n       \\param sz Depth of the structuring element.\n    **/\n    CImg<T>& dilate(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) {\n      if (is_empty() || (sx==1 && sy==1 && sz==1)) return *this;\n      if (sx>1 && _width>1) { // Along X-axis.\n        const int L = width(), off = 1, s = (int)sx, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2;\n        CImg<T> buf(L);\n#ifdef cimg_use_opemp\n#pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288)\n#endif\n        cimg_forYZC(*this,y,z,c) {\n          T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1;\n          const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;\n          T cur = *ptrs; ptrs+=off; bool is_first = true;\n          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {\n            const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; }\n          }\n          *(ptrd++) = cur;\n          if (ptrs>=ptrse) {\n            T *pd = data(0,y,z,c); cur = cimg::max(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; }\n          } else {\n            for (int p = s1; p>0 && ptrd<=ptrde; --p) {\n              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val>=cur) { cur = val; is_first = false; }\n              *(ptrd++) = cur;\n            }\n            for (int p = L - s - 1; p>0; --p) {\n              const T val = *ptrs; ptrs+=off;\n              if (is_first) {\n                const T *nptrs = ptrs - off; cur = val;\n                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; }\n                nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false;\n              } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }\n              *(ptrd++) = cur;\n            }\n            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;\n            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {\n              const T val = *ptrs; ptrs-=off; if (val>cur) cur = val;\n            }\n            *(ptrd--) = cur;\n            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {\n              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur;\n            }\n            T *pd = data(0,y,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }\n          }\n        }\n      }\n\n      if (sy>1 && _height>1) { // Along Y-axis.\n        const int L = height(), off = width(), s = (int)sy, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,\n          s2 = _s2>L?L:_s2;\n        CImg<T> buf(L);\n#ifdef cimg_use_opemp\n#pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288)\n#endif\n        cimg_forXZC(*this,x,z,c) {\n          T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1;\n          const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;\n          T cur = *ptrs; ptrs+=off; bool is_first = true;\n          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {\n            const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; }\n          }\n          *(ptrd++) = cur;\n          if (ptrs>=ptrse) {\n            T *pd = data(x,0,z,c); cur = cimg::max(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; }\n          } else {\n            for (int p = s1; p>0 && ptrd<=ptrde; --p) {\n              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val>=cur) { cur = val; is_first = false; }\n              *(ptrd++) = cur;\n            }\n            for (int p = L - s - 1; p>0; --p) {\n              const T val = *ptrs; ptrs+=off;\n              if (is_first) {\n                const T *nptrs = ptrs - off; cur = val;\n                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; }\n                nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false;\n              } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }\n              *(ptrd++) = cur;\n            }\n            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;\n            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {\n              const T val = *ptrs; ptrs-=off; if (val>cur) cur = val;\n            }\n            *(ptrd--) = cur;\n            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {\n              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur;\n            }\n            T *pd = data(x,0,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }\n          }\n        }\n      }\n\n      if (sz>1 && _depth>1) { // Along Z-axis.\n        const int L = depth(), off = width()*height(), s = (int)sz, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,\n          s2 = _s2>L?L:_s2;\n        CImg<T> buf(L);\n#ifdef cimg_use_opemp\n#pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288)\n#endif\n        cimg_forXYC(*this,x,y,c) {\n          T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1;\n          const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;\n          T cur = *ptrs; ptrs+=off; bool is_first = true;\n          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {\n            const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; }\n          }\n          *(ptrd++) = cur;\n          if (ptrs>=ptrse) {\n            T *pd = data(x,y,0,c); cur = cimg::max(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; }\n          } else {\n            for (int p = s1; p>0 && ptrd<=ptrde; --p) {\n              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val>=cur) { cur = val; is_first = false; }\n              *(ptrd++) = cur;\n            }\n            for (int p = L - s - 1; p>0; --p) {\n              const T val = *ptrs; ptrs+=off;\n              if (is_first) {\n                const T *nptrs = ptrs - off; cur = val;\n                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; }\n                nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false;\n              } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }\n              *(ptrd++) = cur;\n            }\n            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;\n            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {\n              const T val = *ptrs; ptrs-=off; if (val>cur) cur = val;\n            }\n            *(ptrd--) = cur;\n            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {\n              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur;\n            }\n            T *pd = data(x,y,0,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Dilate image by a rectangular structuring element of specified size \\newinstance.\n    CImg<T> get_dilate(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const {\n      return (+*this).dilate(sx,sy,sz);\n    }\n\n    //! Dilate image by a square structuring element of specified size.\n    /**\n       \\param s Size of the structuring element.\n    **/\n    CImg<T>& dilate(const unsigned int s) {\n      return dilate(s,s,s);\n    }\n\n    //! Dilate image by a square structuring element of specified size \\newinstance.\n    CImg<T> get_dilate(const unsigned int s) const {\n      return (+*this).dilate(s);\n    }\n\n    //! Compute watershed transform.\n    /**\n       \\param priority Priority map.\n       \\param is_high_connectivity Boolean that choose between 4(false)- or 8(true)-connectivity\n       in 2d case, and between 6(false)- or 26(true)-connectivity in 3d case.\n       \\note Non-zero values of the instance instance are propagated to zero-valued ones according to\n       specified the priority map.\n    **/\n    template<typename t>\n    CImg<T>& watershed(const CImg<t>& priority, const bool is_high_connectivity=false) {\n#define _cimg_watershed_init(cond,X,Y,Z) \\\n      if (cond && !(*this)(X,Y,Z)) Q._priority_queue_insert(labels,sizeQ,priority(X,Y,Z),X,Y,Z,nb_seeds)\n\n#define _cimg_watershed_propagate(cond,X,Y,Z) \\\n      if (cond) { \\\n        if ((*this)(X,Y,Z)) { \\\n          ns = labels(X,Y,Z) - 1; xs = seeds(ns,0); ys = seeds(ns,1); zs = seeds(ns,2); \\\n          d = cimg::sqr((float)x - xs) + cimg::sqr((float)y - ys) + cimg::sqr((float)z - zs); \\\n          if (d<dmin) { dmin = d; nmin = ns; label = (*this)(xs,ys,zs); } \\\n        } else Q._priority_queue_insert(labels,sizeQ,priority(X,Y,Z),X,Y,Z,n); \\\n      }\n\n      if (is_empty()) return *this;\n      if (!is_sameXYZ(priority))\n        throw CImgArgumentException(_cimg_instance\n                                    \"watershed(): image instance and specified priority (%u,%u,%u,%u,%p) \"\n                                    \"have different dimensions.\",\n                                    cimg_instance,\n                                    priority._width,priority._height,priority._depth,priority._spectrum,priority._data);\n      if (_spectrum!=1) {\n        cimg_forC(*this,c)\n          get_shared_channel(c).watershed(priority.get_shared_channel(c%priority._spectrum));\n        return *this;\n      }\n\n      CImg<uintT> labels(_width,_height,_depth,1,0), seeds(64,3);\n      CImg<typename cimg::superset2<T,t,int>::type> Q;\n      unsigned int sizeQ = 0;\n      int px, nx, py, ny, pz, nz;\n      bool is_px, is_nx, is_py, is_ny, is_pz, is_nz;\n      const bool is_3d = _depth>1;\n\n      // Find seed points and insert them in priority queue.\n      unsigned int nb_seeds = 0;\n      const T *ptrs = _data;\n      cimg_forXYZ(*this,x,y,z) if (*(ptrs++)) { // 3d version\n        if (nb_seeds>=seeds._width) seeds.resize(2*seeds._width,3,1,1,0);\n        seeds(nb_seeds,0) = x; seeds(nb_seeds,1) = y; seeds(nb_seeds++,2) = z;\n        px = x - 1; nx = x + 1;\n        py = y - 1; ny = y + 1;\n        pz = z - 1; nz = z + 1;\n        is_px = px>=0; is_nx = nx<width();\n        is_py = py>=0; is_ny = ny<height();\n        is_pz = pz>=0; is_nz = nz<depth();\n        _cimg_watershed_init(is_px,px,y,z);\n        _cimg_watershed_init(is_nx,nx,y,z);\n        _cimg_watershed_init(is_py,x,py,z);\n        _cimg_watershed_init(is_ny,x,ny,z);\n        if (is_3d) {\n          _cimg_watershed_init(is_pz,x,y,pz);\n          _cimg_watershed_init(is_nz,x,y,nz);\n        }\n        if (is_high_connectivity) {\n          _cimg_watershed_init(is_px && is_py,px,py,z);\n          _cimg_watershed_init(is_nx && is_py,nx,py,z);\n          _cimg_watershed_init(is_px && is_ny,px,ny,z);\n          _cimg_watershed_init(is_nx && is_ny,nx,ny,z);\n          if (is_3d) {\n            _cimg_watershed_init(is_px && is_pz,px,y,pz);\n            _cimg_watershed_init(is_nx && is_pz,nx,y,pz);\n            _cimg_watershed_init(is_px && is_nz,px,y,nz);\n            _cimg_watershed_init(is_nx && is_nz,nx,y,nz);\n            _cimg_watershed_init(is_py && is_pz,x,py,pz);\n            _cimg_watershed_init(is_ny && is_pz,x,ny,pz);\n            _cimg_watershed_init(is_py && is_nz,x,py,nz);\n            _cimg_watershed_init(is_ny && is_nz,x,ny,nz);\n            _cimg_watershed_init(is_px && is_py && is_pz,px,py,pz);\n            _cimg_watershed_init(is_nx && is_py && is_pz,nx,py,pz);\n            _cimg_watershed_init(is_px && is_ny && is_pz,px,ny,pz);\n            _cimg_watershed_init(is_nx && is_ny && is_pz,nx,ny,pz);\n            _cimg_watershed_init(is_px && is_py && is_nz,px,py,nz);\n            _cimg_watershed_init(is_nx && is_py && is_nz,nx,py,nz);\n            _cimg_watershed_init(is_px && is_ny && is_nz,px,ny,nz);\n            _cimg_watershed_init(is_nx && is_ny && is_nz,nx,ny,nz);\n          }\n        }\n        labels(x,y,z) = nb_seeds;\n      }\n\n      // Start watershed computation.\n      while (sizeQ) {\n\n        // Get and remove point with maximal priority from the queue.\n        const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3);\n        const unsigned int n = labels(x,y,z);\n        px = x - 1; nx = x + 1;\n        py = y - 1; ny = y + 1;\n        pz = z - 1; nz = z + 1;\n        is_px = px>=0; is_nx = nx<width();\n        is_py = py>=0; is_ny = ny<height();\n        is_pz = pz>=0; is_nz = nz<depth();\n\n        // Check labels of the neighbors.\n        Q._priority_queue_remove(sizeQ);\n\n        unsigned int xs, ys, zs, ns, nmin = 0;\n        float d, dmin = cimg::type<float>::inf();\n        T label = 0;\n        _cimg_watershed_propagate(is_px,px,y,z);\n        _cimg_watershed_propagate(is_nx,nx,y,z);\n        _cimg_watershed_propagate(is_py,x,py,z);\n        _cimg_watershed_propagate(is_ny,x,ny,z);\n        if (is_3d) {\n          _cimg_watershed_propagate(is_pz,x,y,pz);\n          _cimg_watershed_propagate(is_nz,x,y,nz);\n        }\n        if (is_high_connectivity) {\n          _cimg_watershed_propagate(is_px && is_py,px,py,z);\n          _cimg_watershed_propagate(is_nx && is_py,nx,py,z);\n          _cimg_watershed_propagate(is_px && is_ny,px,ny,z);\n          _cimg_watershed_propagate(is_nx && is_ny,nx,ny,z);\n          if (is_3d) {\n            _cimg_watershed_propagate(is_px && is_pz,px,y,pz);\n            _cimg_watershed_propagate(is_nx && is_pz,nx,y,pz);\n            _cimg_watershed_propagate(is_px && is_nz,px,y,nz);\n            _cimg_watershed_propagate(is_nx && is_nz,nx,y,nz);\n            _cimg_watershed_propagate(is_py && is_pz,x,py,pz);\n            _cimg_watershed_propagate(is_ny && is_pz,x,ny,pz);\n            _cimg_watershed_propagate(is_py && is_nz,x,py,nz);\n            _cimg_watershed_propagate(is_ny && is_nz,x,ny,nz);\n            _cimg_watershed_propagate(is_px && is_py && is_pz,px,py,pz);\n            _cimg_watershed_propagate(is_nx && is_py && is_pz,nx,py,pz);\n            _cimg_watershed_propagate(is_px && is_ny && is_pz,px,ny,pz);\n            _cimg_watershed_propagate(is_nx && is_ny && is_pz,nx,ny,pz);\n            _cimg_watershed_propagate(is_px && is_py && is_nz,px,py,nz);\n            _cimg_watershed_propagate(is_nx && is_py && is_nz,nx,py,nz);\n            _cimg_watershed_propagate(is_px && is_ny && is_nz,px,ny,nz);\n            _cimg_watershed_propagate(is_nx && is_ny && is_nz,nx,ny,nz);\n          }\n        }\n        (*this)(x,y,z) = label;\n        labels(x,y,z) = ++nmin;\n      }\n      return *this;\n    }\n\n    //! Compute watershed transform \\newinstance.\n    template<typename t>\n    CImg<T> get_watershed(const CImg<t>& priority, const bool is_high_connectivity=false) const {\n      return (+*this).watershed(priority,is_high_connectivity);\n    }\n\n    // [internal] Insert/Remove items in priority queue, for watershed/distance transforms.\n    template<typename tq, typename tv>\n    bool _priority_queue_insert(CImg<tq>& is_queued, unsigned int& siz, const tv value,\n                                const unsigned int x, const unsigned int y, const unsigned int z,\n                                const unsigned int n=1) {\n      if (is_queued(x,y,z)) return false;\n      is_queued(x,y,z) = (tq)n;\n      if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); }\n      (*this)(siz - 1,0) = (T)value;\n      (*this)(siz - 1,1) = (T)x;\n      (*this)(siz - 1,2) = (T)y;\n      (*this)(siz - 1,3) = (T)z;\n      for (unsigned int pos = siz - 1, par = 0; pos && value>(*this)(par=(pos + 1)/2 - 1,0); pos = par) {\n        cimg::swap((*this)(pos,0),(*this)(par,0));\n        cimg::swap((*this)(pos,1),(*this)(par,1));\n        cimg::swap((*this)(pos,2),(*this)(par,2));\n        cimg::swap((*this)(pos,3),(*this)(par,3));\n      }\n      return true;\n    }\n\n    CImg<T>& _priority_queue_remove(unsigned int& siz) {\n      (*this)(0,0) = (*this)(--siz,0);\n      (*this)(0,1) = (*this)(siz,1);\n      (*this)(0,2) = (*this)(siz,2);\n      (*this)(0,3) = (*this)(siz,3);\n      const float value = (*this)(0,0);\n      for (unsigned int pos = 0, left = 0, right = 0;\n           ((right=2*(pos + 1),(left=right - 1))<siz && value<(*this)(left,0)) ||\n             (right<siz && value<(*this)(right,0));) {\n        if (right<siz) {\n          if ((*this)(left,0)>(*this)(right,0)) {\n            cimg::swap((*this)(pos,0),(*this)(left,0));\n            cimg::swap((*this)(pos,1),(*this)(left,1));\n            cimg::swap((*this)(pos,2),(*this)(left,2));\n            cimg::swap((*this)(pos,3),(*this)(left,3));\n            pos = left;\n          } else {\n            cimg::swap((*this)(pos,0),(*this)(right,0));\n            cimg::swap((*this)(pos,1),(*this)(right,1));\n            cimg::swap((*this)(pos,2),(*this)(right,2));\n            cimg::swap((*this)(pos,3),(*this)(right,3));\n            pos = right;\n          }\n        } else {\n          cimg::swap((*this)(pos,0),(*this)(left,0));\n          cimg::swap((*this)(pos,1),(*this)(left,1));\n          cimg::swap((*this)(pos,2),(*this)(left,2));\n          cimg::swap((*this)(pos,3),(*this)(left,3));\n          pos = left;\n        }\n      }\n      return *this;\n    }\n\n    //! Apply recursive Deriche filter.\n    /**\n       \\param sigma Standard deviation of the filter.\n       \\param order Order of the filter. Can be <tt>{ 0=smooth-filter | 1=1st-derivative | 2=2nd-derivative }</tt>.\n       \\param axis Axis along which the filter is computed. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n       \\param boundary_conditions Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann }</tt>.\n    **/\n    CImg<T>& deriche(const float sigma, const unsigned int order=0, const char axis='x',\n                     const bool boundary_conditions=true) {\n#define _cimg_deriche_apply \\\n  CImg<Tfloat> Y(N); \\\n  Tfloat *ptrY = Y._data, yb = 0, yp = 0; \\\n  T xp = (T)0; \\\n  if (boundary_conditions) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \\\n  for (int m = 0; m<N; ++m) { \\\n    const T xc = *ptrX; ptrX+=off; \\\n    const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \\\n    xp = xc; yb = yp; yp = yc; \\\n  } \\\n  T xn = (T)0, xa = (T)0; \\\n  Tfloat yn = 0, ya = 0; \\\n  if (boundary_conditions) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \\\n  for (int n = N - 1; n>=0; --n) { \\\n    const T xc = *(ptrX-=off); \\\n    const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \\\n    xa = xn; xn = xc; ya = yn; yn = yc; \\\n    *ptrX = (T)(*(--ptrY)+yc); \\\n  }\n      const char naxis = cimg::uncase(axis);\n      const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100;\n      if (is_empty() || (nsigma<0.1f && !order)) return *this;\n      const float\n        nnsigma = nsigma<0.1f?0.1f:nsigma,\n        alpha = 1.695f/nnsigma,\n        ema = (float)std::exp(-alpha),\n        ema2 = (float)std::exp(-2*alpha),\n        b1 = -2*ema,\n        b2 = ema2;\n      float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0;\n      switch (order) {\n      case 0 : {\n        const float k = (1-ema)*(1-ema)/(1 + 2*alpha*ema-ema2);\n        a0 = k;\n        a1 = k*(alpha - 1)*ema;\n        a2 = k*(alpha + 1)*ema;\n        a3 = -k*ema2;\n      } break;\n      case 1 : {\n        const float k = -(1-ema)*(1-ema)*(1-ema)/(2*(ema + 1)*ema);\n        a0 = a3 = 0;\n        a1 = k*ema;\n        a2 = -a1;\n      } break;\n      case 2 : {\n        const float\n          ea = (float)std::exp(-alpha),\n          k = -(ema2 - 1)/(2*alpha*ema),\n          kn = (-2*(-1 + 3*ea - 3*ea*ea + ea*ea*ea)/(3*ea + 1 + 3*ea*ea + ea*ea*ea));\n        a0 = kn;\n        a1 = -kn*(1 + k*alpha)*ema;\n        a2 = kn*(1 - k*alpha)*ema;\n        a3 = -kn*ema2;\n      } break;\n      default :\n        throw CImgArgumentException(_cimg_instance\n                                    \"deriche(): Invalid specified filter order %u \"\n                                    \"(should be { 0=smoothing | 1=1st-derivative | 2=2nd-derivative }).\",\n                                    cimg_instance,\n                                    order);\n      }\n      coefp = (a0 + a1)/(1 + b1 + b2);\n      coefn = (a2 + a3)/(1 + b1 + b2);\n      switch (naxis) {\n      case 'x' : {\n        const int N = width();\n        const ulongT off = 1U;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forYZC(*this,y,z,c) { T *ptrX = data(0,y,z,c); _cimg_deriche_apply; }\n      } break;\n      case 'y' : {\n        const int N = height();\n        const ulongT off = (ulongT)_width;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forXZC(*this,x,z,c) { T *ptrX = data(x,0,z,c); _cimg_deriche_apply; }\n      } break;\n      case 'z' : {\n        const int N = depth();\n        const ulongT off = (ulongT)_width*_height;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forXYC(*this,x,y,c) { T *ptrX = data(x,y,0,c); _cimg_deriche_apply; }\n      } break;\n      default : {\n        const int N = spectrum();\n        const ulongT off = (ulongT)_width*_height*_depth;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forXYZ(*this,x,y,z) { T *ptrX = data(x,y,z,0); _cimg_deriche_apply; }\n      }\n      }\n      return *this;\n    }\n\n    //! Apply recursive Deriche filter \\newinstance.\n    CImg<Tfloat> get_deriche(const float sigma, const unsigned int order=0, const char axis='x',\n                             const bool boundary_conditions=true) const {\n      return CImg<Tfloat>(*this,false).deriche(sigma,order,axis,boundary_conditions);\n    }\n\n    // [internal] Apply a recursive filter (used by CImg<T>::vanvliet()).\n    /*\n       \\param ptr the pointer of the data\n       \\param filter the coefficient of the filter in the following order [n,n - 1,n - 2,n - 3].\n       \\param N size of the data\n       \\param off the offset between two data point\n       \\param order the order of the filter 0 (smoothing), 1st derivtive, 2nd derivative, 3rd derivative\n       \\param boundary_conditions Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann }</tt>.\n       \\note Boundary condition using B. Triggs method (IEEE trans on Sig Proc 2005).\n    */\n    static void _cimg_recursive_apply(T *data, const double filter[], const int N, const ulongT off,\n                                      const unsigned int order, const bool boundary_conditions) {\n      double val[4] = { 0 };  // res[n,n - 1,n - 2,n - 3,..] or res[n,n + 1,n + 2,n + 3,..]\n      const double\n        sumsq = filter[0], sum = sumsq * sumsq,\n        a1 = filter[1], a2 = filter[2], a3 = filter[3],\n        scaleM = 1.0 / ( (1.0 + a1 - a2 + a3) * (1.0 - a1 - a2 - a3) * (1.0 + a2 + (a1 - a3) * a3) );\n      double M[9]; // Triggs matrix\n      M[0] = scaleM * (-a3 * a1 + 1.0 - a3 * a3 - a2);\n      M[1] = scaleM * (a3 + a1) * (a2 + a3 * a1);\n      M[2] = scaleM * a3 * (a1 + a3 * a2);\n      M[3] = scaleM * (a1 + a3 * a2);\n      M[4] = -scaleM * (a2 - 1.0) * (a2 + a3 * a1);\n      M[5] = -scaleM * a3 * (a3 * a1 + a3 * a3 + a2 - 1.0);\n      M[6] = scaleM * (a3 * a1 + a2 + a1 * a1 - a2 * a2);\n      M[7] = scaleM * (a1 * a2 + a3 * a2 * a2 - a1 * a3 * a3 - a3 * a3 * a3 - a3 * a2 + a3);\n      M[8] = scaleM * a3 * (a1 + a3 * a2);\n      switch (order) {\n      case 0 : {\n        const double iplus = (boundary_conditions?data[(N - 1)*off]:0);\n        for (int pass = 0; pass<2; ++pass) {\n          if (!pass) {\n            for (int k = 1; k<4; ++k) val[k] = (boundary_conditions?*data/sumsq:0);\n          } else {\n            /* apply Triggs border condition */\n            const double\n              uplus = iplus/(1.0 - a1 - a2 - a3), vplus = uplus/(1.0 - a1 - a2 - a3),\n              unp  = val[1] - uplus, unp1 = val[2] - uplus, unp2 = val[3] - uplus;\n            val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2 + vplus) * sum;\n            val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2 + vplus) * sum;\n            val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2 + vplus) * sum;\n            *data = (T)val[0];\n            data -= off;\n            for (int k = 3; k>0; --k) val[k] = val[k - 1];\n          }\n          for (int n = pass; n<N; ++n) {\n            val[0] = (*data);\n            if (pass) val[0] *= sum;\n            for (int k = 1; k<4; ++k) val[0] += val[k] * filter[k];\n            *data = (T)val[0];\n            if (!pass) data += off; else data -= off;\n            for (int k = 3; k>0; --k) val[k] = val[k - 1];\n          }\n          if (!pass) data -= off;\n        }\n      } break;\n      case 1 : {\n        double x[3]; // [front,center,back]\n        for (int pass = 0; pass<2; ++pass) {\n          if (!pass) {\n            for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:0);\n            for (int k = 0; k<4; ++k) val[k] = 0;\n          } else {\n            /* apply Triggs border condition */\n            const double\n              unp  = val[1], unp1 = val[2], unp2 = val[3];\n            val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum;\n            val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum;\n            val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum;\n            *data = (T)val[0];\n            data -= off;\n            for (int k = 3; k>0; --k) val[k] = val[k - 1];\n          }\n          for (int n = pass; n<N - 1; ++n) {\n            if (!pass) {\n              x[0] = *(data + off);\n              val[0] = 0.5f * (x[0] - x[2]);\n            } else val[0] = (*data) * sum;\n            for (int k = 1; k<4; ++k) val[0] += val[k] * filter[k];\n            *data = (T)val[0];\n            if (!pass) {\n              data += off;\n              for (int k = 2; k>0; --k) x[k] = x[k - 1];\n            } else { data-=off;}\n            for (int k = 3; k>0; --k) val[k] = val[k - 1];\n          }\n          *data = (T)0;\n        }\n      } break;\n      case 2: {\n        double x[3]; // [front,center,back]\n        for (int pass = 0; pass<2; ++pass) {\n          if (!pass) {\n            for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:0);\n            for (int k = 0; k<4; ++k) val[k] = 0;\n          } else {\n            /* apply Triggs border condition */\n            const double\n              unp  = val[1], unp1 = val[2], unp2 = val[3];\n            val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum;\n            val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum;\n            val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum;\n            *data = (T)val[0];\n            data -= off;\n            for (int k = 3; k>0; --k) val[k] = val[k - 1];\n          }\n          for (int n = pass; n<N - 1; ++n) {\n            if (!pass) { x[0] = *(data + off); val[0] = (x[1] - x[2]); }\n            else { x[0] = *(data - off); val[0] = (x[2] - x[1]) * sum; }\n            for (int k = 1; k<4; ++k) val[0] += val[k]*filter[k];\n            *data = (T)val[0];\n            if (!pass) data += off; else data -= off;\n            for (int k = 2; k>0; --k) x[k] = x[k - 1];\n            for (int k = 3; k>0; --k) val[k] = val[k - 1];\n          }\n          *data = (T)0;\n        }\n      } break;\n      case 3: {\n        double x[3]; // [front,center,back]\n        for (int pass = 0; pass<2; ++pass) {\n          if (!pass) {\n            for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:0);\n            for (int k = 0; k<4; ++k) val[k] = 0;\n          } else {\n            /* apply Triggs border condition */\n            const double\n              unp = val[1], unp1 = val[2], unp2 = val[3];\n            val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum;\n            val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum;\n            val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum;\n            *data = (T)val[0];\n            data -= off;\n            for (int k = 3; k>0; --k) val[k] = val[k - 1];\n          }\n          for (int n = pass; n<N - 1; ++n) {\n            if (!pass) { x[0] = *(data + off); val[0] = (x[0] - 2*x[1] + x[2]); }\n            else { x[0] = *(data - off); val[0] = 0.5f * (x[2] - x[0]) * sum; }\n            for (int k = 1; k<4; ++k) val[0] += val[k] * filter[k];\n            *data = (T)val[0];\n            if (!pass) data += off; else data -= off;\n            for (int k = 2; k>0; --k) x[k] = x[k - 1];\n            for (int k = 3; k>0; --k) val[k] = val[k - 1];\n          }\n          *data = (T)0;\n        }\n      } break;\n      }\n    }\n\n    //! Van Vliet recursive Gaussian filter.\n    /**\n       \\param sigma standard deviation of the Gaussian filter\n       \\param order the order of the filter 0,1,2,3\n       \\param axis  Axis along which the filter is computed. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n       \\param boundary_conditions Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann }</tt>.\n       \\note dirichlet boundary condition has a strange behavior\n\n       I.T. Young, L.J. van Vliet, M. van Ginkel, Recursive Gabor filtering.\n       IEEE Trans. Sig. Proc., vol. 50, pp. 2799-2805, 2002.\n\n       (this is an improvement over Young-Van Vliet, Sig. Proc. 44, 1995)\n\n       Boundary conditions (only for order 0) using Triggs matrix, from\n       B. Triggs and M. Sdika. Boundary conditions for Young-van Vliet\n       recursive filtering. IEEE Trans. Signal Processing,\n       vol. 54, pp. 2365-2367, 2006.\n    **/\n    CImg<T>& vanvliet(const float sigma, const unsigned int order, const char axis='x',\n                      const bool boundary_conditions=true) {\n      if (is_empty()) return *this;\n      const char naxis = cimg::uncase(axis);\n      const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100;\n      if (is_empty() || (nsigma<0.5f && !order)) return *this;\n      const double\n        nnsigma = nsigma<0.5f?0.5f:nsigma,\n        m0 = 1.16680, m1 = 1.10783, m2 = 1.40586,\n        m1sq = m1 * m1, m2sq = m2 * m2,\n        q = (nnsigma<3.556?-0.2568 + 0.5784*nnsigma + 0.0561*nnsigma*nnsigma:2.5091 + 0.9804*(nnsigma - 3.556)),\n        qsq = q * q,\n        scale = (m0 + q) * (m1sq + m2sq + 2 * m1 * q + qsq),\n        b1 = -q * (2 * m0 * m1 + m1sq + m2sq + (2 * m0 + 4 * m1) * q + 3 * qsq) / scale,\n        b2 = qsq * (m0 + 2 * m1 + 3 * q) / scale,\n        b3 = -qsq * q / scale,\n        B = ( m0 * (m1sq + m2sq) ) / scale;\n      double filter[4];\n      filter[0] = B; filter[1] = -b1; filter[2] = -b2; filter[3] = -b3;\n      switch (naxis) {\n      case 'x' : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forYZC(*this,y,z,c)\n          _cimg_recursive_apply(data(0,y,z,c),filter,_width,1U,order,boundary_conditions);\n      } break;\n      case 'y' : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forXZC(*this,x,z,c)\n          _cimg_recursive_apply(data(x,0,z,c),filter,_height,(ulongT)_width,order,boundary_conditions);\n      } break;\n      case 'z' : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forXYC(*this,x,y,c)\n          _cimg_recursive_apply(data(x,y,0,c),filter,_depth,(ulongT)_width*_height,\n                                order,boundary_conditions);\n      } break;\n      default : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forXYZ(*this,x,y,z)\n          _cimg_recursive_apply(data(x,y,z,0),filter,_spectrum,(ulongT)_width*_height*_depth,\n                                order,boundary_conditions);\n      }\n      }\n      return *this;\n    }\n\n    //! Blur image using Van Vliet recursive Gaussian filter. \\newinstance.\n    CImg<Tfloat> get_vanvliet(const float sigma, const unsigned int order, const char axis='x',\n                              const bool boundary_conditions=true) const {\n      return CImg<Tfloat>(*this,false).vanvliet(sigma,order,axis,boundary_conditions);\n    }\n\n    //! Blur image.\n    /**\n       \\param sigma_x Standard deviation of the blur, along the X-axis.\n       \\param sigma_y Standard deviation of the blur, along the Y-axis.\n       \\param sigma_z Standard deviation of the blur, along the Z-axis.\n       \\param boundary_conditions Boundary conditions. Can be <tt>{ false=dirichlet | true=neumann }</tt>.\n       \\param is_gaussian Tells if the blur uses a gaussian (\\c true) or quasi-gaussian (\\c false) kernel.\n       \\note\n       - The blur is computed as a 0-order Deriche filter. This is not a gaussian blur.\n       - This is a recursive algorithm, not depending on the values of the standard deviations.\n       \\see deriche(), vanvliet().\n    **/\n    CImg<T>& blur(const float sigma_x, const float sigma_y, const float sigma_z,\n                  const bool boundary_conditions=true, const bool is_gaussian=false) {\n      if (is_empty()) return *this;\n      if (is_gaussian) {\n        if (_width>1) vanvliet(sigma_x,0,'x',boundary_conditions);\n        if (_height>1) vanvliet(sigma_y,0,'y',boundary_conditions);\n        if (_depth>1) vanvliet(sigma_z,0,'z',boundary_conditions);\n      } else {\n        if (_width>1) deriche(sigma_x,0,'x',boundary_conditions);\n        if (_height>1) deriche(sigma_y,0,'y',boundary_conditions);\n        if (_depth>1) deriche(sigma_z,0,'z',boundary_conditions);\n      }\n      return *this;\n    }\n\n    //! Blur image \\newinstance.\n    CImg<Tfloat> get_blur(const float sigma_x, const float sigma_y, const float sigma_z,\n                          const bool boundary_conditions=true, const bool is_gaussian=false) const {\n      return CImg<Tfloat>(*this,false).blur(sigma_x,sigma_y,sigma_z,boundary_conditions,is_gaussian);\n    }\n\n    //! Blur image isotropically.\n    /**\n       \\param sigma Standard deviation of the blur.\n       \\param boundary_conditions Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann }</tt>.a\n       \\see deriche(), vanvliet().\n    **/\n    CImg<T>& blur(const float sigma, const bool boundary_conditions=true, const bool is_gaussian=false) {\n      const float nsigma = sigma>=0?sigma:-sigma*cimg::max(_width,_height,_depth)/100;\n      return blur(nsigma,nsigma,nsigma,boundary_conditions,is_gaussian);\n    }\n\n    //! Blur image isotropically \\newinstance.\n    CImg<Tfloat> get_blur(const float sigma, const bool boundary_conditions=true, const bool is_gaussian=false) const {\n      return CImg<Tfloat>(*this,false).blur(sigma,boundary_conditions,is_gaussian);\n    }\n\n    //! Blur image anisotropically, directed by a field of diffusion tensors.\n    /**\n       \\param G Field of square roots of diffusion tensors/vectors used to drive the smoothing.\n       \\param amplitude Amplitude of the smoothing.\n       \\param dl Spatial discretization.\n       \\param da Angular discretization.\n       \\param gauss_prec Precision of the diffusion process.\n       \\param interpolation_type Interpolation scheme.\n         Can be <tt>{ 0=nearest-neighbor | 1=linear | 2=Runge-Kutta }</tt>.\n       \\param is_fast_approx Tells if a fast approximation of the gaussian function is used or not.\n    **/\n    template<typename t>\n    CImg<T>& blur_anisotropic(const CImg<t>& G,\n                              const float amplitude=60, const float dl=0.8f, const float da=30,\n                              const float gauss_prec=2, const unsigned int interpolation_type=0,\n                              const bool is_fast_approx=1) {\n\n      // Check arguments and init variables\n      if (!is_sameXYZ(G) || (G._spectrum!=3 && G._spectrum!=6))\n        throw CImgArgumentException(_cimg_instance\n                                    \"blur_anisotropic(): Invalid specified diffusion tensor field (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    G._width,G._height,G._depth,G._spectrum,G._data);\n\n      if (is_empty() || amplitude<=0 || dl<0) return *this;\n      const bool is_3d = (G._spectrum==6);\n      T val_min, val_max = max_min(val_min);\n\n      if (da<=0) {  // Iterated oriented Laplacians\n        CImg<Tfloat> velocity(_width,_height,_depth,_spectrum);\n        for (unsigned int iteration = 0; iteration<(unsigned int)amplitude; ++iteration) {\n          Tfloat *ptrd = velocity._data, veloc_max = 0;\n          if (is_3d) // 3d version\n            cimg_forC(*this,c) {\n              cimg_test_abort();\n              CImg_3x3x3(I,Tfloat);\n              cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {\n                const Tfloat\n                  ixx = Incc + Ipcc - 2*Iccc,\n                  ixy = (Innc + Ippc - Inpc - Ipnc)/4,\n                  ixz = (Incn + Ipcp - Incp - Ipcn)/4,\n                  iyy = Icnc + Icpc - 2*Iccc,\n                  iyz = (Icnn + Icpp - Icnp - Icpn)/4,\n                  izz = Iccn + Iccp - 2*Iccc,\n                  veloc = (Tfloat)(G(x,y,z,0)*ixx + 2*G(x,y,z,1)*ixy + 2*G(x,y,z,2)*ixz +\n                                   G(x,y,z,3)*iyy + 2*G(x,y,z,4)*iyz + G(x,y,z,5)*izz);\n                *(ptrd++) = veloc;\n                if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;\n              }\n            }\n          else // 2d version\n            cimg_forZC(*this,z,c) {\n              cimg_test_abort();\n              CImg_3x3(I,Tfloat);\n              cimg_for3x3(*this,x,y,z,c,I,Tfloat) {\n                const Tfloat\n                  ixx = Inc + Ipc - 2*Icc,\n                  ixy = (Inn + Ipp - Inp - Ipn)/4,\n                  iyy = Icn + Icp - 2*Icc,\n                  veloc = (Tfloat)(G(x,y,0,0)*ixx + 2*G(x,y,0,1)*ixy + G(x,y,0,2)*iyy);\n                *(ptrd++) = veloc;\n                if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;\n              }\n            }\n          if (veloc_max>0) *this+=(velocity*=dl/veloc_max);\n        }\n      } else { // LIC-based smoothing.\n        const ulongT whd = (ulongT)_width*_height*_depth;\n        const float sqrt2amplitude = (float)std::sqrt(2*amplitude);\n        const int dx1 = width() - 1, dy1 = height() - 1, dz1 = depth() - 1;\n        CImg<Tfloat> res(_width,_height,_depth,_spectrum,0), W(_width,_height,_depth,is_3d?4:3), val(_spectrum,1,1,1,0);\n        int N = 0;\n        if (is_3d) { // 3d version\n          for (float phi = (180%(int)da)/2.0f; phi<=180; phi+=da) {\n            const float phir = (float)(phi*cimg::PI/180), datmp = (float)(da/std::cos(phir)),\n              da2 = datmp<1?360.0f:datmp;\n            for (float theta = 0; theta<360; (theta+=da2),++N) {\n              const float\n                thetar = (float)(theta*cimg::PI/180),\n                vx = (float)(std::cos(thetar)*std::cos(phir)),\n                vy = (float)(std::sin(thetar)*std::cos(phir)),\n                vz = (float)std::sin(phir);\n              const t\n                *pa = G.data(0,0,0,0), *pb = G.data(0,0,0,1), *pc = G.data(0,0,0,2),\n                *pd = G.data(0,0,0,3), *pe = G.data(0,0,0,4), *pf = G.data(0,0,0,5);\n              Tfloat *pd0 = W.data(0,0,0,0), *pd1 = W.data(0,0,0,1), *pd2 = W.data(0,0,0,2), *pd3 = W.data(0,0,0,3);\n              cimg_forXYZ(G,xg,yg,zg) {\n                const t a = *(pa++), b = *(pb++), c = *(pc++), d = *(pd++), e = *(pe++), f = *(pf++);\n                const float\n                  u = (float)(a*vx + b*vy + c*vz),\n                  v = (float)(b*vx + d*vy + e*vz),\n                  w = (float)(c*vx + e*vy + f*vz),\n                  n = (float)std::sqrt(1e-5 + u*u + v*v + w*w),\n                  dln = dl/n;\n                *(pd0++) = (Tfloat)(u*dln);\n                *(pd1++) = (Tfloat)(v*dln);\n                *(pd2++) = (Tfloat)(w*dln);\n                *(pd3++) = (Tfloat)n;\n              }\n\n              cimg_test_abort();\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=2) firstprivate(val)\n#endif\n              cimg_forXYZ(*this,x,y,z) {\n                val.fill(0);\n                const float\n                  n = (float)W(x,y,z,3),\n                  fsigma = (float)(n*sqrt2amplitude),\n                  fsigma2 = 2*fsigma*fsigma,\n                  length = gauss_prec*fsigma;\n                float\n                  S = 0,\n                  X = (float)x,\n                  Y = (float)y,\n                  Z = (float)z;\n                switch (interpolation_type) {\n                case 0 : { // Nearest neighbor\n                  for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {\n                    const int\n                      cx = (int)(X + 0.5f),\n                      cy = (int)(Y + 0.5f),\n                      cz = (int)(Z + 0.5f);\n                    const float\n                      u = (float)W(cx,cy,cz,0),\n                      v = (float)W(cx,cy,cz,1),\n                      w = (float)W(cx,cy,cz,2);\n                    if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)(*this)(cx,cy,cz,c); ++S; }\n                    else {\n                      const float coef = (float)std::exp(-l*l/fsigma2);\n                      cimg_forC(*this,c) val[c]+=(Tfloat)(coef*(*this)(cx,cy,cz,c));\n                      S+=coef;\n                    }\n                    X+=u; Y+=v; Z+=w;\n                  }\n                } break;\n                case 1 : { // Linear interpolation\n                  for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {\n                    const float\n                      u = (float)(W._linear_atXYZ(X,Y,Z,0)),\n                      v = (float)(W._linear_atXYZ(X,Y,Z,1)),\n                      w = (float)(W._linear_atXYZ(X,Y,Z,2));\n                    if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXYZ(X,Y,Z,c); ++S; }\n                    else {\n                      const float coef = (float)std::exp(-l*l/fsigma2);\n                      cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,c));\n                      S+=coef;\n                    }\n                    X+=u; Y+=v; Z+=w;\n                  }\n                } break;\n                default : { // 2nd order Runge Kutta\n                  for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {\n                    const float\n                      u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)),\n                      v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)),\n                      w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2)),\n                      u = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,0)),\n                      v = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,1)),\n                      w = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,2));\n                    if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXYZ(X,Y,Z,c); ++S; }\n                    else {\n                      const float coef = (float)std::exp(-l*l/fsigma2);\n                      cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,c));\n                      S+=coef;\n                    }\n                    X+=u; Y+=v; Z+=w;\n                  }\n                } break;\n                }\n                Tfloat *ptrd = res.data(x,y,z);\n                if (S>0) cimg_forC(res,c) { *ptrd+=val[c]/S; ptrd+=whd; }\n                else cimg_forC(res,c) { *ptrd+=(Tfloat)((*this)(x,y,z,c)); ptrd+=whd; }\n              }\n            }\n          }\n        } else { // 2d LIC algorithm\n          for (float theta = (360%(int)da)/2.0f; theta<360; (theta+=da),++N) {\n            const float thetar = (float)(theta*cimg::PI/180),\n              vx = (float)(std::cos(thetar)), vy = (float)(std::sin(thetar));\n            const t *pa = G.data(0,0,0,0), *pb = G.data(0,0,0,1), *pc = G.data(0,0,0,2);\n            Tfloat *pd0 = W.data(0,0,0,0), *pd1 = W.data(0,0,0,1), *pd2 = W.data(0,0,0,2);\n            cimg_forXY(G,xg,yg) {\n              const t a = *(pa++), b = *(pb++), c = *(pc++);\n              const float\n                u = (float)(a*vx + b*vy),\n                v = (float)(b*vx + c*vy),\n                n = (float)std::sqrt(1e-5 + u*u + v*v),\n                dln = dl/n;\n              *(pd0++) = (Tfloat)(u*dln);\n              *(pd1++) = (Tfloat)(v*dln);\n              *(pd2++) = (Tfloat)n;\n            }\n\n            cimg_test_abort();\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width>=256 && _height>=2) firstprivate(val)\n#endif\n            cimg_forXY(*this,x,y) {\n              val.fill(0);\n              const float\n                n = (float)W(x,y,0,2),\n                fsigma = (float)(n*sqrt2amplitude),\n                fsigma2 = 2*fsigma*fsigma,\n                length = gauss_prec*fsigma;\n              float\n                S = 0,\n                X = (float)x,\n                Y = (float)y;\n              switch (interpolation_type) {\n              case 0 : { // Nearest-neighbor\n                for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {\n                  const int\n                    cx = (int)(X + 0.5f),\n                    cy = (int)(Y + 0.5f);\n                  const float\n                    u = (float)W(cx,cy,0,0),\n                    v = (float)W(cx,cy,0,1);\n                  if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)(*this)(cx,cy,0,c); ++S; }\n                  else {\n                    const float coef = (float)std::exp(-l*l/fsigma2);\n                    cimg_forC(*this,c) val[c]+=(Tfloat)(coef*(*this)(cx,cy,0,c));\n                    S+=coef;\n                  }\n                  X+=u; Y+=v;\n                }\n              } break;\n              case 1 : { // Linear interpolation\n                for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {\n                  const float\n                    u = (float)(W._linear_atXY(X,Y,0,0)),\n                    v = (float)(W._linear_atXY(X,Y,0,1));\n                  if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXY(X,Y,0,c); ++S; }\n                  else {\n                    const float coef = (float)std::exp(-l*l/fsigma2);\n                    cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXY(X,Y,0,c));\n                    S+=coef;\n                  }\n                  X+=u; Y+=v;\n                }\n              } break;\n              default : { // 2nd-order Runge-kutta interpolation\n                for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {\n                  const float\n                    u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)),\n                    v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1)),\n                    u = (float)(W._linear_atXY(X + u0,Y + v0,0,0)),\n                    v = (float)(W._linear_atXY(X + u0,Y + v0,0,1));\n                  if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXY(X,Y,0,c); ++S; }\n                  else {\n                    const float coef = (float)std::exp(-l*l/fsigma2);\n                    cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXY(X,Y,0,c));\n                    S+=coef;\n                  }\n                  X+=u; Y+=v;\n                }\n              }\n              }\n              Tfloat *ptrd = res.data(x,y);\n              if (S>0) cimg_forC(res,c) { *ptrd+=val[c]/S; ptrd+=whd; }\n              else cimg_forC(res,c) { *ptrd+=(Tfloat)((*this)(x,y,0,c)); ptrd+=whd; }\n            }\n          }\n        }\n        const Tfloat *ptrs = res._data;\n        cimg_for(*this,ptrd,T) {\n          const Tfloat val = *(ptrs++)/N;\n          *ptrd = val<val_min?val_min:(val>val_max?val_max:(T)val);\n        }\n      }\n      return *this;\n    }\n\n    //! Blur image anisotropically, directed by a field of diffusion tensors \\newinstance.\n    template<typename t>\n    CImg<Tfloat> get_blur_anisotropic(const CImg<t>& G,\n                                      const float amplitude=60, const float dl=0.8f, const float da=30,\n                                      const float gauss_prec=2, const unsigned int interpolation_type=0,\n                                      const bool is_fast_approx=true) const {\n      return CImg<Tfloat>(*this,false).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,is_fast_approx);\n    }\n\n    //! Blur image anisotropically, in an edge-preserving way.\n    /**\n       \\param amplitude Amplitude of the smoothing.\n       \\param sharpness Sharpness.\n       \\param anisotropy Anisotropy.\n       \\param alpha Standard deviation of the gradient blur.\n       \\param sigma Standard deviation of the structure tensor blur.\n       \\param dl Spatial discretization.\n       \\param da Angular discretization.\n       \\param gauss_prec Precision of the diffusion process.\n       \\param interpolation_type Interpolation scheme.\n         Can be <tt>{ 0=nearest-neighbor | 1=linear | 2=Runge-Kutta }</tt>.\n       \\param is_fast_approx Tells if a fast approximation of the gaussian function is used or not.\n     **/\n    CImg<T>& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f,\n                              const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,\n                              const float gauss_prec=2, const unsigned int interpolation_type=0,\n                              const bool is_fast_approx=true) {\n      return blur_anisotropic(get_diffusion_tensors(sharpness,anisotropy,alpha,sigma,interpolation_type!=3),\n                              amplitude,dl,da,gauss_prec,interpolation_type,is_fast_approx);\n    }\n\n    //! Blur image anisotropically, in an edge-preserving way \\newinstance.\n    CImg<Tfloat> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f,\n                                      const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,\n                                      const float da=30, const float gauss_prec=2,\n                                      const unsigned int interpolation_type=0,\n                                      const bool is_fast_approx=true) const {\n      return CImg<Tfloat>(*this,false).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,\n                                                        interpolation_type,is_fast_approx);\n    }\n\n    //! Blur image, with the joint bilateral filter.\n    /**\n       \\param guide Image used to model the smoothing weights.\n       \\param sigma_x Amount of blur along the X-axis.\n       \\param sigma_y Amount of blur along the Y-axis.\n       \\param sigma_z Amount of blur along the Z-axis.\n       \\param sigma_r Amount of blur along the value axis.\n       \\param sampling_x Amount of downsampling along the X-axis used for the approximation.\n         Defaults (0) to sigma_x.\n       \\param sampling_y Amount of downsampling along the Y-axis used for the approximation.\n         Defaults (0) to sigma_y.\n       \\param sampling_z Amount of downsampling along the Z-axis used for the approximation.\n         Defaults (0) to sigma_z.\n       \\param sampling_r Amount of downsampling along the value axis used for the approximation.\n         Defaults (0) to sigma_r.\n       \\note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006\n       (extended for 3d volumetric images).\n       It is based on the reference implementation http://people.csail.mit.edu/jiawen/software/bilateralFilter.m\n    **/\n    template<typename t>\n    CImg<T>& blur_bilateral(const CImg<t>& guide,\n                            const float sigma_x, const float sigma_y,\n                            const float sigma_z, const float sigma_r,\n                            const float sampling_x, const float sampling_y,\n                            const float sampling_z, const float sampling_r) {\n      if (!is_sameXYZ(guide))\n        throw CImgArgumentException(_cimg_instance\n                                    \"blur_bilateral(): Invalid size for specified guide image (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    guide._width,guide._height,guide._depth,guide._spectrum,guide._data);\n      if (is_empty()) return *this;\n      T edge_min, edge_max = guide.max_min(edge_min);\n      if (edge_min==edge_max || sigma_r == 0.) return *this;\n      const float\n        edge_delta = (float)(edge_max - edge_min),\n        _sigma_x = sigma_x>=0?sigma_x:-sigma_x*_width/100,\n        _sigma_y = sigma_y>=0?sigma_y:-sigma_y*_height/100,\n        _sigma_z = sigma_z>=0?sigma_z:-sigma_z*_depth/100,\n        _sigma_r = sigma_r>=0?sigma_r:-sigma_r*(edge_max-edge_min)/100,\n        _sampling_x = sampling_x?sampling_x:cimg::max(_sigma_x,1.0f),\n        _sampling_y = sampling_y?sampling_y:cimg::max(_sigma_y,1.0f),\n        _sampling_z = sampling_z?sampling_z:cimg::max(_sigma_z,1.0f),\n        _sampling_r = sampling_r?sampling_r:cimg::max(_sigma_r,edge_delta/256),\n        derived_sigma_x = _sigma_x / _sampling_x,\n        derived_sigma_y = _sigma_y / _sampling_y,\n        derived_sigma_z = _sigma_z / _sampling_z,\n        derived_sigma_r = _sigma_r / _sampling_r;\n      const int\n        padding_x = (int)(2*derived_sigma_x) + 1,\n        padding_y = (int)(2*derived_sigma_y) + 1,\n        padding_z = (int)(2*derived_sigma_z) + 1,\n        padding_r = (int)(2*derived_sigma_r) + 1;\n      const unsigned int\n        bx = (unsigned int)((_width  - 1)/_sampling_x + 1 + 2*padding_x),\n        by = (unsigned int)((_height - 1)/_sampling_y + 1 + 2*padding_y),\n        bz = (unsigned int)((_depth  - 1)/_sampling_z + 1 + 2*padding_z),\n        br = (unsigned int)(edge_delta/_sampling_r + 1 + 2*padding_r);\n      if (bx>0 || by>0 || bz>0 || br>0) {\n        const bool is_3d = (_depth>1);\n        if (is_3d) { // 3d version of the algorithm\n          CImg<floatT> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br);\n          cimg_forC(*this,c) {\n            const CImg<t> _guide = guide.get_shared_channel(c%guide._spectrum);\n            bgrid.fill(0); bgridw.fill(0);\n            cimg_forXYZ(*this,x,y,z) {\n              const T val = (*this)(x,y,z,c);\n              const float edge = (float)_guide(x,y,z);\n              const int\n                X = (int)cimg::round(x/_sampling_x) + padding_x,\n                Y = (int)cimg::round(y/_sampling_y) + padding_y,\n                Z = (int)cimg::round(z/_sampling_z) + padding_z,\n                R = (int)cimg::round((edge-edge_min)/_sampling_r) + padding_r;\n              bgrid(X,Y,Z,R)+=(float)val;\n              bgridw(X,Y,Z,R)+=1;\n            }\n            bgrid.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false);\n            bgridw.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false);\n            cimg_forXYZ(*this,x,y,z) {\n              const float edge = (float)_guide(x,y,z);\n              const float\n                X = x/_sampling_x + padding_x,\n                Y = y/_sampling_y + padding_y,\n                Z = z/_sampling_z + padding_z,\n                R = (edge-edge_min)/_sampling_r + padding_r;\n              const float bval0 = bgrid.linear_atXYZC(X,Y,Z,R), bval1 = bgridw.linear_atXYZC(X,Y,Z,R);\n              (*this)(x,y,z,c) = (T)(bval0/bval1);\n            }\n          }\n        } else { // 2d version of the algorithm\n          CImg<floatT> bgrid(bx,by,br,2);\n          cimg_forC(*this,c) {\n            const CImg<t> _guide = guide.get_shared_channel(c%guide._spectrum);\n            bgrid.fill(0);\n            cimg_forXY(*this,x,y) {\n              const T val = (*this)(x,y,c);\n              const float edge = (float)_guide(x,y);\n              const int\n                X = (int)cimg::round(x/_sampling_x) + padding_x,\n                Y = (int)cimg::round(y/_sampling_y) + padding_y,\n                R = (int)cimg::round((edge-edge_min)/_sampling_r) + padding_r;\n              bgrid(X,Y,R,0)+=(float)val;\n              bgrid(X,Y,R,1)+=1;\n            }\n            bgrid.blur(derived_sigma_x,derived_sigma_y,0,true).blur(0,0,derived_sigma_r,false);\n            cimg_forXY(*this,x,y) {\n              const float edge = (float)_guide(x,y);\n              const float\n                X = x/_sampling_x + padding_x,\n                Y = y/_sampling_y + padding_y,\n                R = (edge-edge_min)/_sampling_r + padding_r;\n              const float bval0 = bgrid.linear_atXYZ(X,Y,R,0), bval1 = bgrid.linear_atXYZ(X,Y,R,1);\n              (*this)(x,y,c) = (T)(bval0/bval1);\n            }\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Blur image, with the joint bilateral filter \\newinstance.\n    template<typename t>\n    CImg<Tfloat> get_blur_bilateral(const CImg<t>& guide,\n                                    const float sigma_x, const float sigma_y,\n                                    const float sigma_z, const float sigma_r,\n                                    const float sampling_x, const float sampling_y,\n                                    const float sampling_z, const float sampling_r) const {\n      return CImg<Tfloat>(*this,false).blur_bilateral(guide,sigma_x,sigma_y,sigma_z,sigma_r,\n                                                      sampling_x,sampling_y,sampling_z,sampling_r);\n    }\n\n    //! Blur image using the joint bilateral filter.\n    /**\n       \\param guide Image used to model the smoothing weights.\n       \\param sigma_s Amount of blur along the XYZ-axes.\n       \\param sigma_r Amount of blur along the value axis.\n       \\param sampling_s Amount of downsampling along the XYZ-axes used for the approximation. Defaults to sigma_s.\n       \\param sampling_r Amount of downsampling along the value axis used for the approximation. Defaults to sigma_r.\n    **/\n    template<typename t>\n    CImg<T>& blur_bilateral(const CImg<t>& guide,\n                            const float sigma_s, const float sigma_r,\n                            const float sampling_s=0, const float sampling_r=0) {\n      const float _sigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100;\n      return blur_bilateral(guide,_sigma_s,_sigma_s,_sigma_s,sigma_r,sampling_s,sampling_s,sampling_s,sampling_r);\n    }\n\n    //! Blur image using the bilateral filter \\newinstance.\n    template<typename t>\n    CImg<Tfloat> get_blur_bilateral(const CImg<t>& guide,\n                                    const float sigma_s, const float sigma_r,\n                                    const float sampling_s=0, const float sampling_r=0) const {\n      return CImg<Tfloat>(*this,false).blur_bilateral(guide,sigma_s,sigma_r,sampling_s,sampling_r);\n    }\n\n    // [internal] Apply a box filter (used by CImg<T>::boxfilter() and CImg<T>::blur_box()).\n    /*\n      \\param ptr the pointer of the data\n      \\param N size of the data\n      \\param sigma sigma of the box filter\n      \\param off the offset between two data point\n      \\param order the order of the filter 0 (smoothing), 1st derivtive and 2nd derivative.\n      \\param boundary_conditions Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann }</tt>.\n    */\n    static void _cimg_blur_box_apply(T *ptr, const float sigma, const int N, const ulongT off,\n                                     const int order, const bool boundary_conditions) {\n      // Smooth.\n      if (sigma>1) {\n        const int w2 = (int)(sigma - 1)/2;\n        const unsigned int winsize = 2*w2 + 1U;\n        const double frac = (sigma - winsize)/2.0;\n        CImg<Tfloat> win(winsize);\n        Tfloat sum = 0; // window sum\n        for (int x = -w2; x<=w2; ++x) {\n          win[x + w2] = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x);\n          sum+=win[x + w2];\n        }\n        int ifirst = 0, ilast = 2*w2;\n        Tfloat\n          prev = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,-w2 - 1),\n          next = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,w2 + 1);\n        for (int x = 0; x < N - 1; ++x) {\n          const double sum2 = sum + frac * (prev + next);\n          ptr[x*off] = (T)(sum2/sigma);\n          prev = win[ifirst];\n          sum-=prev;\n          ifirst = (int)((ifirst + 1)%winsize);\n          ilast = (int)((ilast + 1)%winsize);\n          win[ilast] = next;\n          sum+=next;\n          next = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x + w2 + 2);\n        }\n        const double sum2 = sum + frac * (prev + next);\n        ptr[(N - 1)*off] = (T)(sum2/sigma);\n      }\n\n      // Derive.\n      switch (order) {\n      case 0 :\n        break;\n      case 1 : {\n        Tfloat\n          p = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,-1),\n          c = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,0),\n          n = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,1);\n        for (int x = 0; x<N - 1; ++x) {\n          ptr[x*off] = (T)((n-p)/2.0);\n          p = c;\n          c = n;\n          n = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x + 2);\n        }\n        ptr[(N - 1)*off] = (T)((n-p)/2.0);\n      } break;\n      case 2: {\n        Tfloat\n          p = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,-1),\n          c = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,0),\n          n = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,1);\n        for (int x = 0; x<N - 1; ++x) {\n          ptr[x*off] = (T)(n - 2*c + p);\n          p = c;\n          c = n;\n          n = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x + 2);\n        }\n        ptr[(N - 1)*off] = (T)(n - 2*c + p);\n      } break;\n      }\n    }\n\n    static T __cimg_blur_box_apply(T *ptr, const int N, const ulongT off,\n                                   const bool boundary_conditions, const int x) {\n      if (x<0) return boundary_conditions?ptr[0]:T();\n      if (x>=N) return boundary_conditions?ptr[(N - 1)*off]:T();\n      return ptr[x*off];\n    }\n\n    // Apply box filter of order 0,1,2.\n    /**\n      \\param sigma sigma of the box filter\n      \\param order the order of the filter 0,1 or 2.\n      \\param axis  Axis along which the filter is computed. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n      \\param boundary_conditions Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann }</tt>.\n    **/\n    CImg<T>& boxfilter(const float sigma, const int order, const char axis='x',\n                       const bool boundary_conditions=true) {\n      if (is_empty() || !sigma || (sigma<=1 && !order)) return *this;\n      const char naxis = cimg::uncase(axis);\n      const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100;\n      switch (naxis) {\n      case 'x' : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forYZC(*this,y,z,c)\n          _cimg_blur_box_apply(data(0,y,z,c),nsigma,_width,1U,order,boundary_conditions);\n      } break;\n      case 'y' : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forXZC(*this,x,z,c)\n          _cimg_blur_box_apply(data(x,0,z,c),nsigma,_height,(ulongT)_width,order,boundary_conditions);\n      } break;\n      case 'z' : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forXYC(*this,x,y,c)\n          _cimg_blur_box_apply(data(x,y,0,c),nsigma,_depth,(ulongT)_width*_height,order,boundary_conditions);\n      } break;\n      default : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16)\n#endif\n        cimg_forXYZ(*this,x,y,z)\n          _cimg_blur_box_apply(data(x,y,z,0),nsigma,_spectrum,(ulongT)_width*_height*_depth,\n                               order,boundary_conditions);\n      }\n      }\n      return *this;\n    }\n\n    // Apply box filter of order 0,1 or 2 \\newinstance.\n    CImg<Tfloat> get_boxfilter(const float sigma, const int order, const char axis='x',\n                               const bool boundary_conditions=true) const {\n      return CImg<Tfloat>(*this,false).boxfilter(sigma,order,axis,boundary_conditions);\n    }\n\n    //! Blur image with a box filter.\n    /**\n       \\param sigma_x Size of the box window, along the X-axis.\n       \\param sigma_y Size of the box window, along the Y-axis.\n       \\param sigma_z Size of the box window, along the Z-axis.\n       \\param boundary_conditions Boundary conditions. Can be <tt>{ false=dirichlet | true=neumann }</tt>.\n       \\note\n       - This is a recursive algorithm, not depending on the values of the box kernel size.\n       \\see blur().\n    **/\n    CImg<T>& blur_box(const float sigma_x, const float sigma_y, const float sigma_z,\n                      const bool boundary_conditions=true) {\n      if (is_empty()) return *this;\n      if (_width>1) boxfilter(sigma_x,0,'x',boundary_conditions);\n      if (_height>1) boxfilter(sigma_y,0,'y',boundary_conditions);\n      if (_depth>1) boxfilter(sigma_z,0,'z',boundary_conditions);\n      return *this;\n    }\n\n    //! Blur image with a box filter \\newinstance.\n    CImg<Tfloat> get_blur_box(const float sigma_x, const float sigma_y, const float sigma_z,\n                              const bool boundary_conditions=true) const {\n      return CImg<Tfloat>(*this,false).blur_box(sigma_x,sigma_y,sigma_z,boundary_conditions);\n    }\n\n    //! Blur image with a box filter.\n    /**\n       \\param sigma Size of the box window.\n       \\param boundary_conditions Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann }</tt>.a\n       \\see deriche(), vanvliet().\n    **/\n    CImg<T>& blur_box(const float sigma, const bool boundary_conditions=true) {\n      const float nsigma = sigma>=0?sigma:-sigma*cimg::max(_width,_height,_depth)/100;\n      return blur_box(nsigma,nsigma,nsigma,boundary_conditions);\n    }\n\n    //! Blur image with a box filter \\newinstance.\n    CImg<Tfloat> get_blur_box(const float sigma, const bool boundary_conditions=true) const {\n      return CImg<Tfloat>(*this,false).blur_box(sigma,boundary_conditions);\n    }\n\n    //! Blur image, with the image guided filter.\n    /**\n       \\param guide Image used to guide the smoothing process.\n       \\param radius Spatial radius.\n       \\param regularization Regularization parameter.\n\n       \\note This method implements the filtering algorithm described in:\n       He, Kaiming; Sun, Jian; Tang, Xiaoou, \"Guided Image Filtering,\" Pattern Analysis and Machine Intelligence,\n       IEEE Transactions on , vol.35, no.6, pp.1397,1409, June 2013\n    **/\n    template<typename t>\n    CImg<T>& blur_guided(const CImg<t>& guide, const float radius, const float regularization) {\n      return get_blur_guided(guide,radius,regularization).move_to(*this);\n    }\n\n    //! Blur image, with the image guided filter \\newinstance.\n    template<typename t>\n    CImg<Tfloat> get_blur_guided(const CImg<t>& guide, const float radius, const float regularization) const {\n      if (!is_sameXYZ(guide))\n        throw CImgArgumentException(_cimg_instance\n                                    \"blur_guided(): Invalid size for specified guide image (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    guide._width,guide._height,guide._depth,guide._spectrum,guide._data);\n      if (is_empty() || !radius) return *this;\n      const int _radius = radius>=0?(int)radius:(int)(-radius*cimg::max(_width,_height,_depth)/100);\n      const unsigned int psize = (unsigned int)(1 + 2*_radius);\n      const CImg<uintT> N = CImg<uintT>(_width,_height,_depth,1,1)._blur_guided(psize);\n      CImg<Tfloat>\n        mean_I = CImg<Tfloat>(guide,false)._blur_guided(psize).div(N),\n        mean_p = CImg<Tfloat>(*this,false)._blur_guided(psize).div(N),\n        cov_Ip = CImg<Tfloat>(*this,false).mul(guide)._blur_guided(psize).div(N)-=mean_p.get_mul(mean_I),\n        var_I = CImg<Tfloat>(guide,false).sqr()._blur_guided(psize).div(N)-=mean_I.get_sqr(),\n        &a = cov_Ip.div(var_I+=regularization),\n        &b = mean_p-=a.get_mul(mean_I);\n      a._blur_guided(psize).div(N);\n      b._blur_guided(psize).div(N);\n      return a.mul(guide)+=b;\n    }\n\n    // [internal] Perform box filter with dirichlet boundary conditions.\n    CImg<T>& _blur_guided(const unsigned int psize) {\n      const int p1 = (int)psize/2, p2 = (int)psize - p1;\n      if (_depth!=1) {\n        CImg<floatT> cumul = get_cumulate('z'), cumul2 = cumul.get_shift(0,0,p2,0,1);\n        (cumul.shift(0,0,-p1,0,1)-=cumul2).move_to(*this);\n      }\n      if (_height!=1) {\n        CImg<floatT> cumul = get_cumulate('y'), cumul2 = cumul.get_shift(0,p2,0,0,1);\n        (cumul.shift(0,-p1,0,0,1)-=cumul2).move_to(*this);\n      }\n      if (_width!=1) {\n        CImg<floatT> cumul = get_cumulate('x'), cumul2 = cumul.get_shift(p2,0,0,0,1);\n        (cumul.shift(-p1,0,0,0,1)-=cumul2).move_to(*this);\n      }\n      return *this;\n    }\n\n    //! Blur image using patch-based space.\n    /**\n       \\param sigma_s Amount of blur along the XYZ-axes.\n       \\param sigma_p Amount of blur along the value axis.\n       \\param patch_size Size of the patchs.\n       \\param lookup_size Size of the window to search similar patchs.\n       \\param smoothness Smoothness for the patch comparison.\n       \\param is_fast_approx Tells if a fast approximation of the gaussian function is used or not.\n    **/\n    CImg<T>& blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3,\n                        const unsigned int lookup_size=4, const float smoothness=0, const bool is_fast_approx=true) {\n      if (is_empty() || !patch_size || !lookup_size) return *this;\n      return get_blur_patch(sigma_s,sigma_p,patch_size,lookup_size,smoothness,is_fast_approx).move_to(*this);\n    }\n\n    //! Blur image using patch-based space \\newinstance.\n    CImg<Tfloat> get_blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3,\n                                const unsigned int lookup_size=4, const float smoothness=0,\n                                const bool is_fast_approx=true) const {\n\n#define _cimg_blur_patch3d_fast(N) \\\n      cimg_for##N##XYZ(res,x,y,z) { \\\n        T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,x,y,z,c,pP,T); pP+=N3; } \\\n        const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, \\\n          x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \\\n        float sum_weights = 0; \\\n        cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (cimg::abs(img(x,y,z,0) - img(p,q,r,0))<sigma_p3) { \\\n          T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,p,q,r,c,pQ,T); pQ+=N3; } \\\n          float distance2 = 0; \\\n          pQ = Q._data; cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(pQ++); distance2+=dI*dI; } \\\n          distance2/=Pnorm; \\\n          const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \\\n            alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = alldist>3?0.0f:1.0f; \\\n          sum_weights+=weight; \\\n          cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); \\\n        } \\\n        if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; \\\n        else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \\\n    }\n\n#define _cimg_blur_patch3d(N) \\\n      cimg_for##N##XYZ(res,x,y,z) { \\\n        T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,x,y,z,c,pP,T); pP+=N3; } \\\n        const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, \\\n          x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \\\n        float sum_weights = 0, weight_max = 0; \\\n        cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) { \\\n          T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,p,q,r,c,pQ,T); pQ+=N3; } \\\n          float distance2 = 0; \\\n          pQ = Q._data; cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(pQ++); distance2+=dI*dI; } \\\n          distance2/=Pnorm; \\\n          const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \\\n            alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)std::exp(-alldist); \\\n          if (weight>weight_max) weight_max = weight; \\\n          sum_weights+=weight; \\\n          cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); \\\n        } \\\n        sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=weight_max*(*this)(x,y,z,c); \\\n        if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; \\\n        else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \\\n      }\n\n#define _cimg_blur_patch2d_fast(N) \\\n        cimg_for##N##XY(res,x,y) { \\\n          T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N(img,x,y,0,c,pP,T); pP+=N2; } \\\n          const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \\\n          float sum_weights = 0; \\\n          cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) if (cimg::abs(img(x,y,0,0) - img(p,q,0,0))<sigma_p3) { \\\n            T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N(img,p,q,0,c,pQ,T); pQ+=N2; } \\\n            float distance2 = 0; \\\n            pQ = Q._data; cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(pQ++); distance2+=dI*dI; } \\\n            distance2/=Pnorm; \\\n            const float dx = (float)p - x, dy = (float)q - y, \\\n              alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = alldist>3?0.0f:1.0f; \\\n            sum_weights+=weight; \\\n            cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); \\\n          } \\\n          if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; \\\n          else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \\\n        }\n\n#define _cimg_blur_patch2d(N) \\\n        cimg_for##N##XY(res,x,y) { \\\n          T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N(img,x,y,0,c,pP,T); pP+=N2; } \\\n          const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \\\n          float sum_weights = 0, weight_max = 0; \\\n          cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) { \\\n            T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N(img,p,q,0,c,pQ,T); pQ+=N2; } \\\n            float distance2 = 0; \\\n            pQ = Q._data; cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(pQ++); distance2+=dI*dI; } \\\n            distance2/=Pnorm; \\\n            const float dx = (float)p - x, dy = (float)q - y, \\\n              alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)std::exp(-alldist); \\\n            if (weight>weight_max) weight_max = weight; \\\n            sum_weights+=weight; \\\n            cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); \\\n          } \\\n          sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=weight_max*(*this)(x,y,c); \\\n          if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; \\\n          else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \\\n    }\n\n      if (is_empty() || !patch_size || !lookup_size) return +*this;\n      CImg<Tfloat> res(_width,_height,_depth,_spectrum,0);\n      const CImg<T> _img = smoothness>0?get_blur(smoothness):CImg<Tfloat>(),&img = smoothness>0?_img:*this;\n      CImg<T> P(patch_size*patch_size*_spectrum), Q(P);\n      const float\n        nsigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100,\n        sigma_s2 = nsigma_s*nsigma_s, sigma_p2 = sigma_p*sigma_p, sigma_p3 = 3*sigma_p,\n        Pnorm = P.size()*sigma_p2;\n      const int rsize2 = (int)lookup_size/2, rsize1 = (int)lookup_size - rsize2 - 1;\n      const unsigned int N2 = patch_size*patch_size, N3 = N2*patch_size;\n      cimg::unused(N2,N3);\n      if (_depth>1) switch (patch_size) { // 3d\n        case 2 : if (is_fast_approx) _cimg_blur_patch3d_fast(2) else _cimg_blur_patch3d(2) break;\n        case 3 : if (is_fast_approx) _cimg_blur_patch3d_fast(3) else _cimg_blur_patch3d(3) break;\n        default : {\n          const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1;\n          if (is_fast_approx)\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (res._width>=32 && res._height*res._depth>=4) private(P,Q)\n#endif\n            cimg_forXYZ(res,x,y,z) { // Fast\n              P = img.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true);\n              const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1,\n                x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;\n              float sum_weights = 0;\n              cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (cimg::abs(img(x,y,z,0)-img(p,q,r,0))<sigma_p3) {\n                (Q = img.get_crop(p - psize1,q - psize1,r - psize1,p + psize2,q + psize2,r + psize2,true))-=P;\n                const float\n                  dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,\n                  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),\n                  weight = distance2>3?0.0f:1.0f;\n                sum_weights+=weight;\n                cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c);\n              }\n              if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights;\n              else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c));\n            } else\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (res._width>=32 && res._height*res._depth>=4) firstprivate(P,Q)\n#endif\n            cimg_forXYZ(res,x,y,z) { // Exact\n              P = img.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true);\n              const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1,\n                x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;\n              float sum_weights = 0, weight_max = 0;\n              cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) {\n                (Q = img.get_crop(p - psize1,q - psize1,r - psize1,p + psize2,q + psize2,r + psize2,true))-=P;\n                const float\n                  dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,\n                  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),\n                  weight = (float)std::exp(-distance2);\n                if (weight>weight_max) weight_max = weight;\n                sum_weights+=weight;\n                cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c);\n              }\n              sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=weight_max*(*this)(x,y,z,c);\n              if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights;\n              else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c));\n            }\n        }\n        } else switch (patch_size) { // 2d\n        case 2 : if (is_fast_approx) _cimg_blur_patch2d_fast(2) else _cimg_blur_patch2d(2) break;\n        case 3 : if (is_fast_approx) _cimg_blur_patch2d_fast(3) else _cimg_blur_patch2d(3) break;\n        case 4 : if (is_fast_approx) _cimg_blur_patch2d_fast(4) else _cimg_blur_patch2d(4) break;\n        case 5 : if (is_fast_approx) _cimg_blur_patch2d_fast(5) else _cimg_blur_patch2d(5) break;\n        case 6 : if (is_fast_approx) _cimg_blur_patch2d_fast(6) else _cimg_blur_patch2d(6) break;\n        case 7 : if (is_fast_approx) _cimg_blur_patch2d_fast(7) else _cimg_blur_patch2d(7) break;\n        case 8 : if (is_fast_approx) _cimg_blur_patch2d_fast(8) else _cimg_blur_patch2d(8) break;\n        case 9 : if (is_fast_approx) _cimg_blur_patch2d_fast(9) else _cimg_blur_patch2d(9) break;\n        default : { // Fast\n          const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1;\n          if (is_fast_approx)\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(res._width>=32 && res._height>=4) firstprivate(P,Q)\n#endif\n            cimg_forXY(res,x,y) { // 2d fast approximation.\n              P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true);\n              const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;\n              float sum_weights = 0;\n              cimg_for_inXY(res,x0,y0,x1,y1,p,q) if (cimg::abs(img(x,y,0)-img(p,q,0))<sigma_p3) {\n                (Q = img.get_crop(p - psize1,q - psize1,p + psize2,q + psize2,true))-=P;\n                const float\n                  dx = (float)x - p, dy = (float)y - q,\n                  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),\n                  weight = distance2>3?0.0f:1.0f;\n                sum_weights+=weight;\n                cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c);\n              }\n              if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights;\n              else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c));\n            } else\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(res._width>=32 && res._height>=4) firstprivate(P,Q)\n#endif\n            cimg_forXY(res,x,y) { // 2d exact algorithm.\n              P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true);\n              const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;\n              float sum_weights = 0, weight_max = 0;\n              cimg_for_inXY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) {\n                (Q = img.get_crop(p - psize1,q - psize1,p + psize2,q + psize2,true))-=P;\n                const float\n                  dx = (float)x - p, dy = (float)y - q,\n                  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),\n                  weight = (float)std::exp(-distance2);\n                if (weight>weight_max) weight_max = weight;\n                sum_weights+=weight;\n                cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c);\n              }\n              sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=weight_max*(*this)(x,y,c);\n              if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights;\n              else cimg_forC(res,c) res(x,y,0,c) = (Tfloat)((*this)(x,y,c));\n            }\n        }\n        }\n      return res;\n    }\n\n    //! Blur image with the median filter.\n    /**\n       \\param n Size of the median filter.\n       \\param threshold Threshold used to discard pixels too far from the current pixel value in the median computation.\n    **/\n    CImg<T>& blur_median(const unsigned int n, const float threshold=0) {\n      if (!n) return *this;\n      return get_blur_median(n,threshold).move_to(*this);\n    }\n\n    //! Blur image with the median filter \\newinstance.\n    CImg<T> get_blur_median(const unsigned int n, const float threshold=0) const {\n      if (is_empty() || n<=1) return +*this;\n      CImg<T> res(_width,_height,_depth,_spectrum);\n      T *ptrd = res._data;\n      cimg::unused(ptrd);\n      const int hl = (int)n/2, hr = hl - 1 + (int)n%2;\n      if (res._depth!=1) { // 3d\n        if (threshold>0)\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=16 && _height*_depth*_spectrum>=4)\n#endif\n          cimg_forXYZC(*this,x,y,z,c) { // With threshold.\n            const int\n              x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr,\n              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,\n              nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1;\n            const float val0 = (float)(*this)(x,y,z,c);\n            CImg<T> values(n*n*n);\n            unsigned int nb_values = 0;\n            T *ptrd = values.data();\n            cimg_for_inXYZ(*this,nx0,ny0,nz0,nx1,ny1,nz1,p,q,r)\n              if (cimg::abs((float)(*this)(p,q,r,c)-val0)<=threshold) { *(ptrd++) = (*this)(p,q,r,c); ++nb_values; }\n            res(x,y,z,c) = values.get_shared_points(0,nb_values - 1).median();\n          }\n        else\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width>=16 && _height*_depth*_spectrum>=4)\n#endif\n          cimg_forXYZC(*this,x,y,z,c) { // Without threshold.\n            const int\n              x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr,\n              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,\n              nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1;\n            res(x,y,z,c) = get_crop(nx0,ny0,nz0,c,nx1,ny1,nz1,c).median();\n          }\n      } else {\n#define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b)\n        if (res._height!=1) { // 2d\n          if (threshold>0)\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=16 && _height*_spectrum>=4)\n#endif\n            cimg_forXYC(*this,x,y,c) { // With threshold.\n              const int\n                x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,\n                nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,\n                                          nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1;\n              const float val0 = (float)(*this)(x,y,c);\n              CImg<T> values(n*n);\n              unsigned int nb_values = 0;\n              T *ptrd = values.data();\n              cimg_for_inXY(*this,nx0,ny0,nx1,ny1,p,q)\n                if (cimg::abs((float)(*this)(p,q,c)-val0)<=threshold) { *(ptrd++) = (*this)(p,q,c); ++nb_values; }\n              res(x,y,c) = values.get_shared_points(0,nb_values - 1).median();\n            }\n          else switch (n) { // Without threshold.\n            case 3 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_spectrum>=2)\n#endif\n              cimg_forC(*this,c) {\n                T I[9] = { 0 };\n                CImg_3x3(J,T);\n                cimg_for3x3(*this,x,y,0,c,I,T) {\n                  std::memcpy(J,I,9*sizeof(T));\n                  _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);\n                  _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn);\n                  _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);\n                  _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn);\n                  _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc);\n                  _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc);\n                  _cimg_median_sort(Jcc, Jnp);\n                  res(x,y,c) = Jcc;\n                }\n              }\n            } break;\n            case 5 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_spectrum>=2)\n#endif\n              cimg_forC(*this,c) {\n                T I[25] = { 0 };\n                CImg_5x5(J,T);\n                cimg_for5x5(*this,x,y,0,c,I,T) {\n                  std::memcpy(J,I,25*sizeof(T));\n                  _cimg_median_sort(Jbb,Jpb); _cimg_median_sort(Jnb,Jab); _cimg_median_sort(Jcb,Jab);\n                  _cimg_median_sort(Jcb,Jnb); _cimg_median_sort(Jpp,Jcp); _cimg_median_sort(Jbp,Jcp);\n                  _cimg_median_sort(Jbp,Jpp); _cimg_median_sort(Jap,Jbc); _cimg_median_sort(Jnp,Jbc);\n                  _cimg_median_sort(Jnp,Jap); _cimg_median_sort(Jcc,Jnc); _cimg_median_sort(Jpc,Jnc);\n                  _cimg_median_sort(Jpc,Jcc); _cimg_median_sort(Jbn,Jpn); _cimg_median_sort(Jac,Jpn);\n                  _cimg_median_sort(Jac,Jbn); _cimg_median_sort(Jnn,Jan); _cimg_median_sort(Jcn,Jan);\n                  _cimg_median_sort(Jcn,Jnn); _cimg_median_sort(Jpa,Jca); _cimg_median_sort(Jba,Jca);\n                  _cimg_median_sort(Jba,Jpa); _cimg_median_sort(Jna,Jaa); _cimg_median_sort(Jcb,Jbp);\n                  _cimg_median_sort(Jnb,Jpp); _cimg_median_sort(Jbb,Jpp); _cimg_median_sort(Jbb,Jnb);\n                  _cimg_median_sort(Jab,Jcp); _cimg_median_sort(Jpb,Jcp); _cimg_median_sort(Jpb,Jab);\n                  _cimg_median_sort(Jpc,Jac); _cimg_median_sort(Jnp,Jac); _cimg_median_sort(Jnp,Jpc);\n                  _cimg_median_sort(Jcc,Jbn); _cimg_median_sort(Jap,Jbn); _cimg_median_sort(Jap,Jcc);\n                  _cimg_median_sort(Jnc,Jpn); _cimg_median_sort(Jbc,Jpn); _cimg_median_sort(Jbc,Jnc);\n                  _cimg_median_sort(Jba,Jna); _cimg_median_sort(Jcn,Jna); _cimg_median_sort(Jcn,Jba);\n                  _cimg_median_sort(Jpa,Jaa); _cimg_median_sort(Jnn,Jaa); _cimg_median_sort(Jnn,Jpa);\n                  _cimg_median_sort(Jan,Jca); _cimg_median_sort(Jnp,Jcn); _cimg_median_sort(Jap,Jnn);\n                  _cimg_median_sort(Jbb,Jnn); _cimg_median_sort(Jbb,Jap); _cimg_median_sort(Jbc,Jan);\n                  _cimg_median_sort(Jpb,Jan); _cimg_median_sort(Jpb,Jbc); _cimg_median_sort(Jpc,Jba);\n                  _cimg_median_sort(Jcb,Jba); _cimg_median_sort(Jcb,Jpc); _cimg_median_sort(Jcc,Jpa);\n                  _cimg_median_sort(Jnb,Jpa); _cimg_median_sort(Jnb,Jcc); _cimg_median_sort(Jnc,Jca);\n                  _cimg_median_sort(Jab,Jca); _cimg_median_sort(Jab,Jnc); _cimg_median_sort(Jac,Jna);\n                  _cimg_median_sort(Jbp,Jna); _cimg_median_sort(Jbp,Jac); _cimg_median_sort(Jbn,Jaa);\n                  _cimg_median_sort(Jpp,Jaa); _cimg_median_sort(Jpp,Jbn); _cimg_median_sort(Jcp,Jpn);\n                  _cimg_median_sort(Jcp,Jan); _cimg_median_sort(Jnc,Jpa); _cimg_median_sort(Jbn,Jna);\n                  _cimg_median_sort(Jcp,Jnc); _cimg_median_sort(Jcp,Jbn); _cimg_median_sort(Jpb,Jap);\n                  _cimg_median_sort(Jnb,Jpc); _cimg_median_sort(Jbp,Jcn); _cimg_median_sort(Jpc,Jcn);\n                  _cimg_median_sort(Jap,Jcn); _cimg_median_sort(Jab,Jbc); _cimg_median_sort(Jpp,Jcc);\n                  _cimg_median_sort(Jcp,Jac); _cimg_median_sort(Jab,Jpp); _cimg_median_sort(Jab,Jcp);\n                  _cimg_median_sort(Jcc,Jac); _cimg_median_sort(Jbc,Jac); _cimg_median_sort(Jpp,Jcp);\n                  _cimg_median_sort(Jbc,Jcc); _cimg_median_sort(Jpp,Jbc); _cimg_median_sort(Jpp,Jcn);\n                  _cimg_median_sort(Jcc,Jcn); _cimg_median_sort(Jcp,Jcn); _cimg_median_sort(Jcp,Jbc);\n                  _cimg_median_sort(Jcc,Jnn); _cimg_median_sort(Jcp,Jcc); _cimg_median_sort(Jbc,Jnn);\n                  _cimg_median_sort(Jcc,Jba); _cimg_median_sort(Jbc,Jba); _cimg_median_sort(Jbc,Jcc);\n                  res(x,y,c) = Jcc;\n                }\n              }\n            } break;\n            default : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=16 && _height*_spectrum>=4)\n#endif\n              cimg_forXYC(*this,x,y,c) {\n                const int\n                  x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,\n                  nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,\n                  nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1;\n                res(x,y,c) = get_crop(nx0,ny0,0,c,nx1,ny1,0,c).median();\n              }\n            }\n            }\n        } else { // 1d\n\n          CImg<T> I;\n          if (threshold>0)\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width>=16 && _spectrum>=2)\n#endif\n            cimg_forXC(*this,x,c) { // With threshold.\n              const int\n                x0 = x - hl, x1 = x + hr,\n                nx0 = x0<0?0:x0, nx1 = x1>=width()?width() - 1:x1;\n              const float val0 = (float)(*this)(x,c);\n              CImg<T> values(n);\n              unsigned int nb_values = 0;\n              T *ptrd = values.data();\n              cimg_for_inX(*this,nx0,nx1,p)\n                if (cimg::abs((float)(*this)(p,c)-val0)<=threshold) { *(ptrd++) = (*this)(p,c); ++nb_values; }\n              res(x,c) = values.get_shared_points(0,nb_values - 1).median();\n            }\n          else switch (n) { // Without threshold.\n            case 2 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_spectrum>=2)\n#endif\n              cimg_forC(*this,c) {\n                I.assign(4);\n                cimg_for2x2(*this,x,y,0,c,I,T) res(x,c) = (T)(0.5f*(I[0] + I[1]));\n              }\n            } break;\n            case 3 : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_spectrum>=2)\n#endif\n              cimg_forC(*this,c) {\n                I.assign(9);\n                cimg_for3x3(*this,x,y,0,c,I,T)\n                  res(x,c) = I[3]<I[4]?(I[4]<I[5]?I[4]:(I[3]<I[5]?I[5]:I[3])):(I[3]<I[5]?I[3]:(I[4]<I[5]?I[5]:I[4]));\n              }\n            } break;\n            default : {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width>=16 && _spectrum>=2)\n#endif\n              cimg_forXC(*this,x,c) {\n                const int\n                  x0 = x - hl, x1 = x + hr,\n                  nx0 = x0<0?0:x0, nx1 = x1>=width()?width() - 1:x1;\n                res(x,c) = get_crop(nx0,0,0,c,nx1,0,0,c).median();\n              }\n            }\n            }\n        }\n      }\n      return res;\n    }\n\n    //! Sharpen image.\n    /**\n       \\param amplitude Sharpening amplitude\n       \\param sharpen_type Select sharpening method. Can be <tt>{ false=inverse diffusion | true=shock filters }</tt>.\n       \\param edge Edge threshold (shock filters only).\n       \\param alpha Gradient smoothness (shock filters only).\n       \\param sigma Tensor smoothness (shock filters only).\n    **/\n    CImg<T>& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1,\n                     const float alpha=0, const float sigma=0) {\n      if (is_empty()) return *this;\n      T val_min, val_max = max_min(val_min);\n      const float nedge = edge/2;\n      CImg<Tfloat> velocity(_width,_height,_depth,_spectrum), _veloc_max(_spectrum);\n\n      if (_depth>1) { // 3d\n        if (sharpen_type) { // Shock filters.\n          CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors());\n          if (sigma>0) G.blur(sigma);\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>=32 && _height*_depth>=16)\n#endif\n          cimg_forYZ(G,y,z) {\n            Tfloat *ptrG0 = G.data(0,y,z,0), *ptrG1 = G.data(0,y,z,1),\n              *ptrG2 = G.data(0,y,z,2), *ptrG3 = G.data(0,y,z,3);\n            CImg<Tfloat> val, vec;\n            cimg_forX(G,x) {\n              G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);\n              if (val[0]<0) val[0] = 0;\n              if (val[1]<0) val[1] = 0;\n              if (val[2]<0) val[2] = 0;\n              *(ptrG0++) = vec(0,0);\n              *(ptrG1++) = vec(0,1);\n              *(ptrG2++) = vec(0,2);\n              *(ptrG3++) = 1 - (Tfloat)std::pow(1 + val[0] + val[1] + val[2],-(Tfloat)nedge);\n            }\n          }\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=512 && _spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;\n            CImg_3x3x3(I,Tfloat);\n            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {\n              const Tfloat\n                u = G(x,y,z,0),\n                v = G(x,y,z,1),\n                w = G(x,y,z,2),\n                amp = G(x,y,z,3),\n                ixx = Incc + Ipcc - 2*Iccc,\n                ixy = (Innc + Ippc - Inpc - Ipnc)/4,\n                ixz = (Incn + Ipcp - Incp - Ipcn)/4,\n                iyy = Icnc + Icpc - 2*Iccc,\n                iyz = (Icnn + Icpp - Icnp - Icpn)/4,\n                izz = Iccn + Iccp - 2*Iccc,\n                ixf = Incc - Iccc,\n                ixb = Iccc - Ipcc,\n                iyf = Icnc - Iccc,\n                iyb = Iccc - Icpc,\n                izf = Iccn - Iccc,\n                izb = Iccc - Iccp,\n                itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz,\n                it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb),\n                veloc = -amp*cimg::sign(itt)*cimg::abs(it);\n              *(ptrd++) = veloc;\n              if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;\n            }\n            _veloc_max[c] = veloc_max;\n          }\n        } else  // Inverse diffusion.\n          cimg_forC(*this,c) {\n            Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;\n            CImg_3x3x3(I,Tfloat);\n            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {\n              const Tfloat veloc = -Ipcc - Incc - Icpc - Icnc - Iccp - Iccn + 6*Iccc;\n              *(ptrd++) = veloc;\n              if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;\n            }\n            _veloc_max[c] = veloc_max;\n          }\n      } else { // 2d.\n        if (sharpen_type) { // Shock filters.\n          CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors());\n          if (sigma>0) G.blur(sigma);\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width>=32 && _height>=16)\n#endif\n          cimg_forY(G,y) {\n            CImg<Tfloat> val, vec;\n            Tfloat *ptrG0 = G.data(0,y,0,0), *ptrG1 = G.data(0,y,0,1), *ptrG2 = G.data(0,y,0,2);\n            cimg_forX(G,x) {\n              G.get_tensor_at(x,y).symmetric_eigen(val,vec);\n              if (val[0]<0) val[0] = 0;\n              if (val[1]<0) val[1] = 0;\n              *(ptrG0++) = vec(0,0);\n              *(ptrG1++) = vec(0,1);\n              *(ptrG2++) = 1 - (Tfloat)std::pow(1 + val[0] + val[1],-(Tfloat)nedge);\n            }\n          }\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height>=512 && _spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;\n            CImg_3x3(I,Tfloat);\n            cimg_for3x3(*this,x,y,0,c,I,Tfloat) {\n              const Tfloat\n                u = G(x,y,0),\n                v = G(x,y,1),\n                amp = G(x,y,2),\n                ixx = Inc + Ipc - 2*Icc,\n                ixy = (Inn + Ipp - Inp - Ipn)/4,\n                iyy = Icn + Icp - 2*Icc,\n                ixf = Inc - Icc,\n                ixb = Icc - Ipc,\n                iyf = Icn - Icc,\n                iyb = Icc - Icp,\n                itt = u*u*ixx + v*v*iyy + 2*u*v*ixy,\n                it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb),\n                veloc = -amp*cimg::sign(itt)*cimg::abs(it);\n              *(ptrd++) = veloc;\n              if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;\n            }\n            _veloc_max[c] = veloc_max;\n          }\n        } else // Inverse diffusion.\n          cimg_forC(*this,c) {\n            Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;\n            CImg_3x3(I,Tfloat);\n            cimg_for3x3(*this,x,y,0,c,I,Tfloat) {\n              const Tfloat veloc = -Ipc - Inc - Icp - Icn + 4*Icc;\n              *(ptrd++) = veloc;\n              if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;\n            }\n            _veloc_max[c] = veloc_max;\n          }\n      }\n      const Tfloat veloc_max = _veloc_max.max();\n      if (veloc_max<=0) return *this;\n      return ((velocity*=amplitude/veloc_max)+=*this).cut(val_min,val_max).move_to(*this);\n    }\n\n    //! Sharpen image \\newinstance.\n    CImg<T> get_sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1,\n                        const float alpha=0, const float sigma=0) const {\n      return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma);\n    }\n\n    //! Return image gradient.\n    /**\n       \\param axes Axes considered for the gradient computation, as a C-string (e.g \"xy\").\n       \\param scheme = Numerical scheme used for the gradient computation:\n       - -1 = Backward finite differences\n       - 0 = Centered finite differences\n       - 1 = Forward finite differences\n       - 2 = Using Sobel masks\n       - 3 = Using rotation invariant masks\n       - 4 = Using Deriche recusrsive filter.\n       - 5 = Using Van Vliet recusrsive filter.\n    **/\n    CImgList<Tfloat> get_gradient(const char *const axes=0, const int scheme=3) const {\n      CImgList<Tfloat> grad(2,_width,_height,_depth,_spectrum);\n      bool is_3d = false;\n      if (axes) {\n        for (unsigned int a = 0; axes[a]; ++a) {\n          const char axis = cimg::uncase(axes[a]);\n          switch (axis) {\n          case 'x' : case 'y' : break;\n          case 'z' : is_3d = true; break;\n          default :\n            throw CImgArgumentException(_cimg_instance\n                                        \"get_gradient(): Invalid specified axis '%c'.\",\n                                        cimg_instance,\n                                        axis);\n          }\n        }\n      } else is_3d = (_depth>1);\n      if (is_3d) {\n        CImg<Tfloat>(_width,_height,_depth,_spectrum).move_to(grad);\n        switch (scheme) { // 3d.\n        case -1 : { // Backward finite differences.\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            const ulongT off = (ulongT)c*_width*_height*_depth;\n            Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off, *ptrd2 = grad[2]._data + off;\n            CImg_3x3x3(I,Tfloat);\n            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {\n              *(ptrd0++) = Iccc - Ipcc;\n              *(ptrd1++) = Iccc - Icpc;\n              *(ptrd2++) = Iccc - Iccp;\n            }\n          }\n        } break;\n        case 1 : { // Forward finite differences.\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            const ulongT off = (ulongT)c*_width*_height*_depth;\n            Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off, *ptrd2 = grad[2]._data + off;\n            CImg_2x2x2(I,Tfloat);\n            cimg_for2x2x2(*this,x,y,z,c,I,Tfloat) {\n              *(ptrd0++) = Incc - Iccc;\n              *(ptrd1++) = Icnc - Iccc;\n              *(ptrd2++) = Iccn - Iccc;\n            }\n          }\n        } break;\n        case 4 : { // Deriche filter with low standard variation.\n          grad[0] = get_deriche(0,1,'x');\n          grad[1] = get_deriche(0,1,'y');\n          grad[2] = get_deriche(0,1,'z');\n        } break;\n        case 5 : { // Van Vliet filter with low standard variation.\n          grad[0] = get_vanvliet(0,1,'x');\n          grad[1] = get_vanvliet(0,1,'y');\n          grad[2] = get_vanvliet(0,1,'z');\n        } break;\n        default : { // Central finite differences.\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            const ulongT off = (ulongT)c*_width*_height*_depth;\n            Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off, *ptrd2 = grad[2]._data + off;\n            CImg_3x3x3(I,Tfloat);\n            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {\n              *(ptrd0++) = (Incc - Ipcc)/2;\n              *(ptrd1++) = (Icnc - Icpc)/2;\n              *(ptrd2++) = (Iccn - Iccp)/2;\n            }\n          }\n        }\n        }\n      } else switch (scheme) { // 2d.\n      case -1 : { // Backward finite differences.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n        cimg_forZC(*this,z,c) {\n          const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height;\n          Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off;\n          CImg_3x3(I,Tfloat);\n          cimg_for3x3(*this,x,y,z,c,I,Tfloat) {\n            *(ptrd0++) = Icc - Ipc;\n            *(ptrd1++) = Icc - Icp;\n          }\n        }\n      } break;\n      case 1 : { // Forward finite differences.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n        cimg_forZC(*this,z,c) {\n          const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height;\n          Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off;\n          CImg_2x2(I,Tfloat);\n          cimg_for2x2(*this,x,y,z,c,I,Tfloat) {\n            *(ptrd0++) = Inc - Icc;\n            *(ptrd1++) = Icn - Icc;\n          }\n        }\n      } break;\n      case 2 : { // Sobel scheme.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n        cimg_forZC(*this,z,c) {\n          const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height;\n          Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off;\n          CImg_3x3(I,Tfloat);\n          cimg_for3x3(*this,x,y,z,c,I,Tfloat) {\n            *(ptrd0++) = -Ipp - 2*Ipc - Ipn + Inp + 2*Inc + Inn;\n            *(ptrd1++) = -Ipp - 2*Icp - Inp + Ipn + 2*Icn + Inn;\n          }\n        }\n      } break;\n      case 3 : { // Rotation invariant mask.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n        cimg_forZC(*this,z,c) {\n          const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height;\n          Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off;\n          CImg_3x3(I,Tfloat);\n          const Tfloat a = (Tfloat)(0.25f*(2-std::sqrt(2.0f))), b = (Tfloat)(0.5f*(std::sqrt(2.0f) - 1));\n          cimg_for3x3(*this,x,y,z,c,I,Tfloat) {\n            *(ptrd0++) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;\n            *(ptrd1++) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;\n          }\n        }\n      } break;\n      case 4 : { // Van Vliet filter with low standard variation\n        grad[0] = get_deriche(0,1,'x');\n        grad[1] = get_deriche(0,1,'y');\n      } break;\n      case 5 : { // Deriche filter with low standard variation\n        grad[0] = get_vanvliet(0,1,'x');\n        grad[1] = get_vanvliet(0,1,'y');\n      } break;\n      default : { // Central finite differences\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n        cimg_forZC(*this,z,c) {\n          const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height;\n          Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off;\n          CImg_3x3(I,Tfloat);\n          cimg_for3x3(*this,x,y,z,c,I,Tfloat) {\n            *(ptrd0++) = (Inc - Ipc)/2;\n            *(ptrd1++) = (Icn - Icp)/2;\n          }\n        }\n      }\n      }\n      if (!axes) return grad;\n      CImgList<Tfloat> res;\n      for (unsigned int l = 0; axes[l]; ++l) {\n        const char axis = cimg::uncase(axes[l]);\n        switch (axis) {\n        case 'x' : res.insert(grad[0]); break;\n        case 'y' : res.insert(grad[1]); break;\n        case 'z' : res.insert(grad[2]); break;\n        }\n      }\n      grad.assign();\n      return res;\n    }\n\n    //! Return image hessian.\n    /**\n       \\param axes Axes considered for the hessian computation, as a C-string (e.g \"xy\").\n    **/\n    CImgList<Tfloat> get_hessian(const char *const axes=0) const {\n      CImgList<Tfloat> res;\n      const char *naxes = axes, *const def_axes2d = \"xxxyyy\", *const def_axes3d = \"xxxyxzyyyzzz\";\n      if (!axes) naxes = _depth>1?def_axes3d:def_axes2d;\n      const unsigned int lmax = (unsigned int)std::strlen(naxes);\n      if (lmax%2)\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_hessian(): Invalid specified axes '%s'.\",\n                                    cimg_instance,\n                                    naxes);\n\n      res.assign(lmax/2,_width,_height,_depth,_spectrum);\n      if (!cimg::strcasecmp(naxes,def_axes3d)) { // 3d\n\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n        cimg_forC(*this,c) {\n          const ulongT off = (ulongT)c*_width*_height*_depth;\n          Tfloat\n            *ptrd0 = res[0]._data + off, *ptrd1 = res[1]._data + off, *ptrd2 = res[2]._data + off,\n            *ptrd3 = res[3]._data + off, *ptrd4 = res[4]._data + off, *ptrd5 = res[5]._data + off;\n          CImg_3x3x3(I,Tfloat);\n          cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {\n            *(ptrd0++) = Ipcc + Incc - 2*Iccc;          // Ixx\n            *(ptrd1++) = (Ippc + Innc - Ipnc - Inpc)/4; // Ixy\n            *(ptrd2++) = (Ipcp + Incn - Ipcn - Incp)/4; // Ixz\n            *(ptrd3++) = Icpc + Icnc - 2*Iccc;          // Iyy\n            *(ptrd4++) = (Icpp + Icnn - Icpn - Icnp)/4; // Iyz\n            *(ptrd5++) = Iccn + Iccp - 2*Iccc;          // Izz\n          }\n        }\n      } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // 2d\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n        cimg_forZC(*this,z,c) {\n          const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height;\n          Tfloat *ptrd0 = res[0]._data + off, *ptrd1 = res[1]._data + off, *ptrd2 = res[2]._data + off;\n          CImg_3x3(I,Tfloat);\n          cimg_for3x3(*this,x,y,z,c,I,Tfloat) {\n            *(ptrd0++) = Ipc + Inc - 2*Icc;         // Ixx\n            *(ptrd1++) = (Ipp + Inn - Ipn - Inp)/4; // Ixy\n            *(ptrd2++) = Icp + Icn - 2*Icc;         // Iyy\n          }\n        }\n      } else for (unsigned int l = 0; l<lmax; ) { // Version with custom axes.\n          const unsigned int l2 = l/2;\n          char axis1 = naxes[l++], axis2 = naxes[l++];\n          if (axis1>axis2) cimg::swap(axis1,axis2);\n          bool valid_axis = false;\n          if (axis1=='x' && axis2=='x') { // Ixx\n            valid_axis = true;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n            cimg_forZC(*this,z,c) {\n              Tfloat *ptrd = res[l2].data(0,0,z,c);\n              CImg_3x3(I,Tfloat);\n              cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Ipc + Inc - 2*Icc;\n            }\n          }\n          else if (axis1=='x' && axis2=='y') { // Ixy\n            valid_axis = true;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n            cimg_forZC(*this,z,c) {\n              Tfloat *ptrd = res[l2].data(0,0,z,c);\n              CImg_3x3(I,Tfloat);\n              cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipp + Inn - Ipn - Inp)/4;\n            }\n          }\n          else if (axis1=='x' && axis2=='z') { // Ixz\n            valid_axis = true;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n            cimg_forC(*this,c) {\n              Tfloat *ptrd = res[l2].data(0,0,0,c);\n              CImg_3x3x3(I,Tfloat);\n              cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipcp + Incn - Ipcn - Incp)/4;\n            }\n          }\n          else if (axis1=='y' && axis2=='y') { // Iyy\n            valid_axis = true;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n            cimg_forZC(*this,z,c) {\n              Tfloat *ptrd = res[l2].data(0,0,z,c);\n              CImg_3x3(I,Tfloat);\n              cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Icp + Icn - 2*Icc;\n            }\n          }\n          else if (axis1=='y' && axis2=='z') { // Iyz\n            valid_axis = true;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n            cimg_forC(*this,c) {\n              Tfloat *ptrd = res[l2].data(0,0,0,c);\n              CImg_3x3x3(I,Tfloat);\n              cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Icpp + Icnn - Icpn - Icnp)/4;\n            }\n          }\n          else if (axis1=='z' && axis2=='z') { // Izz\n            valid_axis = true;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n            cimg_forC(*this,c) {\n              Tfloat *ptrd = res[l2].data(0,0,0,c);\n              CImg_3x3x3(I,Tfloat);\n              cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Iccn + Iccp - 2*Iccc;\n            }\n          }\n          else if (!valid_axis)\n            throw CImgArgumentException(_cimg_instance\n                                        \"get_hessian(): Invalid specified axes '%s'.\",\n                                        cimg_instance,\n                                        naxes);\n        }\n      return res;\n    }\n\n    //! Compute image laplacian.\n    CImg<T>& laplacian() {\n      return get_laplacian().move_to(*this);\n    }\n\n    //! Compute image laplacian \\newinstance.\n    CImg<Tfloat> get_laplacian() const {\n      if (is_empty()) return CImg<Tfloat>();\n      CImg<Tfloat> res(_width,_height,_depth,_spectrum);\n      if (_depth>1) { // 3d\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n        cimg_forC(*this,c) {\n          Tfloat *ptrd = res.data(0,0,0,c);\n          CImg_3x3x3(I,Tfloat);\n          cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Incc + Ipcc + Icnc + Icpc + Iccn + Iccp - 6*Iccc;\n        }\n      } else if (_height>1) { // 2d\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n        cimg_forC(*this,c) {\n          Tfloat *ptrd = res.data(0,0,0,c);\n          CImg_3x3(I,Tfloat);\n          cimg_for3x3(*this,x,y,0,c,I,Tfloat) *(ptrd++) = Inc + Ipc + Icn + Icp - 4*Icc;\n        }\n      } else { // 1d\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width>=1048576 && _height*_depth*_spectrum>=2)\n#endif\n        cimg_forC(*this,c) {\n          Tfloat *ptrd = res.data(0,0,0,c);\n          CImg_3x3(I,Tfloat);\n          cimg_for3x3(*this,x,y,0,c,I,Tfloat) *(ptrd++) = Inc + Ipc - 2*Icc;\n        }\n      }\n      return res;\n    }\n\n    //! Compute the structure tensor field of an image.\n    /**\n       \\param is_fwbw_scheme scheme. Can be <tt>{ false=centered | true=forward-backward }</tt>\n    **/\n    CImg<T>& structure_tensors(const bool is_fwbw_scheme=false) {\n      return get_structure_tensors(is_fwbw_scheme).move_to(*this);\n    }\n\n    //! Compute the structure tensor field of an image \\newinstance.\n    CImg<Tfloat> get_structure_tensors(const bool is_fwbw_scheme=false) const {\n      if (is_empty()) return *this;\n      CImg<Tfloat> res;\n      if (_depth>1) { // 3d\n        res.assign(_width,_height,_depth,6,0);\n        if (!is_fwbw_scheme) { // Classical central finite differences\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            Tfloat\n              *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2),\n              *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5);\n            CImg_3x3x3(I,Tfloat);\n            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {\n              const Tfloat\n                ix = (Incc - Ipcc)/2,\n                iy = (Icnc - Icpc)/2,\n                iz = (Iccn - Iccp)/2;\n              *(ptrd0++)+=ix*ix;\n              *(ptrd1++)+=ix*iy;\n              *(ptrd2++)+=ix*iz;\n              *(ptrd3++)+=iy*iy;\n              *(ptrd4++)+=iy*iz;\n              *(ptrd5++)+=iz*iz;\n            }\n          }\n        } else { // Forward/backward finite differences.\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            Tfloat\n              *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2),\n              *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5);\n            CImg_3x3x3(I,Tfloat);\n            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {\n              const Tfloat\n                ixf = Incc - Iccc, ixb = Iccc - Ipcc,\n                iyf = Icnc - Iccc, iyb = Iccc - Icpc,\n                izf = Iccn - Iccc, izb = Iccc - Iccp;\n              *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2;\n              *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4;\n              *(ptrd2++)+=(ixf*izf + ixf*izb + ixb*izf + ixb*izb)/4;\n              *(ptrd3++)+=(iyf*iyf + iyb*iyb)/2;\n              *(ptrd4++)+=(iyf*izf + iyf*izb + iyb*izf + iyb*izb)/4;\n              *(ptrd5++)+=(izf*izf + izb*izb)/2;\n            }\n          }\n        }\n      } else { // 2d\n        res.assign(_width,_height,_depth,3,0);\n        if (!is_fwbw_scheme) { // Classical central finite differences\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2);\n            CImg_3x3(I,Tfloat);\n            cimg_for3x3(*this,x,y,0,c,I,Tfloat) {\n              const Tfloat\n                ix = (Inc - Ipc)/2,\n                iy = (Icn - Icp)/2;\n              *(ptrd0++)+=ix*ix;\n              *(ptrd1++)+=ix*iy;\n              *(ptrd2++)+=iy*iy;\n            }\n          }\n        } else { // Forward/backward finite differences (version 2).\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2)\n#endif\n          cimg_forC(*this,c) {\n            Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2);\n            CImg_3x3(I,Tfloat);\n            cimg_for3x3(*this,x,y,0,c,I,Tfloat) {\n              const Tfloat\n                ixf = Inc - Icc, ixb = Icc - Ipc,\n                iyf = Icn - Icc, iyb = Icc - Icp;\n              *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2;\n              *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4;\n              *(ptrd2++)+=(iyf*iyf + iyb*iyb)/2;\n            }\n          }\n        }\n      }\n      return res;\n    }\n\n    //! Compute field of diffusion tensors for edge-preserving smoothing.\n    /**\n       \\param sharpness Sharpness\n       \\param anisotropy Anisotropy\n       \\param alpha Standard deviation of the gradient blur.\n       \\param sigma Standard deviation of the structure tensor blur.\n       \\param is_sqrt Tells if the square root of the tensor field is computed instead.\n    **/\n    CImg<T>& diffusion_tensors(const float sharpness=0.7f, const float anisotropy=0.6f,\n                               const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) {\n      CImg<Tfloat> res;\n      const float\n        nsharpness = cimg::max(sharpness,1e-5f),\n        power1 = (is_sqrt?0.5f:1)*nsharpness,\n        power2 = power1/(1e-7f + 1 - anisotropy);\n      blur(alpha).normalize(0,(T)255);\n\n      if (_depth>1) { // 3d\n        get_structure_tensors().move_to(res).blur(sigma);\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if(_width>=256 && _height*_depth>=256)\n#endif\n        cimg_forYZ(*this,y,z) {\n          Tfloat\n            *ptrd0 = res.data(0,y,z,0), *ptrd1 = res.data(0,y,z,1), *ptrd2 = res.data(0,y,z,2),\n            *ptrd3 = res.data(0,y,z,3), *ptrd4 = res.data(0,y,z,4), *ptrd5 = res.data(0,y,z,5);\n          CImg<floatT> val(3), vec(3,3);\n          cimg_forX(*this,x) {\n            res.get_tensor_at(x,y,z).symmetric_eigen(val,vec);\n            const float\n              _l1 = val[2], _l2 = val[1], _l3 = val[0],\n              l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, l3 = _l3>0?_l3:0,\n              ux = vec(0,0), uy = vec(0,1), uz = vec(0,2),\n              vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),\n              wx = vec(2,0), wy = vec(2,1), wz = vec(2,2),\n              n1 = (float)std::pow(1 + l1 + l2 + l3,-power1),\n              n2 = (float)std::pow(1 + l1 + l2 + l3,-power2);\n            *(ptrd0++) = n1*(ux*ux + vx*vx) + n2*wx*wx;\n            *(ptrd1++) = n1*(ux*uy + vx*vy) + n2*wx*wy;\n            *(ptrd2++) = n1*(ux*uz + vx*vz) + n2*wx*wz;\n            *(ptrd3++) = n1*(uy*uy + vy*vy) + n2*wy*wy;\n            *(ptrd4++) = n1*(uy*uz + vy*vz) + n2*wy*wz;\n            *(ptrd5++) = n1*(uz*uz + vz*vz) + n2*wz*wz;\n          }\n        }\n      } else { // for 2d images\n        get_structure_tensors().move_to(res).blur(sigma);\n#ifdef cimg_use_openmp\n#pragma omp parallel for if(_width>=256 && _height>=256)\n#endif\n        cimg_forY(*this,y) {\n          Tfloat *ptrd0 = res.data(0,y,0,0), *ptrd1 = res.data(0,y,0,1), *ptrd2 = res.data(0,y,0,2);\n          CImg<floatT> val(2), vec(2,2);\n          cimg_forX(*this,x) {\n            res.get_tensor_at(x,y).symmetric_eigen(val,vec);\n            const float\n              _l1 = val[1], _l2 = val[0],\n              l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0,\n              ux = vec(1,0), uy = vec(1,1),\n              vx = vec(0,0), vy = vec(0,1),\n              n1 = (float)std::pow(1 + l1 + l2,-power1),\n              n2 = (float)std::pow(1 + l1 + l2,-power2);\n            *(ptrd0++) = n1*ux*ux + n2*vx*vx;\n            *(ptrd1++) = n1*ux*uy + n2*vx*vy;\n            *(ptrd2++) = n1*uy*uy + n2*vy*vy;\n          }\n        }\n      }\n      return res.move_to(*this);\n    }\n\n    //! Compute field of diffusion tensors for edge-preserving smoothing \\newinstance.\n    CImg<Tfloat> get_diffusion_tensors(const float sharpness=0.7f, const float anisotropy=0.6f,\n                                       const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) const {\n      return CImg<Tfloat>(*this,false).diffusion_tensors(sharpness,anisotropy,alpha,sigma,is_sqrt);\n    }\n\n    //! Estimate displacement field between two images.\n    /**\n       \\param source Reference image.\n       \\param smoothness Smoothness of estimated displacement field.\n       \\param precision Precision required for algorithm convergence.\n       \\param nb_scales Number of scales used to estimate the displacement field.\n       \\param iteration_max Maximum number of iterations allowed for one scale.\n       \\param is_backward If false, match I2(X + U(X)) = I1(X), else match I2(X) = I1(X - U(X)).\n       \\param guide Image used as the initial correspondence estimate for the algorithm.\n       'guide' may have a last channel with boolean values (0=false | other=true) that\n       tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask).\n    **/\n    CImg<T>& displacement(const CImg<T>& source, const float smoothness=0.1f, const float precision=5.0f,\n                          const unsigned int nb_scales=0, const unsigned int iteration_max=10000,\n                          const bool is_backward=false,\n                          const CImg<floatT>& guide=CImg<floatT>::const_empty()) {\n      return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,guide).\n        move_to(*this);\n    }\n\n    //! Estimate displacement field between two images \\newinstance.\n    CImg<floatT> get_displacement(const CImg<T>& source,\n                                  const float smoothness=0.1f, const float precision=5.0f,\n                                  const unsigned int nb_scales=0, const unsigned int iteration_max=10000,\n                                  const bool is_backward=false,\n                                  const CImg<floatT>& guide=CImg<floatT>::const_empty()) const {\n      if (is_empty() || !source) return +*this;\n      if (!is_sameXYZC(source))\n        throw CImgArgumentException(_cimg_instance\n                                    \"displacement(): Instance and source image (%u,%u,%u,%u,%p) have \"\n                                    \"different dimensions.\",\n                                    cimg_instance,\n                                    source._width,source._height,source._depth,source._spectrum,source._data);\n      if (precision<0)\n        throw CImgArgumentException(_cimg_instance\n                                    \"displacement(): Invalid specified precision %g \"\n                                    \"(should be >=0)\",\n                                    cimg_instance,\n                                    precision);\n\n      const bool is_3d = source._depth>1;\n      const unsigned int constraint = is_3d?3:2;\n\n      if (guide &&\n          (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<constraint))\n        throw CImgArgumentException(_cimg_instance\n                                    \"displacement(): Specified guide (%u,%u,%u,%u,%p) \"\n                                    \"has invalid dimensions.\",\n                                    cimg_instance,\n                                    guide._width,guide._height,guide._depth,guide._spectrum,guide._data);\n\n      const unsigned int\n        mins = is_3d?cimg::min(_width,_height,_depth):cimg::min(_width,_height),\n        _nb_scales = nb_scales>0?nb_scales:\n        (unsigned int)cimg::round(std::log(mins/8.0)/std::log(1.5),1,1);\n\n      const float _precision = (float)std::pow(10.0,-(double)precision);\n      float sm, sM = source.max_min(sm), tm, tM = max_min(tm);\n      const float sdelta = sm==sM?1:(sM - sm), tdelta = tm==tM?1:(tM - tm);\n\n      CImg<floatT> U, V;\n      floatT bound = 0;\n      for (int scale = (int)_nb_scales - 1; scale>=0; --scale) {\n        const float factor = (float)std::pow(1.5,(double)scale);\n        const unsigned int\n          _sw = (unsigned int)(_width/factor), sw = _sw?_sw:1,\n          _sh = (unsigned int)(_height/factor), sh = _sh?_sh:1,\n          _sd = (unsigned int)(_depth/factor), sd = _sd?_sd:1;\n        if (sw<5 && sh<5 && (!is_3d || sd<5)) continue;  // skip too small scales.\n        const CImg<Tfloat>\n          I1 = (source.get_resize(sw,sh,sd,-100,2)-=sm)/=sdelta,\n          I2 = (get_resize(I1,2)-=tm)/=tdelta;\n        if (guide._spectrum>constraint) guide.get_resize(I2._width,I2._height,I2._depth,-100,1).move_to(V);\n        if (U) (U*=1.5f).resize(I2._width,I2._height,I2._depth,-100,3);\n        else {\n          if (guide)\n            guide.get_shared_channels(0,is_3d?2:1).get_resize(I2._width,I2._height,I2._depth,-100,2).move_to(U);\n          else U.assign(I2._width,I2._height,I2._depth,is_3d?3:2,0);\n        }\n\n        float dt = 2, energy = cimg::type<float>::max();\n        const CImgList<Tfloat> dI = is_backward?I1.get_gradient():I2.get_gradient();\n\n        for (unsigned int iteration = 0; iteration<iteration_max; ++iteration) {\n          cimg_test_abort();\n          float _energy = 0;\n\n          if (is_3d) { // 3d version.\n            if (smoothness>=0) // Isotropic regularization.\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_height*_depth>=8 && _width>=16) reduction(+:_energy)\n#endif\n              cimg_forYZ(U,y,z) {\n                const int\n                  _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y,\n                  _p1z = z?z - 1:0, _n1z = z<U.depth() - 1?z + 1:z;\n                cimg_for3X(U,x) {\n                  const float\n                    X = is_backward?x - U(x,y,z,0):x + U(x,y,z,0),\n                    Y = is_backward?y - U(x,y,z,1):y + U(x,y,z,1),\n                    Z = is_backward?z - U(x,y,z,2):z + U(x,y,z,2);\n                  float delta_I = 0, _energy_regul = 0;\n                  if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1.linear_atXYZ(X,Y,Z,c) - I2(x,y,z,c));\n                  else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,z,c) - I2.linear_atXYZ(X,Y,Z,c));\n                  cimg_forC(U,c) {\n                    const float\n                      Ux = 0.5f*(U(_n1x,y,z,c) - U(_p1x,y,z,c)),\n                      Uy = 0.5f*(U(x,_n1y,z,c) - U(x,_p1y,z,c)),\n                      Uz = 0.5f*(U(x,y,_n1z,c) - U(x,y,_p1z,c)),\n                      Uxx = U(_n1x,y,z,c) + U(_p1x,y,z,c),\n                      Uyy = U(x,_n1y,z,c) + U(x,_p1y,z,c),\n                      Uzz = U(x,y,_n1z,c) + U(x,y,_p1z,c);\n                    U(x,y,z,c) = (float)(U(x,y,z,c) + dt*(delta_I*dI[c].linear_atXYZ(X,Y,Z) +\n                                                          smoothness* ( Uxx + Uyy + Uzz)))/(1 + 6*smoothness*dt);\n                    _energy_regul+=Ux*Ux + Uy*Uy + Uz*Uz;\n                  }\n                  if (is_backward) { // Constraint displacement vectors to stay in image.\n                    if (U(x,y,z,0)>x) U(x,y,z,0) = (float)x;\n                    if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y;\n                    if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z;\n                    bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound;\n                    bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound;\n                    bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound;\n                  } else {\n                    if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x;\n                    if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y;\n                    if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z;\n                    bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound;\n                    bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound;\n                    bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound;\n                  }\n                  _energy+=delta_I*delta_I + smoothness*_energy_regul;\n                }\n                if (V) cimg_forXYZ(V,x,y,z) if (V(x,y,z,3)) { // Apply constraints.\n                    U(x,y,z,0) = V(x,y,z,0)/factor;\n                    U(x,y,z,1) = V(x,y,z,1)/factor;\n                    U(x,y,z,2) = V(x,y,z,2)/factor;\n                  }\n              } else { // Anisotropic regularization.\n              const float nsmoothness = -smoothness;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_height*_depth>=8 && _width>=16) reduction(+:_energy)\n#endif\n              cimg_forYZ(U,y,z) {\n                const int\n                  _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y,\n                  _p1z = z?z - 1:0, _n1z = z<U.depth() - 1?z + 1:z;\n                cimg_for3X(U,x) {\n                  const float\n                    X = is_backward?x - U(x,y,z,0):x + U(x,y,z,0),\n                    Y = is_backward?y - U(x,y,z,1):y + U(x,y,z,1),\n                    Z = is_backward?z - U(x,y,z,2):z + U(x,y,z,2);\n                  float delta_I = 0, _energy_regul = 0;\n                  if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1.linear_atXYZ(X,Y,Z,c) - I2(x,y,z,c));\n                  else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,z,c) - I2.linear_atXYZ(X,Y,Z,c));\n                  cimg_forC(U,c) {\n                    const float\n                      Ux = 0.5f*(U(_n1x,y,z,c) - U(_p1x,y,z,c)),\n                      Uy = 0.5f*(U(x,_n1y,z,c) - U(x,_p1y,z,c)),\n                      Uz = 0.5f*(U(x,y,_n1z,c) - U(x,y,_p1z,c)),\n                      N2 = Ux*Ux + Uy*Uy + Uz*Uz,\n                      N = std::sqrt(N2),\n                      N3 = 1e-5f + N2*N,\n                      coef_a = (1 - Ux*Ux/N2)/N,\n                      coef_b = -2*Ux*Uy/N3,\n                      coef_c = -2*Ux*Uz/N3,\n                      coef_d = (1 - Uy*Uy/N2)/N,\n                      coef_e = -2*Uy*Uz/N3,\n                      coef_f = (1 - Uz*Uz/N2)/N,\n                      Uxx = U(_n1x,y,z,c) + U(_p1x,y,z,c),\n                      Uyy = U(x,_n1y,z,c) + U(x,_p1y,z,c),\n                      Uzz = U(x,y,_n1z,c) + U(x,y,_p1z,c),\n                      Uxy = 0.25f*(U(_n1x,_n1y,z,c) + U(_p1x,_p1y,z,c) - U(_n1x,_p1y,z,c) - U(_n1x,_p1y,z,c)),\n                      Uxz = 0.25f*(U(_n1x,y,_n1z,c) + U(_p1x,y,_p1z,c) - U(_n1x,y,_p1z,c) - U(_n1x,y,_p1z,c)),\n                      Uyz = 0.25f*(U(x,_n1y,_n1z,c) + U(x,_p1y,_p1z,c) - U(x,_n1y,_p1z,c) - U(x,_n1y,_p1z,c));\n                    U(x,y,z,c) = (float)(U(x,y,z,c) + dt*(delta_I*dI[c].linear_atXYZ(X,Y,Z) +\n                                                          nsmoothness* ( coef_a*Uxx + coef_b*Uxy +\n                                                                         coef_c*Uxz + coef_d*Uyy +\n                                                                         coef_e*Uyz + coef_f*Uzz ))\n                                         )/(1 + 2*(coef_a + coef_d + coef_f)*nsmoothness*dt);\n                    _energy_regul+=N;\n                  }\n                  if (is_backward) { // Constraint displacement vectors to stay in image.\n                    if (U(x,y,z,0)>x) U(x,y,z,0) = (float)x;\n                    if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y;\n                    if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z;\n                    bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound;\n                    bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound;\n                    bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound;\n                  } else {\n                    if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x;\n                    if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y;\n                    if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z;\n                    bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound;\n                    bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound;\n                    bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound;\n                  }\n                  _energy+=delta_I*delta_I + nsmoothness*_energy_regul;\n                }\n                if (V) cimg_forXYZ(V,x,y,z) if (V(x,y,z,3)) { // Apply constraints.\n                    U(x,y,z,0) = V(x,y,z,0)/factor;\n                    U(x,y,z,1) = V(x,y,z,1)/factor;\n                    U(x,y,z,2) = V(x,y,z,2)/factor;\n                  }\n              }\n            }\n          } else { // 2d version.\n            if (smoothness>=0) // Isotropic regularization.\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_height>=8 && _width>=16) reduction(+:_energy)\n#endif\n              cimg_forY(U,y) {\n                const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y;\n                cimg_for3X(U,x) {\n                  const float\n                    X = is_backward?x - U(x,y,0):x + U(x,y,0),\n                    Y = is_backward?y - U(x,y,1):y + U(x,y,1);\n                  float delta_I = 0, _energy_regul = 0;\n                  if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1.linear_atXY(X,Y,c) - I2(x,y,c));\n                  else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,c) - I2.linear_atXY(X,Y,c));\n                  cimg_forC(U,c) {\n                    const float\n                      Ux = 0.5f*(U(_n1x,y,c) - U(_p1x,y,c)),\n                      Uy = 0.5f*(U(x,_n1y,c) - U(x,_p1y,c)),\n                      Uxx = U(_n1x,y,c) + U(_p1x,y,c),\n                      Uyy = U(x,_n1y,c) + U(x,_p1y,c);\n                    U(x,y,c) = (float)(U(x,y,c) + dt*(delta_I*dI[c].linear_atXY(X,Y) +\n                                                      smoothness*( Uxx + Uyy )))/(1 + 4*smoothness*dt);\n                    _energy_regul+=Ux*Ux + Uy*Uy;\n                  }\n                  if (is_backward) { // Constraint displacement vectors to stay in image.\n                    if (U(x,y,0)>x) U(x,y,0) = (float)x;\n                    if (U(x,y,1)>y) U(x,y,1) = (float)y;\n                    bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound;\n                    bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound;\n                  } else {\n                    if (U(x,y,0)<-x) U(x,y,0) = -(float)x;\n                    if (U(x,y,1)<-y) U(x,y,1) = -(float)y;\n                    bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound;\n                    bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound;\n                  }\n                  _energy+=delta_I*delta_I + smoothness*_energy_regul;\n                }\n                if (V) cimg_forX(V,x) if (V(x,y,2)) { // Apply constraints.\n                    U(x,y,0) = V(x,y,0)/factor;\n                    U(x,y,1) = V(x,y,1)/factor;\n                  }\n              } else { // Anisotropic regularization.\n              const float nsmoothness = -smoothness;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_height>=8 && _width>=16) reduction(+:_energy)\n#endif\n              cimg_forY(U,y) {\n                const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y;\n                cimg_for3X(U,x) {\n                  const float\n                    X = is_backward?x - U(x,y,0):x + U(x,y,0),\n                    Y = is_backward?y - U(x,y,1):y + U(x,y,1);\n                  float delta_I = 0, _energy_regul = 0;\n                  if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1.linear_atXY(X,Y,c) - I2(x,y,c));\n                  else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,c) - I2.linear_atXY(X,Y,c));\n                  cimg_forC(U,c) {\n                    const float\n                      Ux = 0.5f*(U(_n1x,y,c) - U(_p1x,y,c)),\n                      Uy = 0.5f*(U(x,_n1y,c) - U(x,_p1y,c)),\n                      N2 = Ux*Ux + Uy*Uy,\n                      N = std::sqrt(N2),\n                      N3 = 1e-5f + N2*N,\n                      coef_a = Uy*Uy/N3,\n                      coef_b = -2*Ux*Uy/N3,\n                      coef_c = Ux*Ux/N3,\n                      Uxx = U(_n1x,y,c) + U(_p1x,y,c),\n                      Uyy = U(x,_n1y,c) + U(x,_p1y,c),\n                      Uxy = 0.25f*(U(_n1x,_n1y,c) + U(_p1x,_p1y,c) - U(_n1x,_p1y,c) - U(_n1x,_p1y,c));\n                    U(x,y,c) = (float)(U(x,y,c) + dt*(delta_I*dI[c].linear_atXY(X,Y) +\n                                                      nsmoothness*( coef_a*Uxx + coef_b*Uxy + coef_c*Uyy )))/\n                      (1 + 2*(coef_a + coef_c)*nsmoothness*dt);\n                    _energy_regul+=N;\n                  }\n                  if (is_backward) { // Constraint displacement vectors to stay in image.\n                    if (U(x,y,0)>x) U(x,y,0) = (float)x;\n                    if (U(x,y,1)>y) U(x,y,1) = (float)y;\n                    bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound;\n                    bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound;\n                  } else {\n                    if (U(x,y,0)<-x) U(x,y,0) = -(float)x;\n                    if (U(x,y,1)<-y) U(x,y,1) = -(float)y;\n                    bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound;\n                    bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound;\n                  }\n                  _energy+=delta_I*delta_I + nsmoothness*_energy_regul;\n                }\n                if (V) cimg_forX(V,x) if (V(x,y,2)) { // Apply constraints.\n                    U(x,y,0) = V(x,y,0)/factor;\n                    U(x,y,1) = V(x,y,1)/factor;\n                  }\n              }\n            }\n          }\n          const float d_energy = (_energy - energy)/(sw*sh*sd);\n          if (d_energy<=0 && -d_energy<_precision) break;\n          if (d_energy>0) dt*=0.5f;\n          energy = _energy;\n        }\n      }\n      return U;\n    }\n\n    //! Compute correspondence map between two images, using the patch-match algorithm.\n    /**\n        \\param patch_image The image containing the reference patches to match with the instance image.\n        \\param patch_width Width of the patch used for matching.\n        \\param patch_height Height of the patch used for matching.\n        \\param patch_depth Depth of the patch used for matching.\n        \\param nb_iterations Number of patch-match iterations.\n        \\param nb_randoms Number of randomization attempts (per pixel).\n        \\param guide Image used as the initial correspondence estimate for the algorithm.\n          'guide' may have a last channel with boolean values (0=false | other=true) that\n          tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask).\n        \\param[out] matching_score Returned as the image of matching scores.\n        \\note\n        The patch-match algorithm is described in this paper:\n        Connelly Barnes, Eli Shechtman, Adam Finkelstein, Dan B Goldman(2009),\n        PatchMatch: A Randomized Correspondence Algorithm for Structural Image Editing\n    **/\n    template<typename t1, typename t2>\n    CImg<T>& patchmatch(const CImg<T>& patch_image,\n                        const unsigned int patch_width,\n                        const unsigned int patch_height,\n                        const unsigned int patch_depth,\n                        const unsigned int nb_iterations,\n                        const unsigned int nb_randoms,\n                        const CImg<t1> &guide,\n                        CImg<t2> &matching_score) {\n      return get_patchmatch(patch_image,patch_width,patch_height,patch_depth,\n                            nb_iterations,nb_randoms,guide,matching_score).move_to(*this);\n    }\n\n    //! Compute correspondence map between two images, using the patch-match algorithm \\newinstance.\n    template<typename t1, typename t2>\n    CImg<intT> get_patchmatch(const CImg<T>& patch_image,\n                              const unsigned int patch_width,\n                              const unsigned int patch_height,\n                              const unsigned int patch_depth,\n                              const unsigned int nb_iterations,\n                              const unsigned int nb_randoms,\n                              const CImg<t1> &guide,\n                              CImg<t2> &matching_score) const {\n      return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth,\n                             nb_iterations,nb_randoms,\n                             guide,true,matching_score);\n    }\n\n    //! Compute correspondence map between two images, using the patch-match algorithm \\overloading.\n    template<typename t>\n    CImg<T>& patchmatch(const CImg<T>& patch_image,\n                        const unsigned int patch_width,\n                        const unsigned int patch_height,\n                        const unsigned int patch_depth,\n                        const unsigned int nb_iterations,\n                        const unsigned int nb_randoms,\n                        const CImg<t> &guide) {\n      return get_patchmatch(patch_image,patch_width,patch_height,patch_depth,\n                            nb_iterations,nb_randoms,guide).move_to(*this);\n    }\n\n    //! Compute correspondence map between two images, using the patch-match algorithm \\overloading.\n    template<typename t>\n    CImg<intT> get_patchmatch(const CImg<T>& patch_image,\n                              const unsigned int patch_width,\n                              const unsigned int patch_height,\n                              const unsigned int patch_depth,\n                              const unsigned int nb_iterations,\n                              const unsigned int nb_randoms,\n                              const CImg<t> &guide) const {\n      return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth,\n                             nb_iterations,nb_randoms,\n                             guide,false,CImg<T>::empty());\n    }\n\n    //! Compute correspondence map between two images, using the patch-match algorithm \\overloading.\n    CImg<T>& patchmatch(const CImg<T>& patch_image,\n                        const unsigned int patch_width,\n                        const unsigned int patch_height,\n                        const unsigned int patch_depth=1,\n                        const unsigned int nb_iterations=5,\n                        const unsigned int nb_randoms=5) {\n      return get_patchmatch(patch_image,patch_width,patch_height,patch_depth,\n                            nb_iterations,nb_randoms).move_to(*this);\n    }\n\n    //! Compute correspondence map between two images, using the patch-match algorithm \\overloading.\n    CImg<intT> get_patchmatch(const CImg<T>& patch_image,\n                              const unsigned int patch_width,\n                              const unsigned int patch_height,\n                              const unsigned int patch_depth=1,\n                              const unsigned int nb_iterations=5,\n                              const unsigned int nb_randoms=5) const {\n      return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth,\n                             nb_iterations,nb_randoms,\n                             CImg<T>::const_empty(),\n                             false,CImg<T>::empty());\n    }\n\n    template<typename t1, typename t2>\n    CImg<intT> _get_patchmatch(const CImg<T>& patch_image,\n                               const unsigned int patch_width,\n                               const unsigned int patch_height,\n                               const unsigned int patch_depth,\n                               const unsigned int nb_iterations,\n                               const unsigned int nb_randoms,\n                               const CImg<t1> &guide,\n                               const bool is_matching_score,\n                               CImg<t2> &matching_score) const {\n      if (is_empty()) return CImg<intT>::const_empty();\n      if (patch_image._spectrum!=_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"patchmatch(): Instance image and specified patch image (%u,%u,%u,%u,%p) \"\n                                    \"have different spectrums.\",\n                                    cimg_instance,\n                                    patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum,\n                                    patch_image._data);\n      if (patch_width>_width || patch_height>_height || patch_depth>_depth)\n        throw CImgArgumentException(_cimg_instance\n                                    \"patchmatch(): Specified patch size %ux%ux%u is bigger than the dimensions \"\n                                    \"of the instance image.\",\n                                    cimg_instance,patch_width,patch_height,patch_depth);\n      if (patch_width>patch_image._width || patch_height>patch_image._height || patch_depth>patch_image._depth)\n        throw CImgArgumentException(_cimg_instance\n                                    \"patchmatch(): Specified patch size %ux%ux%u is bigger than the dimensions \"\n                                    \"of the patch image image (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,patch_width,patch_height,patch_depth,\n                                    patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum,\n                                    patch_image._data);\n      const unsigned int\n        _constraint = patch_image._depth>1?3:2,\n        constraint = guide._spectrum>_constraint?_constraint:0;\n\n      if (guide &&\n          (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<_constraint))\n        throw CImgArgumentException(_cimg_instance\n                                    \"patchmatch(): Specified guide (%u,%u,%u,%u,%p) has invalid dimensions \"\n                                    \"considering instance and patch image image (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    guide._width,guide._height,guide._depth,guide._spectrum,guide._data,\n                                    patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum,\n                                    patch_image._data);\n\n      CImg<intT> map(_width,_height,_depth,patch_image._depth>1?3:2);\n      CImg<floatT> score(_width,_height,_depth);\n      const int\n        psizew = (int)patch_width, psizew1 = psizew/2, psizew2 = psizew - psizew1 - 1,\n        psizeh = (int)patch_height, psizeh1 = psizeh/2, psizeh2 = psizeh - psizeh1 - 1,\n        psized = (int)patch_depth, psized1 = psized/2, psized2 = psized - psized1 - 1;\n\n      if (_depth>1 || patch_image._depth>1) { // 3d version.\n\n        // Initialize correspondence map.\n        if (guide) cimg_forXYZ(*this,x,y,z) { // User-defined initialization.\n            const int\n              cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,\n              cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,\n              cz1 = z<=psized1?z:(z<depth() - psized2?psized1:psized + z - depth()), cz2 = psized - cz1 - 1,\n              u = cimg::min(cimg::max((int)guide(x,y,z,0),cx1),patch_image.width() - 1 - cx2),\n              v = cimg::min(cimg::max((int)guide(x,y,z,1),cy1),patch_image.height() - 1 - cy2),\n              w = cimg::min(cimg::max((int)guide(x,y,z,2),cz1),patch_image.depth() - 1 - cz2);\n            map(x,y,z,0) = u;\n            map(x,y,z,1) = v;\n            map(x,y,z,2) = w;\n            score(x,y,z) = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,\n                                       x - cx1,y - cy1,z - cz1,\n                                       u - cx1,v - cy1,w - cz1,cimg::type<float>::inf());\n          } else cimg_forXYZ(*this,x,y,z) { // Random initialization.\n            const int\n              cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,\n              cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,\n              cz1 = z<=psized1?z:(z<depth() - psized2?psized1:psized + z - depth()), cz2 = psized - cz1 - 1,\n              u = (int)cimg::round(cimg::rand(cx1,patch_image.width() - 1 - cx2)),\n              v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2)),\n              w = (int)cimg::round(cimg::rand(cz1,patch_image.depth() - 1 - cz2));\n            map(x,y,z,0) = u;\n            map(x,y,z,1) = v;\n            map(x,y,z,2) = w;\n            score(x,y,z) = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,\n                                       x - cx1,y - cy1,z - cz1,\n                                       u - cx1,v - cy1,w - cz1,cimg::type<float>::inf());\n          }\n\n        // Start iteration loop.\n        for (unsigned int iter = 0; iter<nb_iterations; ++iter) {\n          cimg_test_abort();\n          const bool is_even = !(iter%2);\n\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if (_width>64 && iter<nb_iterations-2)\n#endif\n          cimg_forXYZ(*this,X,Y,Z) {\n            const int\n              x = is_even?X:width() - 1 - X,\n              y = is_even?Y:height() - 1 - Y,\n              z = is_even?Z:depth() - 1 - Z;\n            if (score(x,y,z)<=1e-5 || (constraint && guide(x,y,z,constraint)!=0)) continue;\n            const int\n              cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,\n              cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,\n              cz1 = z<=psized1?z:(z<depth() - psized2?psized1:psized + z - depth()), cz2 = psized - cz1 - 1,\n              xp = x - cx1,\n              yp = y - cy1,\n              zp = z - cz1;\n\n            // Propagation.\n            if (is_even) {\n              if (x>0) { // Compare with left neighbor.\n                const int u = map(x - 1,y,z,0), v = map(x - 1,y,z,1), w = map(x - 1,y,z,2);\n                if (u>=cx1 - 1 && u<patch_image.width() - 1 - cx2 &&\n                    v>=cy1 && v<patch_image.height() - cy2 &&\n                    w>=cz1 && w<patch_image.depth() - cz2) {\n                  const float\n                    current_score = score(x,y,z),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,\n                                    xp,yp,zp,u + 1 - cx1,v - cy1,w - cz1,current_score);\n                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u + 1; map(x,y,z,1) = v; map(x,y,z,2) = w; }\n                }\n              }\n              if (y>0) { // Compare with up neighbor.\n                const int u = map(x,y - 1,z,0), v = map(x,y - 1,z,1), w = map(x,y - 1,z,2);\n                if (u>=cx1 && u<patch_image.width() - cx2 &&\n                    v>=cy1 - 1 && v<patch_image.height() - 1 - cy2 &&\n                    w>=cz1 && w<patch_image.depth() - cx2) {\n                  const float\n                    current_score = score(x,y,z),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,\n                                    xp,yp,zp,u - cx1,v + 1 - cy1,w - cz1,current_score);\n                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v + 1; map(x,y,z,2) = w; }\n                }\n              }\n              if (z>0) { // Compare with backward neighbor.\n                const int u = map(x,y,z - 1,0), v = map(x,y,z - 1,1), w = map(x,y,z - 1,2);\n                if (u>=cx1 && u<patch_image.width() - cx2 &&\n                    v>=cy1 && v<patch_image.height() - cy2 &&\n                    w>=cz1 - 1 && w<patch_image.depth() - 1 - cz2) {\n                  const float\n                    current_score = score(x,y,z),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,\n                                    xp,yp,zp,u - cx1,v - cy1,w + 1 - cz1,current_score);\n                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v; map(x,y,z,2) = w + 1; }\n                }\n              }\n            } else {\n              if (x<width() - 1) { // Compare with right neighbor.\n                const int u = map(x + 1,y,z,0), v = map(x + 1,y,z,1), w = map(x + 1,y,z,2);\n                if (u>=cx1 + 1 && u<patch_image.width() + 1 - cx2 &&\n                    v>=cy1 && v<patch_image.height() - cy2 &&\n                    w>=cz1 && w<patch_image.depth() - cz2) {\n                  const float\n                    current_score = score(x,y,z),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,\n                                    xp,yp,zp,u - 1 - cx1,v - cy1,w - cz1,current_score);\n                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u - 1; map(x,y,z,1) = v; map(x,y,z,2) = w; }\n                }\n              }\n              if (y<height() - 1) { // Compare with bottom neighbor.\n                const int u = map(x,y + 1,z,0), v = map(x,y + 1,z,1), w = map(x,y + 1,z,2);\n                if (u>=cx1 && u<patch_image.width() - cx2 &&\n                    v>=cy1 + 1 && v<patch_image.height() + 1 - cy2 &&\n                    w>=cz1 && w<patch_image.depth() - cz2) {\n                  const float\n                    current_score = score(x,y,z),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,\n                                    xp,yp,zp,u - cx1,v - 1 - cy1,w - cz1,current_score);\n                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v - 1; map(x,y,z,2) = w; }\n                }\n              }\n              if (z<depth() - 1) { // Compare with forward neighbor.\n                const int u = map(x,y,z + 1,0), v = map(x,y,z + 1,1), w = map(x,y,z + 1,2);\n                if (u>=cx1 && u<patch_image.width() - cx2 &&\n                    v>=cy1 && v<patch_image.height() - cy2 &&\n                    w>=cz1 + 1 && w<patch_image.depth() + 1 - cz2) {\n                  const float\n                    current_score = score(x,y,z),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,\n                                    xp,yp,zp,u - cx1,v - cy1,w - 1 - cz1,current_score);\n                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v; map(x,y,z,2) = w - 1; }\n                }\n              }\n            }\n\n            // Randomization.\n            const int u = map(x,y,z,0), v = map(x,y,z,1), w = map(x,y,z,2);\n            float dw = (float)patch_image.width(), dh = (float)patch_image.height(), dd = (float)patch_image.depth();\n            for (unsigned int i = 0; i<nb_randoms; ++i) {\n              const int\n                ui = (int)cimg::round(cimg::rand(cimg::max(cx1,u - dw),\n                                                 cimg::min(patch_image.width() - 1 - cx2,u + dw))),\n                vi = (int)cimg::round(cimg::rand(cimg::max(cy1,v - dh),\n                                                 cimg::min(patch_image.height() - 1 - cy2,v + dh))),\n                wi = (int)cimg::round(cimg::rand(cimg::max(cz1,w - dd),\n                                                 cimg::min(patch_image.depth() - 1 - cz2,w + dd)));\n              if (ui!=u || vi!=v || wi!=w) {\n                const float\n                  current_score = score(x,y,z),\n                  D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,\n                                  xp,yp,zp,ui - cx1,vi - cy1,wi - cz1,current_score);\n                if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = ui; map(x,y,z,1) = vi; map(x,y,z,2) = wi; }\n                dw = cimg::max(5.0f,dw*0.5f); dh = cimg::max(5.0f,dh*0.5f); dd = cimg::max(5.0f,dd*0.5f);\n              }\n            }\n          }\n        }\n\n      } else { // 2d version.\n\n        // Initialize correspondence map.\n        if (guide) cimg_forXY(*this,x,y) { // Random initialization.\n            const int\n              cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,\n              cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()) , cy2 = psizeh - cy1 - 1,\n              u = cimg::min(cimg::max((int)guide(x,y,0),cx1),patch_image.width() - 1 - cx2),\n              v = cimg::min(cimg::max((int)guide(x,y,1),cy1),patch_image.height() - 1 - cy2);\n            map(x,y,0) = u;\n            map(x,y,1) = v;\n            score(x,y) = _patchmatch(*this,patch_image,patch_width,patch_height,\n                                     x - cx1,y - cy1,u - cx1,v - cy1,cimg::type<float>::inf());\n          } else cimg_forXY(*this,x,y) { // Random initialization.\n            const int\n              cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,\n              cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()) , cy2 = psizeh - cy1 - 1,\n              u = (int)cimg::round(cimg::rand(cx1,patch_image.width() - 1 - cx2)),\n              v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2));\n            map(x,y,0) = u;\n            map(x,y,1) = v;\n            score(x,y) = _patchmatch(*this,patch_image,patch_width,patch_height,\n                                     x - cx1,y - cy1,u - cx1,v - cy1,cimg::type<float>::inf());\n          }\n\n        // Start iteration loop.\n        for (unsigned int iter = 0; iter<nb_iterations; ++iter) {\n          const bool is_even = !(iter%2);\n\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_width>64 && iter<nb_iterations-2)\n#endif\n          cimg_forXY(*this,X,Y) {\n            const int\n              x = is_even?X:width() - 1 - X,\n              y = is_even?Y:height() - 1 - Y;\n            if (score(x,y)<=1e-5 || (constraint && guide(x,y,constraint)!=0)) continue;\n            const int\n              cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,\n              cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()) , cy2 = psizeh - cy1 - 1,\n              xp = x - cx1,\n              yp = y - cy1;\n\n            // Propagation.\n            if (is_even) {\n              if (x>0) { // Compare with left neighbor.\n                const int u = map(x - 1,y,0), v = map(x - 1,y,1);\n                if (u>=cx1 - 1 && u<patch_image.width() - 1 - cx2 &&\n                    v>=cy1 && v<patch_image.height() - cy2) {\n                  const float\n                    current_score = score(x,y),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,\n                                    xp,yp,u + 1 - cx1,v - cy1,current_score);\n                  if (D<current_score) { score(x,y) = D; map(x,y,0) = u + 1; map(x,y,1) = v; }\n                }\n              }\n              if (y>0) { // Compare with up neighbor.\n                const int u = map(x,y - 1,0), v = map(x,y - 1,1);\n                if (u>=cx1 && u<patch_image.width() - cx2 &&\n                    v>=cy1 - 1 && v<patch_image.height() - 1 - cy2) {\n                  const float\n                    current_score = score(x,y),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,\n                                    xp,yp,u - cx1,v + 1 - cy1,current_score);\n                  if (D<current_score) { score(x,y) = D; map(x,y,0) = u; map(x,y,1) = v + 1; }\n                }\n              }\n            } else {\n              if (x<width() - 1) { // Compare with right neighbor.\n                const int u = map(x + 1,y,0), v = map(x + 1,y,1);\n                if (u>=cx1 + 1 && u<patch_image.width() + 1 - cx2 &&\n                    v>=cy1 && v<patch_image.height() - cy2) {\n                  const float\n                    current_score = score(x,y),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,\n                                    xp,yp,u - 1 - cx1,v - cy1,current_score);\n                  if (D<current_score) { score(x,y) = D; map(x,y,0) = u - 1; map(x,y,1) = v; }\n                }\n              }\n              if (y<height() - 1) { // Compare with bottom neighbor.\n                const int u = map(x,y + 1,0), v = map(x,y + 1,1);\n                if (u>=cx1 && u<patch_image.width() - cx2 &&\n                    v>=cy1 + 1 && v<patch_image.height() + 1 - cy2) {\n                  const float\n                    current_score = score(x,y),\n                    D = _patchmatch(*this,patch_image,patch_width,patch_height,\n                                    xp,yp,u - cx1,v - 1 - cy1,current_score);\n                  if (D<current_score) { score(x,y) = D; map(x,y,0) = u; map(x,y,1) = v - 1; }\n                }\n              }\n            }\n\n            // Randomization.\n            const int u = map(x,y,0), v = map(x,y,1);\n            float dw = (float)patch_image.width(), dh = (float)patch_image.height();\n            for (unsigned int i = 0; i<nb_randoms; ++i) {\n              const int\n                ui = (int)cimg::round(cimg::rand(cimg::max(cx1,u - dw),\n                                                 cimg::min(patch_image.width() - 1 - cx2,u + dw))),\n                vi = (int)cimg::round(cimg::rand(cimg::max(cy1,v - dh),\n                                                 cimg::min(patch_image.height() - 1 - cy2,v + dh)));\n              if (ui!=u || vi!=v) {\n                const float\n                  current_score = score(x,y),\n                  D = _patchmatch(*this,patch_image,patch_width,patch_height,\n                                  xp,yp,ui - cx1,vi - cy1,current_score);\n                if (D<current_score) { score(x,y) = D; map(x,y,0) = ui; map(x,y,1) = vi; }\n                dw = cimg::max(5.0f,dw*0.5f); dh = cimg::max(5.0f,dh*0.5f);\n              }\n            }\n          }\n        }\n      }\n      if (is_matching_score) score.move_to(matching_score);\n      return map;\n    }\n\n    // Compute SSD between two patches in different images.\n    static float _patchmatch(const CImg<T>& img1, const CImg<T>& img2,\n                             const unsigned int psizew, const unsigned int psizeh,\n                             const int x1, const int y1,\n                             const int x2, const int y2,\n                             const float max_ssd) { // 2d version.\n      const T *p1 = img1.data(x1,y1), *p2 = img2.data(x2,y2);\n      const ulongT\n        offx1 = (ulongT)img1._width - psizew,\n        offx2 = (ulongT)img2._width - psizew,\n        offy1 = (ulongT)img1._width*img1._height - psizeh*img1._width,\n        offy2 = (ulongT)img2._width*img2._height - psizeh*img2._width;\n      float ssd = 0;\n      cimg_forC(img1,c) {\n        for (unsigned int j = 0; j<psizeh; ++j) {\n          for (unsigned int i = 0; i<psizew; ++i)\n            ssd += cimg::sqr(*(p1++) - *(p2++));\n          if (ssd>max_ssd) return max_ssd;\n          p1+=offx1; p2+=offx2;\n        }\n        p1+=offy1; p2+=offy2;\n      }\n      return ssd;\n    }\n\n    static float _patchmatch(const CImg<T>& img1, const CImg<T>& img2,\n                             const unsigned int psizew, const unsigned int psizeh, const unsigned int psized,\n                             const int x1, const int y1, const int z1,\n                             const int x2, const int y2, const int z2,\n                             const float max_ssd) { // 3d version.\n      const T *p1 = img1.data(x1,y1,z1), *p2 = img2.data(x2,y2,z2);\n      const ulongT\n        offx1 = (ulongT)img1._width - psizew,\n        offx2 = (ulongT)img2._width - psizew,\n        offy1 = (ulongT)img1._width*img1._height - psizeh*img1._width - psizew,\n        offy2 = (ulongT)img2._width*img2._height - psizeh*img2._width - psizew,\n        offz1 = (ulongT)img1._width*img1._height*img1._depth - psized*img1._width*img1._height -\n        psizeh*img1._width - psizew,\n        offz2 = (ulongT)img2._width*img2._height*img2._depth - psized*img2._width*img2._height -\n        psizeh*img2._width - psizew;\n      float ssd = 0;\n      cimg_forC(img1,c) {\n        for (unsigned int k = 0; k<psized; ++k) {\n          for (unsigned int j = 0; j<psizeh; ++j) {\n            for (unsigned int i = 0; i<psizew; ++i)\n              ssd += cimg::sqr(*(p1++) - *(p2++));\n            if (ssd>max_ssd) return max_ssd;\n            p1+=offx1; p2+=offx2;\n          }\n          p1+=offy1; p2+=offy2;\n        }\n        p1+=offz1; p2+=offz2;\n      }\n      return ssd;\n    }\n\n    //! Compute Euclidean distance function to a specified value.\n    /**\n        \\param value Reference value.\n        \\param metric Type of metric. Can be <tt>{ 0=Chebyshev | 1=Manhattan | 2=Euclidean | 3=Squared-euclidean }</tt>.\n        \\note\n        The distance transform implementation has been submitted by A. Meijster, and implements\n        the article 'W.H. Hesselink, A. Meijster, J.B.T.M. Roerdink,\n                     \"A general algorithm for computing distance transforms in linear time.\",\n                     In: Mathematical Morphology and its Applications to Image and Signal Processing,\n                     J. Goutsias, L. Vincent, and D.S. Bloomberg (eds.), Kluwer, 2000, pp. 331-340.'\n         The submitted code has then been modified to fit CImg coding style and constraints.\n    **/\n    CImg<T>& distance(const T& value, const unsigned int metric=2) {\n      if (is_empty()) return *this;\n      if (cimg::type<Tint>::string()!=cimg::type<T>::string()) // For datatype < int.\n        return CImg<Tint>(*this,false).distance((Tint)value,metric).\n          cut((Tint)cimg::type<T>::min(),(Tint)cimg::type<T>::max()).move_to(*this);\n      bool is_value = false;\n      cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,0:(T)cimg::max(0,99999999); // Trick to avoid VC++ warning\n      if (!is_value) return fill(cimg::type<T>::max());\n      switch (metric) {\n      case 0 : return _distance_core(_distance_sep_cdt,_distance_dist_cdt);          // Chebyshev.\n      case 1 : return _distance_core(_distance_sep_mdt,_distance_dist_mdt);          // Manhattan.\n      case 3 : return _distance_core(_distance_sep_edt,_distance_dist_edt);          // Squared Euclidean.\n      default : return _distance_core(_distance_sep_edt,_distance_dist_edt).sqrt();  // Euclidean.\n      }\n      return *this;\n    }\n\n    //! Compute distance to a specified value \\newinstance.\n    CImg<Tfloat> get_distance(const T& value, const unsigned int metric=2) const {\n      return CImg<Tfloat>(*this,false).distance((Tfloat)value,metric);\n    }\n\n    static longT _distance_sep_edt(const longT i, const longT u, const longT *const g) {\n      return (u*u - i*i + g[u] - g[i])/(2*(u - i));\n    }\n\n    static longT _distance_dist_edt(const longT x, const longT i, const longT *const g) {\n      return (x - i)*(x - i) + g[i];\n    }\n\n    static longT _distance_sep_mdt(const longT i, const longT u, const longT *const g) {\n      return (u - i<=g[u] - g[i]?999999999:(g[u] - g[i] + u + i)/2);\n    }\n\n    static longT _distance_dist_mdt(const longT x, const longT i, const longT *const g) {\n      return (x<i?i - x:x - i) + g[i];\n    }\n\n    static longT _distance_sep_cdt(const longT i, const longT u, const longT *const g) {\n      const longT h = (i + u)/2;\n      if (g[i]<=g[u]) { return h<i + g[u]?i + g[u]:h; }\n      return h<u - g[i]?h:u - g[i];\n    }\n\n    static longT _distance_dist_cdt(const longT x, const longT i, const longT *const g) {\n      const longT d = x<i?i - x:x - i;\n      return d<g[i]?g[i]:d;\n    }\n\n    static void _distance_scan(const unsigned int len,\n                               const longT *const g,\n                               longT (*const sep)(const longT, const longT, const longT *const),\n                               longT (*const f)(const longT, const longT, const longT *const),\n                               longT *const s,\n                               longT *const t,\n                               longT *const dt) {\n      longT q = s[0] = t[0] = 0;\n      for (int u = 1; u<(int)len; ++u) { // Forward scan.\n        while ((q>=0) && f(t[q],s[q],g)>f(t[q],u,g)) { --q; }\n        if (q<0) { q = 0; s[0] = u; }\n        else { const longT w = 1 + sep(s[q], u, g); if (w<(longT)len) { ++q; s[q] = u; t[q] = w; }}\n      }\n      for (int u = (int)len - 1; u>=0; --u) { dt[u] = f(u,s[q],g); if (u==t[q]) --q; } // Backward scan.\n    }\n\n    CImg<T>& _distance_core(longT (*const sep)(const longT, const longT, const longT *const),\n                            longT (*const f)(const longT, const longT, const longT *const)) {\n // Check for g++ 4.9.X, as OpenMP seems to crash for this particular function. I have no clues why.\n#define cimg_is_gcc49x (__GNUC__==4 && __GNUC_MINOR__==9)\n\n      const ulongT wh = (ulongT)_width*_height;\n#if defined(cimg_use_openmp) && !cimg_is_gcc49x\n#pragma omp parallel for cimg_openmp_if(_spectrum>=2)\n#endif\n      cimg_forC(*this,c) {\n        CImg<longT> g(_width), dt(_width), s(_width), t(_width);\n        CImg<T> img = get_shared_channel(c);\n#if defined(cimg_use_openmp) && !cimg_is_gcc49x\n#pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) firstprivate(g,dt,s,t)\n#endif\n        cimg_forYZ(*this,y,z) { // Over X-direction.\n          cimg_forX(*this,x) g[x] = (longT)img(x,y,z,0,wh);\n          _distance_scan(_width,g,sep,f,s,t,dt);\n          cimg_forX(*this,x) img(x,y,z,0,wh) = (T)dt[x];\n        }\n        if (_height>1) {\n          g.assign(_height); dt.assign(_height); s.assign(_height); t.assign(_height);\n#if defined(cimg_use_openmp) && !cimg_is_gcc49x\n#pragma omp parallel for collapse(2) if (_height>=512 && _width*_depth>=16) firstprivate(g,dt,s,t)\n#endif\n          cimg_forXZ(*this,x,z) { // Over Y-direction.\n            cimg_forY(*this,y) g[y] = (longT)img(x,y,z,0,wh);\n            _distance_scan(_height,g,sep,f,s,t,dt);\n            cimg_forY(*this,y) img(x,y,z,0,wh) = (T)dt[y];\n          }\n        }\n        if (_depth>1) {\n          g.assign(_depth); dt.assign(_depth); s.assign(_depth); t.assign(_depth);\n#if defined(cimg_use_openmp) && !cimg_is_gcc49x\n#pragma omp parallel for collapse(2) if (_depth>=512 && _width*_height>=16) firstprivate(g,dt,s,t)\n#endif\n          cimg_forXY(*this,x,y) { // Over Z-direction.\n            cimg_forZ(*this,z) g[z] = (longT)img(x,y,z,0,wh);\n            _distance_scan(_depth,g,sep,f,s,t,dt);\n            cimg_forZ(*this,z) img(x,y,z,0,wh) = (T)dt[z];\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Compute chamfer distance to a specified value, with a custom metric.\n    /**\n       \\param value Reference value.\n       \\param metric_mask Metric mask.\n       \\note The algorithm code has been initially proposed by A. Meijster, and modified by D. Tschumperlé.\n    **/\n    template<typename t>\n    CImg<T>& distance(const T& value, const CImg<t>& metric_mask) {\n      if (is_empty()) return *this;\n      bool is_value = false;\n      cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,0:(T)999999999;\n      if (!is_value) return fill(cimg::type<T>::max());\n      const ulongT wh = (ulongT)_width*_height;\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_spectrum>=2)\n#endif\n      cimg_forC(*this,c) {\n        CImg<T> img = get_shared_channel(c);\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(3) if (_width*_height*_depth>=1024)\n#endif\n        cimg_forXYZ(metric_mask,dx,dy,dz) {\n          const t weight = metric_mask(dx,dy,dz);\n          if (weight) {\n            for (int z = dz, nz = 0; z<depth(); ++z,++nz) { // Forward scan.\n              for (int y = dy , ny = 0; y<height(); ++y,++ny) {\n                for (int x = dx, nx = 0; x<width(); ++x,++nx) {\n                  const T dd = img(nx,ny,nz,0,wh) + weight;\n                  if (dd<img(x,y,z,0,wh)) img(x,y,z,0,wh) = dd;\n                }\n              }\n            }\n            for (int z = depth() - 1 - dz, nz = depth() - 1; z>=0; --z,--nz) { // Backward scan.\n              for (int y = height() - 1 - dy, ny = height() - 1; y>=0; --y,--ny) {\n                for (int x = width() - 1 - dx, nx = width() - 1; x>=0; --x,--nx) {\n                  const T dd = img(nx,ny,nz,0,wh) + weight;\n                  if (dd<img(x,y,z,0,wh)) img(x,y,z,0,wh) = dd;\n                }\n              }\n            }\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Compute chamfer distance to a specified value, with a custom metric \\newinstance.\n    template<typename t>\n    CImg<Tfloat> get_distance(const T& value, const CImg<t>& metric_mask) const {\n      return CImg<Tfloat>(*this,false).distance(value,metric_mask);\n    }\n\n    //! Compute distance to a specified value, according to a custom metric (use dijkstra algorithm).\n    /**\n       \\param value Reference value.\n       \\param metric Field of distance potentials.\n       \\param is_high_connectivity Tells if the algorithm uses low or high connectivity.\n     **/\n    template<typename t, typename to>\n    CImg<T>& distance_dijkstra(const T& value, const CImg<t>& metric, const bool is_high_connectivity,\n                               CImg<to>& return_path) {\n      return get_distance_dijkstra(value,metric,is_high_connectivity,return_path).move_to(*this);\n    }\n\n    //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm) \\newinstance.\n    template<typename t, typename to>\n    CImg<typename cimg::superset<t,long>::type>\n    get_distance_dijkstra(const T& value, const CImg<t>& metric, const bool is_high_connectivity,\n                          CImg<to>& return_path) const {\n      if (is_empty()) return return_path.assign();\n      if (!is_sameXYZ(metric))\n        throw CImgArgumentException(_cimg_instance\n                                    \"distance_dijkstra(): image instance and metric map (%u,%u,%u,%u) \"\n                                    \"have incompatible dimensions.\",\n                                    cimg_instance,\n                                    metric._width,metric._height,metric._depth,metric._spectrum);\n      typedef typename cimg::superset<t,long>::type td;  // Type used for computing cumulative distances.\n      CImg<td> result(_width,_height,_depth,_spectrum), Q;\n      CImg<boolT> is_queued(_width,_height,_depth,1);\n      if (return_path) return_path.assign(_width,_height,_depth,_spectrum);\n\n      cimg_forC(*this,c) {\n        const CImg<T> img = get_shared_channel(c);\n        const CImg<t> met = metric.get_shared_channel(c%metric._spectrum);\n        CImg<td> res = result.get_shared_channel(c);\n        CImg<to> path = return_path?return_path.get_shared_channel(c):CImg<to>();\n        unsigned int sizeQ = 0;\n\n        // Detect initial seeds.\n        is_queued.fill(0);\n        cimg_forXYZ(img,x,y,z) if (img(x,y,z)==value) {\n          Q._priority_queue_insert(is_queued,sizeQ,0,x,y,z);\n          res(x,y,z) = 0;\n          if (path) path(x,y,z) = (to)0;\n        }\n\n        // Start distance propagation.\n        while (sizeQ) {\n\n          // Get and remove point with minimal potential from the queue.\n          const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3);\n          const td P = (td)-Q(0,0);\n          Q._priority_queue_remove(sizeQ);\n\n          // Update neighbors.\n          td npot = 0;\n          if (x - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x - 1,y,z) + P),x - 1,y,z)) {\n            res(x - 1,y,z) = npot; if (path) path(x - 1,y,z) = (to)2;\n          }\n          if (x + 1<width() && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x + 1,y,z) + P),x + 1,y,z)) {\n            res(x + 1,y,z) = npot; if (path) path(x + 1,y,z) = (to)1;\n          }\n          if (y - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y - 1,z) + P),x,y - 1,z)) {\n            res(x,y - 1,z) = npot; if (path) path(x,y - 1,z) = (to)8;\n          }\n          if (y + 1<height() && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y + 1,z) + P),x,y + 1,z)) {\n            res(x,y + 1,z) = npot; if (path) path(x,y + 1,z) = (to)4;\n          }\n          if (z - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z - 1) + P),x,y,z - 1)) {\n            res(x,y,z - 1) = npot; if (path) path(x,y,z - 1) = (to)32;\n          }\n          if (z + 1<depth() && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z + 1) + P),x,y,z + 1)) {\n            res(x,y,z + 1) = npot; if (path) path(x,y,z + 1) = (to)16;\n          }\n\n          if (is_high_connectivity) {\n            const float sqrt2 = std::sqrt(2.0f), sqrt3 = std::sqrt(3.0f);\n\n            // Diagonal neighbors on slice z.\n            if (x - 1>=0 && y - 1>=0 &&\n                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y - 1,z) + P)),x - 1,y - 1,z)) {\n              res(x - 1,y - 1,z) = npot; if (path) path(x - 1,y - 1,z) = (to)10;\n            }\n            if (x + 1<width() && y - 1>=0 &&\n                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y - 1,z) + P)),x + 1,y - 1,z)) {\n              res(x + 1,y - 1,z) = npot; if (path) path(x + 1,y - 1,z) = (to)9;\n            }\n            if (x - 1>=0 && y + 1<height() &&\n                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y + 1,z) + P)),x - 1,y + 1,z)) {\n              res(x - 1,y + 1,z) = npot; if (path) path(x - 1,y + 1,z) = (to)6;\n            }\n            if (x + 1<width() && y + 1<height() &&\n                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y + 1,z) + P)),x + 1,y + 1,z)) {\n              res(x + 1,y + 1,z) = npot; if (path) path(x + 1,y + 1,z) = (to)5;\n            }\n\n            if (z - 1>=0) { // Diagonal neighbors on slice z - 1.\n              if (x - 1>=0 &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z - 1) + P)),x - 1,y,z - 1)) {\n                res(x - 1,y,z - 1) = npot; if (path) path(x - 1,y,z - 1) = (to)34;\n              }\n              if (x + 1<width() &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y,z - 1) + P)),x + 1,y,z - 1)) {\n                res(x + 1,y,z - 1) = npot; if (path) path(x + 1,y,z - 1) = (to)33;\n              }\n              if (y - 1>=0 &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z - 1) + P)),x,y - 1,z - 1)) {\n                res(x,y - 1,z - 1) = npot; if (path) path(x,y - 1,z - 1) = (to)40;\n              }\n              if (y + 1<height() &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y + 1,z - 1) + P)),x,y + 1,z - 1)) {\n                res(x,y + 1,z - 1) = npot; if (path) path(x,y + 1,z - 1) = (to)36;\n              }\n              if (x - 1>=0 && y - 1>=0 &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z - 1) + P)),\n                                           x - 1,y - 1,z - 1)) {\n                res(x - 1,y - 1,z - 1) = npot; if (path) path(x - 1,y - 1,z - 1) = (to)42;\n              }\n              if (x + 1<width() && y - 1>=0 &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z - 1) + P)),\n                                           x + 1,y - 1,z - 1)) {\n                res(x + 1,y - 1,z - 1) = npot; if (path) path(x + 1,y - 1,z - 1) = (to)41;\n              }\n              if (x - 1>=0 && y + 1<height() &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y + 1,z - 1) + P)),\n                                           x - 1,y + 1,z - 1)) {\n                res(x - 1,y + 1,z - 1) = npot; if (path) path(x - 1,y + 1,z - 1) = (to)38;\n              }\n              if (x + 1<width() && y + 1<height() &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y + 1,z - 1) + P)),\n                                           x + 1,y + 1,z - 1)) {\n                res(x + 1,y + 1,z - 1) = npot; if (path) path(x + 1,y + 1,z - 1) = (to)37;\n              }\n            }\n\n            if (z + 1<depth()) { // Diagonal neighbors on slice z + 1.\n              if (x - 1>=0 &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z + 1) + P)),x - 1,y,z + 1)) {\n                res(x - 1,y,z + 1) = npot; if (path) path(x - 1,y,z + 1) = (to)18;\n              }\n              if (x + 1<width() &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y,z + 1) + P)),x + 1,y,z + 1)) {\n                res(x + 1,y,z + 1) = npot; if (path) path(x + 1,y,z + 1) = (to)17;\n              }\n              if (y - 1>=0 &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z + 1) + P)),x,y - 1,z + 1)) {\n                res(x,y - 1,z + 1) = npot; if (path) path(x,y - 1,z + 1) = (to)24;\n              }\n              if (y + 1<height() &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y + 1,z + 1) + P)),x,y + 1,z + 1)) {\n                res(x,y + 1,z + 1) = npot; if (path) path(x,y + 1,z + 1) = (to)20;\n              }\n              if (x - 1>=0 && y - 1>=0 &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z + 1) + P)),\n                                           x - 1,y - 1,z + 1)) {\n                res(x - 1,y - 1,z + 1) = npot; if (path) path(x - 1,y - 1,z + 1) = (to)26;\n              }\n              if (x + 1<width() && y - 1>=0 &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z + 1) + P)),\n                                           x + 1,y - 1,z + 1)) {\n                res(x + 1,y - 1,z + 1) = npot; if (path) path(x + 1,y - 1,z + 1) = (to)25;\n              }\n              if (x - 1>=0 && y + 1<height() &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y + 1,z + 1) + P)),\n                                           x - 1,y + 1,z + 1)) {\n                res(x - 1,y + 1,z + 1) = npot; if (path) path(x - 1,y + 1,z + 1) = (to)22;\n              }\n              if (x + 1<width() && y + 1<height() &&\n                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y + 1,z + 1) + P)),\n                                           x + 1,y + 1,z + 1)) {\n                res(x + 1,y + 1,z + 1) = npot; if (path) path(x + 1,y + 1,z + 1) = (to)21;\n              }\n            }\n          }\n        }\n      }\n      return result;\n    }\n\n    //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm). \\overloading.\n    template<typename t>\n    CImg<T>& distance_dijkstra(const T& value, const CImg<t>& metric,\n                               const bool is_high_connectivity=false) {\n      return get_distance_dijkstra(value,metric,is_high_connectivity).move_to(*this);\n    }\n\n    //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm). \\newinstance.\n    template<typename t>\n    CImg<Tfloat> get_distance_dijkstra(const T& value, const CImg<t>& metric,\n                                       const bool is_high_connectivity=false) const {\n      CImg<T> return_path;\n      return get_distance_dijkstra(value,metric,is_high_connectivity,return_path);\n    }\n\n    //! Compute distance map to one source point, according to a custom metric (use fast marching algorithm).\n    /**\n       \\param value Reference value.\n       \\param metric Field of distance potentials.\n     **/\n    template<typename t>\n    CImg<T>& distance_eikonal(const T& value, const CImg<t>& metric) {\n      return get_distance_eikonal(value,metric).move_to(*this);\n    }\n\n    //! Compute distance map to one source point, according to a custom metric (use fast marching algorithm).\n    template<typename t>\n    CImg<Tfloat> get_distance_eikonal(const T& value, const CImg<t>& metric) const {\n      if (is_empty()) return *this;\n      if (!is_sameXYZ(metric))\n        throw CImgArgumentException(_cimg_instance\n                                    \"distance_eikonal(): image instance and metric map (%u,%u,%u,%u) have \"\n                                    \"incompatible dimensions.\",\n                                    cimg_instance,\n                                    metric._width,metric._height,metric._depth,metric._spectrum);\n      CImg<Tfloat> result(_width,_height,_depth,_spectrum,cimg::type<Tfloat>::max()), Q;\n      CImg<charT> state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen.\n\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(_spectrum>=2) firstprivate(Q,state)\n#endif\n      cimg_forC(*this,c) {\n        const CImg<T> img = get_shared_channel(c);\n        const CImg<t> met = metric.get_shared_channel(c%metric._spectrum);\n        CImg<Tfloat> res = result.get_shared_channel(c);\n        unsigned int sizeQ = 0;\n        state.fill(-1);\n\n        // Detect initial seeds.\n        Tfloat *ptr1 = res._data; char *ptr2 = state._data;\n        cimg_for(img,ptr0,T) { if (*ptr0==value) { *ptr1 = 0; *ptr2 = 1; } ++ptr1; ++ptr2; }\n\n        // Initialize seeds neighbors.\n        ptr2 = state._data;\n        cimg_forXYZ(img,x,y,z) if (*(ptr2++)==1) {\n          if (x - 1>=0 && state(x - 1,y,z)==-1) {\n            const Tfloat dist = res(x - 1,y,z) = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z);\n            Q._eik_priority_queue_insert(state,sizeQ,-dist,x - 1,y,z);\n          }\n          if (x + 1<width() && state(x + 1,y,z)==-1) {\n            const Tfloat dist = res(x + 1,y,z) = __distance_eikonal(res,met(x + 1,y,z),x + 1,y,z);\n            Q._eik_priority_queue_insert(state,sizeQ,-dist,x + 1,y,z);\n          }\n          if (y - 1>=0 && state(x,y - 1,z)==-1) {\n            const Tfloat dist = res(x,y - 1,z) = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z);\n            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y - 1,z);\n          }\n          if (y + 1<height() && state(x,y + 1,z)==-1) {\n            const Tfloat dist = res(x,y + 1,z) = __distance_eikonal(res,met(x,y + 1,z),x,y + 1,z);\n            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y + 1,z);\n          }\n          if (z - 1>=0 && state(x,y,z - 1)==-1) {\n            const Tfloat dist = res(x,y,z - 1) = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1);\n            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z - 1);\n          }\n          if (z + 1<depth() && state(x,y,z + 1)==-1) {\n            const Tfloat dist = res(x,y,z + 1) = __distance_eikonal(res,met(x,y,z + 1),x,y,z + 1);\n            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z + 1);\n          }\n        }\n\n        // Propagate front.\n        while (sizeQ) {\n          int x = -1, y = -1, z = -1;\n          while (sizeQ && x<0) {\n            x = (int)Q(0,1); y = (int)Q(0,2); z = (int)Q(0,3);\n            Q._priority_queue_remove(sizeQ);\n            if (state(x,y,z)==1) x = -1; else state(x,y,z) = 1;\n          }\n          if (x>=0) {\n            if (x - 1>=0 && state(x - 1,y,z)!=1) {\n              const Tfloat dist = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z);\n              if (dist<res(x - 1,y,z)) {\n                res(x - 1,y,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x - 1,y,z);\n              }\n            }\n            if (x + 1<width() && state(x + 1,y,z)!=1) {\n              const Tfloat dist = __distance_eikonal(res,met(x + 1,y,z),x + 1,y,z);\n              if (dist<res(x + 1,y,z)) {\n                res(x + 1,y,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x + 1,y,z);\n              }\n            }\n            if (y - 1>=0 && state(x,y - 1,z)!=1) {\n              const Tfloat dist = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z);\n              if (dist<res(x,y - 1,z)) {\n                res(x,y - 1,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y - 1,z);\n              }\n            }\n            if (y + 1<height() && state(x,y + 1,z)!=1) {\n              const Tfloat dist = __distance_eikonal(res,met(x,y + 1,z),x,y + 1,z);\n              if (dist<res(x,y + 1,z)) {\n                res(x,y + 1,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y + 1,z);\n              }\n            }\n            if (z - 1>=0 && state(x,y,z - 1)!=1) {\n              const Tfloat dist = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1);\n              if (dist<res(x,y,z - 1)) {\n                res(x,y,z - 1) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z - 1);\n              }\n            }\n            if (z + 1<depth() && state(x,y,z + 1)!=1) {\n              const Tfloat dist = __distance_eikonal(res,met(x,y,z + 1),x,y,z + 1);\n              if (dist<res(x,y,z + 1)) {\n                res(x,y,z + 1) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z + 1);\n              }\n            }\n          }\n        }\n      }\n      return result;\n    }\n\n    // Locally solve eikonal equation.\n    Tfloat __distance_eikonal(const CImg<Tfloat>& res, const Tfloat P,\n                              const int x=0, const int y=0, const int z=0) const {\n      const T M = cimg::type<T>::max();\n      T T1 = cimg::min(x - 1>=0?res(x - 1,y,z):M,x + 1<width()?res(x + 1,y,z):M);\n      Tfloat root = 0;\n      if (_depth>1) { // 3d.\n        T\n          T2 = cimg::min(y - 1>=0?res(x,y - 1,z):M,y + 1<height()?res(x,y + 1,z):M),\n          T3 = cimg::min(z - 1>=0?res(x,y,z - 1):M,z + 1<depth()?res(x,y,z + 1):M);\n        if (T1>T2) cimg::swap(T1,T2);\n        if (T2>T3) cimg::swap(T2,T3);\n        if (T1>T2) cimg::swap(T1,T2);\n        if (P<=0) return (Tfloat)T1;\n        if (T3<M && ___distance_eikonal(3,-2*(T1 + T2 + T3),T1*T1 + T2*T2 + T3*T3 - P*P,root))\n          return cimg::max((Tfloat)T3,root);\n        if (T2<M && ___distance_eikonal(2,-2*(T1 + T2),T1*T1 + T2*T2 - P*P,root))\n          return cimg::max((Tfloat)T2,root);\n        return P + T1;\n      } else if (_height>1) { // 2d.\n        T T2 = cimg::min(y - 1>=0?res(x,y - 1,z):M,y + 1<height()?res(x,y + 1,z):M);\n        if (T1>T2) cimg::swap(T1,T2);\n        if (P<=0) return (Tfloat)T1;\n        if (T2<M && ___distance_eikonal(2,-2*(T1 + T2),T1*T1 + T2*T2 - P*P,root))\n          return cimg::max((Tfloat)T2,root);\n        return P + T1;\n      } else { // 1d.\n        if (P<=0) return (Tfloat)T1;\n        return P + T1;\n      }\n      return 0;\n    }\n\n    // Find max root of a 2nd-order polynomial.\n    static bool ___distance_eikonal(const Tfloat a, const Tfloat b, const Tfloat c, Tfloat &root) {\n      const Tfloat delta = b*b - 4*a*c;\n      if (delta<0) return false;\n      root = 0.5f*(-b + std::sqrt(delta))/a;\n      return true;\n    }\n\n    // Insert new point in heap.\n    template<typename t>\n    void _eik_priority_queue_insert(CImg<charT>& state, unsigned int& siz, const t value,\n                                    const unsigned int x, const unsigned int y, const unsigned int z) {\n      if (state(x,y,z)>0) return;\n      state(x,y,z) = 0;\n      if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); }\n      (*this)(siz - 1,0) = (T)value; (*this)(siz - 1,1) = (T)x; (*this)(siz - 1,2) = (T)y; (*this)(siz - 1,3) = (T)z;\n      for (unsigned int pos = siz - 1, par = 0; pos && value>(*this)(par=(pos + 1)/2 - 1,0); pos = par) {\n        cimg::swap((*this)(pos,0),(*this)(par,0)); cimg::swap((*this)(pos,1),(*this)(par,1));\n        cimg::swap((*this)(pos,2),(*this)(par,2)); cimg::swap((*this)(pos,3),(*this)(par,3));\n      }\n    }\n\n    //! Compute distance function to 0-valued isophotes, using the Eikonal PDE.\n    /**\n       \\param nb_iterations Number of PDE iterations.\n       \\param band_size Size of the narrow band.\n       \\param time_step Time step of the PDE iterations.\n    **/\n    CImg<T>& distance_eikonal(const unsigned int nb_iterations, const float band_size=0, const float time_step=0.5f) {\n      if (is_empty()) return *this;\n      CImg<Tfloat> velocity(*this);\n      for (unsigned int iteration = 0; iteration<nb_iterations; ++iteration) {\n        Tfloat *ptrd = velocity._data, veloc_max = 0;\n        if (_depth>1) { // 3d\n          CImg_3x3x3(I,Tfloat);\n          cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) if (band_size<=0 || cimg::abs(Iccc)<band_size) {\n            const Tfloat\n              gx = (Incc - Ipcc)/2,\n              gy = (Icnc - Icpc)/2,\n              gz = (Iccn - Iccp)/2,\n              sgn = -cimg::sign(Iccc),\n              ix = gx*sgn>0?(Incc - Iccc):(Iccc - Ipcc),\n              iy = gy*sgn>0?(Icnc - Iccc):(Iccc - Icpc),\n              iz = gz*sgn>0?(Iccn - Iccc):(Iccc - Iccp),\n              ng = (Tfloat)(1e-5f + std::sqrt(gx*gx + gy*gy + gz*gz)),\n              ngx = gx/ng,\n              ngy = gy/ng,\n              ngz = gz/ng,\n              veloc = sgn*(ngx*ix + ngy*iy + ngz*iz - 1);\n            *(ptrd++) = veloc;\n            if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;\n          } else *(ptrd++) = 0;\n        } else { // 2d version\n          CImg_3x3(I,Tfloat);\n          cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) if (band_size<=0 || cimg::abs(Icc)<band_size) {\n            const Tfloat\n              gx = (Inc - Ipc)/2,\n              gy = (Icn - Icp)/2,\n              sgn = -cimg::sign(Icc),\n              ix = gx*sgn>0?(Inc - Icc):(Icc - Ipc),\n              iy = gy*sgn>0?(Icn - Icc):(Icc - Icp),\n              ng = (Tfloat)(1e-5f + std::sqrt(gx*gx + gy*gy)),\n              ngx = gx/ng,\n              ngy = gy/ng,\n              veloc = sgn*(ngx*ix + ngy*iy - 1);\n            *(ptrd++) = veloc;\n            if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;\n          } else *(ptrd++) = 0;\n        }\n        if (veloc_max>0) *this+=(velocity*=time_step/veloc_max);\n      }\n      return *this;\n    }\n\n    //! Compute distance function to 0-valued isophotes, using the Eikonal PDE \\newinstance.\n    CImg<Tfloat> get_distance_eikonal(const unsigned int nb_iterations, const float band_size=0,\n                                      const float time_step=0.5f) const {\n      return CImg<Tfloat>(*this,false).distance_eikonal(nb_iterations,band_size,time_step);\n    }\n\n    //! Compute Haar multiscale wavelet transform.\n    /**\n       \\param axis Axis considered for the transform.\n       \\param invert Set inverse of direct transform.\n       \\param nb_scales Number of scales used for the transform.\n    **/\n    CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {\n      return get_haar(axis,invert,nb_scales).move_to(*this);\n    }\n\n    //! Compute Haar multiscale wavelet transform \\newinstance.\n    CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {\n      if (is_empty() || !nb_scales) return +*this;\n      CImg<Tfloat> res;\n      const Tfloat sqrt2 = std::sqrt(2.0f);\n      if (nb_scales==1) {\n        switch (cimg::uncase(axis)) { // Single scale transform\n        case 'x' : {\n          const unsigned int w = _width/2;\n          if (w) {\n            if ((w%2) && w!=1)\n              throw CImgInstanceException(_cimg_instance\n                                          \"haar(): Sub-image width %u is not even.\",\n                                          cimg_instance,\n                                          w);\n\n            res.assign(_width,_height,_depth,_spectrum);\n            if (invert) cimg_forYZC(*this,y,z,c) { // Inverse transform along X\n              for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {\n                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(xw,y,z,c);\n                res(x2++,y,z,c) = (val0 - val1)/sqrt2;\n                res(x2++,y,z,c) = (val0 + val1)/sqrt2;\n              }\n            } else cimg_forYZC(*this,y,z,c) { // Direct transform along X\n              for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {\n                const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,c), val1 = (Tfloat)(*this)(x2++,y,z,c);\n                res(x,y,z,c) = (val0 + val1)/sqrt2;\n                res(xw,y,z,c) = (val1 - val0)/sqrt2;\n              }\n            }\n          } else return *this;\n        } break;\n        case 'y' : {\n          const unsigned int h = _height/2;\n          if (h) {\n            if ((h%2) && h!=1)\n              throw CImgInstanceException(_cimg_instance\n                                          \"haar(): Sub-image height %u is not even.\",\n                                          cimg_instance,\n                                          h);\n\n            res.assign(_width,_height,_depth,_spectrum);\n            if (invert) cimg_forXZC(*this,x,z,c) { // Inverse transform along Y\n              for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) {\n                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(x,yh,z,c);\n                res(x,y2++,z,c) = (val0 - val1)/sqrt2;\n                res(x,y2++,z,c) = (val0 + val1)/sqrt2;\n              }\n            } else cimg_forXZC(*this,x,z,c) {\n              for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) { // Direct transform along Y\n                const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,c), val1 = (Tfloat)(*this)(x,y2++,z,c);\n                res(x,y,z,c)  = (val0 + val1)/sqrt2;\n                res(x,yh,z,c) = (val1 - val0)/sqrt2;\n              }\n            }\n          } else return *this;\n        } break;\n        case 'z' : {\n          const unsigned int d = _depth/2;\n          if (d) {\n            if ((d%2) && d!=1)\n              throw CImgInstanceException(_cimg_instance\n                                          \"haar(): Sub-image depth %u is not even.\",\n                                          cimg_instance,\n                                          d);\n\n            res.assign(_width,_height,_depth,_spectrum);\n            if (invert) cimg_forXYC(*this,x,y,c) { // Inverse transform along Z\n              for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) {\n                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(x,y,zd,c);\n                res(x,y,z2++,c) = (val0 - val1)/sqrt2;\n                res(x,y,z2++,c) = (val0 + val1)/sqrt2;\n              }\n            } else cimg_forXYC(*this,x,y,c) {\n              for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) { // Direct transform along Z\n                const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,c), val1 = (Tfloat)(*this)(x,y,z2++,c);\n                res(x,y,z,c)  = (val0 + val1)/sqrt2;\n                res(x,y,zd,c) = (val1 - val0)/sqrt2;\n              }\n            }\n          } else return *this;\n        } break;\n        default :\n          throw CImgArgumentException(_cimg_instance\n                                      \"haar(): Invalid specified axis '%c' \"\n                                      \"(should be { x | y | z }).\",\n                                      cimg_instance,\n                                      axis);\n        }\n      } else { // Multi-scale version\n        if (invert) {\n          res.assign(*this);\n          switch (cimg::uncase(axis)) {\n          case 'x' : {\n            unsigned int w = _width;\n            for (unsigned int s = 1; w && s<nb_scales; ++s) w/=2;\n            for (w = w?w:1; w<=_width; w*=2) res.draw_image(res.get_crop(0,w - 1).get_haar('x',true,1));\n          } break;\n          case 'y' : {\n            unsigned int h = _width;\n            for (unsigned int s = 1; h && s<nb_scales; ++s) h/=2;\n            for (h = h?h:1; h<=_height; h*=2) res.draw_image(res.get_crop(0,0,_width - 1,h - 1).get_haar('y',true,1));\n          } break;\n          case 'z' : {\n            unsigned int d = _depth;\n            for (unsigned int s = 1; d && s<nb_scales; ++s) d/=2;\n            for (d = d?d:1; d<=_depth; d*=2)\n              res.draw_image(res.get_crop(0,0,0,_width - 1,_height - 1,d - 1).get_haar('z',true,1));\n          } break;\n          default :\n            throw CImgArgumentException(_cimg_instance\n                                        \"haar(): Invalid specified axis '%c' \"\n                                        \"(should be { x | y | z }).\",\n                                        cimg_instance,\n                                        axis);\n          }\n        } else { // Direct transform\n          res = get_haar(axis,false,1);\n          switch (cimg::uncase(axis)) {\n          case 'x' : {\n            for (unsigned int s = 1, w = _width/2; w && s<nb_scales; ++s, w/=2)\n              res.draw_image(res.get_crop(0,w - 1).get_haar('x',false,1));\n          } break;\n          case 'y' : {\n            for (unsigned int s = 1, h = _height/2; h && s<nb_scales; ++s, h/=2)\n              res.draw_image(res.get_crop(0,0,_width - 1,h - 1).get_haar('y',false,1));\n          } break;\n          case 'z' : {\n            for (unsigned int s = 1, d = _depth/2; d && s<nb_scales; ++s, d/=2)\n              res.draw_image(res.get_crop(0,0,0,_width - 1,_height - 1,d - 1).get_haar('z',false,1));\n          } break;\n          default :\n            throw CImgArgumentException(_cimg_instance\n                                        \"haar(): Invalid specified axis '%c' \"\n                                        \"(should be { x | y | z }).\",\n                                        cimg_instance,\n                                        axis);\n          }\n        }\n      }\n      return res;\n    }\n\n    //! Compute Haar multiscale wavelet transform \\overloading.\n    /**\n       \\param invert Set inverse of direct transform.\n       \\param nb_scales Number of scales used for the transform.\n    **/\n    CImg<T>& haar(const bool invert=false, const unsigned int nb_scales=1) {\n      return get_haar(invert,nb_scales).move_to(*this);\n    }\n\n    //! Compute Haar multiscale wavelet transform \\newinstance.\n    CImg<Tfloat> get_haar(const bool invert=false, const unsigned int nb_scales=1) const {\n      CImg<Tfloat> res;\n      if (nb_scales==1) { // Single scale transform\n        if (_width>1) get_haar('x',invert,1).move_to(res);\n        if (_height>1) { if (res) res.haar('y',invert,1); else get_haar('y',invert,1).move_to(res); }\n        if (_depth>1) { if (res) res.haar('z',invert,1); else get_haar('z',invert,1).move_to(res); }\n        if (res) return res;\n      } else { // Multi-scale transform\n        if (invert) { // Inverse transform\n          res.assign(*this);\n          if (_width>1) {\n            if (_height>1) {\n              if (_depth>1) {\n                unsigned int w = _width, h = _height, d = _depth;\n                for (unsigned int s = 1; w && h && d && s<nb_scales; ++s) { w/=2; h/=2; d/=2; }\n                for (w = w?w:1, h = h?h:1, d = d?d:1; w<=_width && h<=_height && d<=_depth; w*=2, h*=2, d*=2)\n                  res.draw_image(res.get_crop(0,0,0,w - 1,h - 1,d - 1).get_haar(true,1));\n              } else {\n                unsigned int w = _width, h = _height;\n                for (unsigned int s = 1; w && h && s<nb_scales; ++s) { w/=2; h/=2; }\n                for (w = w?w:1, h = h?h:1; w<=_width && h<=_height; w*=2, h*=2)\n                  res.draw_image(res.get_crop(0,0,0,w - 1,h - 1,0).get_haar(true,1));\n              }\n            } else {\n              if (_depth>1) {\n                unsigned int w = _width, d = _depth;\n                for (unsigned int s = 1; w && d && s<nb_scales; ++s) { w/=2; d/=2; }\n                for (w = w?w:1, d = d?d:1; w<=_width && d<=_depth; w*=2, d*=2)\n                  res.draw_image(res.get_crop(0,0,0,w - 1,0,d - 1).get_haar(true,1));\n              } else {\n                unsigned int w = _width;\n                for (unsigned int s = 1; w && s<nb_scales; ++s) w/=2;\n                for (w = w?w:1; w<=_width; w*=2)\n                  res.draw_image(res.get_crop(0,0,0,w - 1,0,0).get_haar(true,1));\n              }\n            }\n          } else {\n            if (_height>1) {\n              if (_depth>1) {\n                unsigned int h = _height, d = _depth;\n                for (unsigned int s = 1; h && d && s<nb_scales; ++s) { h/=2; d/=2; }\n                for (h = h?h:1, d = d?d:1; h<=_height && d<=_depth; h*=2, d*=2)\n                  res.draw_image(res.get_crop(0,0,0,0,h - 1,d - 1).get_haar(true,1));\n              } else {\n                unsigned int h = _height;\n                for (unsigned int s = 1; h && s<nb_scales; ++s) h/=2;\n                for (h = h?h:1; h<=_height; h*=2)\n                  res.draw_image(res.get_crop(0,0,0,0,h - 1,0).get_haar(true,1));\n              }\n            } else {\n              if (_depth>1) {\n                unsigned int d = _depth;\n                for (unsigned int s = 1; d && s<nb_scales; ++s) d/=2;\n                for (d = d?d:1; d<=_depth; d*=2)\n                  res.draw_image(res.get_crop(0,0,0,0,0,d - 1).get_haar(true,1));\n              } else return *this;\n            }\n          }\n        } else { // Direct transform\n          res = get_haar(false,1);\n          if (_width>1) {\n            if (_height>1) {\n              if (_depth>1)\n                for (unsigned int s = 1, w = _width/2, h = _height/2, d = _depth/2; w && h && d && s<nb_scales;\n                     ++s, w/=2, h/=2, d/=2)\n                  res.draw_image(res.get_crop(0,0,0,w - 1,h - 1,d - 1).haar(false,1));\n              else for (unsigned int s = 1, w = _width/2, h = _height/2; w && h && s<nb_scales; ++s, w/=2, h/=2)\n                     res.draw_image(res.get_crop(0,0,0,w - 1,h - 1,0).haar(false,1));\n            } else {\n              if (_depth>1) for (unsigned int s = 1, w = _width/2, d = _depth/2; w && d && s<nb_scales; ++s, w/=2, d/=2)\n                              res.draw_image(res.get_crop(0,0,0,w - 1,0,d - 1).haar(false,1));\n              else for (unsigned int s = 1, w = _width/2; w && s<nb_scales; ++s, w/=2)\n                     res.draw_image(res.get_crop(0,0,0,w - 1,0,0).haar(false,1));\n            }\n          } else {\n            if (_height>1) {\n              if (_depth>1)\n                for (unsigned int s = 1, h = _height/2, d = _depth/2; h && d && s<nb_scales; ++s, h/=2, d/=2)\n                  res.draw_image(res.get_crop(0,0,0,0,h - 1,d - 1).haar(false,1));\n              else for (unsigned int s = 1, h = _height/2; h && s<nb_scales; ++s, h/=2)\n                     res.draw_image(res.get_crop(0,0,0,0,h - 1,0).haar(false,1));\n            } else {\n              if (_depth>1) for (unsigned int s = 1, d = _depth/2; d && s<nb_scales; ++s, d/=2)\n                              res.draw_image(res.get_crop(0,0,0,0,0,d - 1).haar(false,1));\n              else return *this;\n            }\n          }\n        }\n        return res;\n      }\n      return *this;\n    }\n\n    //! Compute 1d Fast Fourier Transform, along a specified axis.\n    /**\n       \\param axis Axis along which the FFT is computed.\n       \\param is_invert Tells if the forward (\\c false) or inverse (\\c true) FFT is computed.\n    **/\n    CImgList<Tfloat> get_FFT(const char axis, const bool is_invert=false) const {\n      CImgList<Tfloat> res(*this,CImg<Tfloat>());\n      CImg<Tfloat>::FFT(res[0],res[1],axis,is_invert);\n      return res;\n    }\n\n    //! Compute n-d Fast Fourier Transform.\n    /*\n      \\param is_invert Tells if the forward (\\c false) or inverse (\\c true) FFT is computed.\n    **/\n    CImgList<Tfloat> get_FFT(const bool is_invert=false) const {\n      CImgList<Tfloat> res(*this,CImg<Tfloat>());\n      CImg<Tfloat>::FFT(res[0],res[1],is_invert);\n      return res;\n    }\n\n    //! Compute 1d Fast Fourier Transform, along a specified axis.\n    /**\n       \\param[in,out] real Real part of the pixel values.\n       \\param[in,out] imag Imaginary part of the pixel values.\n       \\param axis Axis along which the FFT is computed.\n       \\param is_invert Tells if the forward (\\c false) or inverse (\\c true) FFT is computed.\n    **/\n    static void FFT(CImg<T>& real, CImg<T>& imag, const char axis, const bool is_invert=false) {\n      if (!real)\n        throw CImgInstanceException(\"CImg<%s>::FFT(): Specified real part is empty.\",\n                                    pixel_type());\n\n      if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,0);\n      if (!real.is_sameXYZC(imag))\n        throw CImgInstanceException(\"CImg<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and \"\n                                    \"imaginary part (%u,%u,%u,%u,%p) have different dimensions.\",\n                                    pixel_type(),\n                                    real._width,real._height,real._depth,real._spectrum,real._data,\n                                    imag._width,imag._height,imag._depth,imag._spectrum,imag._data);\n#ifdef cimg_use_fftw3\n      cimg::mutex(12);\n      fftw_complex *data_in;\n      fftw_plan data_plan;\n\n      switch (cimg::uncase(axis)) {\n      case 'x' : { // Fourier along X, using FFTW library.\n        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width);\n        if (!data_in) throw CImgInstanceException(\"CImgList<%s>::FFT(): Failed to allocate memory (%s) \"\n                                                  \"for computing FFT of image (%u,%u,%u,%u) along the X-axis.\",\n                                                  pixel_type(),\n                                                  cimg::strbuffersize(sizeof(fftw_complex)*real._width),\n                                                  real._width,real._height,real._depth,real._spectrum);\n\n        data_plan = fftw_plan_dft_1d(real._width,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);\n        cimg_forYZC(real,y,z,c) {\n          T *ptrr = real.data(0,y,z,c), *ptri = imag.data(0,y,z,c);\n          double *ptrd = (double*)data_in;\n          cimg_forX(real,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); }\n          fftw_execute(data_plan);\n          const unsigned int fact = real._width;\n          if (is_invert) cimg_forX(real,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); }\n          else cimg_forX(real,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); }\n        }\n      } break;\n      case 'y' : { // Fourier along Y, using FFTW library.\n        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real._height);\n        if (!data_in) throw CImgInstanceException(\"CImgList<%s>::FFT(): Failed to allocate memory (%s) \"\n                                                  \"for computing FFT of image (%u,%u,%u,%u) along the Y-axis.\",\n                                                  pixel_type(),\n                                                  cimg::strbuffersize(sizeof(fftw_complex)*real._height),\n                                                  real._width,real._height,real._depth,real._spectrum);\n\n        data_plan = fftw_plan_dft_1d(real._height,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);\n        const unsigned int off = real._width;\n        cimg_forXZC(real,x,z,c) {\n          T *ptrr = real.data(x,0,z,c), *ptri = imag.data(x,0,z,c);\n          double *ptrd = (double*)data_in;\n          cimg_forY(real,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }\n          fftw_execute(data_plan);\n          const unsigned int fact = real._height;\n          if (is_invert)\n            cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }\n          else cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }\n        }\n      } break;\n      case 'z' : { // Fourier along Z, using FFTW library.\n        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real._depth);\n        if (!data_in) throw CImgInstanceException(\"CImgList<%s>::FFT(): Failed to allocate memory (%s) \"\n                                                  \"for computing FFT of image (%u,%u,%u,%u) along the Z-axis.\",\n                                                  pixel_type(),\n                                                  cimg::strbuffersize(sizeof(fftw_complex)*real._depth),\n                                                  real._width,real._height,real._depth,real._spectrum);\n\n        data_plan = fftw_plan_dft_1d(real._depth,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);\n        const ulongT off = (ulongT)real._width*real._height;\n        cimg_forXYC(real,x,y,c) {\n          T *ptrr = real.data(x,y,0,c), *ptri = imag.data(x,y,0,c);\n          double *ptrd = (double*)data_in;\n          cimg_forZ(real,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }\n          fftw_execute(data_plan);\n          const unsigned int fact = real._depth;\n          if (is_invert)\n            cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }\n          else cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }\n        }\n      } break;\n      default :\n        throw CImgArgumentException(\"CImgList<%s>::FFT(): Invalid specified axis '%c' for real and imaginary parts \"\n                                    \"(%u,%u,%u,%u) \"\n                                    \"(should be { x | y | z }).\",\n                                    pixel_type(),axis,\n                                    real._width,real._height,real._depth,real._spectrum);\n      }\n      fftw_destroy_plan(data_plan);\n      fftw_free(data_in);\n      cimg::mutex(12,0);\n#else\n      switch (cimg::uncase(axis)) {\n      case 'x' : { // Fourier along X, using built-in functions.\n        const unsigned int N = real._width, N2 = N>>1;\n        if (((N - 1)&N) && N!=1)\n          throw CImgInstanceException(\"CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) \"\n                                      \"have non 2^N dimension along the X-axis.\",\n                                      pixel_type(),\n                                      real._width,real._height,real._depth,real._spectrum);\n\n        for (unsigned int i = 0, j = 0; i<N2; ++i) {\n          if (j>i) cimg_forYZC(real,y,z,c) {\n              cimg::swap(real(i,y,z,c),real(j,y,z,c));\n              cimg::swap(imag(i,y,z,c),imag(j,y,z,c));\n              if (j<N2) {\n                const unsigned int ri = N - 1 - i, rj = N - 1 - j;\n                cimg::swap(real(ri,y,z,c),real(rj,y,z,c));\n                cimg::swap(imag(ri,y,z,c),imag(rj,y,z,c));\n              }\n            }\n          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}\n        }\n        for (unsigned int delta = 2; delta<=N; delta<<=1) {\n          const unsigned int delta2 = delta>>1;\n          for (unsigned int i = 0; i<N; i+=delta) {\n            float wr = 1, wi = 0;\n            const float\n              angle = (float)((is_invert?+1:-1)*2*cimg::PI/delta),\n              ca = (float)std::cos(angle),\n              sa = (float)std::sin(angle);\n            for (unsigned int k = 0; k<delta2; ++k) {\n              const unsigned int j = i + k, nj = j + delta2;\n              cimg_forYZC(real,y,z,c) {\n                T &ir = real(j,y,z,c), &ii = imag(j,y,z,c), &nir = real(nj,y,z,c), &nii = imag(nj,y,z,c);\n                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);\n                nir = (T)(ir - tmpr);\n                nii = (T)(ii - tmpi);\n                ir+=(T)tmpr;\n                ii+=(T)tmpi;\n              }\n              const float nwr = wr*ca-wi*sa;\n              wi = wi*ca + wr*sa;\n              wr = nwr;\n            }\n          }\n        }\n        if (is_invert) { real/=N; imag/=N; }\n      } break;\n      case 'y' : { // Fourier along Y, using built-in functions.\n        const unsigned int N = real._height, N2 = N>>1;\n        if (((N - 1)&N) && N!=1)\n          throw CImgInstanceException(\"CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) \"\n                                      \"have non 2^N dimension along the Y-axis.\",\n                                      pixel_type(),\n                                      real._width,real._height,real._depth,real._spectrum);\n\n        for (unsigned int i = 0, j = 0; i<N2; ++i) {\n          if (j>i) cimg_forXZC(real,x,z,c) {\n              cimg::swap(real(x,i,z,c),real(x,j,z,c));\n              cimg::swap(imag(x,i,z,c),imag(x,j,z,c));\n              if (j<N2) {\n                const unsigned int ri = N - 1 - i, rj = N - 1 - j;\n                cimg::swap(real(x,ri,z,c),real(x,rj,z,c));\n                cimg::swap(imag(x,ri,z,c),imag(x,rj,z,c));\n              }\n            }\n          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}\n        }\n        for (unsigned int delta = 2; delta<=N; delta<<=1) {\n          const unsigned int delta2 = (delta>>1);\n          for (unsigned int i = 0; i<N; i+=delta) {\n            float wr = 1, wi = 0;\n            const float\n              angle = (float)((is_invert?+1:-1)*2*cimg::PI/delta),\n              ca = (float)std::cos(angle),\n              sa = (float)std::sin(angle);\n            for (unsigned int k = 0; k<delta2; ++k) {\n              const unsigned int j = i + k, nj = j + delta2;\n              cimg_forXZC(real,x,z,c) {\n                T &ir = real(x,j,z,c), &ii = imag(x,j,z,c), &nir = real(x,nj,z,c), &nii = imag(x,nj,z,c);\n                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);\n                nir = (T)(ir - tmpr);\n                nii = (T)(ii - tmpi);\n                ir+=(T)tmpr;\n                ii+=(T)tmpi;\n              }\n              const float nwr = wr*ca-wi*sa;\n              wi = wi*ca + wr*sa;\n              wr = nwr;\n            }\n          }\n        }\n        if (is_invert) { real/=N; imag/=N; }\n      } break;\n      case 'z' : { // Fourier along Z, using built-in functions.\n        const unsigned int N = real._depth, N2 = N>>1;\n        if (((N - 1)&N) && N!=1)\n          throw CImgInstanceException(\"CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) \"\n                                      \"have non 2^N dimension along the Z-axis.\",\n                                      pixel_type(),\n                                      real._width,real._height,real._depth,real._spectrum);\n\n        for (unsigned int i = 0, j = 0; i<N2; ++i) {\n          if (j>i) cimg_forXYC(real,x,y,c) {\n              cimg::swap(real(x,y,i,c),real(x,y,j,c));\n              cimg::swap(imag(x,y,i,c),imag(x,y,j,c));\n              if (j<N2) {\n                const unsigned int ri = N - 1 - i, rj = N - 1 - j;\n                cimg::swap(real(x,y,ri,c),real(x,y,rj,c));\n                cimg::swap(imag(x,y,ri,c),imag(x,y,rj,c));\n              }\n            }\n          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}\n        }\n        for (unsigned int delta = 2; delta<=N; delta<<=1) {\n          const unsigned int delta2 = (delta>>1);\n          for (unsigned int i = 0; i<N; i+=delta) {\n            float wr = 1, wi = 0;\n            const float\n              angle = (float)((is_invert?+1:-1)*2*cimg::PI/delta),\n              ca = (float)std::cos(angle),\n              sa = (float)std::sin(angle);\n            for (unsigned int k = 0; k<delta2; ++k) {\n              const unsigned int j = i + k, nj = j + delta2;\n              cimg_forXYC(real,x,y,c) {\n                T &ir = real(x,y,j,c), &ii = imag(x,y,j,c), &nir = real(x,y,nj,c), &nii = imag(x,y,nj,c);\n                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);\n                nir = (T)(ir - tmpr);\n                nii = (T)(ii - tmpi);\n                ir+=(T)tmpr;\n                ii+=(T)tmpi;\n              }\n              const float nwr = wr*ca-wi*sa;\n              wi = wi*ca + wr*sa;\n              wr = nwr;\n            }\n          }\n        }\n        if (is_invert) { real/=N; imag/=N; }\n      } break;\n      default :\n        throw CImgArgumentException(\"CImgList<%s>::FFT(): Invalid specified axis '%c' for real and imaginary parts \"\n                                    \"(%u,%u,%u,%u) \"\n                                    \"(should be { x | y | z }).\",\n                                    pixel_type(),axis,\n                                    real._width,real._height,real._depth,real._spectrum);\n      }\n#endif\n    }\n\n    //! Compute n-d Fast Fourier Transform.\n    /**\n       \\param[in,out] real Real part of the pixel values.\n       \\param[in,out] imag Imaginary part of the pixel values.\n       \\param is_invert Tells if the forward (\\c false) or inverse (\\c true) FFT is computed.\n       \\param nb_threads Number of parallel threads used for the computation.\n         Use \\c 0 to set this to the number of available cpus.\n    **/\n    static void FFT(CImg<T>& real, CImg<T>& imag, const bool is_invert=false, const unsigned int nb_threads=0) {\n      if (!real)\n        throw CImgInstanceException(\"CImgList<%s>::FFT(): Empty specified real part.\",\n                                    pixel_type());\n\n      if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,0);\n      if (!real.is_sameXYZC(imag))\n        throw CImgInstanceException(\"CImgList<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and \"\n                                    \"imaginary part (%u,%u,%u,%u,%p) have different dimensions.\",\n                                    pixel_type(),\n                                    real._width,real._height,real._depth,real._spectrum,real._data,\n                                    imag._width,imag._height,imag._depth,imag._spectrum,imag._data);\n\n#ifdef cimg_use_fftw3\n      cimg::mutex(12);\n#ifndef cimg_use_fftw3_singlethread\n      const unsigned int _nb_threads = nb_threads?nb_threads:cimg::nb_cpus();\n      static int fftw_st = fftw_init_threads();\n      cimg::unused(fftw_st);\n      fftw_plan_with_nthreads(_nb_threads);\n#else\n      cimg::unused(nb_threads);\n#endif\n      fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width*real._height*real._depth);\n      if (!data_in) throw CImgInstanceException(\"CImgList<%s>::FFT(): Failed to allocate memory (%s) \"\n                                                \"for computing FFT of image (%u,%u,%u,%u).\",\n                                                pixel_type(),\n                                                cimg::strbuffersize(sizeof(fftw_complex)*real._width*\n                                                                    real._height*real._depth*real._spectrum),\n                                                real._width,real._height,real._depth,real._spectrum);\n\n      fftw_plan data_plan;\n      const ulongT w = (ulongT)real._width, wh = w*real._height, whd = wh*real._depth;\n      data_plan = fftw_plan_dft_3d(real._width,real._height,real._depth,data_in,data_in,\n                                   is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);\n      cimg_forC(real,c) {\n        T *ptrr = real.data(0,0,0,c), *ptri = imag.data(0,0,0,c);\n        double *ptrd = (double*)data_in;\n        for (unsigned int x = 0; x<real._width; ++x, ptrr-=wh - 1, ptri-=wh - 1)\n          for (unsigned int y = 0; y<real._height; ++y, ptrr-=whd-w, ptri-=whd-w)\n            for (unsigned int z = 0; z<real._depth; ++z, ptrr+=wh, ptri+=wh) {\n              *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri;\n            }\n        fftw_execute(data_plan);\n        ptrd = (double*)data_in;\n        ptrr = real.data(0,0,0,c);\n        ptri = imag.data(0,0,0,c);\n        if (!is_invert) for (unsigned int x = 0; x<real._width; ++x, ptrr-=wh - 1, ptri-=wh - 1)\n          for (unsigned int y = 0; y<real._height; ++y, ptrr-=whd-w, ptri-=whd-w)\n            for (unsigned int z = 0; z<real._depth; ++z, ptrr+=wh, ptri+=wh) {\n              *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++);\n            }\n        else for (unsigned int x = 0; x<real._width; ++x, ptrr-=wh - 1, ptri-=wh - 1)\n          for (unsigned int y = 0; y<real._height; ++y, ptrr-=whd-w, ptri-=whd-w)\n            for (unsigned int z = 0; z<real._depth; ++z, ptrr+=wh, ptri+=wh) {\n              *ptrr = (T)(*(ptrd++)/whd); *ptri = (T)(*(ptrd++)/whd);\n            }\n      }\n      fftw_destroy_plan(data_plan);\n      fftw_free(data_in);\n#ifndef cimg_use_fftw3_singlethread\n      fftw_cleanup_threads();\n#endif\n      cimg::mutex(12,0);\n#else\n      cimg::unused(nb_threads);\n      if (real._depth>1) FFT(real,imag,'z',is_invert);\n      if (real._height>1) FFT(real,imag,'y',is_invert);\n      if (real._width>1) FFT(real,imag,'x',is_invert);\n#endif\n    }\n\n    //@}\n    //-------------------------------------\n    //\n    //! \\name 3d Objects Management\n    //@{\n    //-------------------------------------\n\n    //! Shift 3d object's vertices.\n    /**\n       \\param tx X-coordinate of the 3d displacement vector.\n       \\param ty Y-coordinate of the 3d displacement vector.\n       \\param tz Z-coordinate of the 3d displacement vector.\n    **/\n    CImg<T>& shift_object3d(const float tx, const float ty=0, const float tz=0) {\n      if (_height!=3 || _depth>1 || _spectrum>1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"shift_object3d(): Instance is not a set of 3d vertices.\",\n                                    cimg_instance);\n\n      get_shared_row(0)+=tx; get_shared_row(1)+=ty; get_shared_row(2)+=tz;\n      return *this;\n    }\n\n    //! Shift 3d object's vertices \\newinstance.\n    CImg<Tfloat> get_shift_object3d(const float tx, const float ty=0, const float tz=0) const {\n      return CImg<Tfloat>(*this,false).shift_object3d(tx,ty,tz);\n    }\n\n    //! Shift 3d object's vertices, so that it becomes centered.\n    /**\n       \\note The object center is computed as its barycenter.\n    **/\n    CImg<T>& shift_object3d() {\n      if (_height!=3 || _depth>1 || _spectrum>1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"shift_object3d(): Instance is not a set of 3d vertices.\",\n                                    cimg_instance);\n\n      CImg<T> xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2);\n      float\n        xm, xM = (float)xcoords.max_min(xm),\n        ym, yM = (float)ycoords.max_min(ym),\n        zm, zM = (float)zcoords.max_min(zm);\n      xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2;\n      return *this;\n    }\n\n    //! Shift 3d object's vertices, so that it becomes centered \\newinstance.\n    CImg<Tfloat> get_shift_object3d() const {\n      return CImg<Tfloat>(*this,false).shift_object3d();\n    }\n\n    //! Resize 3d object.\n    /**\n       \\param sx Width of the 3d object's bounding box.\n       \\param sy Height of the 3d object's bounding box.\n       \\param sz Depth of the 3d object's bounding box.\n    **/\n    CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {\n      if (_height!=3 || _depth>1 || _spectrum>1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"resize_object3d(): Instance is not a set of 3d vertices.\",\n                                    cimg_instance);\n\n      CImg<T> xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2);\n      float\n        xm, xM = (float)xcoords.max_min(xm),\n        ym, yM = (float)ycoords.max_min(ym),\n        zm, zM = (float)zcoords.max_min(zm);\n      if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }\n      if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }\n      if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }\n      return *this;\n    }\n\n    //! Resize 3d object \\newinstance.\n    CImg<Tfloat> get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const {\n      return CImg<Tfloat>(*this,false).resize_object3d(sx,sy,sz);\n    }\n\n    //! Resize 3d object to unit size.\n    CImg<T> resize_object3d() {\n      if (_height!=3 || _depth>1 || _spectrum>1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"resize_object3d(): Instance is not a set of 3d vertices.\",\n                                    cimg_instance);\n\n      CImg<T> xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2);\n      float\n        xm, xM = (float)xcoords.max_min(xm),\n        ym, yM = (float)ycoords.max_min(ym),\n        zm, zM = (float)zcoords.max_min(zm);\n      const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz);\n      if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; }\n      return *this;\n    }\n\n    //! Resize 3d object to unit size \\newinstance.\n    CImg<Tfloat> get_resize_object3d() const {\n      return CImg<Tfloat>(*this,false).resize_object3d();\n    }\n\n    //! Merge two 3d objects together.\n    /**\n       \\param[in,out] primitives Primitives data of the current 3d object.\n       \\param obj_vertices Vertices data of the additional 3d object.\n       \\param obj_primitives Primitives data of the additional 3d object.\n    **/\n    template<typename tf, typename tp, typename tff>\n    CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_vertices,\n                             const CImgList<tff>& obj_primitives) {\n      if (!obj_vertices || !obj_primitives) return *this;\n      if (obj_vertices._height!=3 || obj_vertices._depth>1 || obj_vertices._spectrum>1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"append_object3d(): Specified vertice image (%u,%u,%u,%u,%p) is not a \"\n                                    \"set of 3d vertices.\",\n                                    cimg_instance,\n                                    obj_vertices._width,obj_vertices._height,\n                                    obj_vertices._depth,obj_vertices._spectrum,obj_vertices._data);\n\n      if (is_empty()) { primitives.assign(obj_primitives); return assign(obj_vertices); }\n      if (_height!=3 || _depth>1 || _spectrum>1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"append_object3d(): Instance is not a set of 3d vertices.\",\n                                    cimg_instance);\n\n      const unsigned int P = _width;\n      append(obj_vertices,'x');\n      const unsigned int N = primitives._width;\n      primitives.insert(obj_primitives);\n      for (unsigned int i = N; i<primitives._width; ++i) {\n        CImg<tf> &p = primitives[i];\n        switch (p.size()) {\n        case 1 : p[0]+=P; break; // Point.\n        case 5 : p[0]+=P; p[1]+=P; break; // Sphere.\n        case 2 : case 6 : p[0]+=P; p[1]+=P; break; // Segment.\n        case 3 : case 9 : p[0]+=P; p[1]+=P; p[2]+=P; break; // Triangle.\n        case 4 : case 12 : p[0]+=P; p[1]+=P; p[2]+=P; p[3]+=P; break; // Rectangle.\n        }\n      }\n      return *this;\n    }\n\n    //! Texturize primitives of a 3d object.\n    /**\n       \\param[in,out] primitives Primitives data of the 3d object.\n       \\param[in,out] colors Colors data of the 3d object.\n       \\param texture Texture image to map to 3d object.\n       \\param coords Texture-mapping coordinates.\n    **/\n    template<typename tp, typename tc, typename tt, typename tx>\n    const CImg<T>& texturize_object3d(CImgList<tp>& primitives, CImgList<tc>& colors,\n                                      const CImg<tt>& texture, const CImg<tx>& coords=CImg<tx>::const_empty()) const {\n      if (is_empty()) return *this;\n      if (_height!=3)\n        throw CImgInstanceException(_cimg_instance\n                                    \"texturize_object3d(): image instance is not a set of 3d points.\",\n                                    cimg_instance);\n      if (coords && (coords._width!=_width || coords._height!=2))\n        throw CImgArgumentException(_cimg_instance\n                                    \"texturize_object3d(): Invalid specified texture coordinates (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    coords._width,coords._height,coords._depth,coords._spectrum,coords._data);\n      CImg<intT> _coords;\n      if (!coords) { // If no texture coordinates specified, do a default XY-projection.\n        _coords.assign(_width,2);\n        float\n          xmin, xmax = (float)get_shared_row(0).max_min(xmin),\n          ymin, ymax = (float)get_shared_row(1).max_min(ymin),\n          dx = xmax>xmin?xmax-xmin:1,\n          dy = ymax>ymin?ymax-ymin:1;\n        cimg_forX(*this,p) {\n          _coords(p,0) = (int)(((*this)(p,0) - xmin)*texture._width/dx);\n          _coords(p,1) = (int)(((*this)(p,1) - ymin)*texture._height/dy);\n        }\n      } else _coords = coords;\n\n      int texture_ind = -1;\n      cimglist_for(primitives,l) {\n        CImg<tp> &p = primitives[l];\n        const unsigned int siz = p.size();\n        switch (siz) {\n        case 1 : { // Point.\n          const unsigned int i0 = (unsigned int)p[0];\n          const int x0 = _coords(i0,0), y0 = _coords(i0,1);\n          texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0,\n                                y0<=0?0:y0>=texture.height()?texture.height() - 1:y0).move_to(colors[l]);\n        } break;\n        case 2 : case 6 : { // Line.\n          const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1];\n          const int\n            x0 = _coords(i0,0), y0 = _coords(i0,1),\n            x1 = _coords(i1,0), y1 = _coords(i1,1);\n          if (texture_ind<0) colors[texture_ind=l].assign(texture,false);\n          else colors[l].assign(colors[texture_ind],true);\n          CImg<tp>::vector(i0,i1,x0,y0,x1,y1).move_to(p);\n        } break;\n        case 3 : case 9 : { // Triangle.\n          const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2];\n          const int\n            x0 = _coords(i0,0), y0 = _coords(i0,1),\n            x1 = _coords(i1,0), y1 = _coords(i1,1),\n            x2 = _coords(i2,0), y2 = _coords(i2,1);\n          if (texture_ind<0) colors[texture_ind=l].assign(texture,false);\n          else colors[l].assign(colors[texture_ind],true);\n          CImg<tp>::vector(i0,i1,i2,x0,y0,x1,y1,x2,y2).move_to(p);\n        } break;\n        case 4 : case 12 : { // Quadrangle.\n          const unsigned int\n            i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2], i3 = (unsigned int)p[3];\n          const int\n            x0 = _coords(i0,0), y0 = _coords(i0,1),\n            x1 = _coords(i1,0), y1 = _coords(i1,1),\n            x2 = _coords(i2,0), y2 = _coords(i2,1),\n            x3 = _coords(i3,0), y3 = _coords(i3,1);\n          if (texture_ind<0) colors[texture_ind=l].assign(texture,false);\n          else colors[l].assign(colors[texture_ind],true);\n          CImg<tp>::vector(i0,i1,i2,i3,x0,y0,x1,y1,x2,y2,x3,y3).move_to(p);\n        } break;\n        }\n      }\n      return *this;\n    }\n\n    //! Generate a 3d elevation of the image instance.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param[out] colors The returned list of the 3d object colors.\n       \\param elevation The input elevation map.\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\");\n       CImgList<unsigned int> faces3d;\n       CImgList<unsigned char> colors3d;\n       const CImg<float> points3d = img.get_elevation3d(faces3d,colors3d,img.get_norm()*0.2);\n       CImg<unsigned char>().display_object3d(\"Elevation3d\",points3d,faces3d,colors3d);\n       \\endcode\n       \\image html ref_elevation3d.jpg\n    **/\n    template<typename tf, typename tc, typename te>\n    CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const {\n      if (!is_sameXY(elevation) || elevation._depth>1 || elevation._spectrum>1)\n        throw CImgArgumentException(_cimg_instance\n                                    \"get_elevation3d(): Instance and specified elevation (%u,%u,%u,%u,%p) \"\n                                    \"have incompatible dimensions.\",\n                                    cimg_instance,\n                                    elevation._width,elevation._height,elevation._depth,\n                                    elevation._spectrum,elevation._data);\n      if (is_empty()) return *this;\n      float m, M = (float)max_min(m);\n      if (M==m) ++M;\n      colors.assign();\n      const unsigned int size_x1 = _width - 1, size_y1 = _height - 1;\n      for (unsigned int y = 0; y<size_y1; ++y)\n        for (unsigned int x = 0; x<size_x1; ++x) {\n          const unsigned char\n            r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)),\n            g = (unsigned char)(_spectrum>1?((*this)(x,y,1) - m)*255/(M-m):r),\n            b = (unsigned char)(_spectrum>2?((*this)(x,y,2) - m)*255/(M-m):_spectrum>1?0:r);\n          CImg<tc>::vector((tc)r,(tc)g,(tc)b).move_to(colors);\n        }\n      const typename CImg<te>::_functor2d_int func(elevation);\n      return elevation3d(primitives,func,0,0,_width - 1.0f,_height - 1.0f,_width,_height);\n    }\n\n    //! Generate the 3d projection planes of the image instance.\n    /**\n       \\param[out] primitives Primitives data of the returned 3d object.\n       \\param[out] colors Colors data of the returned 3d object.\n       \\param x0 X-coordinate of the projection point.\n       \\param y0 Y-coordinate of the projection point.\n       \\param z0 Z-coordinate of the projection point.\n       \\param normalize_colors Tells if the created textures have normalized colors.\n    **/\n    template<typename tf, typename tc>\n    CImg<floatT> get_projections3d(CImgList<tf>& primitives, CImgList<tc>& colors,\n                                   const unsigned int x0, const unsigned int y0, const unsigned int z0,\n                                   const bool normalize_colors=false) const {\n      float m = 0, M = 0, delta = 1;\n      if (normalize_colors) { m = (float)min_max(M); delta = 255/(m==M?1:M-m); }\n      const unsigned int\n        _x0 = (x0>=_width)?_width - 1:x0,\n        _y0 = (y0>=_height)?_height - 1:y0,\n        _z0 = (z0>=_depth)?_depth - 1:z0;\n      CImg<tc> img_xy, img_xz, img_yz;\n      if (normalize_colors) {\n        ((get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1)-=m)*=delta).move_to(img_xy);\n        ((get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_width,_depth,1,-100,-1).\n          move_to(img_xz);\n        ((get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_height,_depth,1,-100,-1).\n          move_to(img_yz);\n      } else {\n        get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1).move_to(img_xy);\n        get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1).resize(_width,_depth,1,-100,-1).move_to(img_xz);\n        get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1).resize(_height,_depth,1,-100,-1).move_to(img_yz);\n      }\n      CImg<floatT> points(12,3,1,1,\n                          0,_width - 1,_width - 1,0,   0,_width - 1,_width - 1,0, _x0,_x0,_x0,_x0,\n                          0,0,_height - 1,_height - 1, _y0,_y0,_y0,_y0,       0,_height - 1,_height - 1,0,\n                          _z0,_z0,_z0,_z0,         0,0,_depth - 1,_depth - 1, 0,0,_depth - 1,_depth - 1);\n      primitives.assign();\n      CImg<tf>::vector(0,1,2,3,0,0,img_xy._width - 1,0,img_xy._width - 1,img_xy._height - 1,0,img_xy._height - 1).\n        move_to(primitives);\n      CImg<tf>::vector(4,5,6,7,0,0,img_xz._width - 1,0,img_xz._width - 1,img_xz._height - 1,0,img_xz._height - 1).\n        move_to(primitives);\n      CImg<tf>::vector(8,9,10,11,0,0,img_yz._width - 1,0,img_yz._width - 1,img_yz._height - 1,0,img_yz._height - 1).\n        move_to(primitives);\n      colors.assign();\n      img_xy.move_to(colors);\n      img_xz.move_to(colors);\n      img_yz.move_to(colors);\n      return points;\n    }\n\n    //! Generate a isoline of the image instance as a 3d object.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param isovalue The returned list of the 3d object colors.\n       \\param size_x The number of subdivisions along the X-axis.\n       \\param size_y The number of subdisivions along the Y-axis.\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       const CImg<float> img(\"reference.jpg\");\n       CImgList<unsigned int> faces3d;\n       const CImg<float> points3d = img.get_isoline3d(faces3d,100);\n       CImg<unsigned char>().display_object3d(\"Isoline3d\",points3d,faces3d,colors3d);\n       \\endcode\n       \\image html ref_isoline3d.jpg\n    **/\n    template<typename tf>\n    CImg<floatT> get_isoline3d(CImgList<tf>& primitives, const float isovalue,\n                               const int size_x=-100, const int size_y=-100) const {\n      if (_spectrum>1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"get_isoline3d(): Instance is not a scalar image.\",\n                                    cimg_instance);\n      if (_depth>1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"get_isoline3d(): Instance is not a 2d image.\",\n                                    cimg_instance);\n      primitives.assign();\n      if (is_empty()) return *this;\n      CImg<floatT> vertices;\n      if ((size_x==-100 && size_y==-100) || (size_x==width() && size_y==height())) {\n        const _functor2d_int func(*this);\n        vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.0f,height() - 1.0f,width(),height());\n      } else {\n        const _functor2d_float func(*this);\n        vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.0f,height() - 1.0f,size_x,size_y);\n      }\n      return vertices;\n    }\n\n    //! Generate an isosurface of the image instance as a 3d object.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param isovalue The returned list of the 3d object colors.\n       \\param size_x Number of subdivisions along the X-axis.\n       \\param size_y Number of subdisivions along the Y-axis.\n       \\param size_z Number of subdisivions along the Z-axis.\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       const CImg<float> img = CImg<unsigned char>(\"reference.jpg\").resize(-100,-100,20);\n       CImgList<unsigned int> faces3d;\n       const CImg<float> points3d = img.get_isosurface3d(faces3d,100);\n       CImg<unsigned char>().display_object3d(\"Isosurface3d\",points3d,faces3d,colors3d);\n       \\endcode\n       \\image html ref_isosurface3d.jpg\n    **/\n    template<typename tf>\n    CImg<floatT> get_isosurface3d(CImgList<tf>& primitives, const float isovalue,\n                                  const int size_x=-100, const int size_y=-100, const int size_z=-100) const {\n      if (_spectrum>1)\n        throw CImgInstanceException(_cimg_instance\n                                    \"get_isosurface3d(): Instance is not a scalar image.\",\n                                    cimg_instance);\n      primitives.assign();\n      if (is_empty()) return *this;\n      CImg<floatT> vertices;\n      if ((size_x==-100 && size_y==-100 && size_z==-100) || (size_x==width() && size_y==height() && size_z==depth())) {\n        const _functor3d_int func(*this);\n        vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.0f,height() - 1.0f,depth() - 1.0f,\n                                width(),height(),depth());\n      } else {\n        const _functor3d_float func(*this);\n        vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.0f,height() - 1.0f,depth() - 1.0f,\n                                size_x,size_y,size_z);\n      }\n      return vertices;\n    }\n\n    //! Compute 3d elevation of a function as a 3d object.\n    /**\n       \\param[out] primitives Primitives data of the resulting 3d object.\n       \\param func Elevation function. Is of type <tt>float (*func)(const float x,const float y)</tt>.\n       \\param x0 X-coordinate of the starting point.\n       \\param y0 Y-coordinate of the starting point.\n       \\param x1 X-coordinate of the ending point.\n       \\param y1 Y-coordinate of the ending point.\n       \\param size_x Resolution of the function along the X-axis.\n       \\param size_y Resolution of the function along the Y-axis.\n    **/\n    template<typename tf, typename tfunc>\n    static CImg<floatT> elevation3d(CImgList<tf>& primitives, const tfunc& func,\n                                    const float x0, const float y0, const float x1, const float y1,\n                                    const int size_x=256, const int size_y=256) {\n      const float\n        nx0 = x0<x1?x0:x1, ny0 = y0<y1?y0:y1,\n        nx1 = x0<x1?x1:x0, ny1 = y0<y1?y1:y0;\n      const unsigned int\n        _nsize_x = (unsigned int)(size_x>=0?size_x:(nx1-nx0)*-size_x/100),\n        nsize_x = _nsize_x?_nsize_x:1, nsize_x1 = nsize_x - 1,\n        _nsize_y = (unsigned int)(size_y>=0?size_y:(ny1-ny0)*-size_y/100),\n        nsize_y = _nsize_y?_nsize_y:1, nsize_y1 = nsize_y - 1;\n      if (nsize_x<2 || nsize_y<2)\n        throw CImgArgumentException(\"CImg<%s>::elevation3d(): Invalid specified size (%d,%d).\",\n                                    pixel_type(),\n                                    nsize_x,nsize_y);\n\n      CImg<floatT> vertices(nsize_x*nsize_y,3);\n      floatT *ptr_x = vertices.data(0,0), *ptr_y = vertices.data(0,1), *ptr_z = vertices.data(0,2);\n      for (unsigned int y = 0; y<nsize_y; ++y) {\n        const float Y = ny0 + y*(ny1-ny0)/nsize_y1;\n        for (unsigned int x = 0; x<nsize_x; ++x) {\n          const float X = nx0 + x*(nx1-nx0)/nsize_x1;\n          *(ptr_x++) = (float)x;\n          *(ptr_y++) = (float)y;\n          *(ptr_z++) = (float)func(X,Y);\n        }\n      }\n      primitives.assign(nsize_x1*nsize_y1,1,4);\n      for (unsigned int p = 0, y = 0; y<nsize_y1; ++y) {\n        const unsigned int yw = y*nsize_x;\n        for (unsigned int x = 0; x<nsize_x1; ++x) {\n          const unsigned int xpyw = x + yw, xpyww = xpyw + nsize_x;\n          primitives[p++].fill(xpyw,xpyww,xpyww + 1,xpyw + 1);\n        }\n      }\n      return vertices;\n    }\n\n    //! Compute 3d elevation of a function, as a 3d object \\overloading.\n    template<typename tf>\n    static CImg<floatT> elevation3d(CImgList<tf>& primitives, const char *const expression,\n                                    const float x0, const float y0, const float x1, const float y1,\n                                    const int size_x=256, const int size_y=256) {\n      const _functor2d_expr func(expression);\n      return elevation3d(primitives,func,x0,y0,x1,y1,size_x,size_y);\n    }\n\n    //! Compute 0-isolines of a function, as a 3d object.\n    /**\n       \\param[out] primitives Primitives data of the resulting 3d object.\n       \\param func Elevation function. Is of type <tt>float (*func)(const float x,const float y)</tt>.\n       \\param isovalue Isovalue to extract from function.\n       \\param x0 X-coordinate of the starting point.\n       \\param y0 Y-coordinate of the starting point.\n       \\param x1 X-coordinate of the ending point.\n       \\param y1 Y-coordinate of the ending point.\n       \\param size_x Resolution of the function along the X-axis.\n       \\param size_y Resolution of the function along the Y-axis.\n       \\note Use the marching squares algorithm for extracting the isolines.\n     **/\n    template<typename tf, typename tfunc>\n    static CImg<floatT> isoline3d(CImgList<tf>& primitives, const tfunc& func, const float isovalue,\n                                  const float x0, const float y0, const float x1, const float y1,\n                                  const int size_x=256, const int size_y=256) {\n      static const unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc,\n                                              0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 };\n      static const int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 },\n                                           { 1,2,-1,-1 },   { 0,1,2,3 },   { 0,2,-1,-1 }, { 2,3,-1,-1 },\n                                           { 2,3,-1,-1 },   { 0,2,-1,-1},  { 0,3,1,2 },   { 1,2,-1,-1 },\n                                           { 1,3,-1,-1 },   { 0,1,-1,-1},  { 0,3,-1,-1},  { -1,-1,-1,-1 } };\n      const unsigned int\n        _nx = (unsigned int)(size_x>=0?size_x:cimg::round((x1-x0)*-size_x/100 + 1)),\n        _ny = (unsigned int)(size_y>=0?size_y:cimg::round((y1-y0)*-size_y/100 + 1)),\n        nx = _nx?_nx:1,\n        ny = _ny?_ny:1,\n        nxm1 = nx - 1,\n        nym1 = ny - 1;\n      primitives.assign();\n      if (!nxm1 || !nym1) return CImg<floatT>();\n      const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1;\n      CImgList<floatT> vertices;\n      CImg<intT> indices1(nx,1,1,2,-1), indices2(nx,1,1,2);\n      CImg<floatT> values1(nx), values2(nx);\n      float X = x0, Y = y0, nX = X + dx, nY = Y + dy;\n\n      // Fill first line with values\n      cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=dx; }\n\n      // Run the marching squares algorithm\n      for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=dy) {\n        X = x0; nX = X + dx;\n        indices2.fill(-1);\n        for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=dx) {\n\n          // Determine square configuration\n          const float\n            val0 = values1(xi),\n            val1 = values1(nxi),\n            val2 = values2(nxi) = (float)func(nX,nY),\n            val3 = values2(xi) = (float)func(X,nY);\n          const unsigned int\n            configuration = (val0<isovalue?1U:0U) | (val1<isovalue?2U:0U) |\n            (val2<isovalue?4U:0U) | (val3<isovalue?8U:0U),\n            edge = edges[configuration];\n\n          // Compute intersection vertices\n          if (edge) {\n            if ((edge&1) && indices1(xi,0)<0) {\n              const float Xi = X + (isovalue-val0)*dx/(val1-val0);\n              indices1(xi,0) = vertices.width();\n              CImg<floatT>::vector(Xi,Y,0).move_to(vertices);\n            }\n            if ((edge&2) && indices1(nxi,1)<0) {\n              const float Yi = Y + (isovalue-val1)*dy/(val2-val1);\n              indices1(nxi,1) = vertices.width();\n              CImg<floatT>::vector(nX,Yi,0).move_to(vertices);\n            }\n            if ((edge&4) && indices2(xi,0)<0) {\n              const float Xi = X + (isovalue-val3)*dx/(val2-val3);\n              indices2(xi,0) = vertices.width();\n              CImg<floatT>::vector(Xi,nY,0).move_to(vertices);\n            }\n            if ((edge&8) && indices1(xi,1)<0) {\n              const float Yi = Y + (isovalue-val0)*dy/(val3-val0);\n              indices1(xi,1) = vertices.width();\n              CImg<floatT>::vector(X,Yi,0).move_to(vertices);\n            }\n\n            // Create segments\n            for (const int *segment = segments[configuration]; *segment!=-1; ) {\n              const unsigned int p0 = (unsigned int)*(segment++), p1 = (unsigned int)*(segment++);\n              const tf\n                i0 = (tf)(_isoline3d_indice(p0,indices1,indices2,xi,nxi)),\n                i1 = (tf)(_isoline3d_indice(p1,indices1,indices2,xi,nxi));\n              CImg<tf>::vector(i0,i1).move_to(primitives);\n            }\n          }\n        }\n        values1.swap(values2);\n        indices1.swap(indices2);\n      }\n      return vertices>'x';\n    }\n\n    //! Compute isolines of a function, as a 3d object \\overloading.\n    template<typename tf>\n    static CImg<floatT> isoline3d(CImgList<tf>& primitives, const char *const expression, const float isovalue,\n                                  const float x0, const float y0, const float x1, const float y1,\n                                  const int size_x=256, const int size_y=256) {\n      const _functor2d_expr func(expression);\n      return isoline3d(primitives,func,isovalue,x0,y0,x1,y1,size_x,size_y);\n    }\n\n    template<typename t>\n    static int _isoline3d_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,\n                                 const unsigned int x, const unsigned int nx) {\n      switch (edge) {\n      case 0 : return (int)indices1(x,0);\n      case 1 : return (int)indices1(nx,1);\n      case 2 : return (int)indices2(x,0);\n      case 3 : return (int)indices1(x,1);\n      }\n      return 0;\n    }\n\n    //! Compute isosurface of a function, as a 3d object.\n    /**\n       \\param[out] primitives Primitives data of the resulting 3d object.\n       \\param func Implicit function. Is of type <tt>float (*func)(const float x, const float y, const float z)</tt>.\n       \\param isovalue Isovalue to extract.\n       \\param x0 X-coordinate of the starting point.\n       \\param y0 Y-coordinate of the starting point.\n       \\param z0 Z-coordinate of the starting point.\n       \\param x1 X-coordinate of the ending point.\n       \\param y1 Y-coordinate of the ending point.\n       \\param z1 Z-coordinate of the ending point.\n       \\param size_x Resolution of the elevation function along the X-axis.\n       \\param size_y Resolution of the elevation function along the Y-axis.\n       \\param size_z Resolution of the elevation function along the Z-axis.\n       \\note Use the marching cubes algorithm for extracting the isosurface.\n     **/\n    template<typename tf, typename tfunc>\n    static CImg<floatT> isosurface3d(CImgList<tf>& primitives, const tfunc& func, const float isovalue,\n                                     const float x0, const float y0, const float z0,\n                                     const float x1, const float y1, const float z1,\n                                     const int size_x=32, const int size_y=32, const int size_z=32) {\n      static const unsigned int edges[256] = {\n        0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,\n        0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,\n        0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,\n        0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,\n        0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,\n        0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,\n        0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,\n        0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,\n        0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,\n        0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,\n        0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,\n        0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,\n        0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,\n        0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,\n        0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,\n        0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000\n      };\n\n      static const int triangles[256][16] = {\n        { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 },\n        { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 },\n        { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 },\n        { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 },\n        { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },\n        { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 },\n        { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 },\n        { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 },\n        { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 },\n        { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 },\n        { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 },\n        { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 },\n        { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 },\n        { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 },\n        { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 },\n        { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 },\n        { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 },\n        { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 },\n        { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 },\n        { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 },\n        { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },\n        { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 },\n        { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 },\n        { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 },\n        { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 },\n        { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },\n        { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 },\n        { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 },\n        { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 },\n        { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 },\n        { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },\n        { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 },\n        { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 },\n        { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 },\n        { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 },\n        { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 },\n        { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 },\n        { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 },\n        { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 },\n        { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 },\n        { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 },\n        { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 },\n        { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 },\n        { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 },\n        { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 },\n        { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 },\n        { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 },\n        { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 },\n        { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 },\n        { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 },\n        { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 },\n        { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 },\n        { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 },\n        { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 },\n        { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 },\n        { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 },\n        { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 },\n        { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 },\n        { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 },\n        { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 },\n        { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },\n        { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },\n        { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 },\n        { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 },\n        { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 },\n        { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 },\n        { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 },\n        { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 },\n        { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 },\n        { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 },\n        { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 },\n        { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 },\n        { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 },\n        { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 },\n        { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 },\n        { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 },\n        { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 },\n        { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },\n        { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },\n        { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 },\n        { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },\n        { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 },\n        { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 },\n        { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 },\n        { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 },\n        { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 },\n        { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 },\n        { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 },\n        { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 },\n        { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 },\n        { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 },\n        { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 },\n        { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 },\n        { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 },\n        { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 },\n        { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 },\n        { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 },\n        { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 },\n        { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 },\n        { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 },\n        { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 },\n        { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 },\n        { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 },\n        { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 },\n        { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 },\n        { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 },\n        { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 },\n        { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 },\n        { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 },\n        { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 },\n        { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 },\n        { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 },\n        { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 },\n        { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 },\n        { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 },\n        { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 },\n        { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 },\n        { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 },\n        { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 },\n        { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 },\n        { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 },\n        { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 },\n        { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 },\n        { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 },\n        { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 },\n        { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 },\n        { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 },\n        { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 },\n        { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 },\n        { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 },\n        { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 },\n        { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 },\n        { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 },\n        { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 },\n        { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 },\n        { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 },\n        { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n        { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }\n      };\n\n      const unsigned int\n        _nx = (unsigned int)(size_x>=0?size_x:cimg::round((x1-x0)*-size_x/100 + 1)),\n        _ny = (unsigned int)(size_y>=0?size_y:cimg::round((y1-y0)*-size_y/100 + 1)),\n        _nz = (unsigned int)(size_z>=0?size_z:cimg::round((z1-z0)*-size_z/100 + 1)),\n        nx = _nx?_nx:1,\n        ny = _ny?_ny:1,\n        nz = _nz?_nz:1,\n        nxm1 = nx - 1,\n        nym1 = ny - 1,\n        nzm1 = nz - 1;\n      primitives.assign();\n      if (!nxm1 || !nym1 || !nzm1) return CImg<floatT>();\n      const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1, dz = (z1 - z0)/nzm1;\n      CImgList<floatT> vertices;\n      CImg<intT> indices1(nx,ny,1,3,-1), indices2(indices1);\n      CImg<floatT> values1(nx,ny), values2(nx,ny);\n      float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0;\n\n      // Fill the first plane with function values\n      Y = y0;\n      cimg_forY(values1,y) {\n        X = x0;\n        cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=dx; }\n        Y+=dy;\n      }\n\n      // Run Marching Cubes algorithm\n      Z = z0; nZ = Z + dz;\n      for (unsigned int zi = 0; zi<nzm1; ++zi, Z = nZ, nZ+=dz) {\n        Y = y0; nY = Y + dy;\n        indices2.fill(-1);\n        for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y = nY, nY+=dy) {\n          X = x0; nX = X + dx;\n          for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X = nX, nX+=dx) {\n\n            // Determine cube configuration\n            const float\n              val0 = values1(xi,yi),\n              val1 = values1(nxi,yi),\n              val2 = values1(nxi,nyi),\n              val3 = values1(xi,nyi),\n              val4 = values2(xi,yi) = (float)func(X,Y,nZ),\n              val5 = values2(nxi,yi) = (float)func(nX,Y,nZ),\n              val6 = values2(nxi,nyi) = (float)func(nX,nY,nZ),\n              val7 = values2(xi,nyi) = (float)func(X,nY,nZ);\n\n            const unsigned int configuration =\n              (val0<isovalue?1U:0U)  | (val1<isovalue?2U:0U)  | (val2<isovalue?4U:0U)  | (val3<isovalue?8U:0U) |\n              (val4<isovalue?16U:0U) | (val5<isovalue?32U:0U) | (val6<isovalue?64U:0U) | (val7<isovalue?128U:0U),\n              edge = edges[configuration];\n\n            // Compute intersection vertices\n            if (edge) {\n              if ((edge&1) && indices1(xi,yi,0)<0) {\n                const float Xi = X + (isovalue-val0)*dx/(val1-val0);\n                indices1(xi,yi,0) = vertices.width();\n                CImg<floatT>::vector(Xi,Y,Z).move_to(vertices);\n              }\n              if ((edge&2) && indices1(nxi,yi,1)<0) {\n                const float Yi = Y + (isovalue-val1)*dy/(val2-val1);\n                indices1(nxi,yi,1) = vertices.width();\n                CImg<floatT>::vector(nX,Yi,Z).move_to(vertices);\n              }\n              if ((edge&4) && indices1(xi,nyi,0)<0) {\n                const float Xi = X + (isovalue-val3)*dx/(val2-val3);\n                indices1(xi,nyi,0) = vertices.width();\n                CImg<floatT>::vector(Xi,nY,Z).move_to(vertices);\n              }\n              if ((edge&8) && indices1(xi,yi,1)<0) {\n                const float Yi = Y + (isovalue-val0)*dy/(val3-val0);\n                indices1(xi,yi,1) = vertices.width();\n                CImg<floatT>::vector(X,Yi,Z).move_to(vertices);\n              }\n              if ((edge&16) && indices2(xi,yi,0)<0) {\n                const float Xi = X + (isovalue-val4)*dx/(val5-val4);\n                indices2(xi,yi,0) = vertices.width();\n                CImg<floatT>::vector(Xi,Y,nZ).move_to(vertices);\n              }\n              if ((edge&32) && indices2(nxi,yi,1)<0) {\n                const float Yi = Y + (isovalue-val5)*dy/(val6-val5);\n                indices2(nxi,yi,1) = vertices.width();\n                CImg<floatT>::vector(nX,Yi,nZ).move_to(vertices);\n              }\n              if ((edge&64) && indices2(xi,nyi,0)<0) {\n                const float Xi = X + (isovalue-val7)*dx/(val6-val7);\n                indices2(xi,nyi,0) = vertices.width();\n                CImg<floatT>::vector(Xi,nY,nZ).move_to(vertices);\n              }\n              if ((edge&128) && indices2(xi,yi,1)<0)  {\n                const float Yi = Y + (isovalue-val4)*dy/(val7-val4);\n                indices2(xi,yi,1) = vertices.width();\n                CImg<floatT>::vector(X,Yi,nZ).move_to(vertices);\n              }\n              if ((edge&256) && indices1(xi,yi,2)<0) {\n                const float Zi = Z+ (isovalue-val0)*dz/(val4-val0);\n                indices1(xi,yi,2) = vertices.width();\n                CImg<floatT>::vector(X,Y,Zi).move_to(vertices);\n              }\n              if ((edge&512) && indices1(nxi,yi,2)<0)  {\n                const float Zi = Z + (isovalue-val1)*dz/(val5-val1);\n                indices1(nxi,yi,2) = vertices.width();\n                CImg<floatT>::vector(nX,Y,Zi).move_to(vertices);\n              }\n              if ((edge&1024) && indices1(nxi,nyi,2)<0) {\n                const float Zi = Z + (isovalue-val2)*dz/(val6-val2);\n                indices1(nxi,nyi,2) = vertices.width();\n                CImg<floatT>::vector(nX,nY,Zi).move_to(vertices);\n              }\n              if ((edge&2048) && indices1(xi,nyi,2)<0) {\n                const float Zi = Z + (isovalue-val3)*dz/(val7-val3);\n                indices1(xi,nyi,2) = vertices.width();\n                CImg<floatT>::vector(X,nY,Zi).move_to(vertices);\n              }\n\n              // Create triangles\n              for (const int *triangle = triangles[configuration]; *triangle!=-1; ) {\n                const unsigned int\n                  p0 = (unsigned int)*(triangle++),\n                  p1 = (unsigned int)*(triangle++),\n                  p2 = (unsigned int)*(triangle++);\n                const tf\n                  i0 = (tf)(_isosurface3d_indice(p0,indices1,indices2,xi,yi,nxi,nyi)),\n                  i1 = (tf)(_isosurface3d_indice(p1,indices1,indices2,xi,yi,nxi,nyi)),\n                  i2 = (tf)(_isosurface3d_indice(p2,indices1,indices2,xi,yi,nxi,nyi));\n                CImg<tf>::vector(i0,i2,i1).move_to(primitives);\n              }\n            }\n          }\n        }\n        cimg::swap(values1,values2);\n        cimg::swap(indices1,indices2);\n      }\n      return vertices>'x';\n    }\n\n    //! Compute isosurface of a function, as a 3d object \\overloading.\n    template<typename tf>\n    static CImg<floatT> isosurface3d(CImgList<tf>& primitives, const char *const expression, const float isovalue,\n                                     const float x0, const float y0, const float z0,\n                                     const float x1, const float y1, const float z1,\n                                     const int dx=32, const int dy=32, const int dz=32) {\n      const _functor3d_expr func(expression);\n      return isosurface3d(primitives,func,isovalue,x0,y0,z0,x1,y1,z1,dx,dy,dz);\n    }\n\n    template<typename t>\n    static int _isosurface3d_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,\n                                    const unsigned int x, const unsigned int y,\n                                    const unsigned int nx, const unsigned int ny) {\n      switch (edge) {\n      case 0 : return indices1(x,y,0);\n      case 1 : return indices1(nx,y,1);\n      case 2 : return indices1(x,ny,0);\n      case 3 : return indices1(x,y,1);\n      case 4 : return indices2(x,y,0);\n      case 5 : return indices2(nx,y,1);\n      case 6 : return indices2(x,ny,0);\n      case 7 : return indices2(x,y,1);\n      case 8 : return indices1(x,y,2);\n      case 9 : return indices1(nx,y,2);\n      case 10 : return indices1(nx,ny,2);\n      case 11 : return indices1(x,ny,2);\n      }\n      return 0;\n    }\n\n    // Define functors for accessing image values (used in previous functions).\n    struct _functor2d_int {\n      const CImg<T>& ref;\n      _functor2d_int(const CImg<T>& pref):ref(pref) {}\n      float operator()(const float x, const float y) const {\n        return (float)ref((int)x,(int)y);\n      }\n    };\n\n    struct _functor2d_float {\n      const CImg<T>& ref;\n      _functor2d_float(const CImg<T>& pref):ref(pref) {}\n      float operator()(const float x, const float y) const {\n        return (float)ref._linear_atXY(x,y);\n      }\n    };\n\n    struct _functor2d_expr {\n      _cimg_math_parser *mp;\n      _functor2d_expr(const char *const expr):mp(0) {\n        mp = new _cimg_math_parser(expr,0,CImg<T>::const_empty(),0);\n      }\n      ~_functor2d_expr() { delete mp; }\n      float operator()(const float x, const float y) const {\n        return (float)(*mp)(x,y,0,0);\n      }\n    };\n\n    struct _functor3d_int {\n      const CImg<T>& ref;\n      _functor3d_int(const CImg<T>& pref):ref(pref) {}\n      float operator()(const float x, const float y, const float z) const {\n        return (float)ref((int)x,(int)y,(int)z);\n      }\n    };\n\n    struct _functor3d_float {\n      const CImg<T>& ref;\n      _functor3d_float(const CImg<T>& pref):ref(pref) {}\n      float operator()(const float x, const float y, const float z) const {\n        return (float)ref._linear_atXYZ(x,y,z);\n      }\n    };\n\n    struct _functor3d_expr {\n      _cimg_math_parser *mp;\n      ~_functor3d_expr() { delete mp; }\n      _functor3d_expr(const char *const expr):mp(0) {\n        mp = new _cimg_math_parser(expr,0,CImg<T>::const_empty(),0);\n      }\n      float operator()(const float x, const float y, const float z) const {\n        return (float)(*mp)(x,y,z,0);\n      }\n    };\n\n    struct _functor4d_int {\n      const CImg<T>& ref;\n      _functor4d_int(const CImg<T>& pref):ref(pref) {}\n      float operator()(const float x, const float y, const float z, const unsigned int c) const {\n        return (float)ref((int)x,(int)y,(int)z,c);\n      }\n    };\n\n    //! Generate a 3d box object.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param size_x The width of the box (dimension along the X-axis).\n       \\param size_y The height of the box (dimension along the Y-axis).\n       \\param size_z The depth of the box (dimension along the Z-axis).\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       CImgList<unsigned int> faces3d;\n       const CImg<float> points3d = CImg<float>::box3d(faces3d,10,20,30);\n       CImg<unsigned char>().display_object3d(\"Box3d\",points3d,faces3d);\n       \\endcode\n       \\image html ref_box3d.jpg\n    **/\n    template<typename tf>\n    static CImg<floatT> box3d(CImgList<tf>& primitives,\n                              const float size_x=200, const float size_y=100, const float size_z=100) {\n      primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5);\n      return CImg<floatT>(8,3,1,1,\n                          0.,size_x,size_x,    0.,    0.,size_x,size_x,    0.,\n                          0.,    0.,size_y,size_y,    0.,    0.,size_y,size_y,\n                          0.,    0.,    0.,    0.,size_z,size_z,size_z,size_z);\n    }\n\n    //! Generate a 3d cone.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param radius The radius of the cone basis.\n       \\param size_z The cone's height.\n       \\param subdivisions The number of basis angular subdivisions.\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       CImgList<unsigned int> faces3d;\n       const CImg<float> points3d = CImg<float>::cone3d(faces3d,50);\n       CImg<unsigned char>().display_object3d(\"Cone3d\",points3d,faces3d);\n       \\endcode\n       \\image html ref_cone3d.jpg\n    **/\n    template<typename tf>\n    static CImg<floatT> cone3d(CImgList<tf>& primitives,\n                               const float radius=50, const float size_z=100, const unsigned int subdivisions=24) {\n      primitives.assign();\n      if (!subdivisions) return CImg<floatT>();\n      CImgList<floatT> vertices(2,1,3,1,1,\n                                0.,0.,size_z,\n                                0.,0.,0.);\n      for (float delta = 360.0f/subdivisions, angle = 0; angle<360; angle+=delta) {\n        const float a = (float)(angle*cimg::PI/180);\n        CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0).move_to(vertices);\n      }\n      const unsigned int nbr = vertices._width - 2;\n      for (unsigned int p = 0; p<nbr; ++p) {\n        const unsigned int curr = 2 + p, next = 2 + ((p + 1)%nbr);\n        CImg<tf>::vector(1,next,curr).move_to(primitives);\n        CImg<tf>::vector(0,curr,next).move_to(primitives);\n      }\n      return vertices>'x';\n    }\n\n    //! Generate a 3d cylinder.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param radius The radius of the cylinder basis.\n       \\param size_z The cylinder's height.\n       \\param subdivisions The number of basis angular subdivisions.\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       CImgList<unsigned int> faces3d;\n       const CImg<float> points3d = CImg<float>::cylinder3d(faces3d,50);\n       CImg<unsigned char>().display_object3d(\"Cylinder3d\",points3d,faces3d);\n       \\endcode\n       \\image html ref_cylinder3d.jpg\n    **/\n    template<typename tf>\n    static CImg<floatT> cylinder3d(CImgList<tf>& primitives,\n                                   const float radius=50, const float size_z=100, const unsigned int subdivisions=24) {\n      primitives.assign();\n      if (!subdivisions) return CImg<floatT>();\n      CImgList<floatT> vertices(2,1,3,1,1,\n                                0.,0.,0.,\n                                0.,0.,size_z);\n      for (float delta = 360.0f/subdivisions, angle = 0; angle<360; angle+=delta) {\n        const float a = (float)(angle*cimg::PI/180);\n        CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0.0f).move_to(vertices);\n        CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),size_z).move_to(vertices);\n      }\n      const unsigned int nbr = (vertices._width - 2)/2;\n      for (unsigned int p = 0; p<nbr; ++p) {\n        const unsigned int curr = 2 + 2*p, next = 2 + (2*((p + 1)%nbr));\n        CImg<tf>::vector(0,next,curr).move_to(primitives);\n        CImg<tf>::vector(1,curr + 1,next + 1).move_to(primitives);\n        CImg<tf>::vector(curr,next,next + 1,curr + 1).move_to(primitives);\n      }\n      return vertices>'x';\n    }\n\n    //! Generate a 3d torus.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param radius1 The large radius.\n       \\param radius2 The small radius.\n       \\param subdivisions1 The number of angular subdivisions for the large radius.\n       \\param subdivisions2 The number of angular subdivisions for the small radius.\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       CImgList<unsigned int> faces3d;\n       const CImg<float> points3d = CImg<float>::torus3d(faces3d,20,4);\n       CImg<unsigned char>().display_object3d(\"Torus3d\",points3d,faces3d);\n       \\endcode\n       \\image html ref_torus3d.jpg\n    **/\n    template<typename tf>\n    static CImg<floatT> torus3d(CImgList<tf>& primitives,\n                                const float radius1=100, const float radius2=30,\n                                const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) {\n      primitives.assign();\n      if (!subdivisions1 || !subdivisions2) return CImg<floatT>();\n      CImgList<floatT> vertices;\n      for (unsigned int v = 0; v<subdivisions1; ++v) {\n        const float\n          beta = (float)(v*2*cimg::PI/subdivisions1),\n          xc = radius1*(float)std::cos(beta),\n          yc = radius1*(float)std::sin(beta);\n        for (unsigned int u = 0; u<subdivisions2; ++u) {\n          const float\n            alpha = (float)(u*2*cimg::PI/subdivisions2),\n            x = xc + radius2*(float)(std::cos(alpha)*std::cos(beta)),\n            y = yc + radius2*(float)(std::cos(alpha)*std::sin(beta)),\n            z = radius2*(float)std::sin(alpha);\n          CImg<floatT>::vector(x,y,z).move_to(vertices);\n        }\n      }\n      for (unsigned int vv = 0; vv<subdivisions1; ++vv) {\n        const unsigned int nv = (vv + 1)%subdivisions1;\n        for (unsigned int uu = 0; uu<subdivisions2; ++uu) {\n          const unsigned int nu = (uu + 1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv;\n          CImg<tf>::vector(svv + nu,svv + uu,snv + uu,snv + nu).move_to(primitives);\n        }\n      }\n      return vertices>'x';\n    }\n\n    //! Generate a 3d XY-plane.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param size_x The width of the plane (dimension along the X-axis).\n       \\param size_y The height of the plane (dimensions along the Y-axis).\n       \\param subdivisions_x The number of planar subdivisions along the X-axis.\n       \\param subdivisions_y The number of planar subdivisions along the Y-axis.\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       CImgList<unsigned int> faces3d;\n       const CImg<float> points3d = CImg<float>::plane3d(faces3d,100,50);\n       CImg<unsigned char>().display_object3d(\"Plane3d\",points3d,faces3d);\n       \\endcode\n       \\image html ref_plane3d.jpg\n    **/\n    template<typename tf>\n    static CImg<floatT> plane3d(CImgList<tf>& primitives,\n                                const float size_x=100, const float size_y=100,\n                                const unsigned int subdivisions_x=10, const unsigned int subdivisions_y=10) {\n      primitives.assign();\n      if (!subdivisions_x || !subdivisions_y) return CImg<floatT>();\n      CImgList<floatT> vertices;\n      const unsigned int w = subdivisions_x + 1, h = subdivisions_y + 1;\n      const float fx = (float)size_x/w, fy = (float)size_y/h;\n      for (unsigned int y = 0; y<h; ++y) for (unsigned int x = 0; x<w; ++x)\n        CImg<floatT>::vector(fx*x,fy*y,0).move_to(vertices);\n      for (unsigned int y = 0; y<subdivisions_y; ++y) for (unsigned int x = 0; x<subdivisions_x; ++x) {\n        const int off1 = x + y*w, off2 = x + 1 + y*w, off3 = x + 1 + (y + 1)*w, off4 = x + (y + 1)*w;\n        CImg<tf>::vector(off1,off4,off3,off2).move_to(primitives);\n      }\n      return vertices>'x';\n    }\n\n    //! Generate a 3d sphere.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param radius The radius of the sphere (dimension along the X-axis).\n       \\param subdivisions The number of recursive subdivisions from an initial icosahedron.\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       CImgList<unsigned int> faces3d;\n       const CImg<float> points3d = CImg<float>::sphere3d(faces3d,100,4);\n       CImg<unsigned char>().display_object3d(\"Sphere3d\",points3d,faces3d);\n       \\endcode\n       \\image html ref_sphere3d.jpg\n    **/\n    template<typename tf>\n    static CImg<floatT> sphere3d(CImgList<tf>& primitives,\n                                 const float radius=50, const unsigned int subdivisions=3) {\n\n      // Create initial icosahedron\n      primitives.assign();\n      const double tmp = (1 + std::sqrt(5.0f))/2, a = 1.0/std::sqrt(1 + tmp*tmp), b = tmp*a;\n      CImgList<floatT> vertices(12,1,3,1,1, b,a,0.0, -b,a,0.0, -b,-a,0.0, b,-a,0.0, a,0.0,b, a,0.0,-b,\n                                -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a);\n      primitives.assign(20,1,3,1,1, 4,8,7, 4,7,9, 5,6,11, 5,10,6, 0,4,3, 0,3,5, 2,7,1, 2,1,6,\n                        8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3,\n                        5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2);\n      // edge - length/2\n      float he = (float)a;\n\n      // Recurse subdivisions\n      for (unsigned int i = 0; i<subdivisions; ++i) {\n        const unsigned int L = primitives._width;\n        he/=2;\n        const float he2 = he*he;\n        for (unsigned int l = 0; l<L; ++l) {\n          const unsigned int\n            p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2);\n          const float\n            x0 = vertices(p0,0), y0 = vertices(p0,1), z0 = vertices(p0,2),\n            x1 = vertices(p1,0), y1 = vertices(p1,1), z1 = vertices(p1,2),\n            x2 = vertices(p2,0), y2 = vertices(p2,1), z2 = vertices(p2,2),\n            tnx0 = (x0 + x1)/2, tny0 = (y0 + y1)/2, tnz0 = (z0 + z1)/2,\n            nn0 = (float)std::sqrt(tnx0*tnx0 + tny0*tny0 + tnz0*tnz0),\n            tnx1 = (x0 + x2)/2, tny1 = (y0 + y2)/2, tnz1 = (z0 + z2)/2,\n            nn1 = (float)std::sqrt(tnx1*tnx1 + tny1*tny1 + tnz1*tnz1),\n            tnx2 = (x1 + x2)/2, tny2 = (y1 + y2)/2, tnz2 = (z1 + z2)/2,\n            nn2 = (float)std::sqrt(tnx2*tnx2 + tny2*tny2 + tnz2*tnz2),\n            nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0,\n            nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1,\n            nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2;\n          int i0 = -1, i1 = -1, i2 = -1;\n          cimglist_for(vertices,p) {\n            const float x = (float)vertices(p,0), y = (float)vertices(p,1), z = (float)vertices(p,2);\n            if (cimg::sqr(x-nx0) + cimg::sqr(y-ny0) + cimg::sqr(z-nz0)<he2) i0 = p;\n            if (cimg::sqr(x-nx1) + cimg::sqr(y-ny1) + cimg::sqr(z-nz1)<he2) i1 = p;\n            if (cimg::sqr(x-nx2) + cimg::sqr(y-ny2) + cimg::sqr(z-nz2)<he2) i2 = p;\n          }\n          if (i0<0) { CImg<floatT>::vector(nx0,ny0,nz0).move_to(vertices); i0 = vertices.width() - 1; }\n          if (i1<0) { CImg<floatT>::vector(nx1,ny1,nz1).move_to(vertices); i1 = vertices.width() - 1; }\n          if (i2<0) { CImg<floatT>::vector(nx2,ny2,nz2).move_to(vertices); i2 = vertices.width() - 1; }\n          primitives.remove(0);\n          CImg<tf>::vector(p0,i0,i1).move_to(primitives);\n          CImg<tf>::vector((tf)i0,(tf)p1,(tf)i2).move_to(primitives);\n          CImg<tf>::vector((tf)i1,(tf)i2,(tf)p2).move_to(primitives);\n          CImg<tf>::vector((tf)i1,(tf)i0,(tf)i2).move_to(primitives);\n        }\n      }\n      return (vertices>'x')*=radius;\n    }\n\n    //! Generate a 3d ellipsoid.\n    /**\n       \\param[out] primitives The returned list of the 3d object primitives\n                              (template type \\e tf should be at least \\e unsigned \\e int).\n       \\param tensor The tensor which gives the shape and size of the ellipsoid.\n       \\param subdivisions The number of recursive subdivisions from an initial stretched icosahedron.\n       \\return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N - 1).\n       \\par Example\n       \\code\n       CImgList<unsigned int> faces3d;\n       const CImg<float> tensor = CImg<float>::diagonal(10,7,3),\n                         points3d = CImg<float>::ellipsoid3d(faces3d,tensor,4);\n       CImg<unsigned char>().display_object3d(\"Ellipsoid3d\",points3d,faces3d);\n       \\endcode\n       \\image html ref_ellipsoid3d.jpg\n    **/\n    template<typename tf, typename t>\n    static CImg<floatT> ellipsoid3d(CImgList<tf>& primitives,\n                                    const CImg<t>& tensor, const unsigned int subdivisions=3) {\n      primitives.assign();\n      if (!subdivisions) return CImg<floatT>();\n      CImg<floatT> S, V;\n      tensor.symmetric_eigen(S,V);\n      const float orient =\n        (V(0,1)*V(1,2) - V(0,2)*V(1,1))*V(2,0) +\n        (V(0,2)*V(1,0) - V(0,0)*V(1,2))*V(2,1) +\n        (V(0,0)*V(1,1) - V(0,1)*V(1,0))*V(2,2);\n      if (orient<0) { V(2,0) = -V(2,0); V(2,1) = -V(2,1); V(2,2) = -V(2,2); }\n      const float l0 = S[0], l1 = S[1], l2 = S[2];\n      CImg<floatT> vertices = sphere3d(primitives,1.0,subdivisions);\n      vertices.get_shared_row(0)*=l0;\n      vertices.get_shared_row(1)*=l1;\n      vertices.get_shared_row(2)*=l2;\n      return V*vertices;\n    }\n\n    //! Convert 3d object into a CImg3d representation.\n    /**\n       \\param primitives Primitives data of the 3d object.\n       \\param colors Colors data of the 3d object.\n       \\param opacities Opacities data of the 3d object.\n       \\param full_check Tells if full checking of the 3d object must be performed.\n    **/\n    template<typename tp, typename tc, typename to>\n    CImg<T>& object3dtoCImg3d(const CImgList<tp>& primitives,\n                              const CImgList<tc>& colors,\n                              const to& opacities,\n                              const bool full_check=true) {\n      return get_object3dtoCImg3d(primitives,colors,opacities,full_check).move_to(*this);\n    }\n\n    //! Convert 3d object into a CImg3d representation \\overloading.\n    template<typename tp, typename tc>\n    CImg<T>& object3dtoCImg3d(const CImgList<tp>& primitives,\n                              const CImgList<tc>& colors,\n                              const bool full_check=true) {\n      return get_object3dtoCImg3d(primitives,colors,full_check).move_to(*this);\n    }\n\n    //! Convert 3d object into a CImg3d representation \\overloading.\n    template<typename tp>\n    CImg<T>& object3dtoCImg3d(const CImgList<tp>& primitives,\n                              const bool full_check=true) {\n      return get_object3dtoCImg3d(primitives,full_check).move_to(*this);\n    }\n\n    //! Convert 3d object into a CImg3d representation \\overloading.\n    CImg<T>& object3dtoCImg3d(const bool full_check=true) {\n      return get_object3dtoCImg3d(full_check).move_to(*this);\n    }\n\n    //! Convert 3d object into a CImg3d representation \\newinstance.\n    template<typename tp, typename tc, typename to>\n    CImg<floatT> get_object3dtoCImg3d(const CImgList<tp>& primitives,\n                                      const CImgList<tc>& colors,\n                                      const to& opacities,\n                                      const bool full_check=true) const {\n      CImg<charT> error_message(1024);\n      if (!is_object3d(primitives,colors,opacities,full_check,error_message))\n        throw CImgInstanceException(_cimg_instance\n                                    \"object3dtoCImg3d(): Invalid specified 3d object (%u,%u) (%s).\",\n                                    cimg_instance,_width,primitives._width,error_message.data());\n      CImg<floatT> res(1,_size_object3dtoCImg3d(primitives,colors,opacities));\n      float *ptrd = res._data;\n\n      // Put magick number.\n      *(ptrd++) = 'C' + 0.5f; *(ptrd++) = 'I' + 0.5f; *(ptrd++) = 'm' + 0.5f;\n      *(ptrd++) = 'g' + 0.5f; *(ptrd++) = '3' + 0.5f; *(ptrd++) = 'd' + 0.5f;\n\n      // Put number of vertices and primitives.\n      *(ptrd++) = cimg::uint2float(_width);\n      *(ptrd++) = cimg::uint2float(primitives._width);\n\n      // Put vertex data.\n      if (is_empty() || !primitives) return res;\n      const T *ptrx = data(0,0), *ptry = data(0,1), *ptrz = data(0,2);\n      cimg_forX(*this,p) {\n        *(ptrd++) = (float)*(ptrx++);\n        *(ptrd++) = (float)*(ptry++);\n        *(ptrd++) = (float)*(ptrz++);\n      }\n\n      // Put primitive data.\n      cimglist_for(primitives,p) {\n        *(ptrd++) = (float)primitives[p].size();\n        const tp *ptrp = primitives[p]._data;\n        cimg_foroff(primitives[p],i) *(ptrd++) = cimg::uint2float((unsigned int)*(ptrp++));\n      }\n\n      // Put color/texture data.\n      const unsigned int csiz = cimg::min(colors._width,primitives._width);\n      for (int c = 0; c<(int)csiz; ++c) {\n        const CImg<tc>& color = colors[c];\n        const tc *ptrc = color._data;\n        if (color.size()==3) { *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*ptrc; }\n        else {\n          *(ptrd++) = -128.0f;\n          int shared_ind = -1;\n          if (color.is_shared()) for (int i = 0; i<c; ++i) if (ptrc==colors[i]._data) { shared_ind = i; break; }\n          if (shared_ind<0) {\n            *(ptrd++) = (float)color._width;\n            *(ptrd++) = (float)color._height;\n            *(ptrd++) = (float)color._spectrum;\n            cimg_foroff(color,l) *(ptrd++) = (float)*(ptrc++);\n          } else {\n            *(ptrd++) = (float)shared_ind;\n            *(ptrd++) = 0;\n            *(ptrd++) = 0;\n          }\n        }\n      }\n      const int csiz2 = primitives.width() - colors.width();\n      for (int c = 0; c<csiz2; ++c) { *(ptrd++) = 200.0f; *(ptrd++) = 200.0f; *(ptrd++) = 200.0f; }\n\n      // Put opacity data.\n      ptrd = _object3dtoCImg3d(opacities,ptrd);\n      const float *ptre = res.end();\n      while (ptrd<ptre) *(ptrd++) = 1.0f;\n      return res;\n    }\n\n    template<typename to>\n    float* _object3dtoCImg3d(const CImgList<to>& opacities, float *ptrd) const {\n      cimglist_for(opacities,o) {\n        const CImg<to>& opacity = opacities[o];\n        const to *ptro = opacity._data;\n        if (opacity.size()==1) *(ptrd++) = (float)*ptro;\n        else {\n          *(ptrd++) = -128.0f;\n          int shared_ind = -1;\n          if (opacity.is_shared()) for (int i = 0; i<o; ++i) if (ptro==opacities[i]._data) { shared_ind = i; break; }\n          if (shared_ind<0) {\n            *(ptrd++) = (float)opacity._width;\n            *(ptrd++) = (float)opacity._height;\n            *(ptrd++) = (float)opacity._spectrum;\n            cimg_foroff(opacity,l) *(ptrd++) = (float)*(ptro++);\n          } else {\n            *(ptrd++) = (float)shared_ind;\n            *(ptrd++) = 0;\n            *(ptrd++) = 0;\n          }\n        }\n      }\n      return ptrd;\n    }\n\n    template<typename to>\n    float* _object3dtoCImg3d(const CImg<to>& opacities, float *ptrd) const {\n      const to *ptro = opacities._data;\n      cimg_foroff(opacities,o) *(ptrd++) = (float)*(ptro++);\n      return ptrd;\n    }\n\n    template<typename tp, typename tc, typename to>\n    unsigned int _size_object3dtoCImg3d(const CImgList<tp>& primitives,\n                                        const CImgList<tc>& colors,\n                                        const CImgList<to>& opacities) const {\n      unsigned int siz = 8U + 3*_width;\n      cimglist_for(primitives,p) siz+=primitives[p].size() + 1;\n      for (int c = cimg::min(primitives.width(),colors.width()) - 1; c>=0; --c) {\n        if (colors[c].is_shared()) siz+=4;\n        else { const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4 + csiz:3; }\n      }\n      if (colors._width<primitives._width) siz+=3*(primitives._width - colors._width);\n      cimglist_for(opacities,o) {\n        if (opacities[o].is_shared()) siz+=4;\n        else { const unsigned int osiz = opacities[o].size(); siz+=(osiz!=1)?4 + osiz:1; }\n      }\n      siz+=primitives._width - opacities._width;\n      return siz;\n    }\n\n    template<typename tp, typename tc, typename to>\n    unsigned int _size_object3dtoCImg3d(const CImgList<tp>& primitives,\n                                        const CImgList<tc>& colors,\n                                        const CImg<to>& opacities) const {\n      unsigned int siz = 8U + 3*_width;\n      cimglist_for(primitives,p) siz+=primitives[p].size() + 1;\n      for (int c = cimg::min(primitives.width(),colors.width()) - 1; c>=0; --c) {\n        const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4 + csiz:3;\n      }\n      if (colors._width<primitives._width) siz+=3*(primitives._width - colors._width);\n      siz+=primitives.size();\n      cimg::unused(opacities);\n      return siz;\n    }\n\n    //! Convert 3d object into a CImg3d representation \\overloading.\n    template<typename tp, typename tc>\n    CImg<floatT> get_object3dtoCImg3d(const CImgList<tp>& primitives,\n                                      const CImgList<tc>& colors,\n                                      const bool full_check=true) const {\n      CImgList<T> opacities;\n      return get_object3dtoCImg3d(primitives,colors,opacities,full_check);\n    }\n\n    //! Convert 3d object into a CImg3d representation \\overloading.\n    template<typename tp>\n    CImg<floatT> get_object3dtoCImg3d(const CImgList<tp>& primitives,\n                                      const bool full_check=true) const {\n      CImgList<T> colors, opacities;\n      return get_object3dtoCImg3d(primitives,colors,opacities,full_check);\n    }\n\n    //! Convert 3d object into a CImg3d representation \\overloading.\n    CImg<floatT> get_object3dtoCImg3d(const bool full_check=true) const {\n      CImgList<T> opacities, colors;\n      CImgList<uintT> primitives(width(),1,1,1,1);\n      cimglist_for(primitives,p) primitives(p,0) = p;\n      return get_object3dtoCImg3d(primitives,colors,opacities,full_check);\n    }\n\n    //! Convert CImg3d representation into a 3d object.\n    /**\n       \\param[out] primitives Primitives data of the 3d object.\n       \\param[out] colors Colors data of the 3d object.\n       \\param[out] opacities Opacities data of the 3d object.\n       \\param full_check Tells if full checking of the 3d object must be performed.\n    **/\n    template<typename tp, typename tc, typename to>\n    CImg<T>& CImg3dtoobject3d(CImgList<tp>& primitives,\n                              CImgList<tc>& colors,\n                              CImgList<to>& opacities,\n                              const bool full_check=true) {\n      return get_CImg3dtoobject3d(primitives,colors,opacities,full_check).move_to(*this);\n    }\n\n    //! Convert CImg3d representation into a 3d object \\newinstance.\n    template<typename tp, typename tc, typename to>\n    CImg<T> get_CImg3dtoobject3d(CImgList<tp>& primitives,\n                                 CImgList<tc>& colors,\n                                 CImgList<to>& opacities,\n                                 const bool full_check=true) const {\n      CImg<charT> error_message(1024);\n      if (!is_CImg3d(full_check,error_message))\n        throw CImgInstanceException(_cimg_instance\n                                    \"CImg3dtoobject3d(): image instance is not a CImg3d (%s).\",\n                                    cimg_instance,error_message.data());\n      const T *ptrs = _data + 6;\n      const unsigned int\n        nb_points = cimg::float2uint((float)*(ptrs++)),\n        nb_primitives = cimg::float2uint((float)*(ptrs++));\n      const CImg<T> points = CImg<T>(ptrs,3,nb_points,1,1,true).get_transpose();\n      ptrs+=3*nb_points;\n      primitives.assign(nb_primitives);\n      cimglist_for(primitives,p) {\n        const unsigned int nb_inds = (unsigned int)*(ptrs++);\n        primitives[p].assign(1,nb_inds);\n        tp *ptrp = primitives[p]._data;\n        for (unsigned int i = 0; i<nb_inds; ++i) *(ptrp++) = (tp)cimg::float2uint((float)*(ptrs++));\n      }\n      colors.assign(nb_primitives);\n      cimglist_for(colors,c) {\n        if (*ptrs==(T)-128) {\n          ++ptrs;\n          const unsigned int w = (unsigned int)*(ptrs++), h = (unsigned int)*(ptrs++), s = (unsigned int)*(ptrs++);\n          if (!h && !s) colors[c].assign(colors[w],true);\n          else { colors[c].assign(ptrs,w,h,1,s,false); ptrs+=w*h*s; }\n        } else { colors[c].assign(ptrs,1,1,1,3,false); ptrs+=3; }\n      }\n      opacities.assign(nb_primitives);\n      cimglist_for(opacities,o) {\n        if (*ptrs==(T)-128) {\n          ++ptrs;\n          const unsigned int w = (unsigned int)*(ptrs++), h = (unsigned int)*(ptrs++), s = (unsigned int)*(ptrs++);\n          if (!h && !s) opacities[o].assign(opacities[w],true);\n          else { opacities[o].assign(ptrs,w,h,1,s,false); ptrs+=w*h*s; }\n        } else opacities[o].assign(1,1,1,1,*(ptrs++));\n      }\n      return points;\n    }\n\n    //@}\n    //---------------------------\n    //\n    //! \\name Drawing Functions\n    //@{\n    //---------------------------\n\n#define cimg_init_scanline(color,opacity) \\\n    const float _sc_nopacity = cimg::abs((float)opacity), _sc_copacity = 1 - cimg::max((float)opacity,0); \\\n  const ulongT _sc_whd = (ulongT)_width*_height*_depth\n\n#define cimg_draw_scanline(x0,x1,y,color,opacity,brightness) \\\n    _draw_scanline(x0,x1,y,color,opacity,brightness,_sc_nopacity,_sc_copacity,_sc_whd)\n\n    // [internal] The following _draw_scanline() routines are *non user-friendly functions*,\n    // used only for internal purpose.\n    // Pre-requisites: x0<x1, y-coordinate is valid, col is valid.\n    template<typename tc>\n    CImg<T>& _draw_scanline(const int x0, const int x1, const int y,\n                            const tc *const color, const float opacity,\n                            const float brightness,\n                            const float nopacity, const float copacity, const ulongT whd) {\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const int nx0 = x0>0?x0:0, nx1 = x1<width()?x1:width() - 1, dx = nx1 - nx0;\n      if (dx>=0) {\n        const tc *col = color;\n        const ulongT off = whd - dx - 1;\n        T *ptrd = data(nx0,y);\n        if (opacity>=1) { // ** Opaque drawing **\n          if (brightness==1) { // Brightness==1\n            if (sizeof(T)!=1) cimg_forC(*this,c) {\n                const T val = (T)*(col++);\n                for (int x = dx; x>=0; --x) *(ptrd++) = val;\n                ptrd+=off;\n              } else cimg_forC(*this,c) {\n                const T val = (T)*(col++);\n                std::memset(ptrd,(int)val,dx + 1);\n                ptrd+=whd;\n              }\n          } else if (brightness<1) { // Brightness<1\n            if (sizeof(T)!=1) cimg_forC(*this,c) {\n                const T val = (T)(*(col++)*brightness);\n                for (int x = dx; x>=0; --x) *(ptrd++) = val;\n                ptrd+=off;\n              } else cimg_forC(*this,c) {\n                const T val = (T)(*(col++)*brightness);\n                std::memset(ptrd,(int)val,dx + 1);\n                ptrd+=whd;\n              }\n          } else { // Brightness>1\n            if (sizeof(T)!=1) cimg_forC(*this,c) {\n                const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval);\n                for (int x = dx; x>=0; --x) *(ptrd++) = val;\n                ptrd+=off;\n              } else cimg_forC(*this,c) {\n                const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval);\n                std::memset(ptrd,(int)val,dx + 1);\n                ptrd+=whd;\n              }\n          }\n        } else { // ** Transparent drawing **\n          if (brightness==1) { // Brightness==1\n            cimg_forC(*this,c) {\n              const T val = (T)*(col++);\n              for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }\n              ptrd+=off;\n            }\n          } else if (brightness<=1) { // Brightness<1\n            cimg_forC(*this,c) {\n              const T val = (T)(*(col++)*brightness);\n              for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }\n              ptrd+=off;\n            }\n          } else { // Brightness>1\n            cimg_forC(*this,c) {\n              const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval);\n              for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }\n              ptrd+=off;\n            }\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a 3d point.\n    /**\n       \\param x0 X-coordinate of the point.\n       \\param y0 Y-coordinate of the point.\n       \\param z0 Z-coordinate of the point.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\note\n       - To set pixel values without clipping needs, you should use the faster CImg::operator()() function.\n       \\par Example:\n       \\code\n       CImg<unsigned char> img(100,100,1,3,0);\n       const unsigned char color[] = { 255,128,64 };\n       img.draw_point(50,50,color);\n       \\endcode\n    **/\n    template<typename tc>\n    CImg<T>& draw_point(const int x0, const int y0, const int z0,\n                        const tc *const color, const float opacity=1) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_point(): Specified color is (null).\",\n                                    cimg_instance);\n      if (x0>=0 && y0>=0 && z0>=0 && x0<width() && y0<height() && z0<depth()) {\n        const ulongT whd = (ulongT)_width*_height*_depth;\n        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n        T *ptrd = data(x0,y0,z0,0);\n        const tc *col = color;\n        if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; }\n        else cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; }\n      }\n      return *this;\n    }\n\n    //! Draw a 2d point \\simplification.\n    template<typename tc>\n    CImg<T>& draw_point(const int x0, const int y0,\n                        const tc *const color, const float opacity=1) {\n      return draw_point(x0,y0,0,color,opacity);\n    }\n\n    // Draw a points cloud.\n    /**\n       \\param points Image of vertices coordinates.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename t, typename tc>\n    CImg<T>& draw_point(const CImg<t>& points,\n                        const tc *const color, const float opacity=1) {\n      if (is_empty() || !points) return *this;\n      switch (points._height) {\n      case 0 : case 1 :\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_point(): Invalid specified point set (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    points._width,points._height,points._depth,points._spectrum,points._data);\n      case 2 : {\n        cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),color,opacity);\n      } break;\n      default : {\n        cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),(int)points(i,2),color,opacity);\n      }\n      }\n      return *this;\n    }\n\n    //! Draw a 2d line.\n    /**\n       \\param x0 X-coordinate of the starting line point.\n       \\param y0 Y-coordinate of the starting line point.\n       \\param x1 X-coordinate of the ending line point.\n       \\param y1 Y-coordinate of the ending line point.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch Tells if a reinitialization of the hash state must be done.\n       \\note\n       - Line routine uses Bresenham's algorithm.\n       - Set \\p init_hatch = false to draw consecutive hatched segments without breaking the line pattern.\n       \\par Example:\n       \\code\n       CImg<unsigned char> img(100,100,1,3,0);\n       const unsigned char color[] = { 255,128,64 };\n        img.draw_line(40,40,80,70,color);\n       \\endcode\n    **/\n    template<typename tc>\n    CImg<T>& draw_line(const int x0, const int y0,\n                       const int x1, const int y1,\n                       const tc *const color, const float opacity=1,\n                       const unsigned int pattern=~0U, const bool init_hatch=true) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_line(): Specified color is (null).\",\n                                    cimg_instance);\n      static unsigned int hatch = ~0U - (~0U>>1);\n      if (init_hatch) hatch = ~0U - (~0U>>1);\n      const bool xdir = x0<x1, ydir = y0<y1;\n      int\n        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,\n        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,\n        &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,\n        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,\n        &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;\n      if (xright<0 || xleft>=width()) return *this;\n      if (xleft<0) { yleft-=(int)((float)xleft*((float)yright - yleft)/((float)xright - xleft)); xleft = 0; }\n      if (xright>=width()) {\n        yright-=(int)(((float)xright - width())*((float)yright - yleft)/((float)xright - xleft));\n        xright = width() - 1;\n      }\n      if (ydown<0 || yup>=height()) return *this;\n      if (yup<0) { xup-=(int)((float)yup*((float)xdown - xup)/((float)ydown - yup)); yup = 0; }\n      if (ydown>=height()) {\n        xdown-=(int)(((float)ydown - height())*((float)xdown - xup)/((float)ydown - yup));\n        ydown = height() - 1;\n      }\n      T *ptrd0 = data(nx0,ny0);\n      int dx = xright - xleft, dy = ydown - yup;\n      const bool steep = dy>dx;\n      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);\n      const longT\n        offx = (longT)(nx0<nx1?1:-1)*(steep?width():1),\n        offy = (longT)(ny0<ny1?1:-1)*(steep?1:width());\n      const ulongT wh = (ulongT)_width*_height;\n      if (opacity>=1) {\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          if (pattern&hatch) {\n            T *ptrd = ptrd0; const tc* col = color;\n            cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          T *ptrd = ptrd0; const tc* col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; }\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        }\n      } else {\n        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          if (pattern&hatch) {\n            T *ptrd = ptrd0; const tc* col = color;\n            cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          T *ptrd = ptrd0; const tc* col = color;\n          cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a 2d line, with z-buffering.\n    /**\n       \\param zbuffer Zbuffer image.\n       \\param x0 X-coordinate of the starting point.\n       \\param y0 Y-coordinate of the starting point.\n       \\param z0 Z-coordinate of the starting point\n       \\param x1 X-coordinate of the ending point.\n       \\param y1 Y-coordinate of the ending point.\n       \\param z1 Z-coordinate of the ending point.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch Tells if a reinitialization of the hash state must be done.\n    **/\n    template<typename tz,typename tc>\n    CImg<T>& draw_line(CImg<tz>& zbuffer,\n                       const int x0, const int y0, const float z0,\n                       const int x1, const int y1, const float z1,\n                       const tc *const color, const float opacity=1,\n                       const unsigned int pattern=~0U, const bool init_hatch=true) {\n      typedef typename cimg::superset<tz,float>::type tzfloat;\n      if (is_empty() || z0<=0 || z1<=0) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_line(): Specified color is (null).\",\n                                    cimg_instance);\n      if (!is_sameXY(zbuffer))\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_line(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have \"\n                                    \"different dimensions.\",\n                                    cimg_instance,\n                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);\n      static unsigned int hatch = ~0U - (~0U>>1);\n      if (init_hatch) hatch = ~0U - (~0U>>1);\n      const bool xdir = x0<x1, ydir = y0<y1;\n      int\n        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,\n        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,\n        &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,\n        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,\n        &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;\n      tzfloat\n        Z0 = 1/(tzfloat)z0, Z1 = 1/(tzfloat)z1, nz0 = Z0, nz1 = Z1, dz = Z1 - Z0,\n        &zleft = xdir?nz0:nz1,\n        &zright = xdir?nz1:nz0,\n        &zup = ydir?nz0:nz1,\n        &zdown = ydir?nz1:nz0;\n      if (xright<0 || xleft>=width()) return *this;\n      if (xleft<0) {\n        const float D = (float)xright - xleft;\n        yleft-=(int)((float)xleft*((float)yright - yleft)/D);\n        zleft-=(tzfloat)xleft*(zright - zleft)/D;\n        xleft = 0;\n      }\n      if (xright>=width()) {\n        const float d = (float)xright - width(), D = (float)xright - xleft;\n        yright-=(int)(d*((float)yright - yleft)/D);\n        zright-=(tzfloat)d*(zright - zleft)/D;\n        xright = width() - 1;\n      }\n      if (ydown<0 || yup>=height()) return *this;\n      if (yup<0) {\n        const float D = (float)ydown - yup;\n        xup-=(int)((float)yup*((float)xdown - xup)/D);\n        zup-=(tzfloat)yup*(zdown - zup)/D;\n        yup = 0;\n      }\n      if (ydown>=height()) {\n        const float d = (float)ydown - height(), D = (float)ydown - yup;\n        xdown-=(int)(d*((float)xdown - xup)/D);\n        zdown-=(tzfloat)d*(zdown - zup)/D;\n        ydown = height() - 1;\n      }\n      T *ptrd0 = data(nx0,ny0);\n      tz *ptrz = zbuffer.data(nx0,ny0);\n      int dx = xright - xleft, dy = ydown - yup;\n      const bool steep = dy>dx;\n      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);\n      const longT\n        offx = (longT)(nx0<nx1?1:-1)*(steep?width():1),\n        offy = (longT)(ny0<ny1?1:-1)*(steep?1:width());\n      const ulongT\n        wh = (ulongT)_width*_height,\n        ndx = (ulongT)(dx>0?dx:1);\n      if (opacity>=1) {\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          const tzfloat z = Z0 + x*dz/ndx;\n          if (z>=(tzfloat)*ptrz && pattern&hatch) {\n            *ptrz = (tz)z;\n            T *ptrd = ptrd0; const tc *col = color;\n            cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx; ptrz+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          const tzfloat z = Z0 + x*dz/ndx;\n          if (z>=(tzfloat)*ptrz) {\n            *ptrz = (tz)z;\n            T *ptrd = ptrd0; const tc *col = color;\n            cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; }\n          }\n          ptrd0+=offx; ptrz+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }\n        }\n      } else {\n        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          const tzfloat z = Z0 + x*dz/ndx;\n          if (z>=(tzfloat)*ptrz && pattern&hatch) {\n            *ptrz = (tz)z;\n            T *ptrd = ptrd0; const tc *col = color;\n            cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx; ptrz+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          const tzfloat z = Z0 + x*dz/ndx;\n          if (z>=(tzfloat)*ptrz) {\n            *ptrz = (tz)z;\n            T *ptrd = ptrd0; const tc *col = color;\n            cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }\n          }\n          ptrd0+=offx; ptrz+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a 3d line.\n    /**\n       \\param x0 X-coordinate of the starting point.\n       \\param y0 Y-coordinate of the starting point.\n       \\param z0 Z-coordinate of the starting point\n       \\param x1 X-coordinate of the ending point.\n       \\param y1 Y-coordinate of the ending point.\n       \\param z1 Z-coordinate of the ending point.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch Tells if a reinitialization of the hash state must be done.\n    **/\n    template<typename tc>\n    CImg<T>& draw_line(const int x0, const int y0, const int z0,\n                       const int x1, const int y1, const int z1,\n                       const tc *const color, const float opacity=1,\n                       const unsigned int pattern=~0U, const bool init_hatch=true) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_line(): Specified color is (null).\",\n                                    cimg_instance);\n      static unsigned int hatch = ~0U - (~0U>>1);\n      if (init_hatch) hatch = ~0U - (~0U>>1);\n      int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1;\n      if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);\n      if (nx1<0 || nx0>=width()) return *this;\n      if (nx0<0) {\n        const float D = 1.0f + nx1 - nx0;\n        ny0-=(int)((float)nx0*(1.0f + ny1 - ny0)/D);\n        nz0-=(int)((float)nx0*(1.0f + nz1 - nz0)/D);\n        nx0 = 0;\n      }\n      if (nx1>=width()) {\n        const float d = (float)nx1 - width(), D = 1.0f + nx1 - nx0;\n        ny1+=(int)(d*(1.0f + ny0 - ny1)/D);\n        nz1+=(int)(d*(1.0f + nz0 - nz1)/D);\n        nx1 = width() - 1;\n      }\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);\n      if (ny1<0 || ny0>=height()) return *this;\n      if (ny0<0) {\n        const float D = 1.0f + ny1 - ny0;\n        nx0-=(int)((float)ny0*(1.0f + nx1 - nx0)/D);\n        nz0-=(int)((float)ny0*(1.0f + nz1 - nz0)/D);\n        ny0 = 0;\n      }\n      if (ny1>=height()) {\n        const float d = (float)ny1 - height(), D = 1.0f + ny1 - ny0;\n        nx1+=(int)(d*(1.0f + nx0 - nx1)/D);\n        nz1+=(int)(d*(1.0f + nz0 - nz1)/D);\n        ny1 = height() - 1;\n      }\n      if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);\n      if (nz1<0 || nz0>=depth()) return *this;\n      if (nz0<0) {\n        const float D = 1.0f + nz1 - nz0;\n        nx0-=(int)((float)nz0*(1.0f + nx1 - nx0)/D);\n        ny0-=(int)((float)nz0*(1.0f + ny1 - ny0)/D);\n        nz0 = 0;\n      }\n      if (nz1>=depth()) {\n        const float d = (float)nz1 - depth(), D = 1.0f + nz1 - nz0;\n        nx1+=(int)(d*(1.0f + nx0 - nx1)/D);\n        ny1+=(int)(d*(1.0f + ny0 - ny1)/D);\n        nz1 = depth() - 1;\n      }\n      const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0);\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax;\n      float x = (float)nx0, y = (float)ny0, z = (float)nz0;\n      if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) {\n        if (!(~pattern) || (~pattern && pattern&hatch)) {\n          T* ptrd = data((unsigned int)x,(unsigned int)y,(unsigned int)z);\n          const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; }\n        }\n        x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }\n      } else {\n        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n        for (unsigned int t = 0; t<=dmax; ++t) {\n          if (!(~pattern) || (~pattern && pattern&hatch)) {\n            T* ptrd = data((unsigned int)x,(unsigned int)y,(unsigned int)z);\n            const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; }\n          }\n          x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a textured 2d line.\n    /**\n       \\param x0 X-coordinate of the starting line point.\n       \\param y0 Y-coordinate of the starting line point.\n       \\param x1 X-coordinate of the ending line point.\n       \\param y1 Y-coordinate of the ending line point.\n       \\param texture Texture image defining the pixel colors.\n       \\param tx0 X-coordinate of the starting texture point.\n       \\param ty0 Y-coordinate of the starting texture point.\n       \\param tx1 X-coordinate of the ending texture point.\n       \\param ty1 Y-coordinate of the ending texture point.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch Tells if the hash variable must be reinitialized.\n       \\note\n       - Line routine uses the well known Bresenham's algorithm.\n       \\par Example:\n       \\code\n       CImg<unsigned char> img(100,100,1,3,0), texture(\"texture256x256.ppm\");\n       const unsigned char color[] = { 255,128,64 };\n       img.draw_line(40,40,80,70,texture,0,0,255,255);\n       \\endcode\n    **/\n    template<typename tc>\n    CImg<T>& draw_line(const int x0, const int y0,\n                       const int x1, const int y1,\n                       const CImg<tc>& texture,\n                       const int tx0, const int ty0,\n                       const int tx1, const int ty1,\n                       const float opacity=1,\n                       const unsigned int pattern=~0U, const bool init_hatch=true) {\n      if (is_empty()) return *this;\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);\n      static unsigned int hatch = ~0U - (~0U>>1);\n      if (init_hatch) hatch = ~0U - (~0U>>1);\n      const bool xdir = x0<x1, ydir = y0<y1;\n      int\n        dtx = tx1-tx0, dty = ty1-ty0,\n        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,\n        tnx0 = tx0, tnx1 = tx1, tny0 = ty0, tny1 = ty1,\n        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,\n        &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,\n        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0,\n        &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;\n      if (xright<0 || xleft>=width()) return *this;\n      if (xleft<0) {\n        const float D = (float)xright - xleft;\n        yleft-=(int)((float)xleft*((float)yright - yleft)/D);\n        txleft-=(int)((float)xleft*((float)txright - txleft)/D);\n        tyleft-=(int)((float)xleft*((float)tyright - tyleft)/D);\n        xleft = 0;\n      }\n      if (xright>=width()) {\n        const float d = (float)xright - width(), D = (float)xright - xleft;\n        yright-=(int)(d*((float)yright - yleft)/D);\n        txright-=(int)(d*((float)txright - txleft)/D);\n        tyright-=(int)(d*((float)tyright - tyleft)/D);\n        xright = width() - 1;\n      }\n      if (ydown<0 || yup>=height()) return *this;\n      if (yup<0) {\n        const float D = (float)ydown - yup;\n        xup-=(int)((float)yup*((float)xdown - xup)/D);\n        txup-=(int)((float)yup*((float)txdown - txup)/D);\n        tyup-=(int)((float)yup*((float)tydown - tyup)/D);\n        yup = 0;\n      }\n      if (ydown>=height()) {\n        const float d = (float)ydown - height(), D = (float)ydown - yup;\n        xdown-=(int)(d*((float)xdown - xup)/D);\n        txdown-=(int)(d*((float)txdown - txup)/D);\n        tydown-=(int)(d*((float)tydown - tyup)/D);\n        ydown = height() - 1;\n      }\n      T *ptrd0 = data(nx0,ny0);\n      int dx = xright - xleft, dy = ydown - yup;\n      const bool steep = dy>dx;\n      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);\n      const longT\n        offx = (longT)(nx0<nx1?1:-1)*(steep?width():1),\n        offy = (longT)(ny0<ny1?1:-1)*(steep?1:width()),\n        ndx = (longT)(dx>0?dx:1);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height;\n\n      if (opacity>=1) {\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          if (pattern&hatch) {\n            T *ptrd = ptrd0;\n            const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;\n            const tc *col = &texture._atXY(tx,ty);\n            cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          T *ptrd = ptrd0;\n          const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;\n          const tc *col = &texture._atXY(tx,ty);\n          cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        }\n      } else {\n        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          T *ptrd = ptrd0;\n          if (pattern&hatch) {\n            const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;\n            const tc *col = &texture._atXY(tx,ty);\n            cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          T *ptrd = ptrd0;\n          const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;\n          const tc *col = &texture._atXY(tx,ty);\n          cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a textured 2d line, with perspective correction.\n    /**\n       \\param x0 X-coordinate of the starting point.\n       \\param y0 Y-coordinate of the starting point.\n       \\param z0 Z-coordinate of the starting point\n       \\param x1 X-coordinate of the ending point.\n       \\param y1 Y-coordinate of the ending point.\n       \\param z1 Z-coordinate of the ending point.\n       \\param texture Texture image defining the pixel colors.\n       \\param tx0 X-coordinate of the starting texture point.\n       \\param ty0 Y-coordinate of the starting texture point.\n       \\param tx1 X-coordinate of the ending texture point.\n       \\param ty1 Y-coordinate of the ending texture point.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch Tells if the hash variable must be reinitialized.\n    **/\n    template<typename tc>\n    CImg<T>& draw_line(const int x0, const int y0, const float z0,\n                       const int x1, const int y1, const float z1,\n                       const CImg<tc>& texture,\n                       const int tx0, const int ty0,\n                       const int tx1, const int ty1,\n                       const float opacity=1,\n                       const unsigned int pattern=~0U, const bool init_hatch=true) {\n      if (is_empty() && z0<=0 && z1<=0) return *this;\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_overlapped(texture))\n        return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);\n      static unsigned int hatch = ~0U - (~0U>>1);\n      if (init_hatch) hatch = ~0U - (~0U>>1);\n      const bool xdir = x0<x1, ydir = y0<y1;\n      int\n        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,\n        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,\n        &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,\n        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,\n        &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;\n      float\n        Tx0 = tx0/z0, Tx1 = tx1/z1,\n        Ty0 = ty0/z0, Ty1 = ty1/z1,\n        Z0 = 1/z0, Z1 = 1/z1,\n        dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,\n        tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,\n        &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,\n        &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,\n        &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,\n        &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;\n      if (xright<0 || xleft>=width()) return *this;\n      if (xleft<0) {\n        const float D = (float)xright - xleft;\n        yleft-=(int)((float)xleft*((float)yright - yleft)/D);\n        zleft-=(float)xleft*(zright - zleft)/D;\n        txleft-=(float)xleft*(txright - txleft)/D;\n        tyleft-=(float)xleft*(tyright - tyleft)/D;\n        xleft = 0;\n      }\n      if (xright>=width()) {\n        const float d = (float)xright - width(), D = (float)xright - xleft;\n        yright-=(int)(d*((float)yright - yleft)/D);\n        zright-=d*(zright - zleft)/D;\n        txright-=d*(txright - txleft)/D;\n        tyright-=d*(tyright - tyleft)/D;\n        xright = width() - 1;\n      }\n      if (ydown<0 || yup>=height()) return *this;\n      if (yup<0) {\n        const float D = (float)ydown - yup;\n        xup-=(int)((float)yup*((float)xdown - xup)/D);\n        zup-=(float)yup*(zdown - zup)/D;\n        txup-=(float)yup*(txdown - txup)/D;\n        tyup-=(float)yup*(tydown - tyup)/D;\n        yup = 0;\n      }\n      if (ydown>=height()) {\n        const float d = (float)ydown - height(), D = (float)ydown - yup;\n        xdown-=(int)(d*((float)xdown - xup)/D);\n        zdown-=d*(zdown - zup)/D;\n        txdown-=d*(txdown - txup)/D;\n        tydown-=d*(tydown - tyup)/D;\n        ydown = height() - 1;\n      }\n      T *ptrd0 = data(nx0,ny0);\n      int dx = xright - xleft, dy = ydown - yup;\n      const bool steep = dy>dx;\n      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);\n      const longT\n        offx = (longT)(nx0<nx1?1:-1)*(steep?width():1),\n        offy = (longT)(ny0<ny1?1:-1)*(steep?1:width()),\n        ndx = (longT)(dx>0?dx:1);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height;\n\n      if (opacity>=1) {\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          if (pattern&hatch) {\n            const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;\n            const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));\n            T *ptrd = ptrd0;\n            cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;\n          const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));\n          T *ptrd = ptrd0;\n          cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        }\n      } else {\n        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          if (pattern&hatch) {\n            const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;\n            const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));\n            T *ptrd = ptrd0;\n            cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;\n          const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));\n          T *ptrd = ptrd0;\n          cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }\n          ptrd0+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a textured 2d line, with perspective correction and z-buffering.\n    /**\n       \\param zbuffer Z-buffer image.\n       \\param x0 X-coordinate of the starting point.\n       \\param y0 Y-coordinate of the starting point.\n       \\param z0 Z-coordinate of the starting point\n       \\param x1 X-coordinate of the ending point.\n       \\param y1 Y-coordinate of the ending point.\n       \\param z1 Z-coordinate of the ending point.\n       \\param texture Texture image defining the pixel colors.\n       \\param tx0 X-coordinate of the starting texture point.\n       \\param ty0 Y-coordinate of the starting texture point.\n       \\param tx1 X-coordinate of the ending texture point.\n       \\param ty1 Y-coordinate of the ending texture point.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch Tells if the hash variable must be reinitialized.\n    **/\n    template<typename tz, typename tc>\n    CImg<T>& draw_line(CImg<tz>& zbuffer,\n                       const int x0, const int y0, const float z0,\n                       const int x1, const int y1, const float z1,\n                       const CImg<tc>& texture,\n                       const int tx0, const int ty0,\n                       const int tx1, const int ty1,\n                       const float opacity=1,\n                       const unsigned int pattern=~0U, const bool init_hatch=true) {\n      typedef typename cimg::superset<tz,float>::type tzfloat;\n      if (is_empty() || z0<=0 || z1<=0) return *this;\n      if (!is_sameXY(zbuffer))\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_line(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have \"\n                                    \"different dimensions.\",\n                                    cimg_instance,\n                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_overlapped(texture))\n        return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);\n      static unsigned int hatch = ~0U - (~0U>>1);\n      if (init_hatch) hatch = ~0U - (~0U>>1);\n      const bool xdir = x0<x1, ydir = y0<y1;\n      int\n        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,\n        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,\n        &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,\n        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,\n        &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;\n      float\n        Tx0 = tx0/z0, Tx1 = tx1/z1,\n        Ty0 = ty0/z0, Ty1 = ty1/z1,\n        dtx = Tx1 - Tx0, dty = Ty1 - Ty0,\n        tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1,\n        &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,\n        &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,\n        &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,\n        &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;\n      tzfloat\n        Z0 = 1/(tzfloat)z0, Z1 = 1/(tzfloat)z1,\n        dz = Z1 - Z0,  nz0 = Z0, nz1 = Z1,\n        &zleft = xdir?nz0:nz1,\n        &zright = xdir?nz1:nz0,\n        &zup = ydir?nz0:nz1,\n        &zdown = ydir?nz1:nz0;\n      if (xright<0 || xleft>=width()) return *this;\n      if (xleft<0) {\n        const float D = (float)xright - xleft;\n        yleft-=(int)((float)xleft*((float)yright - yleft)/D);\n        zleft-=(float)xleft*(zright - zleft)/D;\n        txleft-=(float)xleft*(txright - txleft)/D;\n        tyleft-=(float)xleft*(tyright - tyleft)/D;\n        xleft = 0;\n      }\n      if (xright>=width()) {\n        const float d = (float)xright - width(), D = (float)xright - xleft;\n        yright-=(int)(d*((float)yright - yleft)/D);\n        zright-=d*(zright - zleft)/D;\n        txright-=d*(txright - txleft)/D;\n        tyright-=d*(tyright - tyleft)/D;\n        xright = width() - 1;\n      }\n      if (ydown<0 || yup>=height()) return *this;\n      if (yup<0) {\n        const float D = (float)ydown - yup;\n        xup-=(int)((float)yup*((float)xdown - xup)/D);\n        zup-=yup*(zdown - zup)/D;\n        txup-=yup*(txdown - txup)/D;\n        tyup-=yup*(tydown - tyup)/D;\n        yup = 0;\n      }\n      if (ydown>=height()) {\n        const float d = (float)ydown - height(), D = (float)ydown - yup;\n        xdown-=(int)(d*((float)xdown - xup)/D);\n        zdown-=d*(zdown - zup)/D;\n        txdown-=d*(txdown - txup)/D;\n        tydown-=d*(tydown - tyup)/D;\n        ydown = height() - 1;\n      }\n      T *ptrd0 = data(nx0,ny0);\n      tz *ptrz = zbuffer.data(nx0,ny0);\n      int dx = xright - xleft, dy = ydown - yup;\n      const bool steep = dy>dx;\n      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);\n      const longT\n        offx = (longT)(nx0<nx1?1:-1)*(steep?width():1),\n        offy = (longT)(ny0<ny1?1:-1)*(steep?1:width()),\n        ndx = (longT)(dx>0?dx:1);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height;\n\n      if (opacity>=1) {\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          if (pattern&hatch) {\n            const tzfloat z = Z0 + x*dz/ndx;\n            if (z>=(tzfloat)*ptrz) {\n              *ptrz = (tz)z;\n              const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;\n              const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));\n              T *ptrd = ptrd0;\n              cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }\n            }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx; ptrz+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          const tzfloat z = Z0 + x*dz/ndx;\n          if (z>=(tzfloat)*ptrz) {\n            *ptrz = (tz)z;\n            const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;\n            const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));\n            T *ptrd = ptrd0;\n            cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }\n          }\n          ptrd0+=offx; ptrz+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }\n        }\n      } else {\n        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          if (pattern&hatch) {\n            const tzfloat z = Z0 + x*dz/ndx;\n            if (z>=(tzfloat)*ptrz) {\n              *ptrz = (tz)z;\n              const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;\n              const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));\n              T *ptrd = ptrd0;\n              cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }\n            }\n          }\n          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);\n          ptrd0+=offx; ptrz+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }\n        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {\n          const tzfloat z = Z0 + x*dz/ndx;\n          if (z>=(tzfloat)*ptrz) {\n            *ptrz = (tz)z;\n            const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;\n            const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));\n            T *ptrd = ptrd0;\n            cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }\n          }\n          ptrd0+=offx; ptrz+=offx;\n          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a set of consecutive lines.\n    /**\n       \\param points Coordinates of vertices, stored as a list of vectors.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch If set to true, init hatch motif.\n       \\note\n       - This function uses several call to the single CImg::draw_line() procedure,\n       depending on the vectors size in \\p points.\n    **/\n    template<typename t, typename tc>\n    CImg<T>& draw_line(const CImg<t>& points,\n                       const tc *const color, const float opacity=1,\n                       const unsigned int pattern=~0U, const bool init_hatch=true) {\n      if (is_empty() || !points || points._width<2) return *this;\n      bool ninit_hatch = init_hatch;\n      switch (points._height) {\n      case 0 : case 1 :\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_line(): Invalid specified point set (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    points._width,points._height,points._depth,points._spectrum,points._data);\n\n      case 2 : {\n        const int x0 = (int)points(0,0), y0 = (int)points(0,1);\n        int ox = x0, oy = y0;\n        for (unsigned int i = 1; i<points._width; ++i) {\n          const int x = (int)points(i,0), y = (int)points(i,1);\n          draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);\n          ninit_hatch = false;\n          ox = x; oy = y;\n        }\n      } break;\n      default : {\n        const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);\n        int ox = x0, oy = y0, oz = z0;\n        for (unsigned int i = 1; i<points._width; ++i) {\n          const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);\n          draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);\n          ninit_hatch = false;\n          ox = x; oy = y; oz = z;\n        }\n      }\n      }\n      return *this;\n    }\n\n    //! Draw a 2d arrow.\n    /**\n       \\param x0 X-coordinate of the starting arrow point (tail).\n       \\param y0 Y-coordinate of the starting arrow point (tail).\n       \\param x1 X-coordinate of the ending arrow point (head).\n       \\param y1 Y-coordinate of the ending arrow point (head).\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param angle Aperture angle of the arrow head.\n       \\param length Length of the arrow head. If negative, describes a percentage of the arrow length.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n    **/\n    template<typename tc>\n    CImg<T>& draw_arrow(const int x0, const int y0,\n                        const int x1, const int y1,\n                        const tc *const color, const float opacity=1,\n                        const float angle=30, const float length=-10,\n                        const unsigned int pattern=~0U) {\n      if (is_empty()) return *this;\n      const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v,\n        deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f,\n        l = (length>=0)?length:-length*(float)std::sqrt(sq)/100;\n      if (sq>0) {\n        const float\n            cl = (float)std::cos(ang - deg), sl = (float)std::sin(ang - deg),\n            cr = (float)std::cos(ang + deg), sr = (float)std::sin(ang + deg);\n        const int\n          xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl),\n          xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr),\n          xc = x1 + (int)((l + 1)*(cl + cr))/2, yc = y1 + (int)((l + 1)*(sl + sr))/2;\n        draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);\n      } else draw_point(x0,y0,color,opacity);\n      return *this;\n    }\n\n    //! Draw a 2d spline.\n    /**\n       \\param x0 X-coordinate of the starting curve point\n       \\param y0 Y-coordinate of the starting curve point\n       \\param u0 X-coordinate of the starting velocity\n       \\param v0 Y-coordinate of the starting velocity\n       \\param x1 X-coordinate of the ending curve point\n       \\param y1 Y-coordinate of the ending curve point\n       \\param u1 X-coordinate of the ending velocity\n       \\param v1 Y-coordinate of the ending velocity\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param precision Curve drawing precision.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch If \\c true, init hatch motif.\n       \\note\n       - The curve is a 2d cubic Bezier spline, from the set of specified starting/ending points\n       and corresponding velocity vectors.\n       - The spline is drawn as a serie of connected segments. The \\p precision parameter sets the\n       average number of pixels in each drawn segment.\n       - A cubic Bezier curve is sometimes defined by a set of 4 points { (\\p x0,\\p y0), (\\p xa,\\p ya),\n         (\\p xb,\\p yb), (\\p x1,\\p y1) } where (\\p x0,\\p y0) is the starting point, (\\p x1,\\p y1) is the ending point\n         and (\\p xa,\\p ya), (\\p xb,\\p yb) are two\n       \\e control points.\n       The starting and ending velocities (\\p u0,\\p v0) and (\\p u1,\\p v1) can be deduced easily from\n       the control points as\n       \\p u0 = (\\p xa - \\p x0), \\p v0 = (\\p ya - \\p y0), \\p u1 = (\\p x1 - \\p xb) and \\p v1 = (\\p y1 - \\p yb).\n       \\par Example:\n       \\code\n       CImg<unsigned char> img(100,100,1,3,0);\n       const unsigned char color[] = { 255,255,255 };\n       img.draw_spline(30,30,0,100,90,40,0,-100,color);\n       \\endcode\n    **/\n    template<typename tc>\n    CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,\n                         const int x1, const int y1, const float u1, const float v1,\n                         const tc *const color, const float opacity=1,\n                         const float precision=0.25, const unsigned int pattern=~0U,\n                         const bool init_hatch=true) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_spline(): Specified color is (null).\",\n                                    cimg_instance);\n      if (x0==x1 && y0==y1) return draw_point(x0,y0,color,opacity);\n      bool ninit_hatch = init_hatch;\n      const float\n        ax = u0 + u1 + 2*(x0 - x1),\n        bx = 3*(x1 - x0) - 2*u0 - u1,\n        ay = v0 + v1 + 2*(y0 - y1),\n        by = 3*(y1 - y0) - 2*v0 - v1,\n        _precision = 1/(std::sqrt(cimg::sqr((float)x0 - x1) + cimg::sqr((float)y0 - y1))*(precision>0?precision:1));\n      int ox = x0, oy = y0;\n      for (float t = 0; t<1; t+=_precision) {\n        const float t2 = t*t, t3 = t2*t;\n        const int\n          nx = (int)(ax*t3 + bx*t2 + u0*t + x0),\n          ny = (int)(ay*t3 + by*t2 + v0*t + y0);\n        draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch);\n        ninit_hatch = false;\n        ox = nx; oy = ny;\n      }\n      return draw_line(ox,oy,x1,y1,color,opacity,pattern,false);\n    }\n\n    //! Draw a 3d spline \\overloading.\n    /**\n       \\note\n       - Similar to CImg::draw_spline() for a 3d spline in a volumetric image.\n    **/\n    template<typename tc>\n    CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,\n                         const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,\n                         const tc *const color, const float opacity=1,\n                         const float precision=4, const unsigned int pattern=~0U,\n                         const bool init_hatch=true) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_spline(): Specified color is (null).\",\n                                    cimg_instance);\n      if (x0==x1 && y0==y1 && z0==z1) return draw_point(x0,y0,z0,color,opacity);\n      bool ninit_hatch = init_hatch;\n      const float\n        ax = u0 + u1 + 2*(x0 - x1),\n        bx = 3*(x1 - x0) - 2*u0 - u1,\n        ay = v0 + v1 + 2*(y0 - y1),\n        by = 3*(y1 - y0) - 2*v0 - v1,\n        az = w0 + w1 + 2*(z0 - z1),\n        bz = 3*(z1 - z0) - 2*w0 - w1,\n        _precision = 1/(std::sqrt(cimg::sqr(x0 - x1) + cimg::sqr(y0 - y1))*(precision>0?precision:1));\n      int ox = x0, oy = y0, oz = z0;\n      for (float t = 0; t<1; t+=_precision) {\n        const float t2 = t*t, t3 = t2*t;\n        const int\n          nx = (int)(ax*t3 + bx*t2 + u0*t + x0),\n          ny = (int)(ay*t3 + by*t2 + v0*t + y0),\n          nz = (int)(az*t3 + bz*t2 + w0*t + z0);\n        draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch);\n        ninit_hatch = false;\n        ox = nx; oy = ny; oz = nz;\n      }\n      return draw_line(ox,oy,oz,x1,y1,z1,color,opacity,pattern,false);\n    }\n\n    //! Draw a textured 2d spline.\n    /**\n       \\param x0 X-coordinate of the starting curve point\n       \\param y0 Y-coordinate of the starting curve point\n       \\param u0 X-coordinate of the starting velocity\n       \\param v0 Y-coordinate of the starting velocity\n       \\param x1 X-coordinate of the ending curve point\n       \\param y1 Y-coordinate of the ending curve point\n       \\param u1 X-coordinate of the ending velocity\n       \\param v1 Y-coordinate of the ending velocity\n       \\param texture Texture image defining line pixel colors.\n       \\param tx0 X-coordinate of the starting texture point.\n       \\param ty0 Y-coordinate of the starting texture point.\n       \\param tx1 X-coordinate of the ending texture point.\n       \\param ty1 Y-coordinate of the ending texture point.\n       \\param precision Curve drawing precision.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch if \\c true, reinit hatch motif.\n    **/\n    template<typename t>\n    CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,\n                         const int x1, const int y1, const float u1, const float v1,\n                         const CImg<t>& texture,\n                         const int tx0, const int ty0, const int tx1, const int ty1,\n                         const float opacity=1,\n                         const float precision=4, const unsigned int pattern=~0U,\n                         const bool init_hatch=true) {\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_spline(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_empty()) return *this;\n      if (is_overlapped(texture))\n        return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch);\n      if (x0==x1 && y0==y1)\n        return draw_point(x0,y0,texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0,\n                                                      y0<=0?0:y0>=texture.height()?texture.height() - 1:y0),opacity);\n      bool ninit_hatch = init_hatch;\n      const float\n        ax = u0 + u1 + 2*(x0 - x1),\n        bx = 3*(x1 - x0) - 2*u0 - u1,\n        ay = v0 + v1 + 2*(y0 - y1),\n        by = 3*(y1 - y0) - 2*v0 - v1,\n        _precision = 1/(std::sqrt(cimg::sqr(x0 - x1) + cimg::sqr(y0 - y1))*(precision>0?precision:1));\n      int ox = x0, oy = y0, otx = tx0, oty = ty0;\n      for (float t1 = 0; t1<1; t1+=_precision) {\n        const float t2 = t1*t1, t3 = t2*t1;\n        const int\n          nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0),\n          ny = (int)(ay*t3 + by*t2 + v0*t1 + y0),\n          ntx = tx0 + (int)((tx1 - tx0)*t1),\n          nty = ty0 + (int)((ty1 - ty0)*t1);\n        draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch);\n        ninit_hatch = false;\n        ox = nx; oy = ny; otx = ntx; oty = nty;\n      }\n      return draw_line(ox,oy,x1,y1,texture,otx,oty,tx1,ty1,opacity,pattern,false);\n    }\n\n    //! Draw a set of consecutive splines.\n    /**\n       \\param points Vertices data.\n       \\param tangents Tangents data.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param is_closed_set Tells if the drawn spline set is closed.\n       \\param precision Precision of the drawing.\n       \\param pattern An integer whose bits describe the line pattern.\n       \\param init_hatch If \\c true, init hatch motif.\n    **/\n    template<typename tp, typename tt, typename tc>\n    CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,\n                         const tc *const color, const float opacity=1,\n                         const bool is_closed_set=false, const float precision=4,\n                         const unsigned int pattern=~0U, const bool init_hatch=true) {\n      if (is_empty() || !points || !tangents || points._width<2 || tangents._width<2) return *this;\n      bool ninit_hatch = init_hatch;\n      switch (points._height) {\n      case 0 : case 1 :\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_spline(): Invalid specified point set (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    points._width,points._height,points._depth,points._spectrum,points._data);\n\n      case 2 : {\n        const int x0 = (int)points(0,0), y0 = (int)points(0,1);\n        const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1);\n        int ox = x0, oy = y0;\n        float ou = u0, ov = v0;\n        for (unsigned int i = 1; i<points._width; ++i) {\n          const int x = (int)points(i,0), y = (int)points(i,1);\n          const float u = (float)tangents(i,0), v = (float)tangents(i,1);\n          draw_spline(ox,oy,ou,ov,x,y,u,v,color,precision,opacity,pattern,ninit_hatch);\n          ninit_hatch = false;\n          ox = x; oy = y; ou = u; ov = v;\n        }\n        if (is_closed_set) draw_spline(ox,oy,ou,ov,x0,y0,u0,v0,color,precision,opacity,pattern,false);\n      } break;\n      default : {\n        const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);\n        const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1), w0 = (float)tangents(0,2);\n        int ox = x0, oy = y0, oz = z0;\n        float ou = u0, ov = v0, ow = w0;\n        for (unsigned int i = 1; i<points._width; ++i) {\n          const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);\n          const float u = (float)tangents(i,0), v = (float)tangents(i,1), w = (float)tangents(i,2);\n          draw_spline(ox,oy,oz,ou,ov,ow,x,y,z,u,v,w,color,opacity,pattern,ninit_hatch);\n          ninit_hatch = false;\n          ox = x; oy = y; oz = z; ou = u; ov = v; ow = w;\n        }\n        if (is_closed_set) draw_spline(ox,oy,oz,ou,ov,ow,x0,y0,z0,u0,v0,w0,color,precision,opacity,pattern,false);\n      }\n      }\n      return *this;\n    }\n\n    //! Draw a set of consecutive splines \\overloading.\n    /**\n       Similar to previous function, with the point tangents automatically estimated from the given points set.\n    **/\n    template<typename tp, typename tc>\n    CImg<T>& draw_spline(const CImg<tp>& points,\n                         const tc *const color, const float opacity=1,\n                         const bool is_closed_set=false, const float precision=4,\n                         const unsigned int pattern=~0U, const bool init_hatch=true) {\n      if (is_empty() || !points || points._width<2) return *this;\n      CImg<Tfloat> tangents;\n      switch (points._height) {\n      case 0 : case 1 :\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_spline(): Invalid specified point set (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    points._width,points._height,points._depth,points._spectrum,points._data);\n      case 2 : {\n        tangents.assign(points._width,points._height);\n        cimg_forX(points,p) {\n          const unsigned int\n            p0 = is_closed_set?(p + points._width - 1)%points._width:(p?p - 1:0),\n            p1 = is_closed_set?(p + 1)%points._width:(p + 1<points._width?p + 1:p);\n          const float\n            x = (float)points(p,0),\n            y = (float)points(p,1),\n            x0 = (float)points(p0,0),\n            y0 = (float)points(p0,1),\n            x1 = (float)points(p1,0),\n            y1 = (float)points(p1,1),\n            u0 = x - x0,\n            v0 = y - y0,\n            n0 = 1e-8f + (float)std::sqrt(u0*u0 + v0*v0),\n            u1 = x1 - x,\n            v1 = y1 - y,\n            n1 = 1e-8f + (float)std::sqrt(u1*u1 + v1*v1),\n            u = u0/n0 + u1/n1,\n            v = v0/n0 + v1/n1,\n            n = 1e-8f + (float)std::sqrt(u*u + v*v),\n            fact = 0.5f*(n0 + n1);\n          tangents(p,0) = (Tfloat)(fact*u/n);\n          tangents(p,1) = (Tfloat)(fact*v/n);\n        }\n      } break;\n      default : {\n        tangents.assign(points._width,points._height);\n        cimg_forX(points,p) {\n          const unsigned int\n            p0 = is_closed_set?(p + points._width - 1)%points._width:(p?p - 1:0),\n            p1 = is_closed_set?(p + 1)%points._width:(p + 1<points._width?p + 1:p);\n          const float\n            x = (float)points(p,0),\n            y = (float)points(p,1),\n            z = (float)points(p,2),\n            x0 = (float)points(p0,0),\n            y0 = (float)points(p0,1),\n            z0 = (float)points(p0,2),\n            x1 = (float)points(p1,0),\n            y1 = (float)points(p1,1),\n            z1 = (float)points(p1,2),\n            u0 = x - x0,\n            v0 = y - y0,\n            w0 = z - z0,\n            n0 = 1e-8f + (float)std::sqrt(u0*u0 + v0*v0 + w0*w0),\n            u1 = x1 - x,\n            v1 = y1 - y,\n            w1 = z1 - z,\n            n1 = 1e-8f + (float)std::sqrt(u1*u1 + v1*v1 + w1*w1),\n            u = u0/n0 + u1/n1,\n            v = v0/n0 + v1/n1,\n            w = w0/n0 + w1/n1,\n            n = 1e-8f + (float)std::sqrt(u*u + v*v + w*w),\n            fact = 0.5f*(n0 + n1);\n          tangents(p,0) = (Tfloat)(fact*u/n);\n          tangents(p,1) = (Tfloat)(fact*v/n);\n          tangents(p,2) = (Tfloat)(fact*w/n);\n        }\n      }\n      }\n      return draw_spline(points,tangents,color,opacity,is_closed_set,precision,pattern,init_hatch);\n    }\n\n    // Inner macro for drawing triangles.\n#define _cimg_for_triangle1(img,xl,xr,y,x0,y0,x1,y1,x2,y2) \\\n        for (int y = y0<0?0:y0, \\\n               xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \\\n               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \\\n               _sxn=1, \\\n               _sxr=1, \\\n               _sxl=1, \\\n               _dxn = x2>x1?x2-x1:(_sxn=-1,x1 - x2), \\\n               _dxr = x2>x0?x2-x0:(_sxr=-1,x0 - x2), \\\n               _dxl = x1>x0?x1-x0:(_sxl=-1,x0 - x1), \\\n               _dyn = y2-y1, \\\n               _dyr = y2-y0, \\\n               _dyl = y1-y0, \\\n               _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \\\n                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \\\n                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \\\n                           cimg::min((int)(img)._height - y - 1,y2 - y)), \\\n               _errn = _dyn/2, \\\n               _errr = _dyr/2, \\\n               _errl = _dyl/2, \\\n               _rxn = _dyn?(x2-x1)/_dyn:0, \\\n               _rxr = _dyr?(x2-x0)/_dyr:0, \\\n               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \\\n                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn); \\\n             _counter>=0; --_counter, ++y, \\\n               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \\\n               xl+=(y!=y1)?_rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0): \\\n                           (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))\n\n#define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \\\n        for (int y = y0<0?0:y0, \\\n               xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \\\n               cr = y0>=0?c0:(c0 - y0*(c2 - c0)/(y2 - y0)), \\\n               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \\\n               cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0 - y0*(c1 - c0)/(y1 - y0))):(c1 - y1*(c2 - c1)/(y2 - y1)), \\\n               _sxn=1, _scn=1, \\\n               _sxr=1, _scr=1, \\\n               _sxl=1, _scl=1, \\\n               _dxn = x2>x1?x2-x1:(_sxn=-1,x1 - x2), \\\n               _dxr = x2>x0?x2-x0:(_sxr=-1,x0 - x2), \\\n               _dxl = x1>x0?x1-x0:(_sxl=-1,x0 - x1), \\\n               _dcn = c2>c1?c2-c1:(_scn=-1,c1 - c2), \\\n               _dcr = c2>c0?c2-c0:(_scr=-1,c0 - c2), \\\n               _dcl = c1>c0?c1-c0:(_scl=-1,c0 - c1), \\\n               _dyn = y2-y1, \\\n               _dyr = y2-y0, \\\n               _dyl = y1-y0, \\\n               _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \\\n                          _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \\\n                          _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \\\n                          _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \\\n                          _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \\\n                          _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \\\n                          cimg::min((int)(img)._height - y - 1,y2 - y)), \\\n               _errn = _dyn/2, _errcn = _errn, \\\n               _errr = _dyr/2, _errcr = _errr, \\\n               _errl = _dyl/2, _errcl = _errl, \\\n               _rxn = _dyn?(x2 - x1)/_dyn:0, \\\n               _rcn = _dyn?(c2 - c1)/_dyn:0, \\\n               _rxr = _dyr?(x2 - x0)/_dyr:0, \\\n               _rcr = _dyr?(c2 - c0)/_dyr:0, \\\n               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \\\n                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \\\n               _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \\\n                                       (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ); \\\n             _counter>=0; --_counter, ++y, \\\n               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \\\n               cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \\\n               xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \\\n                           _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \\\n               (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \\\n                _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))\n\n#define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \\\n        for (int y = y0<0?0:y0, \\\n               xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \\\n               txr = y0>=0?tx0:(tx0 - y0*(tx2 - tx0)/(y2 - y0)), \\\n               tyr = y0>=0?ty0:(ty0 - y0*(ty2 - ty0)/(y2 - y0)), \\\n               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \\\n               txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0 - y0*(tx1 - tx0)/(y1 - y0))):(tx1 - y1*(tx2 - tx1)/(y2 - y1)), \\\n               tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0 - y0*(ty1 - ty0)/(y1 - y0))):(ty1 - y1*(ty2 - ty1)/(y2 - y1)), \\\n               _sxn=1, _stxn=1, _styn=1, \\\n               _sxr=1, _stxr=1, _styr=1, \\\n               _sxl=1, _stxl=1, _styl=1, \\\n               _dxn = x2>x1?x2 - x1:(_sxn=-1,x1 - x2), \\\n               _dxr = x2>x0?x2 - x0:(_sxr=-1,x0 - x2), \\\n               _dxl = x1>x0?x1 - x0:(_sxl=-1,x0 - x1), \\\n               _dtxn = tx2>tx1?tx2 - tx1:(_stxn=-1,tx1 - tx2), \\\n               _dtxr = tx2>tx0?tx2 - tx0:(_stxr=-1,tx0 - tx2), \\\n               _dtxl = tx1>tx0?tx1 - tx0:(_stxl=-1,tx0 - tx1), \\\n               _dtyn = ty2>ty1?ty2 - ty1:(_styn=-1,ty1 - ty2), \\\n               _dtyr = ty2>ty0?ty2 - ty0:(_styr=-1,ty0 - ty2), \\\n               _dtyl = ty1>ty0?ty1 - ty0:(_styl=-1,ty0 - ty1), \\\n               _dyn = y2-y1, \\\n               _dyr = y2-y0, \\\n               _dyl = y1-y0, \\\n               _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \\\n                          _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \\\n                          _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \\\n                          _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \\\n                          _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \\\n                          _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \\\n                          _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \\\n                          _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \\\n                          _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \\\n                          cimg::min((int)(img)._height - y - 1,y2 - y)), \\\n               _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \\\n               _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \\\n               _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \\\n               _rxn = _dyn?(x2 - x1)/_dyn:0, \\\n               _rtxn = _dyn?(tx2 - tx1)/_dyn:0, \\\n               _rtyn = _dyn?(ty2 - ty1)/_dyn:0, \\\n               _rxr = _dyr?(x2 - x0)/_dyr:0, \\\n               _rtxr = _dyr?(tx2 - tx0)/_dyr:0, \\\n               _rtyr = _dyr?(ty2 - ty0)/_dyr:0, \\\n               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1 - x0)/_dyl:0): \\\n                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \\\n               _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1 - tx0)/_dyl:0): \\\n                                       (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \\\n               _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1 - ty0)/_dyl:0): \\\n                                       (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \\\n             _counter>=0; --_counter, ++y, \\\n               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \\\n               txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \\\n               tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \\\n               xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \\\n                            tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \\\n                           _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \\\n               (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \\\n                _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\\\n                _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1 - xl))\n\n#define _cimg_for_triangle4(img,xl,cl,txl,tyl,xr,cr,txr,tyr,y,x0,y0,c0,tx0,ty0,x1,y1,c1,tx1,ty1,x2,y2,c2,tx2,ty2) \\\n        for (int y = y0<0?0:y0, \\\n               xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \\\n               cr = y0>=0?c0:(c0 - y0*(c2 - c0)/(y2 - y0)), \\\n               txr = y0>=0?tx0:(tx0 - y0*(tx2 - tx0)/(y2 - y0)), \\\n               tyr = y0>=0?ty0:(ty0 - y0*(ty2 - ty0)/(y2 - y0)), \\\n               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \\\n               cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0 - y0*(c1 - c0)/(y1 - y0))):(c1 - y1*(c2 - c1)/(y2 - y1)), \\\n               txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0 - y0*(tx1 - tx0)/(y1 - y0))):(tx1 - y1*(tx2 - tx1)/(y2 - y1)), \\\n               tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0 - y0*(ty1 - ty0)/(y1 - y0))):(ty1 - y1*(ty2 - ty1)/(y2 - y1)), \\\n               _sxn=1, _scn=1, _stxn=1, _styn=1, \\\n               _sxr=1, _scr=1, _stxr=1, _styr=1, \\\n               _sxl=1, _scl=1, _stxl=1, _styl=1, \\\n               _dxn = x2>x1?x2 - x1:(_sxn=-1,x1 - x2), \\\n               _dxr = x2>x0?x2 - x0:(_sxr=-1,x0 - x2), \\\n               _dxl = x1>x0?x1 - x0:(_sxl=-1,x0 - x1), \\\n               _dcn = c2>c1?c2 - c1:(_scn=-1,c1 - c2), \\\n               _dcr = c2>c0?c2 - c0:(_scr=-1,c0 - c2), \\\n               _dcl = c1>c0?c1 - c0:(_scl=-1,c0 - c1), \\\n               _dtxn = tx2>tx1?tx2 - tx1:(_stxn=-1,tx1 - tx2), \\\n               _dtxr = tx2>tx0?tx2 - tx0:(_stxr=-1,tx0 - tx2), \\\n               _dtxl = tx1>tx0?tx1 - tx0:(_stxl=-1,tx0 - tx1), \\\n               _dtyn = ty2>ty1?ty2 - ty1:(_styn=-1,ty1 - ty2), \\\n               _dtyr = ty2>ty0?ty2 - ty0:(_styr=-1,ty0 - ty2), \\\n               _dtyl = ty1>ty0?ty1 - ty0:(_styl=-1,ty0 - ty1), \\\n               _dyn = y2 - y1, \\\n               _dyr = y2 - y0, \\\n               _dyl = y1 - y0, \\\n               _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \\\n                          _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \\\n                          _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \\\n                          _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \\\n                          _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \\\n                          _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \\\n                          _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \\\n                          _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \\\n                          _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \\\n                          _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \\\n                          _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \\\n                          _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \\\n                          cimg::min((int)(img)._height - y - 1,y2 - y)), \\\n               _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \\\n               _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \\\n               _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \\\n               _rxn = _dyn?(x2 - x1)/_dyn:0, \\\n               _rcn = _dyn?(c2 - c1)/_dyn:0, \\\n               _rtxn = _dyn?(tx2 - tx1)/_dyn:0, \\\n               _rtyn = _dyn?(ty2 - ty1)/_dyn:0, \\\n               _rxr = _dyr?(x2 - x0)/_dyr:0, \\\n               _rcr = _dyr?(c2 - c0)/_dyr:0, \\\n               _rtxr = _dyr?(tx2 - tx0)/_dyr:0, \\\n               _rtyr = _dyr?(ty2 - ty0)/_dyr:0, \\\n               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1 - x0)/_dyl:0): \\\n                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \\\n               _rcl = (y0!=y1 && y1>0)?(_dyl?(c1 - c0)/_dyl:0): \\\n                                       (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \\\n               _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1 - tx0)/_dyl:0): \\\n                                        (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \\\n               _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1 - ty0)/_dyl:0): \\\n                                        (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \\\n             _counter>=0; --_counter, ++y, \\\n               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \\\n               cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \\\n               txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \\\n               tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \\\n               xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \\\n                            txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \\\n                            tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \\\n                            _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \\\n               (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \\\n                _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \\\n                _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \\\n                _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1 - xl))\n\n#define _cimg_for_triangle5(img,xl,txl,tyl,lxl,lyl,xr,txr,tyr,lxr,lyr,y,x0,y0,\\\n                            tx0,ty0,lx0,ly0,x1,y1,tx1,ty1,lx1,ly1,x2,y2,tx2,ty2,lx2,ly2) \\\n        for (int y = y0<0?0:y0, \\\n               xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \\\n               txr = y0>=0?tx0:(tx0 - y0*(tx2 - tx0)/(y2 - y0)), \\\n               tyr = y0>=0?ty0:(ty0 - y0*(ty2 - ty0)/(y2 - y0)), \\\n               lxr = y0>=0?lx0:(lx0 - y0*(lx2 - lx0)/(y2 - y0)), \\\n               lyr = y0>=0?ly0:(ly0 - y0*(ly2 - ly0)/(y2 - y0)), \\\n               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \\\n               txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0 - y0*(tx1 - tx0)/(y1 - y0))):(tx1 - y1*(tx2 - tx1)/(y2 - y1)), \\\n               tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0 - y0*(ty1 - ty0)/(y1 - y0))):(ty1 - y1*(ty2 - ty1)/(y2 - y1)), \\\n               lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0 - y0*(lx1 - lx0)/(y1 - y0))):(lx1 - y1*(lx2 - lx1)/(y2 - y1)), \\\n               lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0 - y0*(ly1 - ly0)/(y1 - y0))):(ly1 - y1*(ly2 - ly1)/(y2 - y1)), \\\n               _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \\\n               _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \\\n               _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \\\n               _dxn = x2>x1?x2 - x1:(_sxn=-1,x1 - x2), _dyn = y2 - y1, \\\n               _dxr = x2>x0?x2 - x0:(_sxr=-1,x0 - x2), _dyr = y2 - y0, \\\n               _dxl = x1>x0?x1 - x0:(_sxl=-1,x0 - x1), _dyl = y1 - y0, \\\n               _dtxn = tx2>tx1?tx2 - tx1:(_stxn=-1,tx1 - tx2), \\\n               _dtxr = tx2>tx0?tx2 - tx0:(_stxr=-1,tx0 - tx2), \\\n               _dtxl = tx1>tx0?tx1 - tx0:(_stxl=-1,tx0 - tx1), \\\n               _dtyn = ty2>ty1?ty2 - ty1:(_styn=-1,ty1 - ty2), \\\n               _dtyr = ty2>ty0?ty2 - ty0:(_styr=-1,ty0 - ty2), \\\n               _dtyl = ty1>ty0?ty1 - ty0:(_styl=-1,ty0 - ty1), \\\n               _dlxn = lx2>lx1?lx2 - lx1:(_slxn=-1,lx1 - lx2), \\\n               _dlxr = lx2>lx0?lx2 - lx0:(_slxr=-1,lx0 - lx2), \\\n               _dlxl = lx1>lx0?lx1 - lx0:(_slxl=-1,lx0 - lx1), \\\n               _dlyn = ly2>ly1?ly2 - ly1:(_slyn=-1,ly1 - ly2), \\\n               _dlyr = ly2>ly0?ly2 - ly0:(_slyr=-1,ly0 - ly2), \\\n               _dlyl = ly1>ly0?ly1 - ly0:(_slyl=-1,ly0 - ly1), \\\n               _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \\\n                          _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \\\n                          _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \\\n                          _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \\\n                          _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \\\n                          _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \\\n                          _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \\\n                          _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \\\n                          _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \\\n                          _dlxn-=_dyn?_dyn*(_dlxn/_dyn):0, \\\n                          _dlxr-=_dyr?_dyr*(_dlxr/_dyr):0, \\\n                          _dlxl-=_dyl?_dyl*(_dlxl/_dyl):0, \\\n                          _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \\\n                          _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \\\n                          _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \\\n                          cimg::min((int)(img)._height - y - 1,y2 - y)), \\\n               _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \\\n               _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \\\n               _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \\\n               _rxn = _dyn?(x2 - x1)/_dyn:0, \\\n               _rtxn = _dyn?(tx2 - tx1)/_dyn:0, \\\n               _rtyn = _dyn?(ty2 - ty1)/_dyn:0, \\\n               _rlxn = _dyn?(lx2 - lx1)/_dyn:0, \\\n               _rlyn = _dyn?(ly2 - ly1)/_dyn:0, \\\n               _rxr = _dyr?(x2 - x0)/_dyr:0, \\\n               _rtxr = _dyr?(tx2 - tx0)/_dyr:0, \\\n               _rtyr = _dyr?(ty2 - ty0)/_dyr:0, \\\n               _rlxr = _dyr?(lx2 - lx0)/_dyr:0, \\\n               _rlyr = _dyr?(ly2 - ly0)/_dyr:0, \\\n               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1 - x0)/_dyl:0): \\\n                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \\\n               _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1 - tx0)/_dyl:0): \\\n                                        (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \\\n               _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1 - ty0)/_dyl:0): \\\n                                        (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \\\n               _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1 - lx0)/_dyl:0): \\\n                                        (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \\\n               _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1 - ly0)/_dyl:0): \\\n                                        (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \\\n             _counter>=0; --_counter, ++y, \\\n               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \\\n               txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \\\n               tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \\\n               lxr+=_rlxr+((_errlxr-=_dlxr)<0?_errlxr+=_dyr,_slxr:0), \\\n               lyr+=_rlyr+((_errlyr-=_dlyr)<0?_errlyr+=_dyr,_slyr:0), \\\n               xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \\\n                            tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \\\n                            lxl+=_rlxl+((_errlxl-=_dlxl)<0?(_errlxl+=_dyl,_slxl):0), \\\n                            lyl+=_rlyl+((_errlyl-=_dlyl)<0?(_errlyl+=_dyl,_slyl):0), \\\n                            _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \\\n               (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \\\n                _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \\\n                _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \\\n                _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \\\n                _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1 - xl))\n\n    // [internal] Draw a filled triangle.\n    template<typename tc>\n    CImg<T>& _draw_triangle(const int x0, const int y0,\n                            const int x1, const int y1,\n                            const int x2, const int y2,\n                            const tc *const color, const float opacity,\n                            const float brightness) {\n      cimg_init_scanline(color,opacity);\n      const float nbrightness = brightness<0?0:(brightness>2?2:brightness);\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);\n      if (ny0<height() && ny2>=0) {\n        if ((nx1 - nx0)*(ny2 - ny0) - (nx2 - nx0)*(ny1 - ny0)<0)\n          _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2)\n            cimg_draw_scanline(xl,xr,y,color,opacity,nbrightness);\n        else\n          _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2)\n            cimg_draw_scanline(xr,xl,y,color,opacity,nbrightness);\n      }\n      return *this;\n    }\n\n    //! Draw a filled 2d triangle.\n    /**\n       \\param x0 X-coordinate of the first vertex.\n       \\param y0 Y-coordinate of the first vertex.\n       \\param x1 X-coordinate of the second vertex.\n       \\param y1 Y-coordinate of the second vertex.\n       \\param x2 X-coordinate of the third vertex.\n       \\param y2 Y-coordinate of the third vertex.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n     **/\n    template<typename tc>\n    CImg<T>& draw_triangle(const int x0, const int y0,\n                           const int x1, const int y1,\n                           const int x2, const int y2,\n                           const tc *const color, const float opacity=1) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Specified color is (null).\",\n                                    cimg_instance);\n      _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1);\n      return *this;\n    }\n\n    //! Draw a outlined 2d triangle.\n    /**\n       \\param x0 X-coordinate of the first vertex.\n       \\param y0 Y-coordinate of the first vertex.\n       \\param x1 X-coordinate of the second vertex.\n       \\param y1 Y-coordinate of the second vertex.\n       \\param x2 X-coordinate of the third vertex.\n       \\param y2 Y-coordinate of the third vertex.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the outline pattern.\n     **/\n    template<typename tc>\n    CImg<T>& draw_triangle(const int x0, const int y0,\n                           const int x1, const int y1,\n                           const int x2, const int y2,\n                           const tc *const color, const float opacity,\n                           const unsigned int pattern) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Specified color is (null).\",\n                                    cimg_instance);\n      draw_line(x0,y0,x1,y1,color,opacity,pattern,true).\n        draw_line(x1,y1,x2,y2,color,opacity,pattern,false).\n        draw_line(x2,y2,x0,y0,color,opacity,pattern,false);\n      return *this;\n    }\n\n    //! Draw a filled 2d triangle, with z-buffering.\n    /**\n       \\param zbuffer Z-buffer image.\n       \\param x0 X-coordinate of the first vertex.\n       \\param y0 Y-coordinate of the first vertex.\n       \\param z0 Z-coordinate of the first vertex.\n       \\param x1 X-coordinate of the second vertex.\n       \\param y1 Y-coordinate of the second vertex.\n       \\param z1 Z-coordinate of the second vertex.\n       \\param x2 X-coordinate of the third vertex.\n       \\param y2 Y-coordinate of the third vertex.\n       \\param z2 Z-coordinate of the third vertex.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param brightness Brightness factor.\n    **/\n    template<typename tz, typename tc>\n    CImg<T>& draw_triangle(CImg<tz>& zbuffer,\n                           const int x0, const int y0, const float z0,\n                           const int x1, const int y1, const float z1,\n                           const int x2, const int y2, const float z2,\n                           const tc *const color, const float opacity=1,\n                           const float brightness=1) {\n      typedef typename cimg::superset<tz,float>::type tzfloat;\n      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Specified color is (null).\",\n                                    cimg_instance);\n      if (!is_sameXY(zbuffer))\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have \"\n                                    \"different dimensions.\",\n                                    cimg_instance,\n                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float\n        nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),\n        nbrightness = brightness<0?0:(brightness>2?2:brightness);\n      const longT whd = (longT)width()*height()*depth(), offx = spectrum()*whd;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;\n      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2);\n      if (ny0>=height() || ny2<0) return *this;\n      tzfloat\n        pzl = (nz1 - nz0)/(ny1 - ny0),\n        pzr = (nz2 - nz0)/(ny2 - ny0),\n        pzn = (nz2 - nz1)/(ny2 - ny1),\n        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),\n        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));\n      _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {\n        if (y==ny1) { zl = nz1; pzl = pzn; }\n        int xleft = xleft0, xright = xright0;\n        tzfloat zleft = zl, zright = zr;\n        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright);\n        const int dx = xright - xleft;\n        const tzfloat pentez = (zright - zleft)/dx;\n        if (xleft<0 && dx) zleft-=xleft*(zright - zleft)/dx;\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y,0,0);\n        tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0;\n        if (opacity>=1) {\n          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n              const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n              const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nbrightness*(*col++)); ptrd+=whd; }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n              const tc *col = color;\n              cimg_forC(*this,c) { *ptrd = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval); ptrd+=whd; }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n          }\n        } else {\n          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n              const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=whd; }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n              const tc *col = color;\n              cimg_forC(*this,c) { *ptrd = (T)(nopacity*nbrightness**(col++) + *ptrd*copacity); ptrd+=whd; }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n              const tc *col = color;\n              cimg_forC(*this,c) {\n                const T val = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval);\n                *ptrd = (T)(nopacity*val + *ptrd*copacity);\n                ptrd+=whd;\n              }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n          }\n        }\n        zr+=pzr; zl+=pzl;\n      }\n      return *this;\n    }\n\n    //! Draw a Gouraud-shaded 2d triangle.\n    /**\n       \\param x0 X-coordinate of the first vertex in the image instance.\n       \\param y0 Y-coordinate of the first vertex in the image instance.\n       \\param x1 X-coordinate of the second vertex in the image instance.\n       \\param y1 Y-coordinate of the second vertex in the image instance.\n       \\param x2 X-coordinate of the third vertex in the image instance.\n       \\param y2 Y-coordinate of the third vertex in the image instance.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param brightness0 Brightness factor of the first vertex (in [0,2]).\n       \\param brightness1 brightness factor of the second vertex (in [0,2]).\n       \\param brightness2 brightness factor of the third vertex (in [0,2]).\n       \\param opacity Drawing opacity.\n    **/\n    template<typename tc>\n    CImg<T>& draw_triangle(const int x0, const int y0,\n                           const int x1, const int y1,\n                           const int x2, const int y2,\n                           const tc *const color,\n                           const float brightness0,\n                           const float brightness1,\n                           const float brightness2,\n                           const float opacity=1) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Specified color is (null).\",\n                                    cimg_instance);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const longT whd = (longT)width()*height()*depth(), offx = spectrum()*whd - 1;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),\n        nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),\n        nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2);\n      if (ny0>=height() || ny2<0) return *this;\n      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {\n        int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;\n        if (xright<xleft) cimg::swap(xleft,xright,cleft,cright);\n        const int\n          dx = xright - xleft,\n          dc = cright>cleft?cright - cleft:cleft - cright,\n          rc = dx?(cright - cleft)/dx:0,\n          sc = cright>cleft?1:-1,\n          ndc = dc - (dx?dx*(dc/dx):0);\n        int errc = dx>>1;\n        if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx;\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y);\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {\n          const tc *col = color;\n          cimg_forC(*this,c) {\n            *ptrd = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256);\n            ptrd+=whd;\n          }\n          ptrd-=offx;\n          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n        } else for (int x = xleft; x<=xright; ++x) {\n          const tc *col = color;\n          cimg_forC(*this,c) {\n            const T val = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256);\n            *ptrd = (T)(nopacity*val + *ptrd*copacity);\n            ptrd+=whd;\n          }\n          ptrd-=offx;\n          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a Gouraud-shaded 2d triangle, with z-buffering \\overloading.\n    template<typename tz, typename tc>\n    CImg<T>& draw_triangle(CImg<tz>& zbuffer,\n                           const int x0, const int y0, const float z0,\n                           const int x1, const int y1, const float z1,\n                           const int x2, const int y2, const float z2,\n                           const tc *const color,\n                           const float brightness0,\n                           const float brightness1,\n                           const float brightness2,\n                           const float opacity=1) {\n      typedef typename cimg::superset<tz,float>::type tzfloat;\n      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Specified color is (null).\",\n                                    cimg_instance);\n      if (!is_sameXY(zbuffer))\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have \"\n                                    \"different dimensions.\",\n                                    cimg_instance,\n                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const longT whd = (longT)width()*height()*depth(), offx = spectrum()*whd;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),\n        nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),\n        nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);\n      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2);\n      if (ny0>=height() || ny2<0) return *this;\n      tzfloat\n        pzl = (nz1 - nz0)/(ny1 - ny0),\n        pzr = (nz2 - nz0)/(ny2 - ny0),\n        pzn = (nz2 - nz1)/(ny2 - ny1),\n        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),\n        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));\n      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {\n        if (y==ny1) { zl = nz1; pzl = pzn; }\n        int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;\n        tzfloat zleft = zl, zright = zr;\n        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,cleft,cright);\n        const int\n          dx = xright - xleft,\n          dc = cright>cleft?cright - cleft:cleft - cright,\n          rc = dx?(cright - cleft)/dx:0,\n          sc = cright>cleft?1:-1,\n          ndc = dc - (dx?dx*(dc/dx):0);\n        const tzfloat pentez = (zright - zleft)/dx;\n        int errc = dx>>1;\n        if (xleft<0 && dx) {\n          cleft-=xleft*(cright - cleft)/dx;\n          zleft-=xleft*(zright - zleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T *ptrd = data(xleft,y);\n        tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0;\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {\n            if (zleft>=(tzfloat)*ptrz) {\n              *ptrz = (tz)zleft;\n              const tc *col = color;\n              cimg_forC(*this,c) {\n                *ptrd = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256);\n                ptrd+=whd;\n              }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n            cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n          } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {\n            if (zleft>=(tzfloat)*ptrz) {\n              *ptrz = (tz)zleft;\n              const tc *col = color;\n              cimg_forC(*this,c) {\n                const T val = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256);\n                *ptrd = (T)(nopacity*val + *ptrd*copacity);\n                ptrd+=whd;\n              }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n            cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n          }\n        zr+=pzr; zl+=pzl;\n      }\n      return *this;\n    }\n\n    //! Draw a color-interpolated 2d triangle.\n    /**\n       \\param x0 X-coordinate of the first vertex in the image instance.\n       \\param y0 Y-coordinate of the first vertex in the image instance.\n       \\param x1 X-coordinate of the second vertex in the image instance.\n       \\param y1 Y-coordinate of the second vertex in the image instance.\n       \\param x2 X-coordinate of the third vertex in the image instance.\n       \\param y2 Y-coordinate of the third vertex in the image instance.\n       \\param color1 Pointer to \\c spectrum() consecutive values of type \\c T, defining the color of the first vertex.\n       \\param color2 Pointer to \\c spectrum() consecutive values of type \\c T, defining the color of the seconf vertex.\n       \\param color3 Pointer to \\c spectrum() consecutive values of type \\c T, defining the color of the third vertex.\n       \\param opacity Drawing opacity.\n     **/\n    template<typename tc1, typename tc2, typename tc3>\n    CImg<T>& draw_triangle(const int x0, const int y0,\n                           const int x1, const int y1,\n                           const int x2, const int y2,\n                           const tc1 *const color1,\n                           const tc2 *const color2,\n                           const tc3 *const color3,\n                           const float opacity=1) {\n      const unsigned char one = 1;\n      cimg_forC(*this,c)\n        get_shared_channel(c).draw_triangle(x0,y0,x1,y1,x2,y2,&one,color1[c],color2[c],color3[c],opacity);\n      return *this;\n    }\n\n    //! Draw a textured 2d triangle.\n    /**\n       \\param x0 X-coordinate of the first vertex in the image instance.\n       \\param y0 Y-coordinate of the first vertex in the image instance.\n       \\param x1 X-coordinate of the second vertex in the image instance.\n       \\param y1 Y-coordinate of the second vertex in the image instance.\n       \\param x2 X-coordinate of the third vertex in the image instance.\n       \\param y2 Y-coordinate of the third vertex in the image instance.\n       \\param texture Texture image used to fill the triangle.\n       \\param tx0 X-coordinate of the first vertex in the texture image.\n       \\param ty0 Y-coordinate of the first vertex in the texture image.\n       \\param tx1 X-coordinate of the second vertex in the texture image.\n       \\param ty1 Y-coordinate of the second vertex in the texture image.\n       \\param tx2 X-coordinate of the third vertex in the texture image.\n       \\param ty2 Y-coordinate of the third vertex in the texture image.\n       \\param opacity Drawing opacity.\n       \\param brightness Brightness factor of the drawing (in [0,2]).\n    **/\n    template<typename tc>\n    CImg<T>& draw_triangle(const int x0, const int y0,\n                           const int x1, const int y1,\n                           const int x2, const int y2,\n                           const CImg<tc>& texture,\n                           const int tx0, const int ty0,\n                           const int tx1, const int ty1,\n                           const int tx2, const int ty2,\n                           const float opacity=1,\n                           const float brightness=1) {\n      if (is_empty()) return *this;\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_overlapped(texture))\n        return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float\n        nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),\n        nbrightness = brightness<0?0:(brightness>2?2:brightness);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height,\n        offx = _spectrum*whd - 1;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);\n      if (ny0>=height() || ny2<0) return *this;\n      _cimg_for_triangle3(*this,xleft0,txleft0,tyleft0,xright0,txright0,tyright0,y,\n                          nx0,ny0,ntx0,nty0,nx1,ny1,ntx1,nty1,nx2,ny2,ntx2,nty2) {\n        int\n          xleft = xleft0, xright = xright0,\n          txleft = txleft0, txright = txright0,\n          tyleft = tyleft0, tyright = tyright0;\n        if (xright<xleft) cimg::swap(xleft,xright,txleft,txright,tyleft,tyright);\n        const int\n          dx = xright - xleft,\n          dtx = txright>txleft?txright - txleft:txleft - txright,\n          dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,\n          rtx = dx?(txright - txleft)/dx:0,\n          rty = dx?(tyright - tyleft)/dx:0,\n          stx = txright>txleft?1:-1,\n          sty = tyright>tyleft?1:-1,\n          ndtx = dtx - (dx?dx*(dtx/dx):0),\n          ndty = dty - (dx?dx*(dty/dx):0);\n        int errtx = dx>>1, errty = errtx;\n        if (xleft<0 && dx) {\n          txleft-=xleft*(txright - txleft)/dx;\n          tyleft-=xleft*(tyright - tyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y,0,0);\n        if (opacity>=1) {\n          if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {\n            const tc *col = &texture._atXY(txleft,tyleft);\n            cimg_forC(*this,c) {\n              *ptrd = (T)*col;\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx;\n            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {\n            const tc *col = &texture._atXY(txleft,tyleft);\n            cimg_forC(*this,c) {\n              *ptrd = (T)(nbrightness**col);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx;\n            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n          } else for (int x = xleft; x<=xright; ++x) {\n            const tc *col = &texture._atXY(txleft,tyleft);\n            cimg_forC(*this,c) {\n              *ptrd = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx;\n            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n          }\n        } else {\n          if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {\n            const tc *col = &texture._atXY(txleft,tyleft);\n            cimg_forC(*this,c) {\n              *ptrd = (T)(nopacity**col + *ptrd*copacity);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx;\n            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {\n            const tc *col = &texture._atXY(txleft,tyleft);\n            cimg_forC(*this,c) {\n              *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx;\n            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n          } else for (int x = xleft; x<=xright; ++x) {\n            const tc *col = &texture._atXY(txleft,tyleft);\n            cimg_forC(*this,c) {\n              const T val = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval);\n              *ptrd = (T)(nopacity*val + *ptrd*copacity);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx;\n            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a 2d textured triangle, with perspective correction.\n    template<typename tc>\n    CImg<T>& draw_triangle(const int x0, const int y0, const float z0,\n                           const int x1, const int y1, const float z1,\n                           const int x2, const int y2, const float z2,\n                           const CImg<tc>& texture,\n                           const int tx0, const int ty0,\n                           const int tx1, const int ty1,\n                           const int tx2, const int ty2,\n                           const float opacity=1,\n                           const float brightness=1) {\n      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_overlapped(texture))\n        return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float\n        nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),\n        nbrightness = brightness<0?0:(brightness>2?2:brightness);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height,\n        offx = _spectrum*whd - 1;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;\n      float\n        ntx0 = tx0/z0, nty0 = ty0/z0,\n        ntx1 = tx1/z1, nty1 = ty1/z1,\n        ntx2 = tx2/z2, nty2 = ty2/z2,\n        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);\n      if (ny0>=height() || ny2<0) return *this;\n      float\n        ptxl = (ntx1 - ntx0)/(ny1 - ny0),\n        ptxr = (ntx2 - ntx0)/(ny2 - ny0),\n        ptxn = (ntx2 - ntx1)/(ny2 - ny1),\n        ptyl = (nty1 - nty0)/(ny1 - ny0),\n        ptyr = (nty2 - nty0)/(ny2 - ny0),\n        ptyn = (nty2 - nty1)/(ny2 - ny1),\n        pzl = (nz1 - nz0)/(ny1 - ny0),\n        pzr = (nz2 - nz0)/(ny2 - ny0),\n        pzn = (nz2 - nz1)/(ny2 - ny1),\n        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),\n        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),\n        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),\n        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),\n        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):\n          (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),\n        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):\n          (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));\n      _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {\n        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }\n        int xleft = xleft0, xright = xright0;\n        float\n          zleft = zl, zright = zr,\n          txleft = txl, txright = txr,\n          tyleft = tyl, tyright = tyr;\n        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);\n        const int dx = xright - xleft;\n        const float\n          pentez = (zright - zleft)/dx,\n          pentetx = (txright - txleft)/dx,\n          pentety = (tyright - tyleft)/dx;\n        if (xleft<0 && dx) {\n          zleft-=xleft*(zright - zleft)/dx;\n          txleft-=xleft*(txright - txleft)/dx;\n          tyleft-=xleft*(tyright - tyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y,0,0);\n        if (opacity>=1) {\n          if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {\n            const float invz = 1/zleft;\n            const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n            cimg_forC(*this,c) {\n              *ptrd = (T)*col;\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {\n            const float invz = 1/zleft;\n            const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n            cimg_forC(*this,c) {\n              *ptrd = (T)(nbrightness**col);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          } else for (int x = xleft; x<=xright; ++x) {\n            const float invz = 1/zleft;\n            const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n            cimg_forC(*this,c) {\n              *ptrd = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          }\n        } else {\n          if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {\n            const float invz = 1/zleft;\n            const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n            cimg_forC(*this,c) {\n              *ptrd = (T)(nopacity**col + *ptrd*copacity);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {\n            const float invz = 1/zleft;\n            const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n            cimg_forC(*this,c) {\n              *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          } else for (int x = xleft; x<=xright; ++x) {\n            const float invz = 1/zleft;\n            const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n            cimg_forC(*this,c) {\n              const T val = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval);\n              *ptrd = (T)(nopacity*val + *ptrd*copacity);\n              ptrd+=whd; col+=twh;\n            }\n            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          }\n        }\n        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;\n      }\n      return *this;\n    }\n\n    //! Draw a textured 2d triangle, with perspective correction and z-buffering.\n    template<typename tz, typename tc>\n    CImg<T>& draw_triangle(CImg<tz>& zbuffer,\n                           const int x0, const int y0, const float z0,\n                           const int x1, const int y1, const float z1,\n                           const int x2, const int y2, const float z2,\n                           const CImg<tc>& texture,\n                           const int tx0, const int ty0,\n                           const int tx1, const int ty1,\n                           const int tx2, const int ty2,\n                           const float opacity=1,\n                           const float brightness=1) {\n      typedef typename cimg::superset<tz,float>::type tzfloat;\n      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;\n      if (!is_sameXY(zbuffer))\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have \"\n                                    \"different dimensions.\",\n                                    cimg_instance,\n                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);\n\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_overlapped(texture))\n        return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float\n        nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),\n        nbrightness = brightness<0?0:(brightness>2?2:brightness);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height,\n        offx = _spectrum*whd;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;\n      float\n        ntx0 = tx0/z0, nty0 = ty0/z0,\n        ntx1 = tx1/z1, nty1 = ty1/z1,\n        ntx2 = tx2/z2, nty2 = ty2/z2;\n      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);\n      if (ny0>=height() || ny2<0) return *this;\n      float\n        ptxl = (ntx1 - ntx0)/(ny1 - ny0),\n        ptxr = (ntx2 - ntx0)/(ny2 - ny0),\n        ptxn = (ntx2 - ntx1)/(ny2 - ny1),\n        ptyl = (nty1 - nty0)/(ny1 - ny0),\n        ptyr = (nty2 - nty0)/(ny2 - ny0),\n        ptyn = (nty2 - nty1)/(ny2 - ny1),\n        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),\n        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),\n        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):\n          (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),\n        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):\n          (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));\n      tzfloat\n        pzl = (nz1 - nz0)/(ny1 - ny0),\n        pzr = (nz2 - nz0)/(ny2 - ny0),\n        pzn = (nz2 - nz1)/(ny2 - ny1),\n        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),\n        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));\n      _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {\n        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }\n        int xleft = xleft0, xright = xright0;\n        float txleft = txl, txright = txr, tyleft = tyl, tyright = tyr;\n        tzfloat zleft = zl, zright = zr;\n        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);\n        const int dx = xright - xleft;\n        const float pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx;\n        const tzfloat pentez = (zright - zleft)/dx;\n        if (xleft<0 && dx) {\n          zleft-=xleft*(zright - zleft)/dx;\n          txleft-=xleft*(txright - txleft)/dx;\n          tyleft-=xleft*(tyright - tyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T *ptrd = data(xleft,y,0,0);\n        tz *ptrz = zbuffer.data(xleft,y);\n        if (opacity>=1) {\n          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n                const tzfloat invz = 1/zleft;\n                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n                cimg_forC(*this,c) {\n                  *ptrd = (T)*col;\n                  ptrd+=whd; col+=twh;\n                }\n                ptrd-=offx;\n              }\n              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n                const tzfloat invz = 1/zleft;\n                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n                cimg_forC(*this,c) {\n                  *ptrd = (T)(nbrightness**col);\n                  ptrd+=whd; col+=twh;\n                }\n                ptrd-=offx;\n              }\n              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n                const tzfloat invz = 1/zleft;\n                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n                cimg_forC(*this,c) {\n                  *ptrd = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval);\n                  ptrd+=whd; col+=twh;\n                }\n                ptrd-=offx;\n              }\n              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            }\n        } else {\n          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n                const tzfloat invz = 1/zleft;\n                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n                cimg_forC(*this,c) {\n                  *ptrd = (T)(nopacity**col + *ptrd*copacity);\n                  ptrd+=whd; col+=twh;\n                }\n                ptrd-=offx;\n              }\n              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n                const tzfloat invz = 1/zleft;\n                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n                cimg_forC(*this,c) {\n                  *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);\n                  ptrd+=whd; col+=twh;\n                }\n                ptrd-=offx;\n              }\n              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n              if (zleft>=(tzfloat)*ptrz) {\n                *ptrz = (tz)zleft;\n                const tzfloat invz = 1/zleft;\n                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n                cimg_forC(*this,c) {\n                  const T val = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval);\n                  *ptrd = (T)(nopacity*val + *ptrd*copacity);\n                  ptrd+=whd; col+=twh;\n                }\n                ptrd-=offx;\n              }\n              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            }\n        }\n        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;\n      }\n      return *this;\n    }\n\n    //! Draw a Phong-shaded 2d triangle.\n    /**\n       \\param x0 X-coordinate of the first vertex in the image instance.\n       \\param y0 Y-coordinate of the first vertex in the image instance.\n       \\param x1 X-coordinate of the second vertex in the image instance.\n       \\param y1 Y-coordinate of the second vertex in the image instance.\n       \\param x2 X-coordinate of the third vertex in the image instance.\n       \\param y2 Y-coordinate of the third vertex in the image instance.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param light Light image.\n       \\param lx0 X-coordinate of the first vertex in the light image.\n       \\param ly0 Y-coordinate of the first vertex in the light image.\n       \\param lx1 X-coordinate of the second vertex in the light image.\n       \\param ly1 Y-coordinate of the second vertex in the light image.\n       \\param lx2 X-coordinate of the third vertex in the light image.\n       \\param ly2 Y-coordinate of the third vertex in the light image.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename tc, typename tl>\n    CImg<T>& draw_triangle(const int x0, const int y0,\n                           const int x1, const int y1,\n                           const int x2, const int y2,\n                           const tc *const color,\n                           const CImg<tl>& light,\n                           const int lx0, const int ly0,\n                           const int lx1, const int ly1,\n                           const int lx2, const int ly2,\n                           const float opacity=1) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Specified color is (null).\",\n                                    cimg_instance);\n      if (light._depth>1 || light._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data);\n      if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        lwh = (ulongT)light._width*light._height,\n        offx = _spectrum*whd - 1;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2);\n      if (ny0>=height() || ny2<0) return *this;\n      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,\n                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {\n        int\n          xleft = xleft0, xright = xright0,\n          lxleft = lxleft0, lxright = lxright0,\n          lyleft = lyleft0, lyright = lyright0;\n        if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright);\n        const int\n          dx = xright - xleft,\n          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,\n          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,\n          rlx = dx?(lxright - lxleft)/dx:0,\n          rly = dx?(lyright - lyleft)/dx:0,\n          slx = lxright>lxleft?1:-1,\n          sly = lyright>lyleft?1:-1,\n          ndlx = dlx - (dx?dx*(dlx/dx):0),\n          ndly = dly - (dx?dx*(dly/dx):0);\n        int errlx = dx>>1, errly = errlx;\n        if (xleft<0 && dx) {\n          lxleft-=xleft*(lxright - lxleft)/dx;\n          lyleft-=xleft*(lyright - lyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y,0,0);\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {\n          const tc *col = color;\n          const tl *lig = &light._atXY(lxleft,lyleft);\n          cimg_forC(*this,c) {\n            const tl l = *lig;\n            *ptrd = (T)(l<1?l**(col++):((2 - l)**(col++) + (l - 1)*maxval));\n            ptrd+=whd; lig+=lwh;\n          }\n          ptrd-=offx;\n          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n        } else  for (int x = xleft; x<=xright; ++x) {\n          const tc *col = color;\n          const tl *lig = &light._atXY(lxleft,lyleft);\n          cimg_forC(*this,c) {\n            const tl l = *lig;\n            const T val = (T)(l<1?l**(col++):((2 - l)**(col++) + (l - 1)*maxval));\n            *ptrd = (T)(nopacity*val + *ptrd*copacity);\n            ptrd+=whd; lig+=lwh;\n          }\n          ptrd-=offx;\n          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a Phong-shaded 2d triangle, with z-buffering.\n    template<typename tz, typename tc, typename tl>\n    CImg<T>& draw_triangle(CImg<tz>& zbuffer,\n                           const int x0, const int y0, const float z0,\n                           const int x1, const int y1, const float z1,\n                           const int x2, const int y2, const float z2,\n                           const tc *const color,\n                           const CImg<tl>& light,\n                           const int lx0, const int ly0,\n                           const int lx1, const int ly1,\n                           const int lx2, const int ly2,\n                           const float opacity=1) {\n      typedef typename cimg::superset<tz,float>::type tzfloat;\n      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Specified color is (null).\",\n                                    cimg_instance);\n      if (light._depth>1 || light._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data);\n      if (!is_sameXY(zbuffer))\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have \"\n                                    \"different dimensions.\",\n                                    cimg_instance,\n                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);\n      if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,\n                                                     +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        lwh = (ulongT)light._width*light._height,\n        offx = _spectrum*whd;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;\n      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2);\n      if (ny0>=height() || ny2<0) return *this;\n      tzfloat\n        pzl = (nz1 - nz0)/(ny1 - ny0),\n        pzr = (nz2 - nz0)/(ny2 - ny0),\n        pzn = (nz2 - nz1)/(ny2 - ny1),\n        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),\n        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));\n      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,\n                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {\n        if (y==ny1) { zl = nz1; pzl = pzn; }\n        int\n          xleft = xleft0, xright = xright0,\n          lxleft = lxleft0, lxright = lxright0,\n          lyleft = lyleft0, lyright = lyright0;\n        tzfloat zleft = zl, zright = zr;\n        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,lxleft,lxright,lyleft,lyright);\n        const int\n          dx = xright - xleft,\n          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,\n          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,\n          rlx = dx?(lxright - lxleft)/dx:0,\n          rly = dx?(lyright - lyleft)/dx:0,\n          slx = lxright>lxleft?1:-1,\n          sly = lyright>lyleft?1:-1,\n          ndlx = dlx - (dx?dx*(dlx/dx):0),\n          ndly = dly - (dx?dx*(dly/dx):0);\n        const tzfloat pentez = (zright - zleft)/dx;\n        int errlx = dx>>1, errly = errlx;\n        if (xleft<0 && dx) {\n          zleft-=xleft*(zright - zleft)/dx;\n          lxleft-=xleft*(lxright - lxleft)/dx;\n          lyleft-=xleft*(lyright - lyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T *ptrd = data(xleft,y,0,0);\n        tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0;\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n            if (zleft>=(tzfloat)*ptrz) {\n              *ptrz = (tz)zleft;\n              const tc *col = color;\n              const tl *lig = &light._atXY(lxleft,lyleft);\n              cimg_forC(*this,c) {\n                const tl l = *lig;\n                const tc cval = *(col++);\n                *ptrd = (T)(l<1?l*cval:(2 - l)*cval + (l - 1)*maxval);\n                ptrd+=whd; lig+=lwh;\n              }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n            lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n            lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n            if (zleft>=(tzfloat)*ptrz) {\n              *ptrz = (tz)zleft;\n              const tc *col = color;\n              const tl *lig = &light._atXY(lxleft,lyleft);\n              cimg_forC(*this,c) {\n                const tl l = *lig;\n                const tc cval = *(col++);\n                const T val = (T)(l<1?l*cval:(2 - l)*cval + (l - 1)*maxval);\n                *ptrd = (T)(nopacity*val + *ptrd*copacity);\n                ptrd+=whd; lig+=lwh;\n              }\n              ptrd-=offx;\n            }\n            zleft+=pentez;\n            lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n            lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n          }\n        zr+=pzr; zl+=pzl;\n      }\n      return *this;\n    }\n\n    //! Draw a textured Gouraud-shaded 2d triangle.\n    /**\n       \\param x0 X-coordinate of the first vertex in the image instance.\n       \\param y0 Y-coordinate of the first vertex in the image instance.\n       \\param x1 X-coordinate of the second vertex in the image instance.\n       \\param y1 Y-coordinate of the second vertex in the image instance.\n       \\param x2 X-coordinate of the third vertex in the image instance.\n       \\param y2 Y-coordinate of the third vertex in the image instance.\n       \\param texture Texture image used to fill the triangle.\n       \\param tx0 X-coordinate of the first vertex in the texture image.\n       \\param ty0 Y-coordinate of the first vertex in the texture image.\n       \\param tx1 X-coordinate of the second vertex in the texture image.\n       \\param ty1 Y-coordinate of the second vertex in the texture image.\n       \\param tx2 X-coordinate of the third vertex in the texture image.\n       \\param ty2 Y-coordinate of the third vertex in the texture image.\n       \\param brightness0 Brightness factor of the first vertex.\n       \\param brightness1 Brightness factor of the second vertex.\n       \\param brightness2 Brightness factor of the third vertex.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename tc>\n    CImg<T>& draw_triangle(const int x0, const int y0,\n                           const int x1, const int y1,\n                           const int x2, const int y2,\n                           const CImg<tc>& texture,\n                           const int tx0, const int ty0,\n                           const int tx1, const int ty1,\n                           const int tx2, const int ty2,\n                           const float brightness0,\n                           const float brightness1,\n                           const float brightness2,\n                           const float opacity=1) {\n      if (is_empty()) return *this;\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_overlapped(texture))\n        return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,\n                             brightness0,brightness1,brightness2,opacity);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height,\n        offx = _spectrum*whd - 1;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,\n        nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),\n        nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),\n        nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2);\n      if (ny0>=height() || ny2<0) return *this;\n      _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y,\n                          nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) {\n        int\n          xleft = xleft0, xright = xright0,\n          cleft = cleft0, cright = cright0,\n          txleft = txleft0, txright = txright0,\n          tyleft = tyleft0, tyright = tyright0;\n        if (xright<xleft) cimg::swap(xleft,xright,cleft,cright,txleft,txright,tyleft,tyright);\n        const int\n          dx = xright - xleft,\n          dc = cright>cleft?cright - cleft:cleft - cright,\n          dtx = txright>txleft?txright - txleft:txleft - txright,\n          dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,\n          rc = dx?(cright - cleft)/dx:0,\n          rtx = dx?(txright - txleft)/dx:0,\n          rty = dx?(tyright - tyleft)/dx:0,\n          sc = cright>cleft?1:-1,\n          stx = txright>txleft?1:-1,\n          sty = tyright>tyleft?1:-1,\n          ndc = dc - (dx?dx*(dc/dx):0),\n          ndtx = dtx - (dx?dx*(dtx/dx):0),\n          ndty = dty - (dx?dx*(dty/dx):0);\n        int errc = dx>>1, errtx = errc, errty = errc;\n        if (xleft<0 && dx) {\n          cleft-=xleft*(cright - cleft)/dx;\n          txleft-=xleft*(txright - txleft)/dx;\n          tyleft-=xleft*(tyright - tyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y,0,0);\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {\n          const tc *col = &texture._atXY(txleft,tyleft);\n          cimg_forC(*this,c) {\n            *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);\n            ptrd+=whd; col+=twh;\n          }\n          ptrd-=offx;\n          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n        } else for (int x = xleft; x<=xright; ++x) {\n          const tc *col = &texture._atXY(txleft,tyleft);\n          cimg_forC(*this,c) {\n            const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);\n            *ptrd = (T)(nopacity*val + *ptrd*copacity);\n            ptrd+=whd; col+=twh;\n          }\n          ptrd-=offx;\n          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a textured Gouraud-shaded 2d triangle, with perspective correction \\overloading.\n    template<typename tc>\n    CImg<T>& draw_triangle(const int x0, const int y0, const float z0,\n                           const int x1, const int y1, const float z1,\n                           const int x2, const int y2, const float z2,\n                           const CImg<tc>& texture,\n                           const int tx0, const int ty0,\n                           const int tx1, const int ty1,\n                           const int tx2, const int ty2,\n                           const float brightness0,\n                           const float brightness1,\n                           const float brightness2,\n                           const float opacity=1) {\n      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,\n                                                       brightness0,brightness1,brightness2,opacity);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height,\n        offx = _spectrum*whd - 1;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),\n        nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),\n        nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);\n      float\n        ntx0 = tx0/z0, nty0 = ty0/z0,\n        ntx1 = tx1/z1, nty1 = ty1/z1,\n        ntx2 = tx2/z2, nty2 = ty2/z2,\n        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);\n      if (ny0>=height() || ny2<0) return *this;\n      float\n        ptxl = (ntx1 - ntx0)/(ny1 - ny0),\n        ptxr = (ntx2 - ntx0)/(ny2 - ny0),\n        ptxn = (ntx2 - ntx1)/(ny2 - ny1),\n        ptyl = (nty1 - nty0)/(ny1 - ny0),\n        ptyr = (nty2 - nty0)/(ny2 - ny0),\n        ptyn = (nty2 - nty1)/(ny2 - ny1),\n        pzl = (nz1 - nz0)/(ny1 - ny0),\n        pzr = (nz2 - nz0)/(ny2 - ny0),\n        pzn = (nz2 - nz1)/(ny2 - ny1),\n        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),\n        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),\n        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),\n        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),\n        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):\n          (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),\n        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):\n          (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));\n      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {\n        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }\n        int\n          xleft = xleft0, xright = xright0,\n          cleft = cleft0, cright = cright0;\n        float\n          zleft = zl, zright = zr,\n          txleft = txl, txright = txr,\n          tyleft = tyl, tyright = tyr;\n        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);\n        const int\n          dx = xright - xleft,\n          dc = cright>cleft?cright - cleft:cleft - cright,\n          rc = dx?(cright - cleft)/dx:0,\n          sc = cright>cleft?1:-1,\n          ndc = dc - (dx?dx*(dc/dx):0);\n        const float\n          pentez = (zright - zleft)/dx,\n          pentetx = (txright - txleft)/dx,\n          pentety = (tyright - tyleft)/dx;\n        int errc = dx>>1;\n        if (xleft<0 && dx) {\n          cleft-=xleft*(cright - cleft)/dx;\n          zleft-=xleft*(zright - zleft)/dx;\n          txleft-=xleft*(txright - txleft)/dx;\n          tyleft-=xleft*(tyright - tyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y,0,0);\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {\n          const float invz = 1/zleft;\n          const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n          cimg_forC(*this,c) {\n            *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);\n            ptrd+=whd; col+=twh;\n          }\n          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n        } else for (int x = xleft; x<=xright; ++x) {\n          const float invz = 1/zleft;\n          const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n          cimg_forC(*this,c) {\n            const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);\n            *ptrd = (T)(nopacity*val + *ptrd*copacity);\n            ptrd+=whd; col+=twh;\n          }\n          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n        }\n        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;\n      }\n      return *this;\n    }\n\n    //! Draw a textured Gouraud-shaded 2d triangle, with perspective correction and z-buffering \\overloading.\n    template<typename tz, typename tc>\n    CImg<T>& draw_triangle(CImg<tz>& zbuffer,\n                           const int x0, const int y0, const float z0,\n                           const int x1, const int y1, const float z1,\n                           const int x2, const int y2, const float z2,\n                           const CImg<tc>& texture,\n                           const int tx0, const int ty0,\n                           const int tx1, const int ty1,\n                           const int tx2, const int ty2,\n                           const float brightness0,\n                           const float brightness1,\n                           const float brightness2,\n                           const float opacity=1) {\n      typedef typename cimg::superset<tz,float>::type tzfloat;\n      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;\n      if (!is_sameXY(zbuffer))\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have \"\n                                    \"different dimensions.\",\n                                    cimg_instance,\n                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (is_overlapped(texture))\n        return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,\n                                                       brightness0,brightness1,brightness2,opacity);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height,\n        offx = _spectrum*whd;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),\n        nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),\n        nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);\n      float\n        ntx0 = tx0/z0, nty0 = ty0/z0,\n        ntx1 = tx1/z1, nty1 = ty1/z1,\n        ntx2 = tx2/z2, nty2 = ty2/z2;\n      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);\n      if (ny0>=height() || ny2<0) return *this;\n      float\n        ptxl = (ntx1 - ntx0)/(ny1 - ny0),\n        ptxr = (ntx2 - ntx0)/(ny2 - ny0),\n        ptxn = (ntx2 - ntx1)/(ny2 - ny1),\n        ptyl = (nty1 - nty0)/(ny1 - ny0),\n        ptyr = (nty2 - nty0)/(ny2 - ny0),\n        ptyn = (nty2 - nty1)/(ny2 - ny1),\n        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),\n        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),\n        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):\n          (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),\n        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):\n          (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));\n      tzfloat\n        pzl = (nz1 - nz0)/(ny1 - ny0),\n        pzr = (nz2 - nz0)/(ny2 - ny0),\n        pzn = (nz2 - nz1)/(ny2 - ny1),\n        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),\n        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));\n      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {\n        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }\n        int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;\n        float txleft = txl, txright = txr, tyleft = tyl, tyright = tyr;\n        tzfloat zleft = zl, zright = zr;\n        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);\n        const int\n          dx = xright - xleft,\n          dc = cright>cleft?cright - cleft:cleft - cright,\n          rc = dx?(cright - cleft)/dx:0,\n          sc = cright>cleft?1:-1,\n          ndc = dc - (dx?dx*(dc/dx):0);\n        float pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx;\n        const tzfloat pentez = (zright - zleft)/dx;\n        int errc = dx>>1;\n        if (xleft<0 && dx) {\n          cleft-=xleft*(cright - cleft)/dx;\n          zleft-=xleft*(zright - zleft)/dx;\n          txleft-=xleft*(txright - txleft)/dx;\n          tyleft-=xleft*(tyright - tyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y);\n        tz *ptrz = zbuffer.data(xleft,y);\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {\n            if (zleft>=(tzfloat)*ptrz) {\n              *ptrz = (tz)zleft;\n              const tzfloat invz = 1/zleft;\n              const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n              cimg_forC(*this,c) {\n                *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);\n                ptrd+=whd; col+=twh;\n              }\n              ptrd-=offx;\n            }\n            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n          } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {\n            if (zleft>=(tzfloat)*ptrz) {\n              *ptrz = (tz)zleft;\n              const tzfloat invz = 1/zleft;\n              const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n              cimg_forC(*this,c) {\n                const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);\n                *ptrd = (T)(nopacity*val + *ptrd*copacity);\n                ptrd+=whd; col+=twh;\n              }\n              ptrd-=offx;\n            }\n            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);\n          }\n        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;\n      }\n      return *this;\n    }\n\n    //! Draw a textured Phong-shaded 2d triangle.\n    /**\n       \\param x0 X-coordinate of the first vertex in the image instance.\n       \\param y0 Y-coordinate of the first vertex in the image instance.\n       \\param x1 X-coordinate of the second vertex in the image instance.\n       \\param y1 Y-coordinate of the second vertex in the image instance.\n       \\param x2 X-coordinate of the third vertex in the image instance.\n       \\param y2 Y-coordinate of the third vertex in the image instance.\n       \\param texture Texture image used to fill the triangle.\n       \\param tx0 X-coordinate of the first vertex in the texture image.\n       \\param ty0 Y-coordinate of the first vertex in the texture image.\n       \\param tx1 X-coordinate of the second vertex in the texture image.\n       \\param ty1 Y-coordinate of the second vertex in the texture image.\n       \\param tx2 X-coordinate of the third vertex in the texture image.\n       \\param ty2 Y-coordinate of the third vertex in the texture image.\n       \\param light Light image.\n       \\param lx0 X-coordinate of the first vertex in the light image.\n       \\param ly0 Y-coordinate of the first vertex in the light image.\n       \\param lx1 X-coordinate of the second vertex in the light image.\n       \\param ly1 Y-coordinate of the second vertex in the light image.\n       \\param lx2 X-coordinate of the third vertex in the light image.\n       \\param ly2 Y-coordinate of the third vertex in the light image.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename tc, typename tl>\n    CImg<T>& draw_triangle(const int x0, const int y0,\n                           const int x1, const int y1,\n                           const int x2, const int y2,\n                           const CImg<tc>& texture,\n                           const int tx0, const int ty0,\n                           const int tx1, const int ty1,\n                           const int tx2, const int ty2,\n                           const CImg<tl>& light,\n                           const int lx0, const int ly0,\n                           const int lx1, const int ly1,\n                           const int lx2, const int ly2,\n                           const float opacity=1) {\n      if (is_empty()) return *this;\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (light._depth>1 || light._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data);\n      if (is_overlapped(texture))\n        return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n      if (is_overlapped(light))\n        return draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height,\n        lwh = (ulongT)light._width*light._height,\n        offx = _spectrum*whd - 1;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,\n        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2);\n      if (ny0>=height() || ny2<0) return *this;\n      _cimg_for_triangle5(*this,xleft0,lxleft0,lyleft0,txleft0,tyleft0,xright0,lxright0,lyright0,txright0,tyright0,y,\n                          nx0,ny0,nlx0,nly0,ntx0,nty0,nx1,ny1,nlx1,nly1,ntx1,nty1,nx2,ny2,nlx2,nly2,ntx2,nty2) {\n        int\n          xleft = xleft0, xright = xright0,\n          lxleft = lxleft0, lxright = lxright0,\n          lyleft = lyleft0, lyright = lyright0,\n          txleft = txleft0, txright = txright0,\n          tyleft = tyleft0, tyright = tyright0;\n        if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright,txleft,txright,tyleft,tyright);\n        const int\n          dx = xright - xleft,\n          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,\n          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,\n          dtx = txright>txleft?txright - txleft:txleft - txright,\n          dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,\n          rlx = dx?(lxright - lxleft)/dx:0,\n          rly = dx?(lyright - lyleft)/dx:0,\n          rtx = dx?(txright - txleft)/dx:0,\n          rty = dx?(tyright - tyleft)/dx:0,\n          slx = lxright>lxleft?1:-1,\n          sly = lyright>lyleft?1:-1,\n          stx = txright>txleft?1:-1,\n          sty = tyright>tyleft?1:-1,\n          ndlx = dlx - (dx?dx*(dlx/dx):0),\n          ndly = dly - (dx?dx*(dly/dx):0),\n          ndtx = dtx - (dx?dx*(dtx/dx):0),\n          ndty = dty - (dx?dx*(dty/dx):0);\n        int errlx = dx>>1, errly = errlx, errtx = errlx, errty = errlx;\n        if (xleft<0 && dx) {\n          lxleft-=xleft*(lxright - lxleft)/dx;\n          lyleft-=xleft*(lyright - lyleft)/dx;\n          txleft-=xleft*(txright - txleft)/dx;\n          tyleft-=xleft*(tyright - tyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y,0,0);\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {\n          const tc *col = &texture._atXY(txleft,tyleft);\n          const tl *lig = &light._atXY(lxleft,lyleft);\n          cimg_forC(*this,c) {\n            const tl l = *lig;\n            *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval);\n            ptrd+=whd; col+=twh; lig+=lwh;\n          }\n          ptrd-=offx;\n          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n        } else for (int x = xleft; x<=xright; ++x) {\n          const tc *col = &texture._atXY(txleft,tyleft);\n          const tl *lig = &light._atXY(lxleft,lyleft);\n          cimg_forC(*this,c) {\n            const tl l = *lig;\n            const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval);\n            *ptrd = (T)(nopacity*val + *ptrd*copacity);\n            ptrd+=whd; col+=twh; lig+=lwh;\n          }\n          ptrd-=offx;\n          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);\n          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a textured Phong-shaded 2d triangle, with perspective correction.\n    template<typename tc, typename tl>\n    CImg<T>& draw_triangle(const int x0, const int y0, const float z0,\n                           const int x1, const int y1, const float z1,\n                           const int x2, const int y2, const float z2,\n                           const CImg<tc>& texture,\n                           const int tx0, const int ty0,\n                           const int tx1, const int ty1,\n                           const int tx2, const int ty2,\n                           const CImg<tl>& light,\n                           const int lx0, const int ly0,\n                           const int lx1, const int ly1,\n                           const int lx2, const int ly2,\n                           const float opacity=1) {\n      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (light._depth>1 || light._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data);\n      if (is_overlapped(texture))\n        return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,\n                             light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n      if (is_overlapped(light))\n        return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,texture,tx0,ty0,tx1,ty1,tx2,ty2,\n                             +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height,\n        lwh = (ulongT)light._width*light._height,\n        offx = _spectrum*whd - 1;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;\n      float\n        ntx0 = tx0/z0, nty0 = ty0/z0,\n        ntx1 = tx1/z1, nty1 = ty1/z1,\n        ntx2 = tx2/z2, nty2 = ty2/z2,\n        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);\n      if (ny0>=height() || ny2<0) return *this;\n      float\n        ptxl = (ntx1 - ntx0)/(ny1 - ny0),\n        ptxr = (ntx2 - ntx0)/(ny2 - ny0),\n        ptxn = (ntx2 - ntx1)/(ny2 - ny1),\n        ptyl = (nty1 - nty0)/(ny1 - ny0),\n        ptyr = (nty2 - nty0)/(ny2 - ny0),\n        ptyn = (nty2 - nty1)/(ny2 - ny1),\n        pzl = (nz1 - nz0)/(ny1 - ny0),\n        pzr = (nz2 - nz0)/(ny2 - ny0),\n        pzn = (nz2 - nz1)/(ny2 - ny1),\n        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),\n        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),\n        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),\n        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),\n        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):\n          (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),\n        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):\n          (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));\n      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,\n                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {\n        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }\n        int\n          xleft = xleft0, xright = xright0,\n          lxleft = lxleft0, lxright = lxright0,\n          lyleft = lyleft0, lyright = lyright0;\n        float\n          zleft = zl, zright = zr,\n          txleft = txl, txright = txr,\n          tyleft = tyl, tyright = tyr;\n        if (xright<xleft)\n          cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);\n        const int\n          dx = xright - xleft,\n          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,\n          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,\n          rlx = dx?(lxright - lxleft)/dx:0,\n          rly = dx?(lyright - lyleft)/dx:0,\n          slx = lxright>lxleft?1:-1,\n          sly = lyright>lyleft?1:-1,\n          ndlx = dlx - (dx?dx*(dlx/dx):0),\n          ndly = dly - (dx?dx*(dly/dx):0);\n        const float\n          pentez = (zright - zleft)/dx,\n          pentetx = (txright - txleft)/dx,\n          pentety = (tyright - tyleft)/dx;\n        int errlx = dx>>1, errly = errlx;\n        if (xleft<0 && dx) {\n          zleft-=xleft*(zright - zleft)/dx;\n          lxleft-=xleft*(lxright - lxleft)/dx;\n          lyleft-=xleft*(lyright - lyleft)/dx;\n          txleft-=xleft*(txright - txleft)/dx;\n          tyleft-=xleft*(tyright - tyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y,0,0);\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {\n          const float invz = 1/zleft;\n          const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n          const tl *lig = &light._atXY(lxleft,lyleft);\n          cimg_forC(*this,c) {\n            const tl l = *lig;\n            *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval);\n            ptrd+=whd; col+=twh; lig+=lwh;\n          }\n          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n        } else for (int x = xleft; x<=xright; ++x) {\n          const float invz = 1/zleft;\n          const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n          const tl *lig = &light._atXY(lxleft,lyleft);\n          cimg_forC(*this,c) {\n            const tl l = *lig;\n            const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval);\n            *ptrd = (T)(nopacity*val + *ptrd*copacity);\n            ptrd+=whd; col+=twh; lig+=lwh;\n          }\n          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n        }\n        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;\n      }\n      return *this;\n    }\n\n    //! Draw a textured Phong-shaded 2d triangle, with perspective correction and z-buffering.\n    template<typename tz, typename tc, typename tl>\n    CImg<T>& draw_triangle(CImg<tz>& zbuffer,\n                           const int x0, const int y0, const float z0,\n                           const int x1, const int y1, const float z1,\n                           const int x2, const int y2, const float z2,\n                           const CImg<tc>& texture,\n                           const int tx0, const int ty0,\n                           const int tx1, const int ty1,\n                           const int tx2, const int ty2,\n                           const CImg<tl>& light,\n                           const int lx0, const int ly0,\n                           const int lx1, const int ly1,\n                           const int lx2, const int ly2,\n                           const float opacity=1) {\n      typedef typename cimg::superset<tz,float>::type tzfloat;\n      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;\n      if (!is_sameXY(zbuffer))\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have \"\n                                    \"different dimensions.\",\n                                    cimg_instance,\n                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);\n      if (texture._depth>1 || texture._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);\n      if (light._depth>1 || light._spectrum<_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data);\n      if (is_overlapped(texture))\n        return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,\n                             +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n      if (is_overlapped(light))\n        return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,\n                             texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT\n        whd = (ulongT)_width*_height*_depth,\n        twh = (ulongT)texture._width*texture._height,\n        lwh = (ulongT)light._width*light._height,\n        offx = _spectrum*whd;\n      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,\n        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;\n      float\n        ntx0 = tx0/z0, nty0 = ty0/z0,\n        ntx1 = tx1/z1, nty1 = ty1/z1,\n        ntx2 = tx2/z2, nty2 = ty2/z2;\n      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;\n      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);\n      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);\n      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);\n      if (ny0>=height() || ny2<0) return *this;\n      float\n        ptxl = (ntx1 - ntx0)/(ny1 - ny0),\n        ptxr = (ntx2 - ntx0)/(ny2 - ny0),\n        ptxn = (ntx2 - ntx1)/(ny2 - ny1),\n        ptyl = (nty1 - nty0)/(ny1 - ny0),\n        ptyr = (nty2 - nty0)/(ny2 - ny0),\n        ptyn = (nty2 - nty1)/(ny2 - ny1),\n        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),\n        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),\n        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):\n          (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),\n        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):\n          (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));\n      tzfloat\n        pzl = (nz1 - nz0)/(ny1 - ny0),\n        pzr = (nz2 - nz0)/(ny2 - ny0),\n        pzn = (nz2 - nz1)/(ny2 - ny1),\n        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),\n        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));\n      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,\n                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {\n        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }\n        int\n          xleft = xleft0, xright = xright0,\n          lxleft = lxleft0, lxright = lxright0,\n          lyleft = lyleft0, lyright = lyright0;\n        float txleft = txl, txright = txr, tyleft = tyl, tyright = tyr;\n        tzfloat zleft = zl, zright = zr;\n        if (xright<xleft)\n          cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);\n        const int\n          dx = xright - xleft,\n          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,\n          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,\n          rlx = dx?(lxright - lxleft)/dx:0,\n          rly = dx?(lyright - lyleft)/dx:0,\n          slx = lxright>lxleft?1:-1,\n          sly = lyright>lyleft?1:-1,\n          ndlx = dlx - (dx?dx*(dlx/dx):0),\n          ndly = dly - (dx?dx*(dly/dx):0);\n        float pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx;\n        const tzfloat pentez = (zright - zleft)/dx;\n        int errlx = dx>>1, errly = errlx;\n        if (xleft<0 && dx) {\n          zleft-=xleft*(zright - zleft)/dx;\n          lxleft-=xleft*(lxright - lxleft)/dx;\n          lyleft-=xleft*(lyright - lyleft)/dx;\n          txleft-=xleft*(txright - txleft)/dx;\n          tyleft-=xleft*(tyright - tyleft)/dx;\n        }\n        if (xleft<0) xleft = 0;\n        if (xright>=width() - 1) xright = width() - 1;\n        T* ptrd = data(xleft,y);\n        tz *ptrz = zbuffer.data(xleft,y);\n        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n            if (zleft>=(tzfloat)*ptrz) {\n              *ptrz = (tz)zleft;\n              const tzfloat invz = 1/zleft;\n              const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n              const tl *lig = &light._atXY(lxleft,lyleft);\n              cimg_forC(*this,c) {\n                const tl l = *lig;\n                *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval);\n                ptrd+=whd; col+=twh; lig+=lwh;\n              }\n              ptrd-=offx;\n            }\n            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n            lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {\n            if (zleft>=(tzfloat)*ptrz) {\n              *ptrz = (tz)zleft;\n              const tzfloat invz = 1/zleft;\n              const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));\n              const tl *lig = &light._atXY(lxleft,lyleft);\n              cimg_forC(*this,c) {\n                const tl l = *lig;\n                const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval);\n                *ptrd = (T)(nopacity*val + *ptrd*copacity);\n                ptrd+=whd; col+=twh; lig+=lwh;\n              }\n              ptrd-=offx;\n            }\n            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;\n            lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);\n            lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);\n          }\n        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;\n      }\n      return *this;\n    }\n\n    //! Draw a filled 4d rectangle.\n    /**\n       \\param x0 X-coordinate of the upper-left rectangle corner.\n       \\param y0 Y-coordinate of the upper-left rectangle corner.\n       \\param z0 Z-coordinate of the upper-left rectangle corner.\n       \\param c0 C-coordinate of the upper-left rectangle corner.\n       \\param x1 X-coordinate of the lower-right rectangle corner.\n       \\param y1 Y-coordinate of the lower-right rectangle corner.\n       \\param z1 Z-coordinate of the lower-right rectangle corner.\n       \\param c1 C-coordinate of the lower-right rectangle corner.\n       \\param val Scalar value used to fill the rectangle area.\n       \\param opacity Drawing opacity.\n    **/\n    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, const int c0,\n                            const int x1, const int y1, const int z1, const int c1,\n                            const T val, const float opacity=1) {\n      if (is_empty()) return *this;\n      const bool bx = (x0<x1), by = (y0<y1), bz = (z0<z1), bc = (c0<c1);\n      const int\n        nx0 = bx?x0:x1, nx1 = bx?x1:x0,\n        ny0 = by?y0:y1, ny1 = by?y1:y0,\n        nz0 = bz?z0:z1, nz1 = bz?z1:z0,\n        nc0 = bc?c0:c1, nc1 = bc?c1:c0;\n      const int\n        lX = (1 + nx1 - nx0) + (nx1>=width()?width() - 1 - nx1:0) + (nx0<0?nx0:0),\n        lY = (1 + ny1 - ny0) + (ny1>=height()?height() - 1 - ny1:0) + (ny0<0?ny0:0),\n        lZ = (1 + nz1 - nz0) + (nz1>=depth()?depth() - 1 - nz1:0) + (nz0<0?nz0:0),\n        lC = (1 + nc1 - nc0) + (nc1>=spectrum()?spectrum() - 1 - nc1:0) + (nc0<0?nc0:0);\n      const ulongT\n        offX = (ulongT)_width - lX,\n        offY = (ulongT)_width*(_height - lY),\n        offZ = (ulongT)_width*_height*(_depth - lZ);\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      T *ptrd = data(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nc0<0?0:nc0);\n      if (lX>0 && lY>0 && lZ>0 && lC>0)\n        for (int v = 0; v<lC; ++v) {\n          for (int z = 0; z<lZ; ++z) {\n            for (int y = 0; y<lY; ++y) {\n              if (opacity>=1) {\n                if (sizeof(T)!=1) { for (int x = 0; x<lX; ++x) *(ptrd++) = val; ptrd+=offX; }\n                else { std::memset(ptrd,(int)val,lX); ptrd+=_width; }\n              } else { for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*val + *ptrd*copacity); ++ptrd; } ptrd+=offX; }\n            }\n            ptrd+=offY;\n          }\n          ptrd+=offZ;\n        }\n      return *this;\n    }\n\n    //! Draw a filled 3d rectangle.\n    /**\n       \\param x0 X-coordinate of the upper-left rectangle corner.\n       \\param y0 Y-coordinate of the upper-left rectangle corner.\n       \\param z0 Z-coordinate of the upper-left rectangle corner.\n       \\param x1 X-coordinate of the lower-right rectangle corner.\n       \\param y1 Y-coordinate of the lower-right rectangle corner.\n       \\param z1 Z-coordinate of the lower-right rectangle corner.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename tc>\n    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,\n                            const int x1, const int y1, const int z1,\n                            const tc *const color, const float opacity=1) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_rectangle(): Specified color is (null).\",\n                                    cimg_instance);\n      cimg_forC(*this,c) draw_rectangle(x0,y0,z0,c,x1,y1,z1,c,(T)color[c],opacity);\n      return *this;\n    }\n\n    //! Draw an outlined 3d rectangle \\overloading.\n    template<typename tc>\n    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,\n                            const int x1, const int y1, const int z1,\n                            const tc *const color, const float opacity,\n                            const unsigned int pattern) {\n      return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true).\n        draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false).\n        draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false).\n        draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false).\n        draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true).\n        draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false).\n        draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false).\n        draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false).\n        draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true).\n        draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true).\n        draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true).\n        draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true);\n    }\n\n    //! Draw a filled 2d rectangle.\n    /**\n       \\param x0 X-coordinate of the upper-left rectangle corner.\n       \\param y0 Y-coordinate of the upper-left rectangle corner.\n       \\param x1 X-coordinate of the lower-right rectangle corner.\n       \\param y1 Y-coordinate of the lower-right rectangle corner.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename tc>\n    CImg<T>& draw_rectangle(const int x0, const int y0,\n                            const int x1, const int y1,\n                            const tc *const color, const float opacity=1) {\n      return draw_rectangle(x0,y0,0,x1,y1,_depth - 1,color,opacity);\n    }\n\n    //! Draw a outlined 2d rectangle \\overloading.\n    template<typename tc>\n    CImg<T>& draw_rectangle(const int x0, const int y0,\n                            const int x1, const int y1,\n                            const tc *const color, const float opacity,\n                            const unsigned int pattern) {\n      if (is_empty()) return *this;\n      if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true);\n      if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true);\n      const bool bx = (x0<x1), by = (y0<y1);\n      const int\n        nx0 = bx?x0:x1, nx1 = bx?x1:x0,\n        ny0 = by?y0:y1, ny1 = by?y1:y0;\n      if (ny1==ny0 + 1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).\n                      draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);\n      return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).\n        draw_line(nx1,ny0 + 1,nx1,ny1 - 1,color,opacity,pattern,false).\n        draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false).\n        draw_line(nx0,ny1 - 1,nx0,ny0 + 1,color,opacity,pattern,false);\n    }\n\n    //! Draw a filled 2d polygon.\n    /**\n       \\param points Set of polygon vertices.\n       \\param color Pointer to \\c spectrum() consecutive values of type \\c T, defining the drawing color.\n       \\param opacity Drawing opacity.\n     **/\n    template<typename t, typename tc>\n    CImg<T>& draw_polygon(const CImg<t>& points,\n                          const tc *const color, const float opacity=1) {\n      if (is_empty() || !points) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_polygon(): Specified color is (null).\",\n                                    cimg_instance);\n\n      // Normalize 2d input coordinates (remove adjacent duplicates).\n      CImg<intT> npoints(points._width,2);\n      unsigned int nb_points = 1, p = 0;\n      int cx = npoints(0,0) = (int)points(0,0), cy = npoints(0,1) = (int)points(0,1);\n      const int cx0 = cx, cy0 = cy;\n      for (p = 1; p<points._width; ++p) {\n        const int nx = (int)points(p,0), ny = (int)points(p,1);\n        if (nx!=cx || ny!=cy) { npoints(nb_points,0) = nx; npoints(nb_points++,1) = ny; cx = nx; cy = ny; }\n      }\n      --p;\n      if ((int)points(p,0)==cx0 && (int)points(p,1)==cy0) --nb_points;\n      if (nb_points<=1) return draw_point((int)npoints(0,0),(int)npoints(0,1),color,opacity);\n      if (nb_points==2) return draw_line((int)npoints(0,0),(int)npoints(0,1),\n                                         (int)npoints(1,0),(int)npoints(1,1),color,opacity);\n      if (nb_points==3) return draw_triangle((int)npoints(0,0),(int)npoints(0,1),\n                                             (int)npoints(1,0),(int)npoints(1,1),\n                                             (int)npoints(2,0),(int)npoints(2,1),color,opacity);\n\n      // Shift the coordinates so that the first and last vertices are not located on the same scanline.\n      if (npoints(0,1)==npoints(nb_points - 1,1)) {\n        const intT y0 = npoints(0,1);\n        unsigned int off = 1;\n        while ((int)npoints(off,1)==y0 && off<nb_points) ++off;\n        if (off<nb_points) {\n          npoints.get_shared_points(0,nb_points - 1,0).shift(-(int)off,0,0,0,2);\n          npoints.get_shared_points(0,nb_points - 1,1).shift(-(int)off,0,0,0,2);\n        }\n      }\n\n      cimg_init_scanline(color,1);\n\n      if (opacity!=1) { // For non-opaque polygons, do a little trick to avoid horizontal lines artefacts.\n        npoints.resize(nb_points,2,1,1,0);\n        CImg<intT> npoints_x = npoints.get_shared_row(0), npoints_y = npoints.get_shared_row(1);\n        int xmax = 0, xmin = (int)npoints_x.min_max(xmax), ymax = 0, ymin = (int)npoints_y.min_max(ymax);\n        if (xmax<0 || xmin>=width() || ymax<0 || ymin>=height()) return *this;\n        if (ymin==ymax) return cimg_draw_scanline(xmin,xmax,ymin,color,opacity,1);\n        const unsigned int\n          nxmin = xmin<0?0:(unsigned int)xmin, nxmax = xmax>=width()?_width - 1:(unsigned int)xmax,\n          nymin = ymin<0?0:(unsigned int)ymin, nymax = ymax>=height()?_height - 1:(unsigned int)ymax,\n          dx = 1 + nxmax - nxmin,\n          dy = 1 + nymax - nymin;\n        npoints_x-=nxmin; npoints_y-=nymin;\n        unsigned char one = 1;\n        const CImg<unsigned char> mask = CImg<unsigned char>(dx,dy,1,1,0).draw_polygon(npoints,&one,1);\n        CImg<T> _color(dx,dy,1,spectrum());\n        cimg_forC(_color,c) _color.get_shared_channel(c).fill(color[c]);\n        return draw_image(nxmin,nymin,0,0,_color,mask,opacity,1);\n      }\n\n      // Draw polygon segments.\n      int\n        xmax = 0, xmin = (int)npoints.get_shared_points(0,nb_points - 1,0).min_max(xmax),\n        ymax = 0, ymin = (int)npoints.get_shared_points(0,nb_points - 1,1).min_max(ymax);\n      if (xmax<0 || xmin>=width() || ymax<0 || ymin>=height()) return *this;\n      if (ymin==ymax) return cimg_draw_scanline(xmin,xmax,ymin,color,1,1);\n      const unsigned int\n        nymin = ymin<0?0:(unsigned int)ymin,\n        nymax = ymax>=height()?_height - 1:(unsigned int)ymax,\n        dy = 1 + nymax - nymin;\n      CImg<intT> X(1 + 2*nb_points,dy,1,1,0), tmp;\n      cx = (int)npoints(0,0), cy = (int)npoints(0,1);\n      unsigned int cp = 0;\n      for (unsigned int p = 0; p<nb_points; ++p) {\n        const unsigned int np = (p!=nb_points - 1)?p + 1:0, ap = (np!=nb_points - 1)?np + 1:0;\n        const int\n          nx = (int)npoints(np,0), ny = (int)npoints(np,1), ay = (int)npoints(ap,1),\n          y0 = cy - (int)nymin, y1 = ny - (int)nymin;\n        if (y0!=y1) {\n          const int countermin = ((ny<ay && cy<ny) || (ny>ay && cy>ny))?1:0;\n          for (int x = cx, y = y0, _sx = 1, _sy = 1,\n                 _dx = nx>cx?nx - cx:((_sx=-1),cx - nx),\n                 _dy = y1>y0?y1 - y0:((_sy=-1),y0 - y1),\n                 _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy),\n                 _err = _dx>>1,\n                 _rx = _dy?(nx - cx)/_dy:0;\n               _counter>=countermin;\n               --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0))\n            if (y>=0 && y<(int)dy) X(++X(0,y),y) = x;\n          cp = np; cx = nx; cy = ny;\n        } else {\n          const int pp = (int)(cp?cp - 1:nb_points - 1), py = (int)npoints(pp,1);\n          if (y0>=0 && y0<(int)dy) {\n            cimg_draw_scanline(cx<nx?cx:nx,cx<nx?nx:cx,y0 + nymin,color,1,1);\n            if ((cy>py && ay>cy) || (cy<py && ay<cy)) X(++X(0,y0),y0) = cx;\n          }\n          if (cy!=ay) { cp = np; cx = nx; cy = ny; }\n        }\n      }\n\n      // Draw polygon scanlines.\n      for (int y = 0; y<(int)dy; ++y) {\n        tmp.assign(X.data(1,y),X(0,y),1,1,1,true).sort();\n        for (int i = 1; i<=X(0,y); ) {\n          const int xb = X(i++,y), xe = X(i++,y);\n          cimg_draw_scanline(xb,xe,nymin + y,color,1,1);\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a outlined 2d polygon \\overloading.\n    template<typename t, typename tc>\n    CImg<T>& draw_polygon(const CImg<t>& points,\n                          const tc *const color, const float opacity, const unsigned int pattern) {\n      if (is_empty() || !points || points._width<3) return *this;\n      bool ninit_hatch = true;\n      switch (points._height) {\n      case 0 : case 1 :\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_polygon(): Invalid specified point set.\",\n                                    cimg_instance);\n      case 2 : { // 2d version.\n        CImg<intT> npoints(points._width,2);\n        int x = npoints(0,0) = (int)points(0,0), y = npoints(0,1) = (int)points(0,1);\n        unsigned int nb_points = 1;\n        for (unsigned int p = 1; p<points._width; ++p) {\n          const int nx = (int)points(p,0), ny = (int)points(p,1);\n          if (nx!=x || ny!=y) { npoints(nb_points,0) = nx; npoints(nb_points++,1) = ny; x = nx; y = ny; }\n        }\n        const int x0 = (int)npoints(0,0), y0 = (int)npoints(0,1);\n        int ox = x0, oy = y0;\n        for (unsigned int i = 1; i<nb_points; ++i) {\n          const int x = (int)npoints(i,0), y = (int)npoints(i,1);\n          draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);\n          ninit_hatch = false;\n          ox = x; oy = y;\n        }\n        draw_line(ox,oy,x0,y0,color,opacity,pattern,false);\n      } break;\n      default : { // 3d version.\n        CImg<intT> npoints(points._width,3);\n        int\n          x = npoints(0,0) = (int)points(0,0),\n          y = npoints(0,1) = (int)points(0,1),\n          z = npoints(0,2) = (int)points(0,2);\n        unsigned int nb_points = 1;\n        for (unsigned int p = 1; p<points._width; ++p) {\n          const int nx = (int)points(p,0), ny = (int)points(p,1), nz = (int)points(p,2);\n          if (nx!=x || ny!=y || nz!=z) {\n            npoints(nb_points,0) = nx; npoints(nb_points,1) = ny; npoints(nb_points++,2) = nz;\n            x = nx; y = ny; z = nz;\n          }\n        }\n        const int x0 = (int)npoints(0,0), y0 = (int)npoints(0,1), z0 = (int)npoints(0,2);\n        int ox = x0, oy = y0, oz = z0;\n        for (unsigned int i = 1; i<nb_points; ++i) {\n          const int x = (int)npoints(i,0), y = (int)npoints(i,1), z = (int)npoints(i,2);\n          draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);\n          ninit_hatch = false;\n          ox = x; oy = y; oz = z;\n        }\n        draw_line(ox,oy,oz,x0,y0,z0,color,opacity,pattern,false);\n      }\n      }\n      return *this;\n    }\n\n    //! Draw a filled 2d ellipse.\n    /**\n       \\param x0 X-coordinate of the ellipse center.\n       \\param y0 Y-coordinate of the ellipse center.\n       \\param r1 First radius of the ellipse.\n       \\param r2 Second radius of the ellipse.\n       \\param angle Angle of the first radius.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename tc>\n    CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle,\n                          const tc *const color, const float opacity=1) {\n      return _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,0U);\n    }\n\n    //! Draw a filled 2d ellipse \\overloading.\n    /**\n       \\param x0 X-coordinate of the ellipse center.\n       \\param y0 Y-coordinate of the ellipse center.\n       \\param tensor Diffusion tensor describing the ellipse.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename t, typename tc>\n    CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,\n                          const tc *const color, const float opacity=1) {\n      CImgList<t> eig = tensor.get_symmetric_eigen();\n      const CImg<t> &val = eig[0], &vec = eig[1];\n      return draw_ellipse(x0,y0,std::sqrt(val(0)),std::sqrt(val(1)),\n                          std::atan2(vec(0,1),vec(0,0))*180/cimg::PI,\n                          color,opacity);\n    }\n\n    //! Draw an outlined 2d ellipse.\n    /**\n       \\param x0 X-coordinate of the ellipse center.\n       \\param y0 Y-coordinate of the ellipse center.\n       \\param r1 First radius of the ellipse.\n       \\param r2 Second radius of the ellipse.\n       \\param angle Angle of the first radius.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the outline pattern.\n    **/\n    template<typename tc>\n    CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle,\n                          const tc *const color, const float opacity, const unsigned int pattern) {\n      if (pattern) _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,pattern);\n      return *this;\n    }\n\n    //! Draw an outlined 2d ellipse \\overloading.\n    /**\n       \\param x0 X-coordinate of the ellipse center.\n       \\param y0 Y-coordinate of the ellipse center.\n       \\param tensor Diffusion tensor describing the ellipse.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the outline pattern.\n    **/\n    template<typename t, typename tc>\n    CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,\n                          const tc *const color, const float opacity,\n                          const unsigned int pattern) {\n      CImgList<t> eig = tensor.get_symmetric_eigen();\n      const CImg<t> &val = eig[0], &vec = eig[1];\n      return draw_ellipse(x0,y0,std::sqrt(val(0)),std::sqrt(val(1)),\n                          std::atan2(vec(0,1),vec(0,0))*180/cimg::PI,\n                          color,opacity,pattern);\n    }\n\n    template<typename tc>\n    CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle,\n                           const tc *const color, const float opacity,\n                           const unsigned int pattern) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_ellipse(): Specified color is (null).\",\n                                    cimg_instance);\n      if (r1<=0 || r2<=0) return draw_point(x0,y0,color,opacity);\n      cimg_init_scanline(color,opacity);\n      const float\n        nr1 = cimg::abs(r1), nr2 = cimg::abs(r2),\n        nangle = (float)(angle*cimg::PI/180),\n        u = (float)std::cos(nangle),\n        v = (float)std::sin(nangle),\n        rmax = cimg::max(nr1,nr2),\n        l1 = (float)std::pow(rmax/(nr1>0?nr1:1e-6),2),\n        l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2),\n        a = l1*u*u + l2*v*v,\n        b = u*v*(l1 - l2),\n        c = l1*v*v + l2*u*u;\n      const int\n        yb = (int)std::sqrt(a*rmax*rmax/(a*c - b*b)),\n        tymin = y0 - yb - 1,\n        tymax = y0 + yb + 1,\n        ymin = tymin<0?0:tymin,\n        ymax = tymax>=height()?height() - 1:tymax;\n      int oxmin = 0, oxmax = 0;\n      bool first_line = true;\n      for (int y = ymin; y<=ymax; ++y) {\n        const float\n          Y = y - y0 + (y<y0?0.5f:-0.5f),\n          delta = b*b*Y*Y - a*(c*Y*Y - rmax*rmax),\n          sdelta = delta>0?(float)std::sqrt(delta)/a:0.0f,\n          bY = b*Y/a,\n          fxmin = x0 - 0.5f - bY - sdelta,\n          fxmax = x0 + 0.5f - bY + sdelta;\n        const int xmin = (int)fxmin, xmax = (int)fxmax;\n        if (!pattern) cimg_draw_scanline(xmin,xmax,y,color,opacity,1);\n        else {\n          if (first_line) {\n            if (y0 - yb>=0) cimg_draw_scanline(xmin,xmax,y,color,opacity,1);\n            else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity);\n            first_line = false;\n          } else {\n            if (xmin<oxmin) cimg_draw_scanline(xmin,oxmin - 1,y,color,opacity,1);\n            else cimg_draw_scanline(oxmin + (oxmin==xmin?0:1),xmin,y,color,opacity,1);\n            if (xmax<oxmax) cimg_draw_scanline(xmax,oxmax - 1,y,color,opacity,1);\n            else cimg_draw_scanline(oxmax + (oxmax==xmax?0:1),xmax,y,color,opacity,1);\n            if (y==tymax) cimg_draw_scanline(xmin + 1,xmax - 1,y,color,opacity,1);\n          }\n        }\n        oxmin = xmin; oxmax = xmax;\n      }\n      return *this;\n    }\n\n    //! Draw a filled 2d circle.\n    /**\n       \\param x0 X-coordinate of the circle center.\n       \\param y0 Y-coordinate of the circle center.\n       \\param radius  Circle radius.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\note\n       - Circle version of the Bresenham's algorithm is used.\n    **/\n    template<typename tc>\n    CImg<T>& draw_circle(const int x0, const int y0, int radius,\n                         const tc *const color, const float opacity=1) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_circle(): Specified color is (null).\",\n                                    cimg_instance);\n      cimg_init_scanline(color,opacity);\n      if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this;\n      if (y0>=0 && y0<height()) cimg_draw_scanline(x0 - radius,x0 + radius,y0,color,opacity,1);\n      for (int f = 1 - radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) {\n        if (f>=0) {\n          const int x1 = x0 - x, x2 = x0 + x, y1 = y0 - y, y2 = y0 + y;\n          if (y1>=0 && y1<height()) cimg_draw_scanline(x1,x2,y1,color,opacity,1);\n          if (y2>=0 && y2<height()) cimg_draw_scanline(x1,x2,y2,color,opacity,1);\n          f+=(ddFy+=2); --y;\n        }\n        const bool no_diag = y!=(x++);\n        ++(f+=(ddFx+=2));\n        const int x1 = x0 - y, x2 = x0 + y, y1 = y0 - x, y2 = y0 + x;\n        if (no_diag) {\n          if (y1>=0 && y1<height()) cimg_draw_scanline(x1,x2,y1,color,opacity,1);\n          if (y2>=0 && y2<height()) cimg_draw_scanline(x1,x2,y2,color,opacity,1);\n        }\n      }\n      return *this;\n    }\n\n    //! Draw an outlined 2d circle.\n    /**\n       \\param x0 X-coordinate of the circle center.\n       \\param y0 Y-coordinate of the circle center.\n       \\param radius Circle radius.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern An integer whose bits describe the outline pattern.\n    **/\n    template<typename tc>\n    CImg<T>& draw_circle(const int x0, const int y0, int radius,\n                         const tc *const color, const float opacity,\n                         const unsigned int pattern) {\n      cimg::unused(pattern);\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_circle(): Specified color is (null).\",\n                                    cimg_instance);\n      if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this;\n      if (!radius) return draw_point(x0,y0,color,opacity);\n      draw_point(x0 - radius,y0,color,opacity).draw_point(x0 + radius,y0,color,opacity).\n        draw_point(x0,y0 - radius,color,opacity).draw_point(x0,y0 + radius,color,opacity);\n      if (radius==1) return *this;\n      for (int f = 1 - radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) {\n        if (f>=0) { f+=(ddFy+=2); --y; }\n        ++x; ++(f+=(ddFx+=2));\n        if (x!=y + 1) {\n          const int x1 = x0 - y, x2 = x0 + y, y1 = y0 - x, y2 = y0 + x,\n            x3 = x0 - x, x4 = x0 + x, y3 = y0 - y, y4 = y0 + y;\n          draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity).\n            draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity);\n          if (x!=y)\n            draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity).\n              draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity);\n        }\n      }\n      return *this;\n    }\n\n    //! Draw an image.\n    /**\n       \\param sprite Sprite image.\n       \\param x0 X-coordinate of the sprite position.\n       \\param y0 Y-coordinate of the sprite position.\n       \\param z0 Z-coordinate of the sprite position.\n       \\param c0 C-coordinate of the sprite position.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename t>\n    CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0,\n                        const CImg<t>& sprite, const float opacity=1) {\n      if (is_empty() || !sprite) return *this;\n      if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity);\n      if (x0==0 && y0==0 && z0==0 && c0==0 && is_sameXYZC(sprite) && opacity>=1 && !is_shared())\n        return assign(sprite,false);\n      const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0);\n      const int\n        lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0),\n        lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0),\n        lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),\n        lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0);\n      const t\n        *ptrs = sprite._data +\n        (bx?-x0:0) +\n        (by?-y0*(ulongT)sprite.width():0) +\n        (bz?-z0*(ulongT)sprite.width()*sprite.height():0) +\n        (bc?-c0*(ulongT)sprite.width()*sprite.height()*sprite.depth():0);\n      const ulongT\n        offX = (ulongT)_width - lX,\n        soffX = (ulongT)sprite._width - lX,\n        offY = (ulongT)_width*(_height - lY),\n        soffY = (ulongT)sprite._width*(sprite._height - lY),\n        offZ = (ulongT)_width*_height*(_depth - lZ),\n        soffZ = (ulongT)sprite._width*sprite._height*(sprite._depth - lZ);\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      if (lX>0 && lY>0 && lZ>0 && lC>0) {\n        T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0);\n        for (int v = 0; v<lC; ++v) {\n          for (int z = 0; z<lZ; ++z) {\n            for (int y = 0; y<lY; ++y) {\n              if (opacity>=1) for (int x = 0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++);\n              else for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }\n              ptrd+=offX; ptrs+=soffX;\n            }\n            ptrd+=offY; ptrs+=soffY;\n          }\n          ptrd+=offZ; ptrs+=soffZ;\n        }\n      }\n      return *this;\n    }\n\n    //! Draw an image \\specialization.\n    CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0,\n                        const CImg<T>& sprite, const float opacity=1) {\n      if (is_empty() || !sprite) return *this;\n      if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity);\n      if (x0==0 && y0==0 && z0==0 && c0==0 && is_sameXYZC(sprite) && opacity>=1 && !is_shared())\n        return assign(sprite,false);\n      const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0);\n      const int\n        lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0),\n        lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0),\n        lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),\n        lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0);\n      const T\n        *ptrs = sprite._data +\n        (bx?-x0:0) +\n        (by?-y0*(ulongT)sprite.width():0) +\n        (bz?-z0*(ulongT)sprite.width()*sprite.height():0) +\n        (bc?-c0*(ulongT)sprite.width()*sprite.height()*sprite.depth():0);\n      const ulongT\n        offX = (ulongT)_width - lX,\n        soffX = (ulongT)sprite._width - lX,\n        offY = (ulongT)_width*(_height - lY),\n        soffY = (ulongT)sprite._width*(sprite._height - lY),\n        offZ = (ulongT)_width*_height*(_depth - lZ),\n        soffZ = (ulongT)sprite._width*sprite._height*(sprite._depth - lZ),\n        slX = lX*sizeof(T);\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      if (lX>0 && lY>0 && lZ>0 && lC>0) {\n        T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0);\n        for (int v = 0; v<lC; ++v) {\n          for (int z = 0; z<lZ; ++z) {\n            if (opacity>=1)\n              for (int y = 0; y<lY; ++y) { std::memcpy(ptrd,ptrs,slX); ptrd+=_width; ptrs+=sprite._width; }\n            else for (int y = 0; y<lY; ++y) {\n                for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }\n                ptrd+=offX; ptrs+=soffX;\n              }\n            ptrd+=offY; ptrs+=soffY;\n          }\n          ptrd+=offZ; ptrs+=soffZ;\n        }\n      }\n      return *this;\n    }\n\n    //! Draw an image \\overloading.\n    template<typename t>\n    CImg<T>& draw_image(const int x0, const int y0, const int z0,\n                        const CImg<t>& sprite, const float opacity=1) {\n      return draw_image(x0,y0,z0,0,sprite,opacity);\n    }\n\n    //! Draw an image \\overloading.\n    template<typename t>\n    CImg<T>& draw_image(const int x0, const int y0,\n                        const CImg<t>& sprite, const float opacity=1) {\n      return draw_image(x0,y0,0,sprite,opacity);\n    }\n\n    //! Draw an image \\overloading.\n    template<typename t>\n    CImg<T>& draw_image(const int x0,\n                        const CImg<t>& sprite, const float opacity=1) {\n      return draw_image(x0,0,sprite,opacity);\n    }\n\n    //! Draw an image \\overloading.\n    template<typename t>\n    CImg<T>& draw_image(const CImg<t>& sprite, const float opacity=1) {\n      return draw_image(0,sprite,opacity);\n    }\n\n    //! Draw a masked image.\n    /**\n       \\param sprite Sprite image.\n       \\param mask Mask image.\n       \\param x0 X-coordinate of the sprite position in the image instance.\n       \\param y0 Y-coordinate of the sprite position in the image instance.\n       \\param z0 Z-coordinate of the sprite position in the image instance.\n       \\param c0 C-coordinate of the sprite position in the image instance.\n       \\param mask_max_value Maximum pixel value of the mask image \\c mask.\n       \\param opacity Drawing opacity.\n       \\note\n       - Pixel values of \\c mask set the opacity of the corresponding pixels in \\c sprite.\n       - Dimensions along x,y and z of \\p sprite and \\p mask must be the same.\n    **/\n    template<typename ti, typename tm>\n    CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0,\n                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,\n                        const float mask_max_value=1) {\n      if (is_empty() || !sprite || !mask) return *this;\n      if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,mask,opacity,mask_max_value);\n      if (is_overlapped(mask)) return draw_image(x0,y0,z0,c0,sprite,+mask,opacity,mask_max_value);\n      if (mask._width!=sprite._width || mask._height!=sprite._height || mask._depth!=sprite._depth)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_image(): Sprite (%u,%u,%u,%u,%p) and mask (%u,%u,%u,%u,%p) have \"\n                                    \"incompatible dimensions.\",\n                                    cimg_instance,\n                                    sprite._width,sprite._height,sprite._depth,sprite._spectrum,sprite._data,\n                                    mask._width,mask._height,mask._depth,mask._spectrum,mask._data);\n\n      const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0);\n      const int\n        lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0),\n        lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0),\n        lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),\n        lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0);\n      const ulongT\n        coff = (bx?-x0:0) +\n        (by?-y0*(ulongT)mask.width():0) +\n        (bz?-z0*(ulongT)mask.width()*mask.height():0) +\n        (bc?-c0*(ulongT)mask.width()*mask.height()*mask.depth():0),\n        ssize = (ulongT)mask.width()*mask.height()*mask.depth()*mask.spectrum();\n      const ti *ptrs = sprite._data + coff;\n      const tm *ptrm = mask._data + coff;\n      const ulongT\n        offX = (ulongT)_width - lX,\n        soffX = (ulongT)sprite._width - lX,\n        offY = (ulongT)_width*(_height - lY),\n        soffY = (ulongT)sprite._width*(sprite._height - lY),\n        offZ = (ulongT)_width*_height*(_depth - lZ),\n        soffZ = (ulongT)sprite._width*sprite._height*(sprite._depth - lZ);\n      if (lX>0 && lY>0 && lZ>0 && lC>0) {\n        T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0);\n        for (int c = 0; c<lC; ++c) {\n          ptrm = mask._data + (ptrm - mask._data)%ssize;\n          for (int z = 0; z<lZ; ++z) {\n            for (int y = 0; y<lY; ++y) {\n              for (int x = 0; x<lX; ++x) {\n                const float mopacity = (float)(*(ptrm++)*opacity),\n                  nopacity = cimg::abs(mopacity), copacity = mask_max_value - cimg::max(mopacity,0);\n                *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_max_value);\n                ++ptrd;\n              }\n              ptrd+=offX; ptrs+=soffX; ptrm+=soffX;\n            }\n            ptrd+=offY; ptrs+=soffY; ptrm+=soffY;\n          }\n          ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a masked image \\overloading.\n    template<typename ti, typename tm>\n    CImg<T>& draw_image(const int x0, const int y0, const int z0,\n                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,\n                        const float mask_max_value=1) {\n      return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_max_value);\n    }\n\n    //! Draw a image \\overloading.\n    template<typename ti, typename tm>\n    CImg<T>& draw_image(const int x0, const int y0,\n                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,\n                        const float mask_max_value=1) {\n      return draw_image(x0,y0,0,sprite,mask,opacity,mask_max_value);\n    }\n\n    //! Draw a image \\overloading.\n    template<typename ti, typename tm>\n    CImg<T>& draw_image(const int x0,\n                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,\n                        const float mask_max_value=1) {\n      return draw_image(x0,0,sprite,mask,opacity,mask_max_value);\n    }\n\n    //! Draw an image.\n    template<typename ti, typename tm>\n    CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,\n                        const float mask_max_value=1) {\n      return draw_image(0,sprite,mask,opacity,mask_max_value);\n    }\n\n    //! Draw a text string.\n    /**\n       \\param x0 X-coordinate of the text in the image instance.\n       \\param y0 Y-coordinate of the text in the image instance.\n       \\param text Format of the text ('printf'-style format string).\n       \\param foreground_color Pointer to \\c spectrum() consecutive values, defining the foreground drawing color.\n       \\param background_color Pointer to \\c spectrum() consecutive values, defining the background drawing color.\n       \\param opacity Drawing opacity.\n       \\param font Font used for drawing text.\n    **/\n    template<typename tc1, typename tc2, typename t>\n    CImg<T>& draw_text(const int x0, const int y0,\n                       const char *const text,\n                       const tc1 *const foreground_color, const tc2 *const background_color,\n                       const float opacity, const CImgList<t>& font, ...) {\n      if (!font) return *this;\n      CImg<charT> tmp(2048);\n      std::va_list ap; va_start(ap,font);\n      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);\n      return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font,false);\n    }\n\n    //! Draw a text string \\overloading.\n    /**\n       \\note A transparent background is used for the text.\n    **/\n    template<typename tc, typename t>\n    CImg<T>& draw_text(const int x0, const int y0,\n                       const char *const text,\n                       const tc *const foreground_color, const int,\n                       const float opacity, const CImgList<t>& font, ...) {\n      if (!font) return *this;\n      CImg<charT> tmp(2048);\n      std::va_list ap; va_start(ap,font);\n      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);\n      return _draw_text(x0,y0,tmp,foreground_color,(tc*)0,opacity,font,false);\n    }\n\n    //! Draw a text string \\overloading.\n    /**\n       \\note A transparent foreground is used for the text.\n    **/\n    template<typename tc, typename t>\n    CImg<T>& draw_text(const int x0, const int y0,\n                       const char *const text,\n                       const int, const tc *const background_color,\n                       const float opacity, const CImgList<t>& font, ...) {\n      if (!font) return *this;\n      CImg<charT> tmp(2048);\n      std::va_list ap; va_start(ap,font);\n      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);\n      return _draw_text(x0,y0,tmp,(tc*)0,background_color,opacity,font,false);\n    }\n\n    //! Draw a text string \\overloading.\n    /**\n       \\param x0 X-coordinate of the text in the image instance.\n       \\param y0 Y-coordinate of the text in the image instance.\n       \\param text Format of the text ('printf'-style format string).\n       \\param foreground_color Array of spectrum() values of type \\c T,\n         defining the foreground color (0 means 'transparent').\n       \\param background_color Array of spectrum() values of type \\c T,\n         defining the background color (0 means 'transparent').\n       \\param opacity Drawing opacity.\n       \\param font_height Height of the text font (exact match for 13,23,53,103, interpolated otherwise).\n    **/\n    template<typename tc1, typename tc2>\n    CImg<T>& draw_text(const int x0, const int y0,\n                       const char *const text,\n                       const tc1 *const foreground_color, const tc2 *const background_color,\n                       const float opacity=1, const unsigned int font_height=13, ...) {\n      if (!font_height) return *this;\n      CImg<charT> tmp(2048);\n      std::va_list ap; va_start(ap,font_height);\n      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);\n      const CImgList<ucharT>& font = CImgList<ucharT>::font(font_height,true);\n      _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font,true);\n      return *this;\n    }\n\n    //! Draw a text string \\overloading.\n    template<typename tc>\n    CImg<T>& draw_text(const int x0, const int y0,\n                       const char *const text,\n                       const tc *const foreground_color, const int background_color=0,\n                       const float opacity=1, const unsigned int font_height=13, ...) {\n      if (!font_height) return *this;\n      cimg::unused(background_color);\n      CImg<charT> tmp(2048);\n      std::va_list ap; va_start(ap,font_height);\n      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);\n      return draw_text(x0,y0,\"%s\",foreground_color,(const tc*)0,opacity,font_height,tmp._data);\n    }\n\n    //! Draw a text string \\overloading.\n    template<typename tc>\n    CImg<T>& draw_text(const int x0, const int y0,\n                       const char *const text,\n                       const int, const tc *const background_color,\n                       const float opacity=1, const unsigned int font_height=13, ...) {\n      if (!font_height) return *this;\n      CImg<charT> tmp(2048);\n      std::va_list ap; va_start(ap,font_height);\n      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);\n      return draw_text(x0,y0,\"%s\",(tc*)0,background_color,opacity,font_height,tmp._data);\n    }\n\n    template<typename tc1, typename tc2, typename t>\n    CImg<T>& _draw_text(const int x0, const int y0,\n                        const char *const text,\n                        const tc1 *const foreground_color, const tc2 *const background_color,\n                        const float opacity, const CImgList<t>& font,\n                        const bool is_native_font) {\n      if (!text) return *this;\n      if (!font)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_text(): Empty specified font.\",\n                                    cimg_instance);\n\n      const unsigned int text_length = (unsigned int)std::strlen(text);\n      const bool _is_empty = is_empty();\n      if (_is_empty) {\n        // If needed, pre-compute necessary size of the image\n        int x = 0, y = 0, w = 0;\n        unsigned char c = 0;\n        for (unsigned int i = 0; i<text_length; ++i) {\n          c = (unsigned char)text[i];\n          switch (c) {\n          case '\\n' : y+=font[0]._height; if (x>w) w = x; x = 0; break;\n          case '\\t' : x+=4*font[' ']._width; break;\n          default : if (c<font._width) x+=font[c]._width;\n          }\n        }\n        if (x!=0 || c=='\\n') {\n          if (x>w) w=x;\n          y+=font[0]._height;\n        }\n        assign(x0 + w,y0 + y,1,is_native_font?1:font[0]._spectrum,0);\n      }\n\n      int x = x0, y = y0;\n      for (unsigned int i = 0; i<text_length; ++i) {\n        const unsigned char c = (unsigned char)text[i];\n        switch (c) {\n        case '\\n' : y+=font[0]._height; x = x0; break;\n        case '\\t' : x+=4*font[' ']._width; break;\n        default : if (c<font._width) {\n            CImg<T> letter = font[c];\n            if (letter) {\n              if (is_native_font && _spectrum>letter._spectrum) letter.resize(-100,-100,1,_spectrum,0,2);\n              const unsigned int cmin = cimg::min(_spectrum,letter._spectrum);\n              if (foreground_color)\n                for (unsigned int c = 0; c<cmin; ++c)\n                  if (foreground_color[c]!=1) letter.get_shared_channel(c)*=foreground_color[c];\n              if (c + 256<font.width()) { // Letter has mask.\n                if (background_color)\n                  for (unsigned int c = 0; c<cmin; ++c)\n                    draw_rectangle(x,y,0,c,x + letter._width - 1,y + letter._height - 1,0,c,\n                                   background_color[c],opacity);\n                draw_image(x,y,letter,font[c + 256],opacity,255.0f);\n              } else draw_image(x,y,letter,opacity); // Letter has no mask.\n              x+=letter._width;\n            }\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a 2d vector field.\n    /**\n       \\param flow Image of 2d vectors used as input data.\n       \\param color Image of spectrum()-D vectors corresponding to the color of each arrow.\n       \\param opacity Drawing opacity.\n       \\param sampling Length (in pixels) between each arrow.\n       \\param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).\n       \\param is_arrow Tells if arrows must be drawn, instead of oriented segments.\n       \\param pattern Used pattern to draw lines.\n       \\note Clipping is supported.\n    **/\n    template<typename t1, typename t2>\n    CImg<T>& draw_quiver(const CImg<t1>& flow,\n                         const t2 *const color, const float opacity=1,\n                         const unsigned int sampling=25, const float factor=-20,\n                         const bool is_arrow=true, const unsigned int pattern=~0U) {\n      return draw_quiver(flow,CImg<t2>(color,_spectrum,1,1,1,true),opacity,sampling,factor,is_arrow,pattern);\n    }\n\n    //! Draw a 2d vector field, using a field of colors.\n    /**\n       \\param flow Image of 2d vectors used as input data.\n       \\param color Image of spectrum()-D vectors corresponding to the color of each arrow.\n       \\param opacity Opacity of the drawing.\n       \\param sampling Length (in pixels) between each arrow.\n       \\param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).\n       \\param is_arrow Tells if arrows must be drawn, instead of oriented segments.\n       \\param pattern Used pattern to draw lines.\n       \\note Clipping is supported.\n    **/\n    template<typename t1, typename t2>\n    CImg<T>& draw_quiver(const CImg<t1>& flow,\n                         const CImg<t2>& color, const float opacity=1,\n                         const unsigned int sampling=25, const float factor=-20,\n                         const bool is_arrow=true, const unsigned int pattern=~0U) {\n      if (is_empty()) return *this;\n      if (!flow || flow._spectrum!=2)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    flow._width,flow._height,flow._depth,flow._spectrum,flow._data);\n      if (sampling<=0)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_quiver(): Invalid sampling value %g \"\n                                    \"(should be >0)\",\n                                    cimg_instance,\n                                    sampling);\n      const bool colorfield = (color._width==flow._width && color._height==flow._height &&\n                               color._depth==1 && color._spectrum==_spectrum);\n      if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,is_arrow,pattern);\n      float vmax,fact;\n      if (factor<=0) {\n        float m, M = (float)flow.get_norm(2).max_min(m);\n        vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));\n        if (!vmax) vmax = 1;\n        fact = -factor;\n      } else { fact = factor; vmax = 1; }\n\n      for (unsigned int y = sampling/2; y<_height; y+=sampling)\n        for (unsigned int x = sampling/2; x<_width; x+=sampling) {\n          const unsigned int X = x*flow._width/_width, Y = y*flow._height/_height;\n          float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;\n          if (is_arrow) {\n            const int xx = (int)(x + u), yy = (int)(y + v);\n            if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y)._data,opacity,45,sampling/5.0f,pattern);\n            else draw_arrow(x,y,xx,yy,color._data,opacity,45,sampling/5.0f,pattern);\n          } else {\n            if (colorfield)\n              draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v),\n                        color.get_vector_at(X,Y)._data,opacity,pattern);\n            else draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v),\n                           color._data,opacity,pattern);\n          }\n        }\n      return *this;\n    }\n\n    //! Draw a labeled horizontal axis.\n    /**\n       \\param values_x Values along the horizontal axis.\n       \\param y Y-coordinate of the horizontal axis in the image instance.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern Drawing pattern.\n       \\param font_height Height of the labels (exact match for 13,23,53,103, interpolated otherwise).\n       \\param allow_zero Enable/disable the drawing of label '0' if found.\n    **/\n    template<typename t, typename tc>\n    CImg<T>& draw_axis(const CImg<t>& values_x, const int y,\n                       const tc *const color, const float opacity=1,\n                       const unsigned int pattern=~0U, const unsigned int font_height=13,\n                       const bool allow_zero=true) {\n      if (is_empty()) return *this;\n      const int yt = (y + 3 + font_height)<_height?y + 3:y - 2 - (int)font_height;\n      const int siz = (int)values_x.size() - 1;\n      CImg<charT> txt(32);\n      CImg<T> label;\n      if (siz<=0) { // Degenerated case.\n        draw_line(0,y,_width - 1,y,color,opacity,pattern);\n        if (!siz) {\n          cimg_snprintf(txt,txt._width,\"%g\",(double)*values_x);\n          label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);\n          const int\n            _xt = (width() - label.width())/2,\n            xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt;\n          draw_point(width()/2,y - 1,color,opacity).draw_point(width()/2,y + 1,color,opacity);\n          if (allow_zero || *txt!='0' || txt[1]!=0)\n            draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);\n        }\n      } else { // Regular case.\n        if (values_x[0]<values_x[siz]) draw_arrow(0,y,_width - 1,y,color,opacity,30,5,pattern);\n        else draw_arrow(_width - 1,y,0,y,color,opacity,30,5,pattern);\n        cimg_foroff(values_x,x) {\n          cimg_snprintf(txt,txt._width,\"%g\",(double)values_x(x));\n          label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);\n          const int\n            xi = (int)(x*(_width - 1)/siz),\n            _xt = xi - label.width()/2,\n            xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt;\n          draw_point(xi,y - 1,color,opacity).draw_point(xi,y + 1,color,opacity);\n          if (allow_zero || *txt!='0' || txt[1]!=0)\n            draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a labeled vertical axis.\n    /**\n       \\param x X-coordinate of the vertical axis in the image instance.\n       \\param values_y Values along the Y-axis.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern Drawing pattern.\n       \\param font_height Height of the labels (exact match for 13,23,53,103, interpolated otherwise).\n       \\param allow_zero Enable/disable the drawing of label '0' if found.\n    **/\n    template<typename t, typename tc>\n    CImg<T>& draw_axis(const int x, const CImg<t>& values_y,\n                       const tc *const color, const float opacity=1,\n                       const unsigned int pattern=~0U, const unsigned int font_height=13,\n                       const bool allow_zero=true) {\n      if (is_empty()) return *this;\n      int siz = (int)values_y.size() - 1;\n      CImg<charT> txt(32);\n      CImg<T> label;\n      if (siz<=0) { // Degenerated case.\n        draw_line(x,0,x,_height - 1,color,opacity,pattern);\n        if (!siz) {\n          cimg_snprintf(txt,txt._width,\"%g\",(double)*values_y);\n          label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);\n          const int\n            _yt = (height() - label.height())/2,\n            yt = _yt<0?0:_yt + label.height()>=height()?height() - 1-label.height():_yt,\n            _xt = x - 2 - label.width(),\n            xt = _xt>=0?_xt:x + 3;\n          draw_point(x - 1,height()/2,color,opacity).draw_point(x + 1,height()/2,color,opacity);\n          if (allow_zero || *txt!='0' || txt[1]!=0)\n            draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);\n        }\n      } else { // Regular case.\n        if (values_y[0]<values_y[siz]) draw_arrow(x,0,x,_height - 1,color,opacity,30,5,pattern);\n        else draw_arrow(x,_height - 1,x,0,color,opacity,30,5,pattern);\n        cimg_foroff(values_y,y) {\n          cimg_snprintf(txt,txt._width,\"%g\",(double)values_y(y));\n          label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);\n          const int\n            yi = (int)(y*(_height - 1)/siz),\n            _yt = yi - label.height()/2,\n            yt = _yt<0?0:_yt + label.height()>=height()?height() - 1-label.height():_yt,\n            _xt = x - 2 - label.width(),\n            xt = _xt>=0?_xt:x + 3;\n          draw_point(x - 1,yi,color,opacity).draw_point(x + 1,yi,color,opacity);\n          if (allow_zero || *txt!='0' || txt[1]!=0)\n            draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);\n        }\n      }\n      return *this;\n    }\n\n    //! Draw labeled horizontal and vertical axes.\n    /**\n       \\param values_x Values along the X-axis.\n       \\param values_y Values along the Y-axis.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern_x Drawing pattern for the X-axis.\n       \\param pattern_y Drawing pattern for the Y-axis.\n       \\param font_height Height of the labels (exact match for 13,23,53,103, interpolated otherwise).\n       \\param allow_zero Enable/disable the drawing of label '0' if found.\n    **/\n    template<typename tx, typename ty, typename tc>\n    CImg<T>& draw_axes(const CImg<tx>& values_x, const CImg<ty>& values_y,\n                       const tc *const color, const float opacity=1,\n                       const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U,\n                       const unsigned int font_height=13, const bool allow_zero=true) {\n      if (is_empty()) return *this;\n      const CImg<tx> nvalues_x(values_x._data,values_x.size(),1,1,1,true);\n      const int sizx = (int)values_x.size() - 1, wm1 = width() - 1;\n      if (sizx>=0) {\n        float ox = (float)*nvalues_x;\n        for (unsigned int x = sizx?1U:0U; x<_width; ++x) {\n          const float nx = (float)nvalues_x._linear_atX((float)x*sizx/wm1);\n          if (nx*ox<=0) { draw_axis(nx==0?x:x - 1,values_y,color,opacity,pattern_y,font_height,allow_zero); break; }\n          ox = nx;\n        }\n      }\n      const CImg<ty> nvalues_y(values_y._data,values_y.size(),1,1,1,true);\n      const int sizy = (int)values_y.size() - 1, hm1 = height() - 1;\n      if (sizy>0) {\n        float oy = (float)nvalues_y[0];\n        for (unsigned int y = sizy?1U:0U; y<_height; ++y) {\n          const float ny = (float)nvalues_y._linear_atX((float)y*sizy/hm1);\n          if (ny*oy<=0) { draw_axis(values_x,ny==0?y:y - 1,color,opacity,pattern_x,font_height,allow_zero); break; }\n          oy = ny;\n        }\n      }\n      return *this;\n    }\n\n    //! Draw labeled horizontal and vertical axes \\overloading.\n    template<typename tc>\n    CImg<T>& draw_axes(const float x0, const float x1, const float y0, const float y1,\n                       const tc *const color, const float opacity=1,\n                       const int subdivisionx=-60, const int subdivisiony=-60,\n                       const float precisionx=0, const float precisiony=0,\n                       const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U,\n                       const unsigned int font_height=13) {\n      if (is_empty()) return *this;\n      const bool allow_zero = (x0*x1>0) || (y0*y1>0);\n      const float\n        dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0),\n        px = dx<=0?1:precisionx==0?(float)std::pow(10.0,(int)std::log10(dx) - 2.0):precisionx,\n        py = dy<=0?1:precisiony==0?(float)std::pow(10.0,(int)std::log10(dy) - 2.0):precisiony;\n      if (x0!=x1 && y0!=y1)\n        draw_axes(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1).round(px),\n                  CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1).round(py),\n                  color,opacity,pattern_x,pattern_y,font_height,allow_zero);\n      else if (x0==x1 && y0!=y1)\n        draw_axis((int)x0,CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1).round(py),\n                  color,opacity,pattern_y,font_height);\n      else if (x0!=x1 && y0==y1)\n        draw_axis(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1).round(px),(int)y0,\n                  color,opacity,pattern_x,font_height);\n      return *this;\n    }\n\n    //! Draw 2d grid.\n    /**\n       \\param values_x X-coordinates of the vertical lines.\n       \\param values_y Y-coordinates of the horizontal lines.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n       \\param pattern_x Drawing pattern for vertical lines.\n       \\param pattern_y Drawing pattern for horizontal lines.\n    **/\n    template<typename tx, typename ty, typename tc>\n    CImg<T>& draw_grid(const CImg<tx>& values_x, const CImg<ty>& values_y,\n                       const tc *const color, const float opacity=1,\n                       const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U) {\n      if (is_empty()) return *this;\n      if (values_x) cimg_foroff(values_x,x) {\n          const int xi = (int)values_x[x];\n          if (xi>=0 && xi<width()) draw_line(xi,0,xi,_height - 1,color,opacity,pattern_x);\n        }\n      if (values_y) cimg_foroff(values_y,y) {\n          const int yi = (int)values_y[y];\n          if (yi>=0 && yi<height()) draw_line(0,yi,_width - 1,yi,color,opacity,pattern_y);\n        }\n      return *this;\n    }\n\n    //! Draw 2d grid \\simplification.\n    template<typename tc>\n    CImg<T>& draw_grid(const float delta_x,  const float delta_y,\n                       const float offsetx, const float offsety,\n                       const bool invertx, const bool inverty,\n                       const tc *const color, const float opacity=1,\n                       const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U) {\n      if (is_empty()) return *this;\n      CImg<uintT> seqx, seqy;\n      if (delta_x!=0) {\n        const float dx = delta_x>0?delta_x:_width*-delta_x/100;\n        const unsigned int nx = (unsigned int)(_width/dx);\n        seqx = CImg<uintT>::sequence(1 + nx,0,(unsigned int)(dx*nx));\n        if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x) + offsetx,(float)_width);\n        if (invertx) cimg_foroff(seqx,x) seqx(x) = _width - 1 - seqx(x);\n      }\n      if (delta_y!=0) {\n        const float dy = delta_y>0?delta_y:_height*-delta_y/100;\n        const unsigned int ny = (unsigned int)(_height/dy);\n        seqy = CImg<uintT>::sequence(1 + ny,0,(unsigned int)(dy*ny));\n        if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y) + offsety,(float)_height);\n        if (inverty) cimg_foroff(seqy,y) seqy(y) = _height - 1 - seqy(y);\n     }\n      return draw_grid(seqx,seqy,color,opacity,pattern_x,pattern_y);\n    }\n\n    //! Draw 1d graph.\n    /**\n       \\param data Image containing the graph values I = f(x).\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n\n       \\param plot_type Define the type of the plot:\n                      - 0 = No plot.\n                      - 1 = Plot using segments.\n                      - 2 = Plot using cubic splines.\n                      - 3 = Plot with bars.\n       \\param vertex_type Define the type of points:\n                      - 0 = No points.\n                      - 1 = Point.\n                      - 2 = Straight cross.\n                      - 3 = Diagonal cross.\n                      - 4 = Filled circle.\n                      - 5 = Outlined circle.\n                      - 6 = Square.\n                      - 7 = Diamond.\n       \\param ymin Lower bound of the y-range.\n       \\param ymax Upper bound of the y-range.\n       \\param pattern Drawing pattern.\n       \\note\n         - if \\c ymin==ymax==0, the y-range is computed automatically from the input samples.\n    **/\n    template<typename t, typename tc>\n    CImg<T>& draw_graph(const CImg<t>& data,\n                        const tc *const color, const float opacity=1,\n                        const unsigned int plot_type=1, const int vertex_type=1,\n                        const double ymin=0, const double ymax=0, const unsigned int pattern=~0U) {\n      if (is_empty() || _height<=1) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_graph(): Specified color is (null).\",\n                                    cimg_instance);\n\n      // Create shaded colors for displaying bar plots.\n      CImg<tc> color1, color2;\n      if (plot_type==3) {\n        color1.assign(_spectrum); color2.assign(_spectrum);\n        cimg_forC(*this,c) {\n          color1[c] = (tc)cimg::min((float)cimg::type<tc>::max(),color[c]*1.2f);\n          color2[c] = (tc)(color[c]*0.4f);\n        }\n      }\n\n      // Compute min/max and normalization factors.\n      const ulongT\n        siz = data.size(),\n        _siz1 = siz - (plot_type!=3?1:0),\n        siz1 = _siz1?_siz1:1;\n      const unsigned int\n        _width1 = _width - (plot_type!=3?1:0),\n        width1 = _width1?_width1:1;\n      double m = ymin, M = ymax;\n      if (ymin==ymax) m = (double)data.max_min(M);\n      if (m==M) { --m; ++M; }\n      const float ca = (float)(M-m)/(_height - 1);\n      bool init_hatch = true;\n\n      // Draw graph edges\n      switch (plot_type%4) {\n      case 1 : { // Segments\n        int oX = 0, oY = (int)((data[0] - m)/ca);\n        if (siz==1) {\n          const int Y = (int)((*data - m)/ca);\n          draw_line(0,Y,width() - 1,Y,color,opacity,pattern);\n        } else {\n          const float fx = (float)_width/siz1;\n          for (ulongT off = 1; off<siz; ++off) {\n            const int\n              X = (int)(off*fx) - 1,\n              Y = (int)((data[off]-m)/ca);\n            draw_line(oX,oY,X,Y,color,opacity,pattern,init_hatch);\n            oX = X; oY = Y;\n            init_hatch = false;\n          }\n        }\n      } break;\n      case 2 : { // Spline\n        const CImg<t> ndata(data._data,siz,1,1,1,true);\n        int oY = (int)((data[0] - m)/ca);\n        cimg_forX(*this,x) {\n          const int Y = (int)((ndata._cubic_atX((float)x*siz1/width1)-m)/ca);\n          if (x>0) draw_line(x,oY,x + 1,Y,color,opacity,pattern,init_hatch);\n          init_hatch = false;\n          oY = Y;\n        }\n      } break;\n      case 3 : { // Bars\n        const int Y0 = (int)(-m/ca);\n        const float fx = (float)_width/siz1;\n        int oX = 0;\n        cimg_foroff(data,off) {\n          const int\n            X = (int)((off + 1)*fx) - 1,\n            Y = (int)((data[off] - m)/ca);\n          draw_rectangle(oX,Y0,X,Y,color,opacity).\n            draw_line(oX,Y,oX,Y0,color2.data(),opacity).\n            draw_line(oX,Y0,X,Y0,Y<=Y0?color2.data():color1.data(),opacity).\n            draw_line(X,Y,X,Y0,color1.data(),opacity).\n            draw_line(oX,Y,X,Y,Y<=Y0?color1.data():color2.data(),opacity);\n          oX = X + 1;\n        }\n      } break;\n      default : break; // No edges\n      }\n\n      // Draw graph points\n      const unsigned int wb2 = plot_type==3?_width1/(2*siz):0;\n      const float fx = (float)_width1/siz1;\n      switch (vertex_type%8) {\n      case 1 : { // Point\n        cimg_foroff(data,off) {\n          const int\n            X = (int)(off*fx + wb2),\n            Y = (int)((data[off]-m)/ca);\n          draw_point(X,Y,color,opacity);\n        }\n      } break;\n      case 2 : { // Straight Cross\n        cimg_foroff(data,off) {\n          const int\n            X = (int)(off*fx + wb2),\n            Y = (int)((data[off]-m)/ca);\n          draw_line(X - 3,Y,X + 3,Y,color,opacity).draw_line(X,Y - 3,X,Y + 3,color,opacity);\n        }\n      } break;\n      case 3 : { // Diagonal Cross\n        cimg_foroff(data,off) {\n          const int\n            X = (int)(off*fx + wb2),\n            Y = (int)((data[off]-m)/ca);\n          draw_line(X - 3,Y - 3,X + 3,Y + 3,color,opacity).draw_line(X - 3,Y + 3,X + 3,Y - 3,color,opacity);\n        }\n      } break;\n      case 4 : { // Filled Circle\n        cimg_foroff(data,off) {\n          const int\n            X = (int)(off*fx + wb2),\n            Y = (int)((data[off]-m)/ca);\n          draw_circle(X,Y,3,color,opacity);\n        }\n      } break;\n      case 5 : { // Outlined circle\n        cimg_foroff(data,off) {\n          const int\n            X = (int)(off*fx + wb2),\n            Y = (int)((data[off]-m)/ca);\n          draw_circle(X,Y,3,color,opacity,0U);\n        }\n      } break;\n      case 6 : { // Square\n        cimg_foroff(data,off) {\n          const int\n            X = (int)(off*fx + wb2),\n            Y = (int)((data[off]-m)/ca);\n          draw_rectangle(X - 3,Y - 3,X + 3,Y + 3,color,opacity,~0U);\n        }\n      } break;\n      case 7 : { // Diamond\n        cimg_foroff(data,off) {\n          const int\n            X = (int)(off*fx + wb2),\n            Y = (int)((data[off]-m)/ca);\n          draw_line(X,Y - 4,X + 4,Y,color,opacity).\n            draw_line(X + 4,Y,X,Y + 4,color,opacity).\n            draw_line(X,Y + 4,X - 4,Y,color,opacity).\n            draw_line(X - 4,Y,X,Y - 4,color,opacity);\n        }\n      } break;\n      default : break; // No points\n      }\n      return *this;\n    }\n\n    //! Draw filled 3d region with the flood fill algorithm.\n    /**\n       \\param x X-coordinate of the starting point of the region to fill.\n       \\param y Y-coordinate of the starting point of the region to fill.\n       \\param z Z-coordinate of the starting point of the region to fill.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param[out] region Image that will contain the mask of the filled region mask, as an output.\n       \\param sigma Tolerance concerning neighborhood values.\n       \\param opacity Opacity of the drawing.\n       \\param is_high_connexity Tells if 8-connexity must be used (only for 2d images).\n       \\return \\c region is initialized with the binary mask of the filled region.\n    **/\n    template<typename tc, typename t>\n    CImg<T>& draw_fill(const int x, const int y, const int z,\n                       const tc *const color, const float opacity,\n                       CImg<t>& region, const float sigma=0,\n                       const bool is_high_connexity=false) {\n\n#define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \\\n  res = true; \\\n  const T *reference_col = reference_color._data + _spectrum, *ptrs = data(x,y,z) + siz; \\\n  for (unsigned int i = _spectrum; res && i; --i) { ptrs-=whd; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \\\n  region(x,y,z) = (t)(res?1:noregion); \\\n}\n\n#define _cimg_draw_fill_set(x,y,z) { \\\n  const tc *col = color; \\\n  T *ptrd = data(x,y,z); \\\n  if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } \\\n  else cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; } \\\n}\n\n#define _cimg_draw_fill_insert(x,y,z) { \\\n  if (posr1>=remaining._height) remaining.resize(3,remaining._height<<1,1,1,0); \\\n  unsigned int *ptrr = remaining.data(0,posr1); \\\n  *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \\\n}\n\n#define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \\\n  const unsigned int tx = x, ty = y, tz = z; \\\n  _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \\\n}\n\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_fill(): Specified color is (null).\",\n                                    cimg_instance);\n\n      region.assign(_width,_height,_depth,1,(t)0);\n      if (x>=0 && x<width() && y>=0 && y<height() && z>=0 && z<depth()) {\n        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n        const ulongT whd = (ulongT)_width*_height*_depth, siz = (ulongT)_spectrum*whd;\n        const unsigned int W1 = _width - 1, H1 = _height - 1, D1 = _depth - 1;\n        const bool is_3d = (_depth>1);\n        const CImg<T> reference_color = get_vector_at(x,y,z);\n        CImg<uintT> remaining(3,512,1,1,0);\n        remaining(0,0) = (unsigned int)x;\n        remaining(1,0) = (unsigned int)y;\n        remaining(2,0) = (unsigned int)z;\n        unsigned int posr0 = 0, posr1 = 1;\n        region(x,y,z) = (t)1;\n        const t noregion = ((t)1==(t)2)?(t)0:(t)-1;\n        if (is_3d) do { // 3d version of the filling algorithm\n          const unsigned int *pcurr = remaining.data(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++);\n          if (posr0>=512) { remaining.shift(0,-(int)posr0); posr1-=posr0; posr0 = 0; }\n          bool cont, res;\n          unsigned int nxc = xc;\n          do { // X-backward\n            _cimg_draw_fill_set(nxc,yc,zc);\n            _cimg_draw_fill_test_neighbor(nxc,yc - 1,zc,yc!=0);\n            _cimg_draw_fill_test_neighbor(nxc,yc + 1,zc,yc<H1);\n            _cimg_draw_fill_test_neighbor(nxc,yc,zc - 1,zc!=0);\n            _cimg_draw_fill_test_neighbor(nxc,yc,zc + 1,zc<D1);\n            if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;\n          } while (cont);\n          nxc = xc;\n          do { // X-forward\n            if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;\n            if (cont) {\n              _cimg_draw_fill_set(nxc,yc,zc);\n              _cimg_draw_fill_test_neighbor(nxc,yc - 1,zc,yc!=0);\n              _cimg_draw_fill_test_neighbor(nxc,yc + 1,zc,yc<H1);\n              _cimg_draw_fill_test_neighbor(nxc,yc,zc - 1,zc!=0);\n              _cimg_draw_fill_test_neighbor(nxc,yc,zc + 1,zc<D1);\n            }\n          } while (cont);\n          unsigned int nyc = yc;\n          do { // Y-backward\n            if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;\n            if (cont) {\n              _cimg_draw_fill_set(xc,nyc,zc);\n              _cimg_draw_fill_test_neighbor(xc - 1,nyc,zc,xc!=0);\n              _cimg_draw_fill_test_neighbor(xc + 1,nyc,zc,xc<W1);\n              _cimg_draw_fill_test_neighbor(xc,nyc,zc - 1,zc!=0);\n              _cimg_draw_fill_test_neighbor(xc,nyc,zc + 1,zc<D1);\n            }\n          } while (cont);\n          nyc = yc;\n          do { // Y-forward\n            if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;\n            if (cont) {\n              _cimg_draw_fill_set(xc,nyc,zc);\n              _cimg_draw_fill_test_neighbor(xc - 1,nyc,zc,xc!=0);\n              _cimg_draw_fill_test_neighbor(xc + 1,nyc,zc,xc<W1);\n              _cimg_draw_fill_test_neighbor(xc,nyc,zc - 1,zc!=0);\n              _cimg_draw_fill_test_neighbor(xc,nyc,zc + 1,zc<D1);\n            }\n          } while (cont);\n          unsigned int nzc = zc;\n          do { // Z-backward\n            if (nzc) { --nzc; _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;\n            if (cont) {\n              _cimg_draw_fill_set(xc,yc,nzc);\n              _cimg_draw_fill_test_neighbor(xc - 1,yc,nzc,xc!=0);\n              _cimg_draw_fill_test_neighbor(xc + 1,yc,nzc,xc<W1);\n              _cimg_draw_fill_test_neighbor(xc,yc - 1,nzc,yc!=0);\n              _cimg_draw_fill_test_neighbor(xc,yc + 1,nzc,yc<H1);\n            }\n          } while (cont);\n          nzc = zc;\n          do { // Z-forward\n            if ((++nzc)<=D1) { _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;\n            if (cont) {\n              _cimg_draw_fill_set(xc,nyc,zc);\n              _cimg_draw_fill_test_neighbor(xc - 1,yc,nzc,xc!=0);\n              _cimg_draw_fill_test_neighbor(xc + 1,yc,nzc,xc<W1);\n              _cimg_draw_fill_test_neighbor(xc,yc - 1,nzc,yc!=0);\n              _cimg_draw_fill_test_neighbor(xc,yc + 1,nzc,yc<H1);\n            }\n          } while (cont);\n        } while (posr1>posr0);\n        else do { // 2d version of the filling algorithm\n          const unsigned int *pcurr = remaining.data(0,posr0++), xc = *(pcurr++), yc = *(pcurr++);\n          if (posr0>=512) { remaining.shift(0,-(int)posr0); posr1-=posr0; posr0 = 0; }\n          bool cont, res;\n          unsigned int nxc = xc;\n          do { // X-backward\n            _cimg_draw_fill_set(nxc,yc,0);\n            _cimg_draw_fill_test_neighbor(nxc,yc - 1,0,yc!=0);\n            _cimg_draw_fill_test_neighbor(nxc,yc + 1,0,yc<H1);\n            if (is_high_connexity) {\n              _cimg_draw_fill_test_neighbor(nxc - 1,yc - 1,0,(nxc!=0 && yc!=0));\n              _cimg_draw_fill_test_neighbor(nxc + 1,yc - 1,0,(nxc<W1 && yc!=0));\n              _cimg_draw_fill_test_neighbor(nxc - 1,yc + 1,0,(nxc!=0 && yc<H1));\n              _cimg_draw_fill_test_neighbor(nxc + 1,yc + 1,0,(nxc<W1 && yc<H1));\n            }\n            if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;\n          } while (cont);\n          nxc = xc;\n          do { // X-forward\n            if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;\n            if (cont) {\n              _cimg_draw_fill_set(nxc,yc,0);\n              _cimg_draw_fill_test_neighbor(nxc,yc - 1,0,yc!=0);\n              _cimg_draw_fill_test_neighbor(nxc,yc + 1,0,yc<H1);\n              if (is_high_connexity) {\n                _cimg_draw_fill_test_neighbor(nxc - 1,yc - 1,0,(nxc!=0 && yc!=0));\n                _cimg_draw_fill_test_neighbor(nxc + 1,yc - 1,0,(nxc<W1 && yc!=0));\n                _cimg_draw_fill_test_neighbor(nxc - 1,yc + 1,0,(nxc!=0 && yc<H1));\n                _cimg_draw_fill_test_neighbor(nxc + 1,yc + 1,0,(nxc<W1 && yc<H1));\n              }\n            }\n          } while (cont);\n          unsigned int nyc = yc;\n          do { // Y-backward\n            if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;\n            if (cont) {\n              _cimg_draw_fill_set(xc,nyc,0);\n              _cimg_draw_fill_test_neighbor(xc - 1,nyc,0,xc!=0);\n              _cimg_draw_fill_test_neighbor(xc + 1,nyc,0,xc<W1);\n              if (is_high_connexity) {\n                _cimg_draw_fill_test_neighbor(xc - 1,nyc - 1,0,(xc!=0 && nyc!=0));\n                _cimg_draw_fill_test_neighbor(xc + 1,nyc - 1,0,(xc<W1 && nyc!=0));\n                _cimg_draw_fill_test_neighbor(xc - 1,nyc + 1,0,(xc!=0 && nyc<H1));\n                _cimg_draw_fill_test_neighbor(xc + 1,nyc + 1,0,(xc<W1 && nyc<H1));\n              }\n            }\n          } while (cont);\n          nyc = yc;\n          do { // Y-forward\n            if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;\n            if (cont) {\n              _cimg_draw_fill_set(xc,nyc,0);\n              _cimg_draw_fill_test_neighbor(xc - 1,nyc,0,xc!=0);\n              _cimg_draw_fill_test_neighbor(xc + 1,nyc,0,xc<W1);\n              if (is_high_connexity) {\n                _cimg_draw_fill_test_neighbor(xc - 1,nyc - 1,0,(xc!=0 && nyc!=0));\n                _cimg_draw_fill_test_neighbor(xc + 1,nyc - 1,0,(xc<W1 && nyc!=0));\n                _cimg_draw_fill_test_neighbor(xc - 1,nyc + 1,0,(xc!=0 && nyc<H1));\n                _cimg_draw_fill_test_neighbor(xc + 1,nyc + 1,0,(xc<W1 && nyc<H1));\n              }\n            }\n          } while (cont);\n        } while (posr1>posr0);\n        if (noregion) cimg_for(region,ptrd,t) if (*ptrd==noregion) *ptrd = (t)0;\n      }\n      return *this;\n    }\n\n    //! Draw filled 3d region with the flood fill algorithm \\simplification.\n    template<typename tc>\n    CImg<T>& draw_fill(const int x, const int y, const int z,\n                       const tc *const color, const float opacity=1,\n                       const float sigma=0, const bool is_high_connexity=false) {\n      CImg<boolT> tmp;\n      return draw_fill(x,y,z,color,opacity,tmp,sigma,is_high_connexity);\n    }\n\n    //! Draw filled 2d region with the flood fill algorithm \\simplification.\n    template<typename tc>\n    CImg<T>& draw_fill(const int x, const int y,\n                       const tc *const color, const float opacity=1,\n                       const float sigma=0, const bool is_high_connexity=false) {\n      CImg<boolT> tmp;\n      return draw_fill(x,y,0,color,opacity,tmp,sigma,is_high_connexity);\n    }\n\n    //! Draw a random plasma texture.\n    /**\n       \\param alpha Alpha-parameter.\n       \\param beta Beta-parameter.\n       \\param scale Scale-parameter.\n       \\note Use the mid-point algorithm to render.\n    **/\n    CImg<T>& draw_plasma(const float alpha=1, const float beta=0, const unsigned int scale=8) {\n      if (is_empty()) return *this;\n      const int w = width(), h = height();\n      const Tfloat m = (Tfloat)cimg::type<T>::min(), M = (Tfloat)cimg::type<T>::max();\n      cimg_forZC(*this,z,c) {\n        CImg<T> ref = get_shared_slice(z,c);\n        for (int delta = 1<<cimg::min(scale,31U); delta>1; delta>>=1) {\n          const int delta2 = delta>>1;\n          const float r = alpha*delta + beta;\n\n          // Square step.\n          for (int y0 = 0; y0<h; y0+=delta)\n            for (int x0 = 0; x0<w; x0+=delta) {\n              const int x1 = (x0 + delta)%w, y1 = (y0 + delta)%h, xc = (x0 + delta2)%w, yc = (y0 + delta2)%h;\n              const Tfloat val = (Tfloat)(0.25f*(ref(x0,y0) + ref(x0,y1) + ref(x0,y1) + ref(x1,y1)) +\n                                          r*cimg::rand(-1,1));\n              ref(xc,yc) = (T)(val<m?m:val>M?M:val);\n            }\n\n          // Diamond steps.\n          for (int y = -delta2; y<h; y+=delta)\n            for (int x0=0; x0<w; x0+=delta) {\n              const int y0 = cimg::mod(y,h), x1 = (x0 + delta)%w, y1 = (y + delta)%h,\n                xc = (x0 + delta2)%w, yc = (y + delta2)%h;\n              const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) +\n                                          r*cimg::rand(-1,1));\n              ref(xc,yc) = (T)(val<m?m:val>M?M:val);\n            }\n          for (int y0 = 0; y0<h; y0+=delta)\n            for (int x = -delta2; x<w; x+=delta) {\n              const int x0 = cimg::mod(x,w), x1 = (x + delta)%w, y1 = (y0 + delta)%h,\n                xc = (x + delta2)%w, yc = (y0 + delta2)%h;\n              const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) +\n                                          r*cimg::rand(-1,1));\n              ref(xc,yc) = (T)(val<m?m:val>M?M:val);\n            }\n          for (int y = -delta2; y<h; y+=delta)\n            for (int x = -delta2; x<w; x+=delta) {\n              const int x0 = cimg::mod(x,w), y0 = cimg::mod(y,h), x1 = (x + delta)%w, y1 = (y + delta)%h,\n                xc = (x + delta2)%w, yc = (y + delta2)%h;\n              const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) +\n                                          r*cimg::rand(-1,1));\n                ref(xc,yc) = (T)(val<m?m:val>M?M:val);\n            }\n        }\n      }\n      return *this;\n    }\n\n    //! Draw a quadratic Mandelbrot or Julia 2d fractal.\n    /**\n       \\param x0 X-coordinate of the upper-left pixel.\n       \\param y0 Y-coordinate of the upper-left pixel.\n       \\param x1 X-coordinate of the lower-right pixel.\n       \\param y1 Y-coordinate of the lower-right pixel.\n       \\param colormap Colormap.\n       \\param opacity Drawing opacity.\n       \\param z0r Real part of the upper-left fractal vertex.\n       \\param z0i Imaginary part of the upper-left fractal vertex.\n       \\param z1r Real part of the lower-right fractal vertex.\n       \\param z1i Imaginary part of the lower-right fractal vertex.\n       \\param iteration_max Maximum number of iterations for each estimated point.\n       \\param is_normalized_iteration Tells if iterations are normalized.\n       \\param is_julia_set Tells if the Mandelbrot or Julia set is rendered.\n       \\param param_r Real part of the Julia set parameter.\n       \\param param_i Imaginary part of the Julia set parameter.\n       \\note Fractal rendering is done by the Escape Time Algorithm.\n    **/\n    template<typename tc>\n    CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1,\n                             const CImg<tc>& colormap, const float opacity=1,\n                             const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,\n                             const unsigned int iteration_max=255,\n                             const bool is_normalized_iteration=false,\n                             const bool is_julia_set=false,\n                             const double param_r=0, const double param_i=0) {\n      if (is_empty()) return *this;\n      CImg<tc> palette;\n      if (colormap) palette.assign(colormap._data,colormap.size()/colormap._spectrum,1,1,colormap._spectrum,true);\n      if (palette && palette._spectrum!=_spectrum)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_mandelbrot(): Instance and specified colormap (%u,%u,%u,%u,%p) have \"\n                                    \"incompatible dimensions.\",\n                                    cimg_instance,\n                                    colormap._width,colormap._height,colormap._depth,colormap._spectrum,colormap._data);\n\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), ln2 = (float)std::log(2.0);\n      const int\n        _x0 = x0<0?0:x0>=width()?width() - 1:x0,\n        _y0 = y0<0?0:y0>=height()?height() - 1:y0,\n        _x1 = x1<0?1:x1>=width()?width() - 1:x1,\n        _y1 = y1<0?1:y1>=height()?height() - 1:y1;\n#ifdef cimg_use_openmp\n#pragma omp parallel for collapse(2) if ((1 + _x1 - _x0)*(1 + _y1 - _y0)>=2048)\n#endif\n      for (int q = _y0; q<=_y1; ++q)\n        for (int p = _x0; p<=_x1; ++p) {\n          unsigned int iteration = 0;\n          const double x = z0r + p*(z1r-z0r)/_width, y = z0i + q*(z1i-z0i)/_height;\n          double zr, zi, cr, ci;\n          if (is_julia_set) { zr = x; zi = y; cr = param_r; ci = param_i; }\n          else { zr = param_r; zi = param_i; cr = x; ci = y; }\n          for (iteration=1; zr*zr + zi*zi<=4 && iteration<=iteration_max; ++iteration) {\n            const double temp = zr*zr - zi*zi + cr;\n            zi = 2*zr*zi + ci;\n            zr = temp;\n          }\n          if (iteration>iteration_max) {\n            if (palette) {\n              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette(0,c);\n              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(0,c)*nopacity + (*this)(p,q,0,c)*copacity);\n            } else {\n              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)0;\n              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)((*this)(p,q,0,c)*copacity);\n            }\n          } else if (is_normalized_iteration) {\n            const float\n              normz = (float)cimg::abs(zr*zr + zi*zi),\n              niteration = (float)(iteration + 1 - std::log(std::log(normz))/ln2);\n            if (palette) {\n              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._linear_atX(niteration,c);\n              else cimg_forC(*this,c)\n                     (*this)(p,q,0,c) = (T)(palette._linear_atX(niteration,c)*nopacity + (*this)(p,q,0,c)*copacity);\n            } else {\n              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)niteration;\n              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(niteration*nopacity + (*this)(p,q,0,c)*copacity);\n            }\n          } else {\n            if (palette) {\n              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._atX(iteration,c);\n              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(iteration,c)*nopacity + (*this)(p,q,0,c)*copacity);\n            } else {\n              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)iteration;\n              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(iteration*nopacity + (*this)(p,q,0,c)*copacity);\n            }\n          }\n        }\n      return *this;\n    }\n\n    //! Draw a quadratic Mandelbrot or Julia 2d fractal \\overloading.\n    template<typename tc>\n    CImg<T>& draw_mandelbrot(const CImg<tc>& colormap, const float opacity=1,\n                             const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,\n                             const unsigned int iteration_max=255,\n                             const bool is_normalized_iteration=false,\n                             const bool is_julia_set=false,\n                             const double param_r=0, const double param_i=0) {\n      return draw_mandelbrot(0,0,_width - 1,_height - 1,colormap,opacity,\n                             z0r,z0i,z1r,z1i,iteration_max,is_normalized_iteration,is_julia_set,param_r,param_i);\n    }\n\n    //! Draw a 1d gaussian function.\n    /**\n       \\param xc X-coordinate of the gaussian center.\n       \\param sigma Standard variation of the gaussian distribution.\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename tc>\n    CImg<T>& draw_gaussian(const float xc, const float sigma,\n                           const tc *const color, const float opacity=1) {\n      if (is_empty()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_gaussian(): Specified color is (null).\",\n                                    cimg_instance);\n      const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      const tc *col = color;\n      cimg_forX(*this,x) {\n        const float dx = (x - xc), val = (float)std::exp(-dx*dx/sigma2);\n        T *ptrd = data(x,0,0,0);\n        if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; }\n        else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; }\n        col-=_spectrum;\n      }\n      return *this;\n    }\n\n    //! Draw a 2d gaussian function.\n    /**\n       \\param xc X-coordinate of the gaussian center.\n       \\param yc Y-coordinate of the gaussian center.\n       \\param tensor Covariance matrix (must be 2x2).\n       \\param color Pointer to \\c spectrum() consecutive values, defining the drawing color.\n       \\param opacity Drawing opacity.\n    **/\n    template<typename t, typename tc>\n    CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,\n                           const tc *const color, const float opacity=1) {\n      if (is_empty()) return *this;\n      if (tensor._width!=2 || tensor._height!=2 || tensor._depth!=1 || tensor._spectrum!=1)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a 2x2 matrix.\",\n                                    cimg_instance,\n                                    tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data);\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_gaussian(): Specified color is (null).\",\n                                    cimg_instance);\n      typedef typename CImg<t>::Tfloat tfloat;\n      const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);\n      const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      const tc *col = color;\n      float dy = -yc;\n      cimg_forY(*this,y) {\n        float dx = -xc;\n        cimg_forX(*this,x) {\n          const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy);\n          T *ptrd = data(x,y,0,0);\n          if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; }\n          else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; }\n          col-=_spectrum;\n          ++dx;\n        }\n        ++dy;\n      }\n      return *this;\n    }\n\n    //! Draw a 2d gaussian function \\overloading.\n    template<typename tc>\n    CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,\n                           const tc *const color, const float opacity=1) {\n      const double\n        a = r1*ru*ru + r2*rv*rv,\n        b = (r1-r2)*ru*rv,\n        c = r1*rv*rv + r2*ru*ru;\n      const CImg<Tfloat> tensor(2,2,1,1, a,b,b,c);\n      return draw_gaussian(xc,yc,tensor,color,opacity);\n    }\n\n    //! Draw a 2d gaussian function \\overloading.\n    template<typename tc>\n    CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,\n                           const tc *const color, const float opacity=1) {\n      return draw_gaussian(xc,yc,CImg<floatT>::diagonal(sigma,sigma),color,opacity);\n    }\n\n    //! Draw a 3d gaussian function \\overloading.\n    template<typename t, typename tc>\n    CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,\n                           const tc *const color, const float opacity=1) {\n      if (is_empty()) return *this;\n      typedef typename CImg<t>::Tfloat tfloat;\n      if (tensor._width!=3 || tensor._height!=3 || tensor._depth!=1 || tensor._spectrum!=1)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a 3x3 matrix.\",\n                                    cimg_instance,\n                                    tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data);\n\n      const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);\n      const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = 2*invT2(2,0), d = invT2(1,1), e = 2*invT2(2,1), f = invT2(2,2);\n      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);\n      const ulongT whd = (ulongT)_width*_height*_depth;\n      const tc *col = color;\n      cimg_forXYZ(*this,x,y,z) {\n        const float\n          dx = (x - xc), dy = (y - yc), dz = (z - zc),\n          val = (float)std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);\n        T *ptrd = data(x,y,z,0);\n        if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; }\n        else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; }\n        col-=_spectrum;\n      }\n      return *this;\n    }\n\n    //! Draw a 3d gaussian function \\overloading.\n    template<typename tc>\n    CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,\n                           const tc *const color, const float opacity=1) {\n      return draw_gaussian(xc,yc,zc,CImg<floatT>::diagonal(sigma,sigma,sigma),color,opacity);\n    }\n\n    //! Draw a 3d object.\n    /**\n       \\param x0 X-coordinate of the 3d object position\n       \\param y0 Y-coordinate of the 3d object position\n       \\param z0 Z-coordinate of the 3d object position\n       \\param vertices Image Nx3 describing 3d point coordinates\n       \\param primitives List of P primitives\n       \\param colors List of P color (or textures)\n       \\param opacities Image or list of P opacities\n       \\param render_type d Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud)\n       \\param is_double_sided Tells if object faces have two sides or are oriented.\n       \\param focale length of the focale (0 for parallel projection)\n       \\param lightx X-coordinate of the light\n       \\param lighty Y-coordinate of the light\n       \\param lightz Z-coordinate of the light\n       \\param specular_lightness Amount of specular light.\n       \\param specular_shininess Shininess of the object\n    **/\n    template<typename tp, typename tf, typename tc, typename to>\n    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors, const CImg<to>& opacities,\n                           const unsigned int render_type=4,\n                           const bool is_double_sided=false, const float focale=700,\n                           const float lightx=0, const float lighty=0, const float lightz=-5e8,\n                           const float specular_lightness=0.2f, const float specular_shininess=0.1f) {\n      return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,render_type,\n                           is_double_sided,focale,lightx,lighty,lightz,\n                           specular_lightness,specular_shininess,CImg<floatT>::empty());\n    }\n\n    //! Draw a 3d object \\simplification.\n    template<typename tp, typename tf, typename tc, typename to, typename tz>\n    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors, const CImg<to>& opacities,\n                           const unsigned int render_type,\n                           const bool is_double_sided, const float focale,\n                           const float lightx, const float lighty, const float lightz,\n                           const float specular_lightness, const float specular_shininess,\n                           CImg<tz>& zbuffer) {\n      return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,\n                            render_type,is_double_sided,focale,lightx,lighty,lightz,\n                            specular_lightness,specular_shininess,1);\n    }\n\n#ifdef cimg_use_board\n    template<typename tp, typename tf, typename tc, typename to>\n    CImg<T>& draw_object3d(LibBoard::Board& board,\n                           const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors, const CImg<to>& opacities,\n                           const unsigned int render_type=4,\n                           const bool is_double_sided=false, const float focale=700,\n                           const float lightx=0, const float lighty=0, const float lightz=-5e8,\n                           const float specular_lightness=0.2f, const float specular_shininess=0.1f) {\n      return draw_object3d(board,x0,y0,z0,vertices,primitives,colors,opacities,render_type,\n                           is_double_sided,focale,lightx,lighty,lightz,\n                           specular_lightness,specular_shininess,CImg<floatT>::empty());\n    }\n\n    template<typename tp, typename tf, typename tc, typename to, typename tz>\n    CImg<T>& draw_object3d(LibBoard::Board& board,\n                           const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors, const CImg<to>& opacities,\n                           const unsigned int render_type,\n                           const bool is_double_sided, const float focale,\n                           const float lightx, const float lighty, const float lightz,\n                           const float specular_lightness, const float specular_shininess,\n                           CImg<tz>& zbuffer) {\n      return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,\n                            render_type,is_double_sided,focale,lightx,lighty,lightz,\n                            specular_lightness,specular_shininess,1);\n    }\n#endif\n\n    //! Draw a 3d object \\simplification.\n    template<typename tp, typename tf, typename tc, typename to>\n    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors, const CImgList<to>& opacities,\n                           const unsigned int render_type=4,\n                           const bool is_double_sided=false, const float focale=700,\n                           const float lightx=0, const float lighty=0, const float lightz=-5e8,\n                           const float specular_lightness=0.2f, const float specular_shininess=0.1f) {\n      return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,render_type,\n                           is_double_sided,focale,lightx,lighty,lightz,\n                           specular_lightness,specular_shininess,CImg<floatT>::empty());\n    }\n\n    //! Draw a 3d object \\simplification.\n    template<typename tp, typename tf, typename tc, typename to, typename tz>\n    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors, const CImgList<to>& opacities,\n                           const unsigned int render_type,\n                           const bool is_double_sided, const float focale,\n                           const float lightx, const float lighty, const float lightz,\n                           const float specular_lightness, const float specular_shininess,\n                           CImg<tz>& zbuffer) {\n      return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,\n                            render_type,is_double_sided,focale,lightx,lighty,lightz,\n                            specular_lightness,specular_shininess,1);\n    }\n\n#ifdef cimg_use_board\n    template<typename tp, typename tf, typename tc, typename to>\n    CImg<T>& draw_object3d(LibBoard::Board& board,\n                           const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors, const CImgList<to>& opacities,\n                           const unsigned int render_type=4,\n                           const bool is_double_sided=false, const float focale=700,\n                           const float lightx=0, const float lighty=0, const float lightz=-5e8,\n                           const float specular_lightness=0.2f, const float specular_shininess=0.1f) {\n      return draw_object3d(board,x0,y0,z0,vertices,primitives,colors,opacities,render_type,\n                           is_double_sided,focale,lightx,lighty,lightz,\n                           specular_lightness,specular_shininess,CImg<floatT>::empty());\n    }\n\n    template<typename tp, typename tf, typename tc, typename to, typename tz>\n    CImg<T>& draw_object3d(LibBoard::Board& board,\n                           const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors, const CImgList<to>& opacities,\n                           const unsigned int render_type,\n                           const bool is_double_sided, const float focale,\n                           const float lightx, const float lighty, const float lightz,\n                           const float specular_lightness, const float specular_shininess,\n                           CImg<tz>& zbuffer) {\n      return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,\n                            render_type,is_double_sided,focale,lightx,lighty,lightz,\n                            specular_lightness,specular_shininess,1);\n    }\n#endif\n\n    //! Draw a 3d object \\simplification.\n    template<typename tp, typename tf, typename tc>\n    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors,\n                           const unsigned int render_type=4,\n                           const bool is_double_sided=false, const float focale=700,\n                           const float lightx=0, const float lighty=0, const float lightz=-5e8,\n                           const float specular_lightness=0.2f, const float specular_shininess=0.1f) {\n      return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),\n                           render_type,is_double_sided,focale,lightx,lighty,lightz,\n                           specular_lightness,specular_shininess,CImg<floatT>::empty());\n    }\n\n    //! Draw a 3d object \\simplification.\n    template<typename tp, typename tf, typename tc, typename tz>\n    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors,\n                           const unsigned int render_type,\n                           const bool is_double_sided, const float focale,\n                           const float lightx, const float lighty, const float lightz,\n                           const float specular_lightness, const float specular_shininess,\n                           CImg<tz>& zbuffer) {\n      return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),\n                           render_type,is_double_sided,focale,lightx,lighty,lightz,\n                           specular_lightness,specular_shininess,zbuffer);\n    }\n\n#ifdef cimg_use_board\n    template<typename tp, typename tf, typename tc, typename to>\n    CImg<T>& draw_object3d(LibBoard::Board& board,\n                           const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors,\n                           const unsigned int render_type=4,\n                           const bool is_double_sided=false, const float focale=700,\n                           const float lightx=0, const float lighty=0, const float lightz=-5e8,\n                           const float specular_lightness=0.2f, const float specular_shininess=0.1f) {\n      return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),\n                           render_type,is_double_sided,focale,lightx,lighty,lightz,\n                           specular_lightness,specular_shininess,CImg<floatT>::empty());\n    }\n\n    template<typename tp, typename tf, typename tc, typename to, typename tz>\n    CImg<T>& draw_object3d(LibBoard::Board& board,\n                           const float x0, const float y0, const float z0,\n                           const CImg<tp>& vertices, const CImgList<tf>& primitives,\n                           const CImgList<tc>& colors,\n                           const unsigned int render_type,\n                           const bool is_double_sided, const float focale,\n                           const float lightx, const float lighty, const float lightz,\n                           const float specular_lightness, const float specular_shininess,\n                           CImg<tz>& zbuffer) {\n      return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),\n                           render_type,is_double_sided,focale,lightx,lighty,lightz,\n                           specular_lightness,specular_shininess,zbuffer);\n    }\n#endif\n\n    template<typename t, typename to>\n    static float __draw_object3d(const CImgList<t>& opacities, const unsigned int n_primitive, CImg<to>& opacity) {\n      if (n_primitive>=opacities._width || opacities[n_primitive].is_empty()) { opacity.assign(); return 1; }\n      if (opacities[n_primitive].size()==1) { opacity.assign(); return opacities(n_primitive,0); }\n      opacity.assign(opacities[n_primitive],true);\n      return 1.0f;\n    }\n\n    template<typename t, typename to>\n    static float __draw_object3d(const CImg<t>& opacities, const unsigned int n_primitive, CImg<to>& opacity) {\n      opacity.assign();\n      return n_primitive>=opacities._width?1.0f:(float)opacities[n_primitive];\n    }\n\n    template<typename t>\n    static float ___draw_object3d(const CImgList<t>& opacities, const unsigned int n_primitive) {\n      return n_primitive<opacities._width && opacities[n_primitive].size()==1?(float)opacities(n_primitive,0):1.0f;\n    }\n\n    template<typename t>\n    static float ___draw_object3d(const CImg<t>& opacities, const unsigned int n_primitive) {\n      return n_primitive<opacities._width?(float)opacities[n_primitive]:1.0f;\n    }\n\n    template<typename tz, typename tp, typename tf, typename tc, typename to>\n    CImg<T>& _draw_object3d(void *const pboard, CImg<tz>& zbuffer,\n                            const float X, const float Y, const float Z,\n                            const CImg<tp>& vertices,\n                            const CImgList<tf>& primitives,\n                            const CImgList<tc>& colors,\n                            const to& opacities,\n                            const unsigned int render_type,\n                            const bool is_double_sided, const float focale,\n                            const float lightx, const float lighty, const float lightz,\n                            const float specular_lightness, const float specular_shininess,\n                            const float sprite_scale) {\n      typedef typename cimg::superset2<tp,tz,float>::type tpfloat;\n      typedef typename to::value_type _to;\n      if (is_empty() || !vertices || !primitives) return *this;\n      CImg<char> error_message(1024);\n      if (!vertices.is_object3d(primitives,colors,opacities,false,error_message))\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_object3d(): Invalid specified 3d object (%u,%u) (%s).\",\n                                    cimg_instance,vertices._width,primitives._width,error_message.data());\n#ifndef cimg_use_board\n      if (pboard) return *this;\n#endif\n      if (render_type==5) cimg::mutex(10);  // Static variable used in this case, breaks thread-safety.\n\n      const float\n        nspec = 1 - (specular_lightness<0.0f?0.0f:(specular_lightness>1.0f?1.0f:specular_lightness)),\n        nspec2 = 1 + (specular_shininess<0.0f?0.0f:specular_shininess),\n        nsl1 = (nspec2 - 1)/cimg::sqr(nspec - 1),\n        nsl2 = 1 - 2*nsl1*nspec,\n        nsl3 = nspec2 - nsl1 - nsl2;\n\n      // Create light texture for phong-like rendering.\n      CImg<floatT> light_texture;\n      if (render_type==5) {\n        if (colors._width>primitives._width) {\n          static CImg<floatT> default_light_texture;\n          static const tc *lptr = 0;\n          static tc ref_values[64] = { 0 };\n          const CImg<tc>& img = colors.back();\n          bool is_same_texture = (lptr==img._data);\n          if (is_same_texture)\n            for (unsigned int r = 0, j = 0; j<8; ++j)\n              for (unsigned int i = 0; i<8; ++i)\n                if (ref_values[r++]!=img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum)) {\n                  is_same_texture = false; break;\n                }\n          if (!is_same_texture || default_light_texture._spectrum<_spectrum) {\n            (default_light_texture.assign(img,false)/=255).resize(-100,-100,1,_spectrum);\n            lptr = colors.back().data();\n            for (unsigned int r = 0, j = 0; j<8; ++j)\n              for (unsigned int i = 0; i<8; ++i)\n                ref_values[r++] = img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum);\n          }\n          light_texture.assign(default_light_texture,true);\n        } else {\n          static CImg<floatT> default_light_texture;\n          static float olightx = 0, olighty = 0, olightz = 0, ospecular_shininess = 0;\n          if (!default_light_texture ||\n              lightx!=olightx || lighty!=olighty || lightz!=olightz ||\n              specular_shininess!=ospecular_shininess || default_light_texture._spectrum<_spectrum) {\n            default_light_texture.assign(512,512);\n            const float\n              dlx = lightx - X,\n              dly = lighty - Y,\n              dlz = lightz - Z,\n              nl = (float)std::sqrt(dlx*dlx + dly*dly + dlz*dlz),\n              nlx = (default_light_texture._width - 1)/2*(1 + dlx/nl),\n              nly = (default_light_texture._height - 1)/2*(1 + dly/nl),\n              white[] = { 1 };\n            default_light_texture.draw_gaussian(nlx,nly,default_light_texture._width/3.0f,white);\n            cimg_forXY(default_light_texture,x,y) {\n              const float factor = default_light_texture(x,y);\n              if (factor>nspec) default_light_texture(x,y) = cimg::min(2,nsl1*factor*factor + nsl2*factor + nsl3);\n            }\n            default_light_texture.resize(-100,-100,1,_spectrum);\n            olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shininess = specular_shininess;\n          }\n          light_texture.assign(default_light_texture,true);\n        }\n      }\n\n      // Compute 3d to 2d projection.\n      CImg<tpfloat> projections(vertices._width,2);\n      tpfloat parallzmin = cimg::type<tpfloat>::max();\n      const float absfocale = focale?cimg::abs(focale):0;\n      if (absfocale) {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(projections.size()>4096)\n#endif\n        cimg_forX(projections,l) { // Perspective projection\n          const tpfloat\n            x = (tpfloat)vertices(l,0),\n            y = (tpfloat)vertices(l,1),\n            z = (tpfloat)vertices(l,2);\n          const tpfloat projectedz = z + Z + absfocale;\n          projections(l,1) = Y + absfocale*y/projectedz;\n          projections(l,0) = X + absfocale*x/projectedz;\n        }\n\n      } else {\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(projections.size()>4096)\n#endif\n        cimg_forX(projections,l) { // Parallel projection\n          const tpfloat\n            x = (tpfloat)vertices(l,0),\n            y = (tpfloat)vertices(l,1),\n            z = (tpfloat)vertices(l,2);\n          if (z<parallzmin) parallzmin = z;\n          projections(l,1) = Y + y;\n          projections(l,0) = X + x;\n        }\n      }\n      const float _focale = absfocale?absfocale:(1e5f-parallzmin);\n      float zmax = 0;\n      if (zbuffer) zmax = vertices.get_shared_row(2).max();\n\n      // Compute visible primitives.\n      CImg<uintT> visibles(primitives._width,1,1,1,~0U);\n      CImg<tpfloat> zrange(primitives._width);\n      const tpfloat zmin = absfocale?(tpfloat)(1.5f - absfocale):cimg::type<tpfloat>::min();\n      bool is_forward = zbuffer?true:false;\n\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(primitives.size()>4096)\n#endif\n      cimglist_for(primitives,l) {\n        const CImg<tf>& primitive = primitives[l];\n        switch (primitive.size()) {\n        case 1 : { // Point\n          CImg<_to> _opacity;\n          __draw_object3d(opacities,l,_opacity);\n          if (l<=colors.width() && (colors[l].size()!=_spectrum || _opacity)) is_forward = false;\n          const unsigned int i0 = (unsigned int)primitive(0);\n          const tpfloat z0 = Z + vertices(i0,2);\n          if (z0>zmin) {\n            visibles(l) = (unsigned int)l;\n            zrange(l) = z0;\n          }\n        } break;\n        case 5 : { // Sphere\n          const unsigned int\n            i0 = (unsigned int)primitive(0),\n            i1 = (unsigned int)primitive(1);\n          const tpfloat\n            Xc = 0.5f*((float)vertices(i0,0) + (float)vertices(i1,0)),\n            Yc = 0.5f*((float)vertices(i0,1) + (float)vertices(i1,1)),\n            Zc = 0.5f*((float)vertices(i0,2) + (float)vertices(i1,2)),\n            _zc = Z + Zc,\n            zc = _zc + _focale,\n            xc = X + Xc*(absfocale?absfocale/zc:1),\n            yc = Y + Yc*(absfocale?absfocale/zc:1),\n            radius = 0.5f*std::sqrt(cimg::sqr(vertices(i1,0) - vertices(i0,0)) +\n                                    cimg::sqr(vertices(i1,1) - vertices(i0,1)) +\n                                    cimg::sqr(vertices(i1,2) - vertices(i0,2)))*(absfocale?absfocale/zc:1),\n            xm = xc - radius,\n            ym = yc - radius,\n            xM = xc + radius,\n            yM = yc + radius;\n          if (xM>=0 && xm<_width && yM>=0 && ym<_height && _zc>zmin) {\n            visibles(l) = (unsigned int)l;\n            zrange(l) = _zc;\n          }\n          is_forward = false;\n        } break;\n        case 2 : // Segment\n        case 6 : {\n          const unsigned int\n            i0 = (unsigned int)primitive(0),\n            i1 = (unsigned int)primitive(1);\n          const tpfloat\n            x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2),\n            x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2);\n          tpfloat xm, xM, ym, yM;\n          if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }\n          if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }\n          if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin) {\n            visibles(l) = (unsigned int)l;\n            zrange(l) = (z0 + z1)/2;\n          }\n        } break;\n        case 3 :  // Triangle\n        case 9 : {\n          const unsigned int\n            i0 = (unsigned int)primitive(0),\n            i1 = (unsigned int)primitive(1),\n            i2 = (unsigned int)primitive(2);\n          const tpfloat\n            x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2),\n            x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2),\n            x2 = projections(i2,0), y2 = projections(i2,1), z2 = Z + vertices(i2,2);\n          tpfloat xm, xM, ym, yM;\n          if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }\n          if (x2<xm) xm = x2;\n          if (x2>xM) xM = x2;\n          if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }\n          if (y2<ym) ym = y2;\n          if (y2>yM) yM = y2;\n          if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin && z2>zmin) {\n            const tpfloat d = (x1-x0)*(y2-y0) - (x2-x0)*(y1-y0);\n            if (is_double_sided || d<0) {\n              visibles(l) = (unsigned int)l;\n              zrange(l) = (z0 + z1 + z2)/3;\n            }\n          }\n        } break;\n        case 4 : // Rectangle\n        case 12 : {\n          const unsigned int\n            i0 = (unsigned int)primitive(0),\n            i1 = (unsigned int)primitive(1),\n            i2 = (unsigned int)primitive(2),\n            i3 = (unsigned int)primitive(3);\n          const tpfloat\n            x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2),\n            x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2),\n            x2 = projections(i2,0), y2 = projections(i2,1), z2 = Z + vertices(i2,2),\n            x3 = projections(i3,0), y3 = projections(i3,1), z3 = Z + vertices(i3,2);\n          tpfloat xm, xM, ym, yM;\n          if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }\n          if (x2<xm) xm = x2;\n          if (x2>xM) xM = x2;\n          if (x3<xm) xm = x3;\n          if (x3>xM) xM = x3;\n          if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }\n          if (y2<ym) ym = y2;\n          if (y2>yM) yM = y2;\n          if (y3<ym) ym = y3;\n          if (y3>yM) yM = y3;\n          if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin && z2>zmin) {\n            const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0);\n            if (is_double_sided || d<0) {\n              visibles(l) = (unsigned int)l;\n              zrange(l) = (z0 + z1 + z2 + z3)/4;\n            }\n          }\n        } break;\n        default :\n          if (render_type==5) cimg::mutex(10,0);\n          throw CImgArgumentException(_cimg_instance\n                                      \"draw_object3d(): Invalid primitive[%u] with size %u \"\n                                      \"(should have size 1,2,3,4,5,6,9 or 12).\",\n                                      cimg_instance,\n                                      l,primitive.size());\n        }\n      }\n\n      // Force transparent primitives to be drawn last when zbuffer is activated\n      // (and if object contains no spheres or sprites).\n      if (is_forward)\n        cimglist_for(primitives,l)\n          if (___draw_object3d(opacities,l)!=1) zrange(l) = 2*zmax - zrange(l);\n\n      // Sort only visibles primitives.\n      unsigned int *p_visibles = visibles._data;\n      tpfloat *p_zrange = zrange._data;\n      const tpfloat *ptrz = p_zrange;\n      cimg_for(visibles,ptr,unsigned int) {\n        if (*ptr!=~0U) { *(p_visibles++) = *ptr; *(p_zrange++) = *ptrz; }\n        ++ptrz;\n      }\n      const unsigned int nb_visibles = (unsigned int)(p_zrange - zrange._data);\n      if (!nb_visibles) {\n        if (render_type==5) cimg::mutex(10,0);\n        return *this;\n      }\n      CImg<uintT> permutations;\n      CImg<tpfloat>(zrange._data,nb_visibles,1,1,1,true).sort(permutations,is_forward);\n\n      // Compute light properties\n      CImg<floatT> lightprops;\n      switch (render_type) {\n      case 3 : { // Flat Shading\n        lightprops.assign(nb_visibles);\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(nb_visibles>4096)\n#endif\n        cimg_forX(lightprops,l) {\n          const CImg<tf>& primitive = primitives(visibles(permutations(l)));\n          const unsigned int psize = primitive.size();\n          if (psize==3 || psize==4 || psize==9 || psize==12) {\n            const unsigned int\n              i0 = (unsigned int)primitive(0),\n              i1 = (unsigned int)primitive(1),\n              i2 = (unsigned int)primitive(2);\n            const tpfloat\n              x0 = (tpfloat)vertices(i0,0), y0 = (tpfloat)vertices(i0,1), z0 = (tpfloat)vertices(i0,2),\n              x1 = (tpfloat)vertices(i1,0), y1 = (tpfloat)vertices(i1,1), z1 = (tpfloat)vertices(i1,2),\n              x2 = (tpfloat)vertices(i2,0), y2 = (tpfloat)vertices(i2,1), z2 = (tpfloat)vertices(i2,2),\n              dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,\n              dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,\n              nx = dy1*dz2 - dz1*dy2,\n              ny = dz1*dx2 - dx1*dz2,\n              nz = dx1*dy2 - dy1*dx2,\n              norm = (tpfloat)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),\n              lx = X + (x0 + x1 + x2)/3 - lightx,\n              ly = Y + (y0 + y1 + y2)/3 - lighty,\n              lz = Z + (z0 + z1 + z2)/3 - lightz,\n              nl = (tpfloat)std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),\n              factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0);\n            lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);\n          } else lightprops[l] = 1;\n        }\n      } break;\n\n      case 4 : // Gouraud Shading\n      case 5 : { // Phong-Shading\n        CImg<tpfloat> vertices_normals(vertices._width,6,1,1,0);\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(nb_visibles>4096)\n#endif\n        for (unsigned int l = 0; l<nb_visibles; ++l) {\n          const CImg<tf>& primitive = primitives[visibles(l)];\n          const unsigned int psize = primitive.size();\n          const bool\n            triangle_flag = (psize==3) || (psize==9),\n            rectangle_flag = (psize==4) || (psize==12);\n          if (triangle_flag || rectangle_flag) {\n            const unsigned int\n              i0 = (unsigned int)primitive(0),\n              i1 = (unsigned int)primitive(1),\n              i2 = (unsigned int)primitive(2),\n              i3 = rectangle_flag?(unsigned int)primitive(3):0;\n            const tpfloat\n              x0 = (tpfloat)vertices(i0,0), y0 = (tpfloat)vertices(i0,1), z0 = (tpfloat)vertices(i0,2),\n              x1 = (tpfloat)vertices(i1,0), y1 = (tpfloat)vertices(i1,1), z1 = (tpfloat)vertices(i1,2),\n              x2 = (tpfloat)vertices(i2,0), y2 = (tpfloat)vertices(i2,1), z2 = (tpfloat)vertices(i2,2),\n              dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,\n              dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,\n              nnx = dy1*dz2 - dz1*dy2,\n              nny = dz1*dx2 - dx1*dz2,\n              nnz = dx1*dy2 - dy1*dx2,\n              norm = (tpfloat)(1e-5f + std::sqrt(nnx*nnx + nny*nny + nnz*nnz)),\n              nx = nnx/norm,\n              ny = nny/norm,\n              nz = nnz/norm;\n            unsigned int ix = 0, iy = 1, iz = 2;\n            if (is_double_sided && nz>0) { ix = 3; iy = 4; iz = 5; }\n            vertices_normals(i0,ix)+=nx; vertices_normals(i0,iy)+=ny; vertices_normals(i0,iz)+=nz;\n            vertices_normals(i1,ix)+=nx; vertices_normals(i1,iy)+=ny; vertices_normals(i1,iz)+=nz;\n            vertices_normals(i2,ix)+=nx; vertices_normals(i2,iy)+=ny; vertices_normals(i2,iz)+=nz;\n            if (rectangle_flag) {\n              vertices_normals(i3,ix)+=nx; vertices_normals(i3,iy)+=ny; vertices_normals(i3,iz)+=nz;\n            }\n          }\n        }\n\n        if (is_double_sided) cimg_forX(vertices_normals,p) {\n            const float\n              nx0 = vertices_normals(p,0), ny0 = vertices_normals(p,1), nz0 = vertices_normals(p,2),\n              nx1 = vertices_normals(p,3), ny1 = vertices_normals(p,4), nz1 = vertices_normals(p,5),\n              n0 = nx0*nx0 + ny0*ny0 + nz0*nz0, n1 = nx1*nx1 + ny1*ny1 + nz1*nz1;\n            if (n1>n0) {\n              vertices_normals(p,0) = -nx1;\n              vertices_normals(p,1) = -ny1;\n              vertices_normals(p,2) = -nz1;\n            }\n          }\n\n        if (render_type==4) {\n          lightprops.assign(vertices._width);\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(nb_visibles>4096)\n#endif\n          cimg_forX(lightprops,l) {\n            const tpfloat\n              nx = vertices_normals(l,0),\n              ny = vertices_normals(l,1),\n              nz = vertices_normals(l,2),\n              norm = (tpfloat)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),\n              lx = X + vertices(l,0) - lightx,\n              ly = Y + vertices(l,1) - lighty,\n              lz = Z + vertices(l,2) - lightz,\n              nl = (tpfloat)std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),\n              factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0);\n            lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);\n          }\n        } else {\n          const unsigned int\n            lw2 = light_texture._width/2 - 1,\n            lh2 = light_texture._height/2 - 1;\n          lightprops.assign(vertices._width,2);\n#ifdef cimg_use_openmp\n#pragma omp parallel for cimg_openmp_if(nb_visibles>4096)\n#endif\n          cimg_forX(lightprops,l) {\n            const tpfloat\n              nx = vertices_normals(l,0),\n              ny = vertices_normals(l,1),\n              nz = vertices_normals(l,2),\n              norm = (tpfloat)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),\n              nnx = nx/norm,\n              nny = ny/norm;\n            lightprops(l,0) = lw2*(1 + nnx);\n            lightprops(l,1) = lh2*(1 + nny);\n          }\n        }\n      } break;\n      }\n\n      // Draw visible primitives\n      const CImg<tc> default_color(1,_spectrum,1,1,(tc)200);\n      CImg<_to> _opacity;\n\n      for (unsigned int l = 0; l<nb_visibles; ++l) {\n        const unsigned int n_primitive = visibles(permutations(l));\n        const CImg<tf>& primitive = primitives[n_primitive];\n        const CImg<tc>\n          &__color = n_primitive<colors._width?colors[n_primitive]:CImg<tc>(),\n          _color = (__color && __color.size()!=_spectrum && __color._spectrum<_spectrum)?\n            __color.get_resize(-100,-100,-100,_spectrum,0):CImg<tc>(),\n          &color = _color?_color:(__color?__color:default_color);\n        const tc *const pcolor = color._data;\n        const float opacity = __draw_object3d(opacities,n_primitive,_opacity);\n\n#ifdef cimg_use_board\n        LibBoard::Board &board = *(LibBoard::Board*)pboard;\n#endif\n\n        switch (primitive.size()) {\n        case 1 : { // Colored point or sprite\n          const unsigned int n0 = (unsigned int)primitive[0];\n          const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);\n\n          if (_opacity.is_empty()) { // Scalar opacity.\n\n            if (color.size()==_spectrum) { // Colored point.\n              draw_point(x0,y0,pcolor,opacity);\n#ifdef cimg_use_board\n              if (pboard) {\n                board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n                board.fillCircle((float)x0,height()-(float)y0,0);\n              }\n#endif\n            } else { // Sprite.\n              const tpfloat z = Z + vertices(n0,2);\n              const float factor = focale<0?1:sprite_scale*(absfocale?absfocale/(z + absfocale):1);\n              const unsigned int\n                _sw = (unsigned int)(color._width*factor),\n                _sh = (unsigned int)(color._height*factor),\n                sw = _sw?_sw:1, sh = _sh?_sh:1;\n              const int nx0 = x0 - (int)sw/2, ny0 = y0 - (int)sh/2;\n              if (sw<=3*_width/2 && sh<=3*_height/2 &&\n                  (nx0 + (int)sw/2>=0 || nx0 - (int)sw/2<width() || ny0 + (int)sh/2>=0 || ny0 - (int)sh/2<height())) {\n                const CImg<tc>\n                  _sprite = (sw!=color._width || sh!=color._height)?\n                    color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg<tc>(),\n                  &sprite = _sprite?_sprite:color;\n                draw_image(nx0,ny0,sprite,opacity);\n#ifdef cimg_use_board\n                if (pboard) {\n                  board.setPenColorRGBi(128,128,128);\n                  board.setFillColor(LibBoard::Color::None);\n                  board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh);\n                }\n#endif\n              }\n            }\n          } else { // Opacity mask.\n            const tpfloat z = Z + vertices(n0,2);\n            const float factor = focale<0?1:sprite_scale*(absfocale?absfocale/(z + absfocale):1);\n            const unsigned int\n              _sw = (unsigned int)(cimg::max(color._width,_opacity._width)*factor),\n              _sh = (unsigned int)(cimg::max(color._height,_opacity._height)*factor),\n              sw = _sw?_sw:1, sh = _sh?_sh:1;\n            const int nx0 = x0 - (int)sw/2, ny0 = y0 - (int)sh/2;\n            if (sw<=3*_width/2 && sh<=3*_height/2 &&\n                (nx0 + (int)sw/2>=0 || nx0 - (int)sw/2<width() || ny0 + (int)sh/2>=0 || ny0 - (int)sh/2<height())) {\n              const CImg<tc>\n                _sprite = (sw!=color._width || sh!=color._height)?\n                  color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg<tc>(),\n                &sprite = _sprite?_sprite:color;\n              const CImg<_to>\n                _nopacity = (sw!=_opacity._width || sh!=_opacity._height)?\n                  _opacity.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg<_to>(),\n                &nopacity = _nopacity?_nopacity:_opacity;\n              draw_image(nx0,ny0,sprite,nopacity);\n#ifdef cimg_use_board\n              if (pboard) {\n                board.setPenColorRGBi(128,128,128);\n                board.setFillColor(LibBoard::Color::None);\n                board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh);\n              }\n#endif\n            }\n          }\n        } break;\n        case 2 : { // Colored line\n          const unsigned int\n            n0 = (unsigned int)primitive[0],\n            n1 = (unsigned int)primitive[1];\n          const int\n            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),\n            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);\n          const float\n            z0 = vertices(n0,2) + Z + _focale,\n            z1 = vertices(n1,2) + Z + _focale;\n          if (render_type) {\n            if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity);\n            else draw_line(x0,y0,x1,y1,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.drawLine((float)x0,height() - (float)y0,x1,height() - (float)y1);\n            }\n#endif\n          } else {\n            draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.drawCircle((float)x0,height() - (float)y0,0);\n              board.drawCircle((float)x1,height() - (float)y1,0);\n            }\n#endif\n          }\n        } break;\n        case 5 : { // Colored sphere\n          const unsigned int\n            n0 = (unsigned int)primitive[0],\n            n1 = (unsigned int)primitive[1],\n            is_wireframe = (unsigned int)primitive[2];\n          const float\n            Xc = 0.5f*((float)vertices(n0,0) + (float)vertices(n1,0)),\n            Yc = 0.5f*((float)vertices(n0,1) + (float)vertices(n1,1)),\n            Zc = 0.5f*((float)vertices(n0,2) + (float)vertices(n1,2)),\n            zc = Z + Zc + _focale,\n            xc = X + Xc*(absfocale?absfocale/zc:1),\n            yc = Y + Yc*(absfocale?absfocale/zc:1),\n            radius = 0.5f*std::sqrt(cimg::sqr(vertices(n1,0) - vertices(n0,0)) +\n                                    cimg::sqr(vertices(n1,1) - vertices(n0,1)) +\n                                    cimg::sqr(vertices(n1,2) - vertices(n0,2)))*(absfocale?absfocale/zc:1);\n          switch (render_type) {\n          case 0 :\n            draw_point((int)xc,(int)yc,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.fillCircle(xc,height() - yc,0);\n            }\n#endif\n            break;\n          case 1 :\n            draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity,~0U);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.setFillColor(LibBoard::Color::None);\n              board.drawCircle(xc,height() - yc,radius);\n            }\n#endif\n            break;\n          default :\n            if (is_wireframe) draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity,~0U);\n            else draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              if (!is_wireframe) board.fillCircle(xc,height() - yc,radius);\n              else {\n                board.setFillColor(LibBoard::Color::None);\n                board.drawCircle(xc,height() - yc,radius);\n              }\n            }\n#endif\n            break;\n          }\n        } break;\n        case 6 : { // Textured line\n          if (!__color) {\n            if (render_type==5) cimg::mutex(10,0);\n            throw CImgArgumentException(_cimg_instance\n                                        \"draw_object3d(): Undefined texture for line primitive [%u].\",\n                                        cimg_instance,n_primitive);\n          }\n          const unsigned int\n            n0 = (unsigned int)primitive[0],\n            n1 = (unsigned int)primitive[1];\n          const int\n            tx0 = (int)primitive[2], ty0 = (int)primitive[3],\n            tx1 = (int)primitive[4], ty1 = (int)primitive[5],\n            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),\n            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);\n          const float\n            z0 = vertices(n0,2) + Z + _focale,\n            z1 = vertices(n1,2) + Z + _focale;\n          if (render_type) {\n            if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity);\n            else draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);\n            }\n#endif\n          } else {\n            draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0,\n                                                 ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity).\n              draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1,\n                                                   ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.drawCircle((float)x0,height() - (float)y0,0);\n              board.drawCircle((float)x1,height() - (float)y1,0);\n            }\n#endif\n          }\n        } break;\n        case 3 : { // Colored triangle\n          const unsigned int\n            n0 = (unsigned int)primitive[0],\n            n1 = (unsigned int)primitive[1],\n            n2 = (unsigned int)primitive[2];\n          const int\n            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),\n            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),\n            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);\n          const float\n            z0 = vertices(n0,2) + Z + _focale,\n            z1 = vertices(n1,2) + Z + _focale,\n            z2 = vertices(n2,2) + Z + _focale;\n          switch (render_type) {\n          case 0 :\n            draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity).draw_point(x2,y2,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.drawCircle((float)x0,height() - (float)y0,0);\n              board.drawCircle((float)x1,height() - (float)y1,0);\n              board.drawCircle((float)x2,height() - (float)y2,0);\n            }\n#endif\n            break;\n          case 1 :\n            if (zbuffer)\n              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,pcolor,opacity).\n                draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opacity);\n            else\n              draw_line(x0,y0,x1,y1,pcolor,opacity).draw_line(x0,y0,x2,y2,pcolor,opacity).\n                draw_line(x1,y1,x2,y2,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);\n              board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2);\n              board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2);\n            }\n#endif\n            break;\n          case 2 :\n            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity);\n            else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x1,height() - (float)y1,\n                                 (float)x2,height() - (float)y2);\n            }\n#endif\n            break;\n          case 3 :\n            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity,lightprops(l));\n            else _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity,lightprops(l));\n#ifdef cimg_use_board\n            if (pboard) {\n              const float lp = cimg::min(lightprops(l),1);\n              board.setPenColorRGBi((unsigned char)(color[0]*lp),\n                                     (unsigned char)(color[1]*lp),\n                                     (unsigned char)(color[2]*lp),\n                                     (unsigned char)(opacity*255));\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x1,height() - (float)y1,\n                                 (float)x2,height() - (float)y2);\n            }\n#endif\n            break;\n          case 4 :\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,\n                            lightprops(n0),lightprops(n1),lightprops(n2),opacity);\n            else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,lightprops(n0),lightprops(n1),lightprops(n2),opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi((unsigned char)(color[0]),\n                                     (unsigned char)(color[1]),\n                                     (unsigned char)(color[2]),\n                                     (unsigned char)(opacity*255));\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0),\n                                         (float)x1,height() - (float)y1,lightprops(n1),\n                                         (float)x2,height() - (float)y2,lightprops(n2));\n            }\n#endif\n            break;\n          case 5 : {\n            const unsigned int\n              lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),\n              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),\n              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1);\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n            else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              const float\n                l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))),\n                                   (int)(light_texture.height()/2*(1 + lightprops(n0,1)))),\n                l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))),\n                                   (int)(light_texture.height()/2*(1 + lightprops(n1,1)))),\n                l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))),\n                                   (int)(light_texture.height()/2*(1 + lightprops(n2,1))));\n              board.setPenColorRGBi((unsigned char)(color[0]),\n                                     (unsigned char)(color[1]),\n                                     (unsigned char)(color[2]),\n                                     (unsigned char)(opacity*255));\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,\n                                         (float)x1,height() - (float)y1,l1,\n                                         (float)x2,height() - (float)y2,l2);\n            }\n#endif\n          } break;\n          }\n        } break;\n        case 4 : { // Colored rectangle\n          const unsigned int\n            n0 = (unsigned int)primitive[0],\n            n1 = (unsigned int)primitive[1],\n            n2 = (unsigned int)primitive[2],\n            n3 = (unsigned int)primitive[3];\n          const int\n            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),\n            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),\n            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),\n            x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);\n          const float\n            z0 = vertices(n0,2) + Z + _focale,\n            z1 = vertices(n1,2) + Z + _focale,\n            z2 = vertices(n2,2) + Z + _focale,\n            z3 = vertices(n3,2) + Z + _focale;\n\n          switch (render_type) {\n          case 0 :\n            draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity).\n              draw_point(x2,y2,pcolor,opacity).draw_point(x3,y3,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.drawCircle((float)x0,height() - (float)y0,0);\n              board.drawCircle((float)x1,height() - (float)y1,0);\n              board.drawCircle((float)x2,height() - (float)y2,0);\n              board.drawCircle((float)x3,height() - (float)y3,0);\n            }\n#endif\n            break;\n          case 1 :\n            if (zbuffer)\n              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opacity).\n                draw_line(zbuffer,x2,y2,z2,x3,y3,z3,pcolor,opacity).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,pcolor,opacity);\n            else\n              draw_line(x0,y0,x1,y1,pcolor,opacity).draw_line(x1,y1,x2,y2,pcolor,opacity).\n                draw_line(x2,y2,x3,y3,pcolor,opacity).draw_line(x3,y3,x0,y0,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);\n              board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2);\n              board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3);\n              board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0);\n            }\n#endif\n            break;\n          case 2 :\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity).\n                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opacity);\n            else\n              draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity).draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x1,height() - (float)y1,\n                                 (float)x2,height() - (float)y2);\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x2,height() - (float)y2,\n                                 (float)x3,height() - (float)y3);\n            }\n#endif\n            break;\n          case 3 :\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity,lightprops(l)).\n                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opacity,lightprops(l));\n            else\n              _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity,lightprops(l)).\n                _draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opacity,lightprops(l));\n#ifdef cimg_use_board\n            if (pboard) {\n              const float lp = cimg::min(lightprops(l),1);\n              board.setPenColorRGBi((unsigned char)(color[0]*lp),\n                                     (unsigned char)(color[1]*lp),\n                                     (unsigned char)(color[2]*lp),(unsigned char)(opacity*255));\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x1,height() - (float)y1,\n                                 (float)x2,height() - (float)y2);\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x2,height() - (float)y2,\n                                 (float)x3,height() - (float)y3);\n            }\n#endif\n            break;\n          case 4 : {\n            const float\n              lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),\n              lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,lightprop0,lightprop1,lightprop2,opacity).\n                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,lightprop0,lightprop2,lightprop3,opacity);\n            else\n              draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,lightprop0,lightprop1,lightprop2,opacity).\n                draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,lightprop0,lightprop2,lightprop3,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi((unsigned char)(color[0]),\n                                     (unsigned char)(color[1]),\n                                     (unsigned char)(color[2]),\n                                     (unsigned char)(opacity*255));\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0,\n                                         (float)x1,height() - (float)y1,lightprop1,\n                                         (float)x2,height() - (float)y2,lightprop2);\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0,\n                                         (float)x2,height() - (float)y2,lightprop2,\n                                         (float)x3,height() - (float)y3,lightprop3);\n            }\n#endif\n          } break;\n          case 5 : {\n            const unsigned int\n              lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),\n              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),\n              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),\n              lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity).\n                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity);\n            else\n              draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity).\n                draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              const float\n                l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))),\n                l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))),\n                l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))),\n                l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3)));\n              board.setPenColorRGBi((unsigned char)(color[0]),\n                                     (unsigned char)(color[1]),\n                                     (unsigned char)(color[2]),\n                                     (unsigned char)(opacity*255));\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,\n                                         (float)x1,height() - (float)y1,l1,\n                                         (float)x2,height() - (float)y2,l2);\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,\n                                         (float)x2,height() - (float)y2,l2,\n                                         (float)x3,height() - (float)y3,l3);\n            }\n#endif\n          } break;\n          }\n        } break;\n        case 9 : { // Textured triangle\n          if (!__color) {\n            if (render_type==5) cimg::mutex(10,0);\n            throw CImgArgumentException(_cimg_instance\n                                        \"draw_object3d(): Undefined texture for triangle primitive [%u].\",\n                                        cimg_instance,n_primitive);\n          }\n          const unsigned int\n            n0 = (unsigned int)primitive[0],\n            n1 = (unsigned int)primitive[1],\n            n2 = (unsigned int)primitive[2];\n          const int\n            tx0 = (int)primitive[3], ty0 = (int)primitive[4],\n            tx1 = (int)primitive[5], ty1 = (int)primitive[6],\n            tx2 = (int)primitive[7], ty2 = (int)primitive[8],\n            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),\n            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),\n            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);\n          const float\n            z0 = vertices(n0,2) + Z + _focale,\n            z1 = vertices(n1,2) + Z + _focale,\n            z2 = vertices(n2,2) + Z + _focale;\n          switch (render_type) {\n          case 0 :\n            draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0,\n                                                 ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity).\n              draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1,\n                                                   ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity).\n              draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2,\n                                                   ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.drawCircle((float)x0,height() - (float)y0,0);\n              board.drawCircle((float)x1,height() - (float)y1,0);\n              board.drawCircle((float)x2,height() - (float)y2,0);\n            }\n#endif\n            break;\n          case 1 :\n            if (zbuffer)\n              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity).\n                draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opacity).\n                draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity);\n            else\n              draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity).\n                draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opacity).\n                draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);\n              board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2);\n              board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2);\n            }\n#endif\n            break;\n          case 2 :\n            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity);\n            else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x1,height() - (float)y1,\n                                 (float)x2,height() - (float)y2);\n            }\n#endif\n            break;\n          case 3 :\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l));\n            else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l));\n#ifdef cimg_use_board\n            if (pboard) {\n              const float lp = cimg::min(lightprops(l),1);\n              board.setPenColorRGBi((unsigned char)(128*lp),\n                                    (unsigned char)(128*lp),\n                                    (unsigned char)(128*lp),\n                                    (unsigned char)(opacity*255));\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x1,height() - (float)y1,\n                                 (float)x2,height() - (float)y2);\n            }\n#endif\n            break;\n          case 4 :\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,\n                            lightprops(n0),lightprops(n1),lightprops(n2),opacity);\n            else\n              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,\n                            lightprops(n0),lightprops(n1),lightprops(n2),opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0),\n                                        (float)x1,height() - (float)y1,lightprops(n1),\n                                        (float)x2,height() - (float)y2,lightprops(n2));\n            }\n#endif\n            break;\n          case 5 :\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,\n                            (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1),\n                            (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1),\n                            (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1),\n                            opacity);\n            else\n              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,\n                            (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1),\n                            (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1),\n                            (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1),\n                            opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              const float\n                l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))),\n                                   (int)(light_texture.height()/2*(1 + lightprops(n0,1)))),\n                l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))),\n                                   (int)(light_texture.height()/2*(1 + lightprops(n1,1)))),\n                l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))),\n                                   (int)(light_texture.height()/2*(1 + lightprops(n2,1))));\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,\n                                        (float)x1,height() - (float)y1,l1,\n                                        (float)x2,height() - (float)y2,l2);\n            }\n#endif\n            break;\n          }\n        } break;\n        case 12 : { // Textured quadrangle\n          if (!__color) {\n            if (render_type==5) cimg::mutex(10,0);\n            throw CImgArgumentException(_cimg_instance\n                                        \"draw_object3d(): Undefined texture for quadrangle primitive [%u].\",\n                                        cimg_instance,n_primitive);\n          }\n          const unsigned int\n            n0 = (unsigned int)primitive[0],\n            n1 = (unsigned int)primitive[1],\n            n2 = (unsigned int)primitive[2],\n            n3 = (unsigned int)primitive[3];\n          const int\n            tx0 = (int)primitive[4], ty0 = (int)primitive[5],\n            tx1 = (int)primitive[6], ty1 = (int)primitive[7],\n            tx2 = (int)primitive[8], ty2 = (int)primitive[9],\n            tx3 = (int)primitive[10], ty3 = (int)primitive[11],\n            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),\n            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),\n            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),\n            x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);\n          const float\n            z0 = vertices(n0,2) + Z + _focale,\n            z1 = vertices(n1,2) + Z + _focale,\n            z2 = vertices(n2,2) + Z + _focale,\n            z3 = vertices(n3,2) + Z + _focale;\n\n          switch (render_type) {\n          case 0 :\n            draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0,\n                                                 ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity).\n              draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1,\n                                                   ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity).\n              draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2,\n                                                   ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity).\n              draw_point(x3,y3,color.get_vector_at(tx3<=0?0:tx3>=color.width()?color.width() - 1:tx3,\n                                                   ty3<=0?0:ty3>=color.height()?color.height() - 1:ty3)._data,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.drawCircle((float)x0,height() - (float)y0,0);\n              board.drawCircle((float)x1,height() - (float)y1,0);\n              board.drawCircle((float)x2,height() - (float)y2,0);\n              board.drawCircle((float)x3,height() - (float)y3,0);\n            }\n#endif\n            break;\n          case 1 :\n            if (zbuffer)\n              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity).\n                draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity).\n                draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opacity).\n                draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opacity);\n            else\n              draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity).\n                draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity).\n                draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opacity).\n                draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);\n              board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2);\n              board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3);\n              board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0);\n            }\n#endif\n            break;\n          case 2 :\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity).\n                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity);\n            else\n              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity).\n                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x1,height() - (float)y1,\n                                 (float)x2,height() - (float)y2);\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x2,height() - (float)y2,\n                                 (float)x3,height() - (float)y3);\n            }\n#endif\n            break;\n          case 3 :\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)).\n                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity,lightprops(l));\n            else\n              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)).\n                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity,lightprops(l));\n#ifdef cimg_use_board\n            if (pboard) {\n              const float lp = cimg::min(lightprops(l),1);\n              board.setPenColorRGBi((unsigned char)(128*lp),\n                                     (unsigned char)(128*lp),\n                                     (unsigned char)(128*lp),\n                                     (unsigned char)(opacity*255));\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x1,height() - (float)y1,\n                                 (float)x2,height() - (float)y2);\n              board.fillTriangle((float)x0,height() - (float)y0,\n                                 (float)x2,height() - (float)y2,\n                                 (float)x3,height() - (float)y3);\n            }\n#endif\n            break;\n          case 4 : {\n            const float\n              lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),\n              lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,\n                            lightprop0,lightprop1,lightprop2,opacity).\n                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,\n                              lightprop0,lightprop2,lightprop3,opacity);\n            else\n              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,\n                            lightprop0,lightprop1,lightprop2,opacity).\n                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,\n                              lightprop0,lightprop2,lightprop3,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0,\n                                         (float)x1,height() - (float)y1,lightprop1,\n                                         (float)x2,height() - (float)y2,lightprop2);\n              board.fillGouraudTriangle((float)x0,height()  -(float)y0,lightprop0,\n                                         (float)x2,height() - (float)y2,lightprop2,\n                                         (float)x3,height() - (float)y3,lightprop3);\n            }\n#endif\n          } break;\n          case 5 : {\n            const unsigned int\n              lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),\n              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),\n              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),\n              lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);\n            if (zbuffer)\n              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,\n                            light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity).\n                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,\n                              light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity);\n            else\n              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,\n                            light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity).\n                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,\n                              light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity);\n#ifdef cimg_use_board\n            if (pboard) {\n              const float\n                l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))),\n                l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))),\n                l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))),\n                l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3)));\n              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));\n              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,\n                                         (float)x1,height() - (float)y1,l1,\n                                         (float)x2,height() - (float)y2,l2);\n              board.fillGouraudTriangle((float)x0,height()  -(float)y0,l0,\n                                         (float)x2,height() - (float)y2,l2,\n                                         (float)x3,height() - (float)y3,l3);\n            }\n#endif\n          } break;\n          }\n        } break;\n        }\n      }\n\n      if (render_type==5) cimg::mutex(10,0);\n      return *this;\n    }\n\n    //@}\n    //---------------------------\n    //\n    //! \\name Data Input\n    //@{\n    //---------------------------\n\n    //! Launch simple interface to select a shape from an image.\n    /**\n       \\param disp Display window to use.\n       \\param feature_type Type of feature to select. Can be <tt>{ 0=point | 1=line | 2=rectangle | 3=ellipse }</tt>.\n       \\param XYZ Pointer to 3 values X,Y,Z which tells about the projection point coordinates, for volumetric images.\n    **/\n    CImg<T>& select(CImgDisplay &disp,\n                    const unsigned int feature_type=2, unsigned int *const XYZ=0,\n                    const bool exit_on_anykey=false) {\n      return get_select(disp,feature_type,XYZ,exit_on_anykey).move_to(*this);\n    }\n\n    //! Simple interface to select a shape from an image \\overloading.\n    CImg<T>& select(const char *const title,\n                    const unsigned int feature_type=2, unsigned int *const XYZ=0,\n                    const bool exit_on_anykey=false) {\n      return get_select(title,feature_type,XYZ,exit_on_anykey).move_to(*this);\n    }\n\n    //! Simple interface to select a shape from an image \\newinstance.\n    CImg<intT> get_select(CImgDisplay &disp,\n                          const unsigned int feature_type=2, unsigned int *const XYZ=0,\n                          const bool exit_on_anykey=false) const {\n      return _get_select(disp,0,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);\n    }\n\n    //! Simple interface to select a shape from an image \\newinstance.\n    CImg<intT> get_select(const char *const title,\n                          const unsigned int feature_type=2, unsigned int *const XYZ=0,\n                          const bool exit_on_anykey=false) const {\n      CImgDisplay disp;\n      return _get_select(disp,title,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);\n    }\n\n    CImg<intT> _get_select(CImgDisplay &disp, const char *const title,\n                           const unsigned int feature_type, unsigned int *const XYZ,\n                           const int origX, const int origY, const int origZ,\n                           const bool exit_on_anykey,\n                           const bool reset_view3d,\n                           const bool force_display_z_coord) const {\n      if (is_empty()) return CImg<intT>(1,feature_type==0?3:6,1,1,-1);\n      if (!disp) {\n        disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1);\n        if (!title) disp.set_title(\"CImg<%s> (%ux%ux%ux%u)\",pixel_type(),_width,_height,_depth,_spectrum);\n      } else if (title) disp.set_title(\"%s\",title);\n\n      CImg<T> thumb;\n      if (width()>disp.screen_width() || height()>disp.screen_height()) {\n        const double ratio = cimg::min((double)disp.screen_width()/width(),(double)disp.screen_height()/height());\n        get_resize(cimg::max(1,(int)(ratio*width())),cimg::max(1,(int)(ratio*height())),-100,-100).move_to(thumb);\n      }\n\n      const unsigned int old_normalization = disp.normalization();\n      bool old_is_resized = disp.is_resized();\n      disp._normalization = 0;\n      disp.show().set_key(0).set_wheel().show_mouse();\n\n      static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 };\n\n      int area = 0, starting_area = 0, clicked_area = 0, phase = 0,\n        X0 = (int)((XYZ?XYZ[0]:(_width - 1)/2)%_width),\n        Y0 = (int)((XYZ?XYZ[1]:(_height - 1)/2)%_height),\n        Z0 = (int)((XYZ?XYZ[2]:(_depth - 1)/2)%_depth),\n        X1 =-1, Y1 = -1, Z1 = -1,\n        X3d = -1, Y3d = -1,\n        oX3d = X3d, oY3d = -1,\n        omx = -1, omy = -1;\n      float X = -1, Y = -1, Z = -1;\n      unsigned int old_button = 0, key = 0;\n\n      bool shape_selected = false, text_down = false, visible_cursor = true;\n      static CImg<floatT> pose3d;\n      static bool is_view3d = false, is_axes = true;\n      if (reset_view3d) { pose3d.assign(); is_view3d = false; }\n      CImg<floatT> points3d, opacities3d, sel_opacities3d;\n      CImgList<uintT> primitives3d, sel_primitives3d;\n      CImgList<ucharT> colors3d, sel_colors3d;\n      CImg<ucharT> visu, visu0, view3d;\n      CImg<charT> text(1024); *text = 0;\n\n      while (!key && !disp.is_closed() && !shape_selected) {\n\n        // Handle mouse motion and selection\n        int\n          mx = disp.mouse_x(),\n          my = disp.mouse_y();\n\n        const float\n          mX = mx<0?-1.0f:(float)mx*(width() + (depth()>1?depth():0))/disp.width(),\n          mY = my<0?-1.0f:(float)my*(height() + (depth()>1?depth():0))/disp.height();\n\n        area = 0;\n        if (mX>=0 && mY>=0 && mX<width() && mY<height())  { area = 1; X = mX; Y = mY; Z = (float)(phase?Z1:Z0); }\n        if (mX>=0 && mX<width() && mY>=height()) { area = 2; X = mX; Z = mY - _height; Y = (float)(phase?Y1:Y0); }\n        if (mY>=0 && mX>=width() && mY<height()) { area = 3; Y = mY; Z = mX - _width; X = (float)(phase?X1:X0); }\n        if (mX>=width() && mY>=height()) area = 4;\n        if (disp.button()) { if (!clicked_area) clicked_area = area; } else clicked_area = 0;\n\n        CImg<charT> filename(32);\n\n        switch (key = disp.key()) {\n#if cimg_OS!=2\n        case cimg::keyCTRLRIGHT :\n#endif\n        case 0 : case cimg::keyCTRLLEFT : key = 0; break;\n        case cimg::keyPAGEUP :\n          if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(1); key = 0; } break;\n        case cimg::keyPAGEDOWN :\n          if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(-1); key = 0; } break;\n        case cimg::keyA : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            is_axes = !is_axes; disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).\n              resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false),\n                     CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false).\n              _is_resized = true;\n            disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).\n              resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true;\n            disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true;\n            disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true;\n            disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            is_view3d = !is_view3d; disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            static unsigned int snap_number = 0;\n            std::FILE *file;\n            do {\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.bmp\",snap_number++);\n              if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n            } while (file);\n            if (visu0) {\n              (+visu0).draw_text(0,0,\" Saving snapshot... \",foreground_color,background_color,0.7f,13).display(disp);\n              visu0.save(filename);\n              (+visu0).draw_text(0,0,\" Snapshot '%s' saved. \",foreground_color,background_color,0.7f,13,filename._data).\n                display(disp);\n            }\n            disp.set_key(key,false); key = 0;\n          } break;\n        case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            static unsigned int snap_number = 0;\n            std::FILE *file;\n            do {\n#ifdef cimg_use_zlib\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.cimgz\",snap_number++);\n#else\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.cimg\",snap_number++);\n#endif\n              if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n            } while (file);\n            (+visu0).draw_text(0,0,\" Saving instance... \",foreground_color,background_color,0.7f,13).display(disp);\n            save(filename);\n            (+visu0).draw_text(0,0,\" Instance '%s' saved. \",foreground_color,background_color,0.7f,13,filename._data).\n              display(disp);\n            disp.set_key(key,false); key = 0;\n          } break;\n        }\n\n        switch (area) {\n\n        case 0 : // When mouse is out of image range.\n          mx = my = -1; X = Y = Z = -1;\n          break;\n\n        case 1 : case 2 : case 3 : // When mouse is over the XY,XZ or YZ projections.\n          if (disp.button()&1 && phase<2 && clicked_area==area) { // When selection has been started (1st step).\n            if (_depth>1 && (X1!=(int)X || Y1!=(int)Y || Z1!=(int)Z)) visu0.assign();\n            X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z;\n          }\n          if (!(disp.button()&1) && phase>=2 && clicked_area!=area) { // When selection is at 2nd step (for volumes).\n            switch (starting_area) {\n            case 1 : if (Z1!=(int)Z) visu0.assign(); Z1 = (int)Z; break;\n            case 2 : if (Y1!=(int)Y) visu0.assign(); Y1 = (int)Y; break;\n            case 3 : if (X1!=(int)X) visu0.assign(); X1 = (int)X; break;\n            }\n          }\n          if (disp.button()&2 && clicked_area==area) { // When moving through the image/volume.\n            if (phase) {\n              if (_depth>1 && (X1!=(int)X || Y1!=(int)Y || Z1!=(int)Z)) visu0.assign();\n              X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z;\n            } else {\n              if (_depth>1 && (X0!=(int)X || Y0!=(int)Y || Z0!=(int)Z)) visu0.assign();\n              X0 = (int)X; Y0 = (int)Y; Z0 = (int)Z;\n            }\n          }\n          if (disp.button()&4) {\n            X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = area = clicked_area = starting_area = 0;\n            visu0.assign();\n          }\n          if (disp.wheel()) { // When moving through the slices of the volume (with mouse wheel).\n            if (_depth>1 && !disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT() &&\n                !disp.is_keySHIFTLEFT() && !disp.is_keySHIFTRIGHT() &&\n                !disp.is_keyALT() && !disp.is_keyALTGR()) {\n              switch (area) {\n              case 1 :\n                if (phase) Z = (float)(Z1+=disp.wheel()); else Z = (float)(Z0+=disp.wheel());\n                visu0.assign(); break;\n              case 2 :\n                if (phase) Y = (float)(Y1+=disp.wheel()); else Y = (float)(Y0+=disp.wheel());\n                visu0.assign(); break;\n              case 3 :\n                if (phase) X = (float)(X1+=disp.wheel()); else X = (float)(X0+=disp.wheel());\n                visu0.assign(); break;\n              }\n              disp.set_wheel();\n            } else key = ~0U;\n          }\n          if ((disp.button()&1)!=old_button) { // When left button has just been pressed or released.\n            switch (phase) {\n            case 0 :\n              if (area==clicked_area) {\n                X0 = X1 = (int)X; Y0 = Y1 = (int)Y; Z0 = Z1 = (int)Z; starting_area = area; ++phase;\n              } break;\n            case 1 :\n              if (area==starting_area) {\n                X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z; ++phase;\n              } else if (!(disp.button()&1)) { X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = 0; visu0.assign(); }\n              break;\n            case 2 : ++phase; break;\n            }\n            old_button = disp.button()&1;\n          }\n          break;\n\n        case 4 : // When mouse is over the 3d view.\n          if (is_view3d && points3d) {\n            X3d = mx - width()*disp.width()/(width() + (depth()>1?depth():0));\n            Y3d = my - height()*disp.height()/(height() + (depth()>1?depth():0));\n            if (oX3d<0) { oX3d = X3d; oY3d = Y3d; }\n            // Left + right buttons: reset.\n            if ((disp.button()&3)==3) { pose3d.assign(); view3d.assign(); oX3d = oY3d = X3d = Y3d = -1; }\n            else if (disp.button()&1 && pose3d && (oX3d!=X3d || oY3d!=Y3d)) { // Left button: rotate.\n              const float\n                R = 0.45f*cimg::min(view3d._width,view3d._height),\n                R2 = R*R,\n                u0 = (float)(oX3d - view3d.width()/2),\n                v0 = (float)(oY3d - view3d.height()/2),\n                u1 = (float)(X3d - view3d.width()/2),\n                v1 = (float)(Y3d - view3d.height()/2),\n                n0 = (float)std::sqrt(u0*u0 + v0*v0),\n                n1 = (float)std::sqrt(u1*u1 + v1*v1),\n                nu0 = n0>R?(u0*R/n0):u0,\n                nv0 = n0>R?(v0*R/n0):v0,\n                nw0 = (float)std::sqrt(cimg::max(0,R2 - nu0*nu0 - nv0*nv0)),\n                nu1 = n1>R?(u1*R/n1):u1,\n                nv1 = n1>R?(v1*R/n1):v1,\n                nw1 = (float)std::sqrt(cimg::max(0,R2 - nu1*nu1 - nv1*nv1)),\n                u = nv0*nw1 - nw0*nv1,\n                v = nw0*nu1 - nu0*nw1,\n                w = nv0*nu1 - nu0*nv1,\n                n = (float)std::sqrt(u*u + v*v + w*w),\n                alpha = (float)std::asin(n/R2);\n              pose3d.draw_image(CImg<floatT>::rotation_matrix(u,v,w,alpha)*pose3d.get_crop(0,0,2,2));\n              view3d.assign();\n            } else if (disp.button()&2 && pose3d && oY3d!=Y3d) {  // Right button: zoom.\n              pose3d(3,2)-=(oY3d - Y3d)*1.5f; view3d.assign();\n            }\n            if (disp.wheel()) { // Wheel: zoom\n              pose3d(3,2)-=disp.wheel()*15; view3d.assign(); disp.set_wheel();\n            }\n            if (disp.button()&4 && pose3d && (oX3d!=X3d || oY3d!=Y3d)) { // Middle button: shift.\n              pose3d(3,0)-=oX3d - X3d; pose3d(3,1)-=oY3d - Y3d; view3d.assign();\n            }\n            oX3d = X3d; oY3d = Y3d;\n          }\n          mx = my = -1; X = Y = Z = -1;\n          break;\n        }\n\n        if (phase) {\n          if (!feature_type) shape_selected = phase?true:false;\n          else {\n            if (_depth>1) shape_selected = (phase==3)?true:false;\n            else shape_selected = (phase==2)?true:false;\n          }\n        }\n\n        if (X0<0) X0 = 0; if (X0>=width()) X0 = width() - 1;\n        if (Y0<0) Y0 = 0; if (Y0>=height()) Y0 = height() - 1;\n        if (Z0<0) Z0 = 0; if (Z0>=depth()) Z0 = depth() - 1;\n        if (X1<1) X1 = 0; if (X1>=width()) X1 = width() - 1;\n        if (Y1<0) Y1 = 0; if (Y1>=height()) Y1 = height() - 1;\n        if (Z1<0) Z1 = 0; if (Z1>=depth()) Z1 = depth() - 1;\n\n        // Draw visualization image on the display\n        if (mx!=omx || my!=omy || !visu0 || (_depth>1 && !view3d)) {\n\n          if (!visu0) { // Create image of projected planes.\n            if (thumb) thumb.__get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0);\n            else __get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0);\n            visu0.resize(disp);\n            view3d.assign();\n            points3d.assign();\n          }\n\n          if (is_view3d && _depth>1 && !view3d) { // Create 3d view for volumetric images.\n            const unsigned int\n              _x3d = (unsigned int)cimg::round((float)_width*visu0._width/(_width + _depth),1,1),\n              _y3d = (unsigned int)cimg::round((float)_height*visu0._height/(_height + _depth),1,1),\n              x3d = _x3d>=visu0._width?visu0._width - 1:_x3d,\n              y3d = _y3d>=visu0._height?visu0._height - 1:_y3d;\n            CImg<ucharT>(1,2,1,1,64,128).resize(visu0._width - x3d,visu0._height - y3d,1,visu0._spectrum,3).\n              move_to(view3d);\n            if (!points3d) {\n              get_projections3d(primitives3d,colors3d,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0,true).move_to(points3d);\n              points3d.append(CImg<floatT>(8,3,1,1,\n                                           0,_width - 1,_width - 1,0,0,_width - 1,_width - 1,0,\n                                           0,0,_height - 1,_height - 1,0,0,_height - 1,_height - 1,\n                                           0,0,0,0,_depth - 1,_depth - 1,_depth - 1,_depth - 1),'x');\n              CImg<uintT>::vector(12,13).move_to(primitives3d); CImg<uintT>::vector(13,14).move_to(primitives3d);\n              CImg<uintT>::vector(14,15).move_to(primitives3d); CImg<uintT>::vector(15,12).move_to(primitives3d);\n              CImg<uintT>::vector(16,17).move_to(primitives3d); CImg<uintT>::vector(17,18).move_to(primitives3d);\n              CImg<uintT>::vector(18,19).move_to(primitives3d); CImg<uintT>::vector(19,16).move_to(primitives3d);\n              CImg<uintT>::vector(12,16).move_to(primitives3d); CImg<uintT>::vector(13,17).move_to(primitives3d);\n              CImg<uintT>::vector(14,18).move_to(primitives3d); CImg<uintT>::vector(15,19).move_to(primitives3d);\n              colors3d.insert(12,CImg<ucharT>::vector(255,255,255));\n              opacities3d.assign(primitives3d.width(),1,1,1,0.5f);\n              if (!phase) {\n                opacities3d[0] = opacities3d[1] = opacities3d[2] = 0.8f;\n                sel_primitives3d.assign();\n                sel_colors3d.assign();\n                sel_opacities3d.assign();\n              } else {\n                if (feature_type==2) {\n                  points3d.append(CImg<floatT>(8,3,1,1,\n                                               X0,X1,X1,X0,X0,X1,X1,X0,\n                                               Y0,Y0,Y1,Y1,Y0,Y0,Y1,Y1,\n                                               Z0,Z0,Z0,Z0,Z1,Z1,Z1,Z1),'x');\n                  sel_primitives3d.assign();\n                  CImg<uintT>::vector(20,21).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(21,22).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(22,23).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(23,20).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(24,25).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(25,26).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(26,27).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(27,24).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(20,24).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(21,25).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(22,26).move_to(sel_primitives3d);\n                  CImg<uintT>::vector(23,27).move_to(sel_primitives3d);\n                } else {\n                  points3d.append(CImg<floatT>(2,3,1,1,\n                                               X0,X1,\n                                               Y0,Y1,\n                                               Z0,Z1),'x');\n                  sel_primitives3d.assign(CImg<uintT>::vector(20,21));\n                }\n                sel_colors3d.assign(sel_primitives3d._width,CImg<ucharT>::vector(255,255,255));\n                sel_opacities3d.assign(sel_primitives3d._width,1,1,1,0.8f);\n              }\n              points3d.shift_object3d(-0.5f*(_width - 1),-0.5f*(_height - 1),-0.5f*(_depth - 1)).resize_object3d();\n              points3d*=0.75f*cimg::min(view3d._width,view3d._height);\n            }\n\n            if (!pose3d) CImg<floatT>(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0).move_to(pose3d);\n            CImg<floatT> zbuffer3d(view3d._width,view3d._height,1,1,0);\n            const CImg<floatT> rotated_points3d = pose3d.get_crop(0,0,2,2)*points3d;\n            if (sel_primitives3d)\n              view3d.draw_object3d(pose3d(3,0) + 0.5f*view3d._width,\n                                   pose3d(3,1) + 0.5f*view3d._height,\n                                   pose3d(3,2),\n                                   rotated_points3d,sel_primitives3d,sel_colors3d,sel_opacities3d,\n                                   2,true,500,0,0,0,0,0,zbuffer3d);\n            view3d.draw_object3d(pose3d(3,0) + 0.5f*view3d._width,\n                                 pose3d(3,1) + 0.5f*view3d._height,\n                                 pose3d(3,2),\n                                 rotated_points3d,primitives3d,colors3d,opacities3d,\n                                 2,true,500,0,0,0,0,0,zbuffer3d);\n            visu0.draw_image(x3d,y3d,view3d);\n          }\n          visu = visu0;\n\n          if (X<0 || Y<0 || Z<0) { if (!visible_cursor) { disp.show_mouse(); visible_cursor = true; }}\n          else {\n            if (is_axes) { if (visible_cursor) { disp.hide_mouse(); visible_cursor = false; }}\n            else { if (!visible_cursor) { disp.show_mouse(); visible_cursor = true; }}\n            const int d = (depth()>1)?depth():0;\n            int\n              _X = (int)X, _Y = (int)Y, _Z = (int)Z,\n              w = disp.width(), W = width() + d,\n              h = disp.height(), H = height() + d,\n              _xp = (int)(_X*(float)w/W), xp = _xp + ((int)(_xp*(float)W/w)!=_X?1:0),\n              _yp = (int)(_Y*(float)h/H), yp = _yp + ((int)(_yp*(float)H/h)!=_Y?1:0),\n              _xn = (int)((_X + 1.0f)*w/W - 1), xn = _xn + ((int)((_xn + 1.0f)*W/w)!=_X + 1?1:0),\n              _yn = (int)((_Y + 1.0f)*h/H - 1), yn = _yn + ((int)((_yn + 1.0f)*H/h)!=_Y + 1?1:0),\n              _zxp = (int)((_Z + width())*(float)w/W), zxp = _zxp + ((int)(_zxp*(float)W/w)!=_Z + width()?1:0),\n              _zyp = (int)((_Z + height())*(float)h/H), zyp = _zyp + ((int)(_zyp*(float)H/h)!=_Z + height()?1:0),\n              _zxn = (int)((_Z + width() + 1.0f)*w/W - 1),\n                       zxn = _zxn + ((int)((_zxn + 1.0f)*W/w)!=_Z + width() + 1?1:0),\n              _zyn = (int)((_Z + height() + 1.0f)*h/H - 1),\n                       zyn = _zyn + ((int)((_zyn + 1.0f)*H/h)!=_Z + height() + 1?1:0),\n              _xM = (int)(width()*(float)w/W - 1), xM = _xM + ((int)((_xM + 1.0f)*W/w)!=width()?1:0),\n              _yM = (int)(height()*(float)h/H - 1), yM = _yM + ((int)((_yM + 1.0f)*H/h)!=height()?1:0),\n              xc = (xp + xn)/2,\n              yc = (yp + yn)/2,\n              zxc = (zxp + zxn)/2,\n              zyc = (zyp + zyn)/2,\n              xf = (int)(X*w/W),\n              yf = (int)(Y*h/H),\n              zxf = (int)((Z + width())*w/W),\n              zyf = (int)((Z + height())*h/H);\n\n            if (is_axes) { // Draw axes.\n              visu.draw_line(0,yf,visu.width() - 1,yf,foreground_color,0.7f,0xFF00FF00).\n                draw_line(0,yf,visu.width() - 1,yf,background_color,0.7f,0x00FF00FF).\n                draw_line(xf,0,xf,visu.height() - 1,foreground_color,0.7f,0xFF00FF00).\n                draw_line(xf,0,xf,visu.height() - 1,background_color,0.7f,0x00FF00FF);\n              if (_depth>1)\n                visu.draw_line(zxf,0,zxf,yM,foreground_color,0.7f,0xFF00FF00).\n                  draw_line(zxf,0,zxf,yM,background_color,0.7f,0x00FF00FF).\n                  draw_line(0,zyf,xM,zyf,foreground_color,0.7f,0xFF00FF00).\n                  draw_line(0,zyf,xM,zyf,background_color,0.7f,0x00FF00FF);\n            }\n\n            // Draw box cursor.\n            if (xn - xp>=4 && yn - yp>=4) visu.draw_rectangle(xp,yp,xn,yn,foreground_color,0.2f).\n                                        draw_rectangle(xp,yp,xn,yn,foreground_color,1,0xAAAAAAAA).\n                                        draw_rectangle(xp,yp,xn,yn,background_color,1,0x55555555);\n            if (_depth>1) {\n              if (yn - yp>=4 && zxn - zxp>=4) visu.draw_rectangle(zxp,yp,zxn,yn,background_color,0.2f).\n                                            draw_rectangle(zxp,yp,zxn,yn,foreground_color,1,0xAAAAAAAA).\n                                            draw_rectangle(zxp,yp,zxn,yn,background_color,1,0x55555555);\n              if (xn - xp>=4 && zyn - zyp>=4) visu.draw_rectangle(xp,zyp,xn,zyn,background_color,0.2f).\n                                            draw_rectangle(xp,zyp,xn,zyn,foreground_color,1,0xAAAAAAAA).\n                                            draw_rectangle(xp,zyp,xn,zyn,background_color,1,0x55555555);\n            }\n\n            // Draw selection.\n            if (phase) {\n              const int\n                _xp0 = (int)(X0*(float)w/W), xp0 = _xp0 + ((int)(_xp0*(float)W/w)!=X0?1:0),\n                _yp0 = (int)(Y0*(float)h/H), yp0 = _yp0 + ((int)(_yp0*(float)H/h)!=Y0?1:0),\n                _xn0 = (int)((X0 + 1.0f)*w/W - 1), xn0 = _xn0 + ((int)((_xn0 + 1.0f)*W/w)!=X0 + 1?1:0),\n                _yn0 = (int)((Y0 + 1.0f)*h/H - 1), yn0 = _yn0 + ((int)((_yn0 + 1.0f)*H/h)!=Y0 + 1?1:0),\n                _zxp0 = (int)((Z0 + width())*(float)w/W), zxp0 = _zxp0 + ((int)(_zxp0*(float)W/w)!=Z0 + width()?1:0),\n                _zyp0 = (int)((Z0 + height())*(float)h/H), zyp0 = _zyp0 + ((int)(_zyp0*(float)H/h)!=Z0 + height()?1:0),\n                _zxn0 = (int)((Z0 + width() + 1.0f)*w/W - 1),\n                zxn0 = _zxn0 + ((int)((_zxn0 + 1.0f)*W/w)!=Z0 + width() + 1?1:0),\n                _zyn0 = (int)((Z0 + height() + 1.0f)*h/H - 1),\n                zyn0 = _zyn0 + ((int)((_zyn0 + 1.0f)*H/h)!=Z0 + height() + 1?1:0),\n                xc0 = (xp0 + xn0)/2,\n                yc0 = (yp0 + yn0)/2,\n                zxc0 = (zxp0 + zxn0)/2,\n                zyc0 = (zyp0 + zyn0)/2;\n\n              switch (feature_type) {\n              case 1 : {\n                visu.draw_arrow(xc0,yc0,xc,yc,background_color,0.9f,30,5,0x55555555).\n                  draw_arrow(xc0,yc0,xc,yc,foreground_color,0.9f,30,5,0xAAAAAAAA);\n                if (d) {\n                  visu.draw_arrow(zxc0,yc0,zxc,yc,background_color,0.9f,30,5,0x55555555).\n                    draw_arrow(zxc0,yc0,zxc,yc,foreground_color,0.9f,30,5,0xAAAAAAAA).\n                    draw_arrow(xc0,zyc0,xc,zyc,background_color,0.9f,30,5,0x55555555).\n                    draw_arrow(xc0,zyc0,xc,zyc,foreground_color,0.9f,30,5,0xAAAAAAAA);\n                }\n              } break;\n              case 2 : {\n                visu.draw_rectangle(X0<X1?xp0:xp,Y0<Y1?yp0:yp,X0<X1?xn:xn0,Y0<Y1?yn:yn0,background_color,0.2f).\n                  draw_rectangle(X0<X1?xp0:xp,Y0<Y1?yp0:yp,X0<X1?xn:xn0,Y0<Y1?yn:yn0,foreground_color,0.9f,0xAAAAAAAA).\n                  draw_rectangle(X0<X1?xp0:xp,Y0<Y1?yp0:yp,X0<X1?xn:xn0,Y0<Y1?yn:yn0,background_color,0.9f,0x55555555);\n                if (d) {\n                  visu.draw_rectangle(Z0<Z1?zxp0:zxp,Y0<Y1?yp0:yp,Z0<Z1?zxn:zxn0,Y0<Y1?yn:yn0,background_color,0.2f).\n                    draw_rectangle(Z0<Z1?zxp0:zxp,Y0<Y1?yp0:yp,Z0<Z1?zxn:zxn0,Y0<Y1?yn:yn0,\n                                   foreground_color,0.9f,0xAAAAAAAA).\n                    draw_rectangle(Z0<Z1?zxp0:zxp,Y0<Y1?yp0:yp,Z0<Z1?zxn:zxn0,Y0<Y1?yn:yn0,\n                                   background_color,0.9f,0x55555555).\n                    draw_rectangle(X0<X1?xp0:xp,Z0<Z1?zyp0:zyp,X0<X1?xn:xn0,Z0<Z1?zyn:zyn0,\n                                   background_color,0.2f).\n                    draw_rectangle(X0<X1?xp0:xp,Z0<Z1?zyp0:zyp,X0<X1?xn:xn0,Z0<Z1?zyn:zyn0,\n                                   foreground_color,0.9f,0xAAAAAAAA).\n                    draw_rectangle(X0<X1?xp0:xp,Z0<Z1?zyp0:zyp,X0<X1?xn:xn0,Z0<Z1?zyn:zyn0,\n                                   background_color,0.9f,0x55555555);\n                }\n              } break;\n              case 3 : {\n                visu.draw_ellipse(xc0,yc0,\n                                  (float)cimg::abs(xc - xc0),\n                                  (float)cimg::abs(yc - yc0),0,background_color,0.2f).\n                  draw_ellipse(xc0,yc0,\n                               (float)cimg::abs(xc - xc0),\n                               (float)cimg::abs(yc - yc0),0,foreground_color,0.9f,~0U).\n                  draw_point(xc0,yc0,foreground_color,0.9f);\n                if (d) {\n                  visu.draw_ellipse(zxc0,yc0,(float)cimg::abs(zxc - zxc0),(float)cimg::abs(yc - yc0),0,\n                                    background_color,0.2f).\n                    draw_ellipse(zxc0,yc0,(float)cimg::abs(zxc - zxc0),(float)cimg::abs(yc - yc0),0,\n                                 foreground_color,0.9f,~0U).\n                    draw_point(zxc0,yc0,foreground_color,0.9f).\n                    draw_ellipse(xc0,zyc0,(float)cimg::abs(xc - xc0),(float)cimg::abs(zyc - zyc0),0,\n                                 background_color,0.2f).\n                    draw_ellipse(xc0,zyc0,(float)cimg::abs(xc - xc0),(float)cimg::abs(zyc - zyc0),0,\n                                 foreground_color,0.9f,~0U).\n                    draw_point(xc0,zyc0,foreground_color,0.9f);\n                }\n              } break;\n              }\n            }\n\n            // Draw text info.\n            if (my>=0 && my<13) text_down = true; else if (my>=visu.height() - 13) text_down = false;\n            if (!feature_type || !phase) {\n              if (X>=0 && Y>=0 && Z>=0 && X<width() && Y<height() && Z<depth()) {\n                if (_depth>1 || force_display_z_coord)\n                  cimg_snprintf(text,text._width,\" Point (%d,%d,%d) = [ \",origX + (int)X,origY + (int)Y,origZ + (int)Z);\n                else cimg_snprintf(text,text._width,\" Point (%d,%d) = [ \",origX + (int)X,origY + (int)Y);\n                char *ctext = text._data + std::strlen(text), *const ltext = text._data + 512;\n                for (unsigned int c = 0; c<_spectrum && ctext<ltext; ++c) {\n                  cimg_snprintf(ctext,text._width/2,cimg::type<T>::format(),\n                                cimg::type<T>::format((*this)((int)X,(int)Y,(int)Z,c)));\n                  ctext = text._data + std::strlen(text);\n                  *(ctext++) = ' '; *ctext = 0;\n                }\n                std::strcpy(text._data + std::strlen(text),\"] \");\n              }\n            } else switch (feature_type) {\n              case 1 : {\n                const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1),\n                  norm = std::sqrt(dX*dX + dY*dY + dZ*dZ);\n                if (_depth>1 || force_display_z_coord)\n                  cimg_snprintf(text,text._width,\" Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g \",\n                                origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1,norm);\n                else cimg_snprintf(text,text._width,\" Vect (%d,%d)-(%d,%d), Norm = %g \",\n                                   origX + X0,origY + Y0,origX + X1,origY + Y1,norm);\n              } break;\n              case 2 :\n                if (_depth>1 || force_display_z_coord)\n                  cimg_snprintf(text,text._width,\" Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d) \",\n                                origX + (X0<X1?X0:X1),origY + (Y0<Y1?Y0:Y1),origZ + (Z0<Z1?Z0:Z1),\n                                origX + (X0<X1?X1:X0),origY + (Y0<Y1?Y1:Y0),origZ + (Z0<Z1?Z1:Z0),\n                                1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1),1 + cimg::abs(Z0 - Z1));\n                else cimg_snprintf(text,text._width,\" Box (%d,%d)-(%d,%d), Size = (%d,%d) \",\n                                   origX + (X0<X1?X0:X1),origY + (Y0<Y1?Y0:Y1),\n                                   origX + (X0<X1?X1:X0),origY + (Y0<Y1?Y1:Y0),\n                                   1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1));\n                break;\n              default :\n                if (_depth>1 || force_display_z_coord)\n                  cimg_snprintf(text,text._width,\" Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d) \",\n                                origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1,\n                                1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1),1 + cimg::abs(Z0 - Z1));\n                else cimg_snprintf(text,text._width,\" Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d) \",\n                                   origX + X0,origY + Y0,origX + X1,origY + Y1,\n                                   1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1));\n              }\n            if (phase || (mx>=0 && my>=0))\n              visu.draw_text(0,text_down?visu.height() - 13:0,text,foreground_color,background_color,0.7f,13);\n          }\n\n          disp.display(visu).wait();\n        } else if (!shape_selected) disp.wait();\n        if (disp.is_resized()) { disp.resize(false)._is_resized = false; old_is_resized = true; visu0.assign(); }\n        omx = mx; omy = my;\n        if (!exit_on_anykey && key && key!=cimg::keyESC &&\n            (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {\n          key = 0;\n        }\n      }\n\n      // Return result.\n      CImg<intT> res(1,feature_type==0?3:6,1,1,-1);\n      if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; }\n      if (shape_selected) {\n        if (feature_type==2) {\n          if (X0>X1) cimg::swap(X0,X1);\n          if (Y0>Y1) cimg::swap(Y0,Y1);\n          if (Z0>Z1) cimg::swap(Z0,Z1);\n        }\n        if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1;\n        switch (feature_type) {\n        case 1 : case 2 : res[0] = X0; res[1] = Y0; res[2] = Z0; res[3] = X1; res[4] = Y1; res[5] = Z1; break;\n        case 3 :\n          res[3] = cimg::abs(X1 - X0); res[4] = cimg::abs(Y1 - Y0); res[5] = cimg::abs(Z1 - Z0); // keep no break here!\n        default : res[0] = X0; res[1] = Y0; res[2] = Z0;\n        }\n      }\n      if (!exit_on_anykey || !(disp.button()&4)) disp.set_button();\n      if (!visible_cursor) disp.show_mouse();\n      disp._normalization = old_normalization;\n      disp._is_resized = old_is_resized;\n      if (key!=~0U) disp.set_key(key);\n      return res;\n    }\n\n    // Return a visualizable uchar8 image for display routines.\n    CImg<ucharT> __get_select(const CImgDisplay& disp, const int normalization,\n                              const int x, const int y, const int z) const {\n      if (is_empty()) return CImg<ucharT>(1,1,1,1,0);\n      const CImg<T> crop = get_shared_channels(0,cimg::min(2,spectrum() - 1));\n      CImg<Tuchar> img2d;\n      if (_depth>1) crop.get_projections2d(x,y,z).move_to(img2d);\n      else CImg<Tuchar>(crop,false).move_to(img2d);\n\n      // Check for inf and NaN values.\n      if (cimg::type<T>::is_float() && normalization) {\n        bool is_inf = false, is_nan = false;\n        cimg_for(img2d,ptr,Tuchar)\n          if (cimg::type<T>::is_inf(*ptr)) { is_inf = true; break; }\n          else if (cimg::type<T>::is_nan(*ptr)) { is_nan = true; break; }\n        if (is_inf || is_nan) {\n          Tint m0 = (Tint)cimg::type<T>::max(), M0 = (Tint)cimg::type<T>::min();\n          if (!normalization) { m0 = 0; M0 = 255; }\n          else if (normalization==2) { m0 = (Tint)disp._min; M0 = (Tint)disp._max; }\n          else\n            cimg_for(img2d,ptr,Tuchar)\n              if (!cimg::type<T>::is_inf(*ptr) && !cimg::type<T>::is_nan(*ptr)) {\n                if (*ptr<(Tuchar)m0) m0 = *ptr;\n                if (*ptr>(Tuchar)M0) M0 = *ptr;\n              }\n          const T\n            val_minf = (T)(normalization==1 || normalization==3?m0 - (M0 - m0)*20 - 1:m0),\n            val_pinf = (T)(normalization==1 || normalization==3?M0 + (M0 - m0)*20 + 1:M0);\n          if (is_nan)\n            cimg_for(img2d,ptr,Tuchar)\n              if (cimg::type<T>::is_nan(*ptr)) *ptr = val_minf; // Replace NaN values.\n          if (is_inf)\n            cimg_for(img2d,ptr,Tuchar)\n              if (cimg::type<T>::is_inf(*ptr)) *ptr = (float)*ptr<0?val_minf:val_pinf; // Replace +-inf values.\n        }\n      }\n\n      switch (normalization) {\n      case 1 : img2d.normalize(0,255); break;\n      case 2 : {\n        const float m = disp._min, M = disp._max;\n        (img2d-=m)*=255.0f/(M - m>0?M - m:1);\n      } break;\n      case 3 :\n        if (cimg::type<T>::is_float()) img2d.normalize(0,255);\n        else {\n          const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();\n          (img2d-=m)*=255.0f/(M - m>0?M - m:1);\n        } break;\n      }\n\n      if (img2d.spectrum()==2) img2d.channels(0,2);\n      return img2d;\n    }\n\n    //! Select sub-graph in a graph.\n    CImg<intT> get_select_graph(CImgDisplay &disp,\n                                const unsigned int plot_type=1, const unsigned int vertex_type=1,\n                                const char *const labelx=0, const double xmin=0, const double xmax=0,\n                                const char *const labely=0, const double ymin=0, const double ymax=0,\n                                const bool exit_on_anykey=false) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"select_graph(): Empty instance.\",\n                                    cimg_instance);\n      if (!disp) disp.assign(cimg_fitscreen(CImgDisplay::screen_width()/2,CImgDisplay::screen_height()/2,1),0,0).\n                   set_title(\"CImg<%s>\",pixel_type());\n      const ulongT siz = (ulongT)_width*_height*_depth;\n      const unsigned int old_normalization = disp.normalization();\n      disp.show().set_button().set_wheel()._normalization = 0;\n\n      double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax;\n      if (nymin==nymax) { nymin = (Tfloat)min_max(nymax); const double dy = nymax - nymin; nymin-=dy/20; nymax+=dy/20; }\n      if (nymin==nymax) { --nymin; ++nymax; }\n      if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; }\n\n      static const unsigned char black[] = { 0, 0, 0 }, white[] = { 255, 255, 255 }, gray[] = { 220, 220, 220 };\n      static const unsigned char gray2[] = { 110, 110, 110 }, ngray[] = { 35, 35, 35 };\n      static unsigned int odimv = 0;\n      static CImg<ucharT> colormap;\n      if (odimv!=_spectrum) {\n        odimv = _spectrum;\n        colormap = CImg<ucharT>(3,_spectrum,1,1,120).noise(70,1);\n        if (_spectrum==1) { colormap[0] = colormap[1] = 120; colormap[2] = 200; }\n        else {\n          colormap(0,0) = 220; colormap(1,0) = 10; colormap(2,0) = 10;\n          if (_spectrum>1) { colormap(0,1) = 10; colormap(1,1) = 220; colormap(2,1) = 10; }\n          if (_spectrum>2) { colormap(0,2) = 10; colormap(1,2) = 10; colormap(2,2) = 220; }\n        }\n      }\n\n      CImg<ucharT> visu0, visu, graph, text, axes;\n      int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2;\n      const unsigned int one = plot_type==3?0U:1U;\n      unsigned int okey = 0, obutton = 0;\n      CImg<charT> message(1024);\n      CImg_3x3(I,unsigned char);\n\n      for (bool selected = false; !selected && !disp.is_closed() && !okey && !disp.wheel(); ) {\n        const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y();\n        const unsigned int key = disp.key(), button = disp.button();\n\n        // Generate graph representation.\n        if (!visu0) {\n          visu0.assign(disp.width(),disp.height(),1,3,220);\n          const int gdimx = disp.width() - 32, gdimy = disp.height() - 32;\n          if (gdimx>0 && gdimy>0) {\n            graph.assign(gdimx,gdimy,1,3,255);\n            if (siz<32) {\n              if (siz>1) graph.draw_grid(gdimx/(float)(siz - one),gdimy/(float)(siz - one),0,0,\n                                         false,true,black,0.2f,0x33333333,0x33333333);\n            } else graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333);\n            cimg_forC(*this,c)\n              graph.draw_graph(get_shared_channel(c),&colormap(0,c),(plot_type!=3 || _spectrum==1)?1:0.6f,\n                               plot_type,vertex_type,nymax,nymin);\n\n            axes.assign(gdimx,gdimy,1,1,0);\n            const float\n              dx = (float)cimg::abs(nxmax - nxmin), dy = (float)cimg::abs(nymax - nymin),\n              px = (float)std::pow(10.0,(int)std::log10(dx?dx:1) - 2.0),\n              py = (float)std::pow(10.0,(int)std::log10(dy?dy:1) - 2.0);\n            const CImg<Tdouble>\n              seqx = dx<=0?CImg<Tdouble>::vector(nxmin):\n                CImg<Tdouble>::sequence(1 + gdimx/60,nxmin,one?nxmax:nxmin + (nxmax - nxmin)*(siz + 1)/siz).round(px),\n              seqy = CImg<Tdouble>::sequence(1 + gdimy/60,nymax,nymin).round(py);\n\n            const bool allow_zero = (nxmin*nxmax>0) || (nymin*nymax>0);\n            axes.draw_axes(seqx,seqy,white,1,~0U,~0U,13,allow_zero);\n            if (nymin>0) axes.draw_axis(seqx,gdimy - 1,gray,1,~0U,13,allow_zero);\n            if (nymax<0) axes.draw_axis(seqx,0,gray,1,~0U,13,allow_zero);\n            if (nxmin>0) axes.draw_axis(0,seqy,gray,1,~0U,13,allow_zero);\n            if (nxmax<0) axes.draw_axis(gdimx - 1,seqy,gray,1,~0U,13,allow_zero);\n\n            cimg_for3x3(axes,x,y,0,0,I,unsigned char)\n              if (Icc) {\n                if (Icc==255) cimg_forC(graph,c) graph(x,y,c) = 0;\n                else cimg_forC(graph,c) graph(x,y,c) = (unsigned char)(2*graph(x,y,c)/3);\n              }\n              else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp)\n                cimg_forC(graph,c) graph(x,y,c) = (unsigned char)((graph(x,y,c) + 511)/3);\n\n            visu0.draw_image(16,16,graph);\n            visu0.draw_line(15,15,16 + gdimx,15,gray2).draw_line(16 + gdimx,15,16 + gdimx,16 + gdimy,gray2).\n              draw_line(16 + gdimx,16 + gdimy,15,16 + gdimy,white).draw_line(15,16 + gdimy,15,15,white);\n          } else graph.assign();\n          text.assign().draw_text(0,0,labelx?labelx:\"X-axis\",white,ngray,1,13).resize(-100,-100,1,3);\n          visu0.draw_image((visu0.width() - text.width())/2,visu0.height() - 14,~text);\n          text.assign().draw_text(0,0,labely?labely:\"Y-axis\",white,ngray,1,13).rotate(-90).resize(-100,-100,1,3);\n          visu0.draw_image(1,(visu0.height() - text.height())/2,~text);\n          visu.assign();\n        }\n\n        // Generate and display current view.\n        if (!visu) {\n          visu.assign(visu0);\n          if (graph && x0>=0 && x1>=0) {\n            const int\n              nx0 = x0<=x1?x0:x1,\n              nx1 = x0<=x1?x1:x0,\n              ny0 = y0<=y1?y0:y1,\n              ny1 = y0<=y1?y1:y0,\n              sx0 = (int)(16 + nx0*(visu.width() - 32)/cimg::max(1U,siz - one)),\n              sx1 = (int)(15 + (nx1 + 1)*(visu.width() - 32)/cimg::max(1U,siz - one)),\n              sy0 = 16 + ny0,\n              sy1 = 16 + ny1;\n            if (y0>=0 && y1>=0)\n              visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU);\n            else visu.draw_rectangle(sx0,0,sx1,visu.height() - 17,gray,0.5f).\n                   draw_line(sx0,16,sx0,visu.height() - 17,black,0.5f,0xCCCCCCCCU).\n                   draw_line(sx1,16,sx1,visu.height() - 17,black,0.5f,0xCCCCCCCCU);\n          }\n          if (mouse_x>=16 && mouse_y>=16 && mouse_x<visu.width() - 16 && mouse_y<visu.height() - 16) {\n            if (graph) visu.draw_line(mouse_x,16,mouse_x,visu.height() - 17,black,0.5f,0x55555555U);\n            const unsigned int\n              x = (unsigned int)cimg::round((mouse_x - 16.0f)*(siz - one)/(disp.width() - 32),1,one?0:-1);\n            const double cx = nxmin + x*(nxmax - nxmin)/cimg::max(1U,siz - 1);\n            if (_spectrum>=7)\n              cimg_snprintf(message,message._width,\"Value[%u:%g] = ( %g %g %g ... %g %g %g )\",x,cx,\n                            (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2),\n                            (double)(*this)(x,0,0,_spectrum - 4),(double)(*this)(x,0,0,_spectrum - 3),\n                            (double)(*this)(x,0,0,_spectrum - 1));\n            else {\n              cimg_snprintf(message,message._width,\"Value[%u:%g] = ( \",x,cx);\n              cimg_forC(*this,c) cimg_sprintf(message._data + std::strlen(message),\"%g \",(double)(*this)(x,0,0,c));\n              cimg_sprintf(message._data + std::strlen(message),\")\");\n            }\n            if (x0>=0 && x1>=0) {\n              const unsigned int\n                nx0 = (unsigned int)(x0<=x1?x0:x1),\n                nx1 = (unsigned int)(x0<=x1?x1:x0),\n                ny0 = (unsigned int)(y0<=y1?y0:y1),\n                ny1 = (unsigned int)(y0<=y1?y1:y0);\n              const double\n                cx0 = nxmin + nx0*(nxmax - nxmin)/cimg::max(1U,siz - 1),\n                cx1 = nxmin + (nx1 + one)*(nxmax - nxmin)/cimg::max(1U,siz - 1),\n                cy0 = nymax - ny0*(nymax - nymin)/(visu._height - 32),\n                cy1 = nymax - ny1*(nymax - nymin)/(visu._height - 32);\n              if (y0>=0 && y1>=0)\n                cimg_sprintf(message._data + std::strlen(message),\" - Range ( %u:%g, %g ) - ( %u:%g, %g )\",\n                             x0,cx0,cy0,x1 + one,cx1,cy1);\n              else\n                cimg_sprintf(message._data + std::strlen(message),\" - Range [ %u:%g - %u:%g ]\",\n                             x0,cx0,x1 + one,cx1);\n            }\n            text.assign().draw_text(0,0,message,white,ngray,1,13).resize(-100,-100,1,3);\n            visu.draw_image((visu.width() - text.width())/2,1,~text);\n          }\n          visu.display(disp);\n        }\n\n        // Test keys.\n        CImg<charT> filename(32);\n        switch (okey = key) {\n#if cimg_OS!=2\n        case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT :\n#endif\n        case cimg::keyCTRLLEFT : case cimg::keySHIFTLEFT : okey = 0; break;\n        case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n          disp.set_fullscreen(false).\n            resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false),\n                   CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false).\n            _is_resized = true;\n          disp.set_key(key,false); okey = 0;\n        } break;\n        case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n          disp.set_fullscreen(false).\n            resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true;\n          disp.set_key(key,false); okey = 0;\n        } break;\n        case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).\n              resize(cimg_fitscreen(CImgDisplay::screen_width()/2,\n                                    CImgDisplay::screen_height()/2,1),false)._is_resized = true;\n            disp.set_key(key,false); okey = 0;\n          } break;\n        case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true;\n            disp.set_key(key,false); okey = 0;\n          } break;\n        case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            static unsigned int snap_number = 0;\n            if (visu || visu0) {\n              CImg<ucharT> &screen = visu?visu:visu0;\n              std::FILE *file;\n              do {\n                cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.bmp\",snap_number++);\n                if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n              } while (file);\n              (+screen).draw_text(0,0,\" Saving snapshot... \",black,gray,1,13).display(disp);\n              screen.save(filename);\n              (+screen).draw_text(0,0,\" Snapshot '%s' saved. \",black,gray,1,13,filename._data).display(disp);\n            }\n            disp.set_key(key,false); okey = 0;\n          } break;\n        case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            static unsigned int snap_number = 0;\n            if (visu || visu0) {\n              CImg<ucharT> &screen = visu?visu:visu0;\n              std::FILE *file;\n              do {\n#ifdef cimg_use_zlib\n                cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.cimgz\",snap_number++);\n#else\n                cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.cimg\",snap_number++);\n#endif\n                if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n              } while (file);\n              (+screen).draw_text(0,0,\" Saving instance... \",black,gray,1,13).display(disp);\n              save(filename);\n              (+screen).draw_text(0,0,\" Instance '%s' saved. \",black,gray,1,13,filename._data).display(disp);\n            }\n            disp.set_key(key,false); okey = 0;\n          } break;\n        }\n\n        // Handle mouse motion and mouse buttons\n        if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) {\n          visu.assign();\n          if (disp.mouse_x()>=0 && disp.mouse_y()>=0) {\n            const int\n              mx = (mouse_x - 16)*(int)(siz - one)/(disp.width() - 32),\n              cx = mx<0?0:(mx>=(int)(siz - one)?(int)(siz - 1 - one):mx),\n              my = mouse_y - 16,\n              cy = my<=0?0:(my>=(disp.height() - 32)?(disp.height() - 32):my);\n            if (button&1) {\n              if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; }\n            }\n            else if (button&2) {\n              if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; }\n            }\n            else if (obutton) { x1 = x1>=0?cx:-1; y1 = y1>=0?cy:-1; selected = true; }\n          } else if (!button && obutton) selected = true;\n          obutton = button; omouse_x = mouse_x; omouse_y = mouse_y;\n        }\n        if (disp.is_resized()) { disp.resize(false); visu0.assign(); }\n        if (visu && visu0) disp.wait();\n        if (!exit_on_anykey && okey && okey!=cimg::keyESC &&\n            (okey!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {\n          disp.set_key(key,false);\n          okey = 0;\n        }\n      }\n\n      disp._normalization = old_normalization;\n      if (x1>=0 && x1<x0) cimg::swap(x0,x1);\n      if (y1<y0) cimg::swap(y0,y1);\n      disp.set_key(okey);\n      return CImg<intT>(4,1,1,1,x0,y0,x1>=0?x1 + (int)one:-1,y1);\n    }\n\n    //! Load image from a file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\note The extension of \\c filename defines the file format. If no filename\n       extension is provided, CImg<T>::get_load() will try to load the file as a .cimg or .cimgz file.\n    **/\n    CImg<T>& load(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      if (!cimg::strncasecmp(filename,\"http://\",7) || !cimg::strncasecmp(filename,\"https://\",8)) {\n        CImg<charT> filename_local(256);\n        load(cimg::load_network(filename,filename_local));\n        std::remove(filename_local);\n        return *this;\n      }\n\n      const char *const ext = cimg::split_filename(filename);\n      const unsigned int omode = cimg::exception_mode();\n      cimg::exception_mode(0);\n      try {\n#ifdef cimg_load_plugin\n        cimg_load_plugin(filename);\n#endif\n#ifdef cimg_load_plugin1\n        cimg_load_plugin1(filename);\n#endif\n#ifdef cimg_load_plugin2\n        cimg_load_plugin2(filename);\n#endif\n#ifdef cimg_load_plugin3\n        cimg_load_plugin3(filename);\n#endif\n#ifdef cimg_load_plugin4\n        cimg_load_plugin4(filename);\n#endif\n#ifdef cimg_load_plugin5\n        cimg_load_plugin5(filename);\n#endif\n#ifdef cimg_load_plugin6\n        cimg_load_plugin6(filename);\n#endif\n#ifdef cimg_load_plugin7\n        cimg_load_plugin7(filename);\n#endif\n#ifdef cimg_load_plugin8\n        cimg_load_plugin8(filename);\n#endif\n        // Ascii formats\n        if (!cimg::strcasecmp(ext,\"asc\")) load_ascii(filename);\n        else if (!cimg::strcasecmp(ext,\"dlm\") ||\n                 !cimg::strcasecmp(ext,\"txt\")) load_dlm(filename);\n\n        // 2d binary formats\n        else if (!cimg::strcasecmp(ext,\"bmp\")) load_bmp(filename);\n        else if (!cimg::strcasecmp(ext,\"jpg\") ||\n                 !cimg::strcasecmp(ext,\"jpeg\") ||\n                 !cimg::strcasecmp(ext,\"jpe\") ||\n                 !cimg::strcasecmp(ext,\"jfif\") ||\n                 !cimg::strcasecmp(ext,\"jif\")) load_jpeg(filename);\n        else if (!cimg::strcasecmp(ext,\"png\")) load_png(filename);\n        else if (!cimg::strcasecmp(ext,\"ppm\") ||\n                 !cimg::strcasecmp(ext,\"pgm\") ||\n                 !cimg::strcasecmp(ext,\"pnm\") ||\n                 !cimg::strcasecmp(ext,\"pbm\") ||\n                 !cimg::strcasecmp(ext,\"pnk\")) load_pnm(filename);\n        else if (!cimg::strcasecmp(ext,\"pfm\")) load_pfm(filename);\n        else if (!cimg::strcasecmp(ext,\"tif\") ||\n                 !cimg::strcasecmp(ext,\"tiff\")) load_tiff(filename);\n        else if (!cimg::strcasecmp(ext,\"exr\")) load_exr(filename);\n        else if (!cimg::strcasecmp(ext,\"cr2\") ||\n                 !cimg::strcasecmp(ext,\"crw\") ||\n                 !cimg::strcasecmp(ext,\"dcr\") ||\n                 !cimg::strcasecmp(ext,\"mrw\") ||\n                 !cimg::strcasecmp(ext,\"nef\") ||\n                 !cimg::strcasecmp(ext,\"orf\") ||\n                 !cimg::strcasecmp(ext,\"pix\") ||\n                 !cimg::strcasecmp(ext,\"ptx\") ||\n                 !cimg::strcasecmp(ext,\"raf\") ||\n                 !cimg::strcasecmp(ext,\"srf\")) load_dcraw_external(filename);\n        else if (!cimg::strcasecmp(ext,\"gif\")) load_gif_external(filename);\n\n        // 3d binary formats\n        else if (!cimg::strcasecmp(ext,\"dcm\") ||\n                 !cimg::strcasecmp(ext,\"dicom\")) load_medcon_external(filename);\n        else if (!cimg::strcasecmp(ext,\"hdr\") ||\n                 !cimg::strcasecmp(ext,\"nii\")) load_analyze(filename);\n        else if (!cimg::strcasecmp(ext,\"par\") ||\n                 !cimg::strcasecmp(ext,\"rec\")) load_parrec(filename);\n        else if (!cimg::strcasecmp(ext,\"mnc\")) load_minc2(filename);\n        else if (!cimg::strcasecmp(ext,\"inr\")) load_inr(filename);\n        else if (!cimg::strcasecmp(ext,\"pan\")) load_pandore(filename);\n        else if (!cimg::strcasecmp(ext,\"cimg\") ||\n                 !cimg::strcasecmp(ext,\"cimgz\") ||\n                 !*ext)  return load_cimg(filename);\n\n        // Archive files\n        else if (!cimg::strcasecmp(ext,\"gz\")) load_gzip_external(filename);\n\n        // Image sequences\n        else if (!cimg::strcasecmp(ext,\"avi\") ||\n                 !cimg::strcasecmp(ext,\"mov\") ||\n                 !cimg::strcasecmp(ext,\"asf\") ||\n                 !cimg::strcasecmp(ext,\"divx\") ||\n                 !cimg::strcasecmp(ext,\"flv\") ||\n                 !cimg::strcasecmp(ext,\"mpg\") ||\n                 !cimg::strcasecmp(ext,\"m1v\") ||\n                 !cimg::strcasecmp(ext,\"m2v\") ||\n                 !cimg::strcasecmp(ext,\"m4v\") ||\n                 !cimg::strcasecmp(ext,\"mjp\") ||\n                 !cimg::strcasecmp(ext,\"mp4\") ||\n                 !cimg::strcasecmp(ext,\"mkv\") ||\n                 !cimg::strcasecmp(ext,\"mpe\") ||\n                 !cimg::strcasecmp(ext,\"movie\") ||\n                 !cimg::strcasecmp(ext,\"ogm\") ||\n                 !cimg::strcasecmp(ext,\"ogg\") ||\n                 !cimg::strcasecmp(ext,\"ogv\") ||\n                 !cimg::strcasecmp(ext,\"qt\") ||\n                 !cimg::strcasecmp(ext,\"rm\") ||\n                 !cimg::strcasecmp(ext,\"vob\") ||\n                 !cimg::strcasecmp(ext,\"wmv\") ||\n                 !cimg::strcasecmp(ext,\"xvid\") ||\n                 !cimg::strcasecmp(ext,\"mpeg\")) load_video(filename);\n        else throw CImgIOException(\"CImg<%s>::load()\",\n                                   pixel_type());\n      } catch (CImgIOException&) {\n        std::FILE *file = 0;\n        try {\n          file = cimg::fopen(filename,\"rb\");\n        } catch (CImgIOException&) {\n          cimg::exception_mode(omode);\n          throw CImgIOException(_cimg_instance\n                                \"load(): Failed to open file '%s'.\",\n                                cimg_instance,\n                                filename);\n        }\n\n        try {\n          const char *const f_type = cimg::ftype(file,filename);\n          std::fclose(file);\n          if (!cimg::strcasecmp(f_type,\"pnm\")) load_pnm(filename);\n          else if (!cimg::strcasecmp(f_type,\"pfm\")) load_pfm(filename);\n          else if (!cimg::strcasecmp(f_type,\"bmp\")) load_bmp(filename);\n          else if (!cimg::strcasecmp(f_type,\"inr\")) load_inr(filename);\n          else if (!cimg::strcasecmp(f_type,\"jpg\")) load_jpeg(filename);\n          else if (!cimg::strcasecmp(f_type,\"pan\")) load_pandore(filename);\n          else if (!cimg::strcasecmp(f_type,\"png\")) load_png(filename);\n          else if (!cimg::strcasecmp(f_type,\"tif\")) load_tiff(filename);\n          else if (!cimg::strcasecmp(f_type,\"gif\")) load_gif_external(filename);\n          else if (!cimg::strcasecmp(f_type,\"dcm\")) load_medcon_external(filename);\n          else throw CImgIOException(\"CImg<%s>::load()\",\n                                     pixel_type());\n        } catch (CImgIOException&) {\n          try {\n            load_other(filename);\n          } catch (CImgIOException&) {\n            cimg::exception_mode(omode);\n            throw CImgIOException(_cimg_instance\n                                  \"load(): Failed to recognize format of file '%s'.\",\n                                  cimg_instance,\n                                  filename);\n          }\n        }\n      }\n      cimg::exception_mode(omode);\n      return *this;\n    }\n\n    //! Load image from a file \\newinstance.\n    static CImg<T> get_load(const char *const filename) {\n      return CImg<T>().load(filename);\n    }\n\n    //! Load image from an ascii file.\n    /**\n       \\param filename Filename, as a C -string.\n    **/\n    CImg<T>& load_ascii(const char *const filename) {\n      return _load_ascii(0,filename);\n    }\n\n    //! Load image from an ascii file \\inplace.\n    static CImg<T> get_load_ascii(const char *const filename) {\n      return CImg<T>().load_ascii(filename);\n    }\n\n    //! Load image from an ascii file \\overloading.\n    CImg<T>& load_ascii(std::FILE *const file) {\n      return _load_ascii(file,0);\n    }\n\n    //! Loadimage from an ascii file \\newinstance.\n    static CImg<T> get_load_ascii(std::FILE *const file) {\n      return CImg<T>().load_ascii(file);\n    }\n\n    CImg<T>& _load_ascii(std::FILE *const file, const char *const filename) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_ascii(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      CImg<charT> line(256); *line = 0;\n      int err = std::fscanf(nfile,\"%255[^\\n]\",line._data);\n      unsigned int dx = 0, dy = 1, dz = 1, dc = 1;\n      cimg_sscanf(line,\"%u%*c%u%*c%u%*c%u\",&dx,&dy,&dz,&dc);\n      err = std::fscanf(nfile,\"%*[^0-9.eEinfa+-]\");\n      if (!dx || !dy || !dz || !dc) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_ascii(): Invalid ascii header in file '%s', image dimensions are set \"\n                              \"to (%u,%u,%u,%u).\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\",dx,dy,dz,dc);\n      }\n      assign(dx,dy,dz,dc);\n      const ulongT siz = size();\n      ulongT off = 0;\n      double val;\n      T *ptr = _data;\n      for (err = 1, off = 0; off<siz && err==1; ++off) {\n        err = std::fscanf(nfile,\"%lf%*[^0-9.eEinfa+-]\",&val);\n        *(ptr++) = (T)val;\n      }\n      if (err!=1)\n        cimg::warn(_cimg_instance\n                   \"load_ascii(): Only %lu/%lu values read from file '%s'.\",\n                   cimg_instance,\n                   off - 1,siz,filename?filename:\"(FILE*)\");\n\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image from a DLM file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_dlm(const char *const filename) {\n      return _load_dlm(0,filename);\n    }\n\n    //! Load image from a DLM file \\newinstance.\n    static CImg<T> get_load_dlm(const char *const filename) {\n      return CImg<T>().load_dlm(filename);\n    }\n\n    //! Load image from a DLM file \\overloading.\n    CImg<T>& load_dlm(std::FILE *const file) {\n      return _load_dlm(file,0);\n    }\n\n    //! Load image from a DLM file \\newinstance.\n    static CImg<T> get_load_dlm(std::FILE *const file) {\n      return CImg<T>().load_dlm(file);\n    }\n\n    CImg<T>& _load_dlm(std::FILE *const file, const char *const filename) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_dlm(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"r\");\n      CImg<charT> delimiter(256), tmp(256); *delimiter = *tmp = 0;\n      unsigned int cdx = 0, dx = 0, dy = 0;\n      int err = 0;\n      double val;\n      assign(256,256,1,1,0);\n      while ((err = std::fscanf(nfile,\"%lf%255[^0-9eEinfa.+-]\",&val,delimiter._data))>0) {\n        if (err>0) (*this)(cdx++,dy) = (T)val;\n        if (cdx>=_width) resize(3*_width/2,_height,1,1,0);\n        char c = 0;\n        if (!cimg_sscanf(delimiter,\"%255[^\\n]%c\",tmp._data,&c) || c=='\\n') {\n          dx = cimg::max(cdx,dx);\n          if (++dy>=_height) resize(_width,3*_height/2,1,1,0);\n          cdx = 0;\n        }\n      }\n      if (cdx && err==1) { dx = cdx; ++dy; }\n      if (!dx || !dy) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_dlm(): Invalid DLM file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      resize(dx,dy,1,1,0);\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image from a BMP file.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_bmp(const char *const filename) {\n      return _load_bmp(0,filename);\n    }\n\n    //! Load image from a BMP file \\newinstance.\n    static CImg<T> get_load_bmp(const char *const filename) {\n      return CImg<T>().load_bmp(filename);\n    }\n\n    //! Load image from a BMP file \\overloading.\n    CImg<T>& load_bmp(std::FILE *const file) {\n      return _load_bmp(file,0);\n    }\n\n    //! Load image from a BMP file \\newinstance.\n    static CImg<T> get_load_bmp(std::FILE *const file) {\n      return CImg<T>().load_bmp(file);\n    }\n\n    CImg<T>& _load_bmp(std::FILE *const file, const char *const filename) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_bmp(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      CImg<ucharT> header(54);\n      cimg::fread(header._data,54,nfile);\n      if (*header!='B' || header[1]!='M') {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_bmp(): Invalid BMP file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n\n      // Read header and pixel buffer\n      int\n        file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),\n        offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),\n        header_size = header[0x0E] + (header[0x0F]<<8) + (header[0x10]<<16) + (header[0x11]<<24),\n        dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),\n        dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),\n        compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),\n        nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),\n        bpp = header[0x1C] + (header[0x1D]<<8);\n\n      if (!file_size || file_size==offset) {\n        cimg::fseek(nfile,0,SEEK_END);\n        file_size = (int)cimg::ftell(nfile);\n        cimg::fseek(nfile,54,SEEK_SET);\n      }\n      if (header_size>40) cimg::fseek(nfile,header_size - 40,SEEK_CUR);\n\n      const int\n        cimg_iobuffer = 24*1024*1024,\n        dx_bytes = (bpp==1)?(dx/8 + (dx%8?1:0)):((bpp==4)?(dx/2 + (dx%2?1:0)):(dx*bpp/8)),\n        align_bytes = (4 - dx_bytes%4)%4,\n        buf_size = cimg::min(cimg::abs(dy)*(dx_bytes + align_bytes),file_size - offset);\n\n      CImg<intT> colormap;\n      if (bpp<16) { if (!nb_colors) nb_colors = 1<<bpp; } else nb_colors = 0;\n      if (nb_colors) { colormap.assign(nb_colors); cimg::fread(colormap._data,nb_colors,nfile); }\n      const int xoffset = offset - 14 - header_size - 4*nb_colors;\n      if (xoffset>0) cimg::fseek(nfile,xoffset,SEEK_CUR);\n\n      CImg<ucharT> buffer;\n      if (buf_size<cimg_iobuffer) { buffer.assign(buf_size); cimg::fread(buffer._data,buf_size,nfile); }\n      else buffer.assign(dx_bytes + align_bytes);\n      unsigned char *ptrs = buffer;\n\n      // Decompress buffer (if necessary)\n      if (compression) {\n        if (file)\n          throw CImgIOException(_cimg_instance\n                                \"load_bmp(): Unable to load compressed data from '(*FILE)' inputs.\",\n                                cimg_instance);\n        else {\n          if (!file) cimg::fclose(nfile);\n          return load_other(filename);\n        }\n      }\n\n      // Read pixel data\n      assign(dx,cimg::abs(dy),1,3);\n      switch (bpp) {\n      case 1 : { // Monochrome\n        for (int y = height() - 1; y>=0; --y) {\n          if (buf_size>=cimg_iobuffer) {\n            cimg::fread(ptrs=buffer._data,dx_bytes,nfile);\n            cimg::fseek(nfile,align_bytes,SEEK_CUR);\n          }\n          unsigned char mask = 0x80, val = 0;\n          cimg_forX(*this,x) {\n            if (mask==0x80) val = *(ptrs++);\n            const unsigned char *col = (unsigned char*)(colormap._data + (val&mask?1:0));\n            (*this)(x,y,2) = (T)*(col++);\n            (*this)(x,y,1) = (T)*(col++);\n            (*this)(x,y,0) = (T)*(col++);\n            mask = cimg::ror(mask);\n          }\n          ptrs+=align_bytes;\n        }\n      } break;\n      case 4 : { // 16 colors\n        for (int y = height() - 1; y>=0; --y) {\n          if (buf_size>=cimg_iobuffer) {\n            cimg::fread(ptrs=buffer._data,dx_bytes,nfile);\n            cimg::fseek(nfile,align_bytes,SEEK_CUR);\n          }\n          unsigned char mask = 0xF0, val = 0;\n          cimg_forX(*this,x) {\n            if (mask==0xF0) val = *(ptrs++);\n            const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4));\n            const unsigned char *col = (unsigned char*)(colormap._data + color);\n            (*this)(x,y,2) = (T)*(col++);\n            (*this)(x,y,1) = (T)*(col++);\n            (*this)(x,y,0) = (T)*(col++);\n            mask = cimg::ror(mask,4);\n          }\n          ptrs+=align_bytes;\n        }\n      } break;\n      case 8 : { //  256 colors\n        for (int y = height() - 1; y>=0; --y) {\n          if (buf_size>=cimg_iobuffer) {\n            cimg::fread(ptrs=buffer._data,dx_bytes,nfile);\n            cimg::fseek(nfile,align_bytes,SEEK_CUR);\n          }\n          cimg_forX(*this,x) {\n            const unsigned char *col = (unsigned char*)(colormap._data + *(ptrs++));\n            (*this)(x,y,2) = (T)*(col++);\n            (*this)(x,y,1) = (T)*(col++);\n            (*this)(x,y,0) = (T)*(col++);\n          }\n          ptrs+=align_bytes;\n        }\n      } break;\n      case 16 : { // 16 bits colors\n        for (int y = height() - 1; y>=0; --y) {\n          if (buf_size>=cimg_iobuffer) {\n            cimg::fread(ptrs=buffer._data,dx_bytes,nfile);\n            cimg::fseek(nfile,align_bytes,SEEK_CUR);\n          }\n          cimg_forX(*this,x) {\n            const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);\n            const unsigned short col = (unsigned short)(c1|(c2<<8));\n            (*this)(x,y,2) = (T)(col&0x1F);\n            (*this)(x,y,1) = (T)((col>>5)&0x1F);\n            (*this)(x,y,0) = (T)((col>>10)&0x1F);\n          }\n          ptrs+=align_bytes;\n        }\n      } break;\n      case 24 : { // 24 bits colors\n        for (int y = height() - 1; y>=0; --y) {\n          if (buf_size>=cimg_iobuffer) {\n            cimg::fread(ptrs=buffer._data,dx_bytes,nfile);\n            cimg::fseek(nfile,align_bytes,SEEK_CUR);\n          }\n          cimg_forX(*this,x) {\n            (*this)(x,y,2) = (T)*(ptrs++);\n            (*this)(x,y,1) = (T)*(ptrs++);\n            (*this)(x,y,0) = (T)*(ptrs++);\n          }\n          ptrs+=align_bytes;\n        }\n      } break;\n      case 32 : { // 32 bits colors\n        for (int y = height() - 1; y>=0; --y) {\n          if (buf_size>=cimg_iobuffer) {\n            cimg::fread(ptrs=buffer._data,dx_bytes,nfile);\n            cimg::fseek(nfile,align_bytes,SEEK_CUR);\n          }\n          cimg_forX(*this,x) {\n            (*this)(x,y,2) = (T)*(ptrs++);\n            (*this)(x,y,1) = (T)*(ptrs++);\n            (*this)(x,y,0) = (T)*(ptrs++);\n            ++ptrs;\n          }\n          ptrs+=align_bytes;\n        }\n      } break;\n      }\n      if (dy<0) mirror('y');\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image from a JPEG file.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_jpeg(const char *const filename) {\n      return _load_jpeg(0,filename);\n    }\n\n    //! Load image from a JPEG file \\newinstance.\n    static CImg<T> get_load_jpeg(const char *const filename) {\n      return CImg<T>().load_jpeg(filename);\n    }\n\n    //! Load image from a JPEG file \\overloading.\n    CImg<T>& load_jpeg(std::FILE *const file) {\n      return _load_jpeg(file,0);\n    }\n\n    //! Load image from a JPEG file \\newinstance.\n    static CImg<T> get_load_jpeg(std::FILE *const file) {\n      return CImg<T>().load_jpeg(file);\n    }\n\n    // Custom error handler for libjpeg.\n#ifdef cimg_use_jpeg\n    struct _cimg_error_mgr {\n      struct jpeg_error_mgr original;\n      jmp_buf setjmp_buffer;\n      char message[JMSG_LENGTH_MAX];\n    };\n\n    typedef struct _cimg_error_mgr *_cimg_error_ptr;\n\n    METHODDEF(void) _cimg_jpeg_error_exit(j_common_ptr cinfo) {\n      _cimg_error_ptr c_err = (_cimg_error_ptr) cinfo->err;  // Return control to the setjmp point\n      (*cinfo->err->format_message)(cinfo,c_err->message);\n      jpeg_destroy(cinfo);  // Clean memory and temp files.\n      longjmp(c_err->setjmp_buffer,1);\n    }\n#endif\n\n    CImg<T>& _load_jpeg(std::FILE *const file, const char *const filename) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_jpeg(): Specified filename is (null).\",\n                                    cimg_instance);\n\n#ifndef cimg_use_jpeg\n      if (file)\n        throw CImgIOException(_cimg_instance\n                              \"load_jpeg(): Unable to load data from '(FILE*)' unless libjpeg is enabled.\",\n                              cimg_instance);\n      else return load_other(filename);\n#else\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      struct jpeg_decompress_struct cinfo;\n      struct _cimg_error_mgr jerr;\n      cinfo.err = jpeg_std_error(&jerr.original);\n      jerr.original.error_exit = _cimg_jpeg_error_exit;\n      if (setjmp(jerr.setjmp_buffer)) { // JPEG error\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                             \"load_jpeg(): Error message returned by libjpeg: %s.\",\n                             cimg_instance,jerr.message);\n      }\n\n      jpeg_create_decompress(&cinfo);\n      jpeg_stdio_src(&cinfo,nfile);\n      jpeg_read_header(&cinfo,TRUE);\n      jpeg_start_decompress(&cinfo);\n\n      if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) {\n        if (!file) {\n          cimg::fclose(nfile);\n          return load_other(filename);\n        } else\n          throw CImgIOException(_cimg_instance\n                                \"load_jpeg(): Failed to load JPEG data from file '%s'.\",\n                                cimg_instance,filename?filename:\"(FILE*)\");\n      }\n      CImg<ucharT> buffer(cinfo.output_width*cinfo.output_components);\n      JSAMPROW row_pointer[1];\n      try { assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components); }\n      catch (...) { if (!file) cimg::fclose(nfile); throw; }\n      T *ptr_r = _data, *ptr_g = _data + 1UL*_width*_height, *ptr_b = _data + 2UL*_width*_height,\n        *ptr_a = _data + 3UL*_width*_height;\n      while (cinfo.output_scanline<cinfo.output_height) {\n        *row_pointer = buffer._data;\n        if (jpeg_read_scanlines(&cinfo,row_pointer,1)!=1) {\n          cimg::warn(_cimg_instance\n                     \"load_jpeg(): Incomplete data in file '%s'.\",\n                     cimg_instance,filename?filename:\"(FILE*)\");\n          break;\n        }\n        const unsigned char *ptrs = buffer._data;\n        switch (_spectrum) {\n        case 1 : {\n          cimg_forX(*this,x) *(ptr_r++) = (T)*(ptrs++);\n        } break;\n        case 3 : {\n          cimg_forX(*this,x) {\n            *(ptr_r++) = (T)*(ptrs++);\n            *(ptr_g++) = (T)*(ptrs++);\n            *(ptr_b++) = (T)*(ptrs++);\n          }\n        } break;\n        case 4 : {\n          cimg_forX(*this,x) {\n            *(ptr_r++) = (T)*(ptrs++);\n            *(ptr_g++) = (T)*(ptrs++);\n            *(ptr_b++) = (T)*(ptrs++);\n            *(ptr_a++) = (T)*(ptrs++);\n          }\n        } break;\n        }\n      }\n      jpeg_finish_decompress(&cinfo);\n      jpeg_destroy_decompress(&cinfo);\n      if (!file) cimg::fclose(nfile);\n      return *this;\n#endif\n    }\n\n    //! Load image from a file, using Magick++ library.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    // Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de>\n    //   This is experimental code, not much tested, use with care.\n    CImg<T>& load_magick(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_magick(): Specified filename is (null).\",\n                                    cimg_instance);\n#ifdef cimg_use_magick\n      Magick::Image image(filename);\n      const unsigned int W = image.size().width(), H = image.size().height();\n      switch (image.type()) {\n      case Magick::PaletteMatteType :\n      case Magick::TrueColorMatteType :\n      case Magick::ColorSeparationType : {\n        assign(W,H,1,4);\n        T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3);\n        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);\n        for (ulongT off = (ulongT)W*H; off; --off) {\n          *(ptr_r++) = (T)(pixels->red);\n          *(ptr_g++) = (T)(pixels->green);\n          *(ptr_b++) = (T)(pixels->blue);\n          *(ptr_a++) = (T)(pixels->opacity);\n          ++pixels;\n        }\n      } break;\n      case Magick::PaletteType :\n      case Magick::TrueColorType : {\n        assign(W,H,1,3);\n        T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2);\n        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);\n        for (ulongT off = (ulongT)W*H; off; --off) {\n          *(ptr_r++) = (T)(pixels->red);\n          *(ptr_g++) = (T)(pixels->green);\n          *(ptr_b++) = (T)(pixels->blue);\n          ++pixels;\n        }\n      } break;\n      case Magick::GrayscaleMatteType : {\n        assign(W,H,1,2);\n        T *ptr_r = data(0,0,0,0), *ptr_a = data(0,0,0,1);\n        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);\n        for (ulongT off = (ulongT)W*H; off; --off) {\n          *(ptr_r++) = (T)(pixels->red);\n          *(ptr_a++) = (T)(pixels->opacity);\n          ++pixels;\n        }\n      } break;\n      default : {\n        assign(W,H,1,1);\n        T *ptr_r = data(0,0,0,0);\n        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);\n        for (ulongT off = (ulongT)W*H; off; --off) {\n          *(ptr_r++) = (T)(pixels->red);\n          ++pixels;\n        }\n      }\n      }\n      return *this;\n#else\n      throw CImgIOException(_cimg_instance\n                            \"load_magick(): Unable to load file '%s' unless libMagick++ is enabled.\",\n                            cimg_instance,\n                            filename);\n#endif\n    }\n\n    //! Load image from a file, using Magick++ library \\newinstance.\n    static CImg<T> get_load_magick(const char *const filename) {\n      return CImg<T>().load_magick(filename);\n    }\n\n    //! Load image from a PNG file.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_png(const char *const filename) {\n      return _load_png(0,filename);\n    }\n\n    //! Load image from a PNG file \\newinstance.\n    static CImg<T> get_load_png(const char *const filename) {\n      return CImg<T>().load_png(filename);\n    }\n\n    //! Load image from a PNG file \\overloading.\n    CImg<T>& load_png(std::FILE *const file) {\n      return _load_png(file,0);\n    }\n\n    //! Load image from a PNG file \\newinstance.\n    static CImg<T> get_load_png(std::FILE *const file) {\n      return CImg<T>().load_png(file);\n    }\n\n    // (Note: Most of this function has been written by Eric Fausett)\n    CImg<T>& _load_png(std::FILE *const file, const char *const filename) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_png(): Specified filename is (null).\",\n                                    cimg_instance);\n\n#ifndef cimg_use_png\n      if (file)\n        throw CImgIOException(_cimg_instance\n                              \"load_png(): Unable to load data from '(FILE*)' unless libpng is enabled.\",\n                              cimg_instance);\n\n      else return load_other(filename);\n#else\n      // Open file and check for PNG validity\n      const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.\n      std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,\"rb\");\n\n      unsigned char pngCheck[8] = { 0 };\n      cimg::fread(pngCheck,8,(std::FILE*)nfile);\n      if (png_sig_cmp(pngCheck,0,8)) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_png(): Invalid PNG file '%s'.\",\n                              cimg_instance,\n                              nfilename?nfilename:\"(FILE*)\");\n      }\n\n      // Setup PNG structures for read\n      png_voidp user_error_ptr = 0;\n      png_error_ptr user_error_fn = 0, user_warning_fn = 0;\n      png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);\n      if (!png_ptr) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_png(): Failed to initialize 'png_ptr' structure for file '%s'.\",\n                              cimg_instance,\n                              nfilename?nfilename:\"(FILE*)\");\n      }\n      png_infop info_ptr = png_create_info_struct(png_ptr);\n      if (!info_ptr) {\n        if (!file) cimg::fclose(nfile);\n        png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0);\n        throw CImgIOException(_cimg_instance\n                              \"load_png(): Failed to initialize 'info_ptr' structure for file '%s'.\",\n                              cimg_instance,\n                              nfilename?nfilename:\"(FILE*)\");\n      }\n      png_infop end_info = png_create_info_struct(png_ptr);\n      if (!end_info) {\n        if (!file) cimg::fclose(nfile);\n        png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0);\n        throw CImgIOException(_cimg_instance\n                              \"load_png(): Failed to initialize 'end_info' structure for file '%s'.\",\n                              cimg_instance,\n                              nfilename?nfilename:\"(FILE*)\");\n      }\n\n      // Error handling callback for png file reading\n      if (setjmp(png_jmpbuf(png_ptr))) {\n        if (!file) cimg::fclose((std::FILE*)nfile);\n        png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);\n        throw CImgIOException(_cimg_instance\n                              \"load_png(): Encountered unknown fatal error in libpng for file '%s'.\",\n                              cimg_instance,\n                              nfilename?nfilename:\"(FILE*)\");\n      }\n      png_init_io(png_ptr, nfile);\n      png_set_sig_bytes(png_ptr, 8);\n\n      // Get PNG Header Info up to data block\n      png_read_info(png_ptr,info_ptr);\n      png_uint_32 W, H;\n      int bit_depth, color_type, interlace_type;\n      bool is_gray = false;\n      png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,(int*)0,(int*)0);\n\n      // Transforms to unify image data\n      if (color_type==PNG_COLOR_TYPE_PALETTE) {\n        png_set_palette_to_rgb(png_ptr);\n        color_type = PNG_COLOR_TYPE_RGB;\n        bit_depth = 8;\n      }\n      if (color_type==PNG_COLOR_TYPE_GRAY && bit_depth<8) {\n        png_set_expand_gray_1_2_4_to_8(png_ptr);\n        is_gray = true;\n        bit_depth = 8;\n      }\n      if (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) {\n        png_set_tRNS_to_alpha(png_ptr);\n        color_type |= PNG_COLOR_MASK_ALPHA;\n      }\n      if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) {\n        png_set_gray_to_rgb(png_ptr);\n        color_type |= PNG_COLOR_MASK_COLOR;\n        is_gray = true;\n      }\n      if (color_type==PNG_COLOR_TYPE_RGB)\n        png_set_filler(png_ptr,0xffffU,PNG_FILLER_AFTER);\n\n      png_read_update_info(png_ptr,info_ptr);\n      if (bit_depth!=8 && bit_depth!=16) {\n        if (!file) cimg::fclose(nfile);\n        png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);\n        throw CImgIOException(_cimg_instance\n                              \"load_png(): Invalid bit depth %u in file '%s'.\",\n                              cimg_instance,\n                              bit_depth,nfilename?nfilename:\"(FILE*)\");\n      }\n      const int byte_depth = bit_depth>>3;\n\n      // Allocate Memory for Image Read\n      png_bytep *const imgData = new png_bytep[H];\n      for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[(size_t)byte_depth*4*W];\n      png_read_image(png_ptr,imgData);\n      png_read_end(png_ptr,end_info);\n\n      // Read pixel data\n      if (color_type!=PNG_COLOR_TYPE_RGB && color_type!=PNG_COLOR_TYPE_RGB_ALPHA) {\n        if (!file) cimg::fclose(nfile);\n        png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);\n        throw CImgIOException(_cimg_instance\n                              \"load_png(): Invalid color coding type %u in file '%s'.\",\n                              cimg_instance,\n                              color_type,nfilename?nfilename:\"(FILE*)\");\n      }\n      const bool is_alpha = (color_type==PNG_COLOR_TYPE_RGBA);\n      try { assign(W,H,1,(is_gray?1:3) + (is_alpha?1:0)); }\n      catch (...) { if (!file) cimg::fclose(nfile); throw; }\n      T\n        *ptr_r = data(0,0,0,0),\n        *ptr_g = is_gray?0:data(0,0,0,1),\n        *ptr_b = is_gray?0:data(0,0,0,2),\n        *ptr_a = !is_alpha?0:data(0,0,0,is_gray?1:3);\n      switch (bit_depth) {\n      case 8 : {\n        cimg_forY(*this,y) {\n          const unsigned char *ptrs = (unsigned char*)imgData[y];\n          cimg_forX(*this,x) {\n            *(ptr_r++) = (T)*(ptrs++);\n            if (ptr_g) *(ptr_g++) = (T)*(ptrs++); else ++ptrs;\n            if (ptr_b) *(ptr_b++) = (T)*(ptrs++); else ++ptrs;\n            if (ptr_a) *(ptr_a++) = (T)*(ptrs++); else ++ptrs;\n          }\n        }\n      } break;\n      case 16 : {\n        cimg_forY(*this,y) {\n          const unsigned short *ptrs = (unsigned short*)(imgData[y]);\n          if (!cimg::endianness()) cimg::invert_endianness(ptrs,4*_width);\n          cimg_forX(*this,x) {\n            *(ptr_r++) = (T)*(ptrs++);\n            if (ptr_g) *(ptr_g++) = (T)*(ptrs++); else ++ptrs;\n            if (ptr_b) *(ptr_b++) = (T)*(ptrs++); else ++ptrs;\n            if (ptr_a) *(ptr_a++) = (T)*(ptrs++); else ++ptrs;\n          }\n        }\n      } break;\n      }\n      png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);\n\n      // Deallocate Image Read Memory\n      cimg_forY(*this,n) delete[] imgData[n];\n      delete[] imgData;\n      if (!file) cimg::fclose(nfile);\n      return *this;\n#endif\n    }\n\n    //! Load image from a PNM file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_pnm(const char *const filename) {\n      return _load_pnm(0,filename);\n    }\n\n    //! Load image from a PNM file \\newinstance.\n    static CImg<T> get_load_pnm(const char *const filename) {\n      return CImg<T>().load_pnm(filename);\n    }\n\n    //! Load image from a PNM file \\overloading.\n    CImg<T>& load_pnm(std::FILE *const file) {\n      return _load_pnm(file,0);\n    }\n\n    //! Load image from a PNM file \\newinstance.\n    static CImg<T> get_load_pnm(std::FILE *const file) {\n      return CImg<T>().load_pnm(file);\n    }\n\n    CImg<T>& _load_pnm(std::FILE *const file, const char *const filename) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_pnm(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      unsigned int ppm_type, W, H, D = 1, colormax = 255;\n      CImg<charT> item(16384,1,1,1,0);\n      int err, rval, gval, bval;\n      const longT cimg_iobuffer = (longT)24*1024*1024;\n      while ((err=std::fscanf(nfile,\"%16383[^\\n]\",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);\n      if (cimg_sscanf(item,\" P%u\",&ppm_type)!=1) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_pnm(): PNM header not found in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      while ((err=std::fscanf(nfile,\" %16383[^\\n]\",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);\n      if ((err=cimg_sscanf(item,\" %u %u %u %u\",&W,&H,&D,&colormax))<2) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_pnm(): WIDTH and HEIGHT fields undefined in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      if (ppm_type!=1 && ppm_type!=4) {\n        if (err==2 || (err==3 && (ppm_type==5 || ppm_type==7 || ppm_type==8 || ppm_type==9))) {\n          while ((err=std::fscanf(nfile,\" %16383[^\\n]\",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);\n          if (cimg_sscanf(item,\"%u\",&colormax)!=1)\n            cimg::warn(_cimg_instance\n                       \"load_pnm(): COLORMAX field is undefined in file '%s'.\",\n                       cimg_instance,\n                       filename?filename:\"(FILE*)\");\n        } else { colormax = D; D = 1; }\n      }\n      std::fgetc(nfile);\n\n      switch (ppm_type) {\n      case 1 : { // 2d b&w ascii.\n        assign(W,H,1,1);\n        T* ptrd = _data;\n        cimg_foroff(*this,off) { if (std::fscanf(nfile,\"%d\",&rval)>0) *(ptrd++) = (T)(rval?0:255); else break; }\n      } break;\n      case 2 : { // 2d grey ascii.\n        assign(W,H,1,1);\n        T* ptrd = _data;\n        cimg_foroff(*this,off) { if (std::fscanf(nfile,\"%d\",&rval)>0) *(ptrd++) = (T)rval; else break; }\n      } break;\n      case 3 : { // 2d color ascii.\n        assign(W,H,1,3);\n        T *ptrd = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2);\n        cimg_forXY(*this,x,y) {\n          if (std::fscanf(nfile,\"%d %d %d\",&rval,&gval,&bval)==3) {\n            *(ptrd++) = (T)rval; *(ptr_g++) = (T)gval; *(ptr_b++) = (T)bval;\n          } else break;\n        }\n      } break;\n      case 4 : { // 2d b&w binary (support 3D PINK extension).\n        CImg<ucharT> raw;\n        assign(W,H,D,1);\n        T *ptrd = data(0,0,0,0);\n        unsigned int w = 0, h = 0, d = 0;\n        for (longT to_read = (longT)((W/8 + (W%8?1:0))*H*D); to_read>0; ) {\n          raw.assign(cimg::min(to_read,cimg_iobuffer));\n          cimg::fread(raw._data,raw._width,nfile);\n          to_read-=raw._width;\n          const unsigned char *ptrs = raw._data;\n          unsigned char mask = 0, val = 0;\n          for (ulongT off = (ulongT)raw._width; off || mask; mask>>=1) {\n            if (!mask) { if (off--) val = *(ptrs++); mask = 128; }\n            *(ptrd++) = (T)((val&mask)?0:255);\n            if (++w==W) { w = 0; mask = 0; if (++h==H) { h = 0; if (++d==D) break; }}\n          }\n        }\n      } break;\n      case 5 : case 7 : { // 2d/3d grey binary (support 3D PINK extension).\n        if (colormax<256) { // 8 bits.\n          CImg<ucharT> raw;\n          assign(W,H,D,1);\n          T *ptrd = data(0,0,0,0);\n          for (longT to_read = (longT)size(); to_read>0; ) {\n            raw.assign(cimg::min(to_read,cimg_iobuffer));\n            cimg::fread(raw._data,raw._width,nfile);\n            to_read-=raw._width;\n            const unsigned char *ptrs = raw._data;\n            for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++);\n          }\n        } else { // 16 bits.\n          CImg<ushortT> raw;\n          assign(W,H,D,1);\n          T *ptrd = data(0,0,0,0);\n          for (longT to_read = (longT)size(); to_read>0; ) {\n            raw.assign(cimg::min(to_read,cimg_iobuffer/2));\n            cimg::fread(raw._data,raw._width,nfile);\n            if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width);\n            to_read-=raw._width;\n            const unsigned short *ptrs = raw._data;\n            for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++);\n          }\n        }\n      } break;\n      case 6 : { // 2d color binary.\n        if (colormax<256) { // 8 bits.\n          CImg<ucharT> raw;\n          assign(W,H,1,3);\n          T\n            *ptr_r = data(0,0,0,0),\n            *ptr_g = data(0,0,0,1),\n            *ptr_b = data(0,0,0,2);\n          for (longT to_read = (longT)size(); to_read>0; ) {\n            raw.assign(cimg::min(to_read,cimg_iobuffer));\n            cimg::fread(raw._data,raw._width,nfile);\n            to_read-=raw._width;\n            const unsigned char *ptrs = raw._data;\n            for (ulongT off = (ulongT)raw._width/3; off; --off) {\n              *(ptr_r++) = (T)*(ptrs++);\n              *(ptr_g++) = (T)*(ptrs++);\n              *(ptr_b++) = (T)*(ptrs++);\n            }\n          }\n        } else { // 16 bits.\n          CImg<ushortT> raw;\n          assign(W,H,1,3);\n          T\n            *ptr_r = data(0,0,0,0),\n            *ptr_g = data(0,0,0,1),\n            *ptr_b = data(0,0,0,2);\n          for (longT to_read = (longT)size(); to_read>0; ) {\n            raw.assign(cimg::min(to_read,cimg_iobuffer/2));\n            cimg::fread(raw._data,raw._width,nfile);\n            if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width);\n            to_read-=raw._width;\n            const unsigned short *ptrs = raw._data;\n            for (ulongT off = (ulongT)raw._width/3; off; --off) {\n              *(ptr_r++) = (T)*(ptrs++);\n              *(ptr_g++) = (T)*(ptrs++);\n              *(ptr_b++) = (T)*(ptrs++);\n            }\n          }\n        }\n      } break;\n      case 8 : { // 2d/3d grey binary with int32 integers (PINK extension).\n        CImg<intT> raw;\n        assign(W,H,D,1);\n        T *ptrd = data(0,0,0,0);\n        for (longT to_read = (longT)size(); to_read>0; ) {\n          raw.assign(cimg::min(to_read,cimg_iobuffer));\n          cimg::fread(raw._data,raw._width,nfile);\n          to_read-=raw._width;\n          const int *ptrs = raw._data;\n          for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++);\n        }\n      } break;\n      case 9 : { // 2d/3d grey binary with float values (PINK extension).\n        CImg<floatT> raw;\n        assign(W,H,D,1);\n        T *ptrd = data(0,0,0,0);\n        for (longT to_read = (longT)size(); to_read>0; ) {\n          raw.assign(cimg::min(to_read,cimg_iobuffer));\n          cimg::fread(raw._data,raw._width,nfile);\n          to_read-=raw._width;\n          const float *ptrs = raw._data;\n          for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++);\n        }\n      } break;\n      default :\n        assign();\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_pnm(): PNM type 'P%d' found, but type is not supported.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\",ppm_type);\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image from a PFM file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_pfm(const char *const filename) {\n      return _load_pfm(0,filename);\n    }\n\n    //! Load image from a PFM file \\newinstance.\n    static CImg<T> get_load_pfm(const char *const filename) {\n      return CImg<T>().load_pfm(filename);\n    }\n\n    //! Load image from a PFM file \\overloading.\n    CImg<T>& load_pfm(std::FILE *const file) {\n      return _load_pfm(file,0);\n    }\n\n    //! Load image from a PFM file \\newinstance.\n    static CImg<T> get_load_pfm(std::FILE *const file) {\n      return CImg<T>().load_pfm(file);\n    }\n\n    CImg<T>& _load_pfm(std::FILE *const file, const char *const filename) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_pfm(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      char pfm_type;\n      CImg<charT> item(16384,1,1,1,0);\n      int W = 0, H = 0, err = 0;\n      double scale = 0;\n      while ((err=std::fscanf(nfile,\"%16383[^\\n]\",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);\n      if (cimg_sscanf(item,\" P%c\",&pfm_type)!=1) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_pfm(): PFM header not found in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      while ((err=std::fscanf(nfile,\" %16383[^\\n]\",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);\n      if ((err=cimg_sscanf(item,\" %d %d\",&W,&H))<2) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_pfm(): WIDTH and HEIGHT fields are undefined in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      if (err==2) {\n        while ((err=std::fscanf(nfile,\" %16383[^\\n]\",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);\n        if (cimg_sscanf(item,\"%lf\",&scale)!=1)\n          cimg::warn(_cimg_instance\n                     \"load_pfm(): SCALE field is undefined in file '%s'.\",\n                     cimg_instance,\n                     filename?filename:\"(FILE*)\");\n      }\n      std::fgetc(nfile);\n      const bool is_color = (pfm_type=='F'), is_inverted = (scale>0)!=cimg::endianness();\n      if (is_color) {\n        assign(W,H,1,3,0);\n        CImg<floatT> buf(3*W);\n        T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2);\n        cimg_forY(*this,y) {\n          cimg::fread(buf._data,3*W,nfile);\n          if (is_inverted) cimg::invert_endianness(buf._data,3*W);\n          const float *ptrs = buf._data;\n          cimg_forX(*this,x) {\n            *(ptr_r++) = (T)*(ptrs++);\n            *(ptr_g++) = (T)*(ptrs++);\n            *(ptr_b++) = (T)*(ptrs++);\n          }\n        }\n      } else {\n        assign(W,H,1,1,0);\n        CImg<floatT> buf(W);\n        T *ptrd = data(0,0,0,0);\n        cimg_forY(*this,y) {\n          cimg::fread(buf._data,W,nfile);\n          if (is_inverted) cimg::invert_endianness(buf._data,W);\n          const float *ptrs = buf._data;\n          cimg_forX(*this,x) *(ptrd++) = (T)*(ptrs++);\n        }\n      }\n      if (!file) cimg::fclose(nfile);\n      return mirror('y');  // Most of the .pfm files are flipped along the y-axis.\n    }\n\n    //! Load image from a RGB file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param dimw Width of the image buffer.\n      \\param dimh Height of the image buffer.\n    **/\n    CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {\n      return _load_rgb(0,filename,dimw,dimh);\n    }\n\n    //! Load image from a RGB file \\newinstance.\n    static CImg<T> get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {\n      return CImg<T>().load_rgb(filename,dimw,dimh);\n    }\n\n    //! Load image from a RGB file \\overloading.\n    CImg<T>& load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {\n      return _load_rgb(file,0,dimw,dimh);\n    }\n\n    //! Load image from a RGB file \\newinstance.\n    static CImg<T> get_load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {\n      return CImg<T>().load_rgb(file,dimw,dimh);\n    }\n\n    CImg<T>& _load_rgb(std::FILE *const file, const char *const filename,\n                       const unsigned int dimw, const unsigned int dimh) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_rgb(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      if (!dimw || !dimh) return assign();\n      const longT cimg_iobuffer = (longT)24*1024*1024;\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      CImg<ucharT> raw;\n      assign(dimw,dimh,1,3);\n      T\n        *ptr_r = data(0,0,0,0),\n        *ptr_g = data(0,0,0,1),\n        *ptr_b = data(0,0,0,2);\n      for (longT to_read = (longT)size(); to_read>0; ) {\n        raw.assign(cimg::min(to_read,cimg_iobuffer));\n        cimg::fread(raw._data,raw._width,nfile);\n        to_read-=raw._width;\n        const unsigned char *ptrs = raw._data;\n        for (ulongT off = raw._width/3UL; off; --off) {\n          *(ptr_r++) = (T)*(ptrs++);\n          *(ptr_g++) = (T)*(ptrs++);\n          *(ptr_b++) = (T)*(ptrs++);\n        }\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image from a RGBA file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param dimw Width of the image buffer.\n       \\param dimh Height of the image buffer.\n    **/\n    CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {\n      return _load_rgba(0,filename,dimw,dimh);\n    }\n\n    //! Load image from a RGBA file \\newinstance.\n    static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {\n      return CImg<T>().load_rgba(filename,dimw,dimh);\n    }\n\n    //! Load image from a RGBA file \\overloading.\n    CImg<T>& load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {\n      return _load_rgba(file,0,dimw,dimh);\n    }\n\n    //! Load image from a RGBA file \\newinstance.\n    static CImg<T> get_load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {\n      return CImg<T>().load_rgba(file,dimw,dimh);\n    }\n\n    CImg<T>& _load_rgba(std::FILE *const file, const char *const filename,\n                        const unsigned int dimw, const unsigned int dimh) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_rgba(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      if (!dimw || !dimh) return assign();\n      const longT cimg_iobuffer = (longT)24*1024*1024;\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      CImg<ucharT> raw;\n      assign(dimw,dimh,1,4);\n      T\n        *ptr_r = data(0,0,0,0),\n        *ptr_g = data(0,0,0,1),\n        *ptr_b = data(0,0,0,2),\n        *ptr_a = data(0,0,0,3);\n      for (longT to_read = (longT)size(); to_read>0; ) {\n        raw.assign(cimg::min(to_read,cimg_iobuffer));\n        cimg::fread(raw._data,raw._width,nfile);\n        to_read-=raw._width;\n        const unsigned char *ptrs = raw._data;\n        for (ulongT off = raw._width/4UL; off; --off) {\n          *(ptr_r++) = (T)*(ptrs++);\n          *(ptr_g++) = (T)*(ptrs++);\n          *(ptr_b++) = (T)*(ptrs++);\n          *(ptr_a++) = (T)*(ptrs++);\n        }\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image from a TIFF file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param first_frame First frame to read (for multi-pages tiff).\n       \\param last_frame Last frame to read (for multi-pages tiff).\n       \\param step_frame Step value of frame reading.\n       \\note\n       - libtiff support is enabled by defining the precompilation\n        directive \\c cimg_use_tif.\n       - When libtiff is enabled, 2D and 3D (multipage) several\n        channel per pixel are supported for\n        <tt>char,uchar,short,ushort,float</tt> and \\c double pixel types.\n       - If \\c cimg_use_tif is not defined at compile time the\n        function uses CImg<T>& load_other(const char*).\n     **/\n    CImg<T>& load_tiff(const char *const filename,\n                       const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                       const unsigned int step_frame=1,\n                       float *const voxel_size=0,\n                       CImg<charT> *const description=0) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_tiff(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      const unsigned int\n        nfirst_frame = first_frame<last_frame?first_frame:last_frame,\n        nstep_frame = step_frame?step_frame:1;\n      unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;\n\n#ifndef cimg_use_tiff\n      cimg::unused(voxel_size,description);\n      if (nfirst_frame || nlast_frame!=~0U || nstep_frame>1)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_tiff(): Unable to read sub-images from file '%s' unless libtiff is enabled.\",\n                                    cimg_instance,\n                                    filename);\n      return load_other(filename);\n#else\n      TIFF *tif = TIFFOpen(filename,\"r\");\n      if (tif) {\n        unsigned int nb_images = 0;\n        do ++nb_images; while (TIFFReadDirectory(tif));\n        if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))\n          cimg::warn(_cimg_instance\n                     \"load_tiff(): File '%s' contains %u image(s) while specified frame range is [%u,%u] (step %u).\",\n                     cimg_instance,\n                     filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);\n\n        if (nfirst_frame>=nb_images) return assign();\n        if (nlast_frame>=nb_images) nlast_frame = nb_images - 1;\n        TIFFSetDirectory(tif,0);\n        CImg<T> frame;\n        for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) {\n          frame._load_tiff(tif,l,voxel_size,description);\n          if (l==nfirst_frame)\n            assign(frame._width,frame._height,1 + (nlast_frame - nfirst_frame)/nstep_frame,frame._spectrum);\n          if (frame._width>_width || frame._height>_height || frame._spectrum>_spectrum)\n            resize(cimg::max(frame._width,_width),\n                   cimg::max(frame._height,_height),-100,\n                   cimg::max(frame._spectrum,_spectrum),0);\n          draw_image(0,0,(l - nfirst_frame)/nstep_frame,frame);\n        }\n        TIFFClose(tif);\n      } else throw CImgIOException(_cimg_instance\n                                   \"load_tiff(): Failed to open file '%s'.\",\n                                   cimg_instance,\n                                   filename);\n      return *this;\n#endif\n    }\n\n    //! Load image from a TIFF file \\newinstance.\n    static CImg<T> get_load_tiff(const char *const filename,\n                                 const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                                 const unsigned int step_frame=1,\n                                 float *const voxel_size=0,\n                                 CImg<charT> *const description=0) {\n      return CImg<T>().load_tiff(filename,first_frame,last_frame,step_frame,voxel_size,description);\n    }\n\n    // (Original contribution by Jerome Boulanger).\n#ifdef cimg_use_tiff\n    template<typename t>\n    void _load_tiff_tiled_contig(TIFF *const tif, const uint16 samplesperpixel,\n                                 const uint32 nx, const uint32 ny, const uint32 tw, const uint32 th) {\n      t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif));\n      if (buf) {\n        for (unsigned int row = 0; row<ny; row+=th)\n          for (unsigned int col = 0; col<nx; col+=tw) {\n            if (TIFFReadTile(tif,buf,col,row,0,0)<0) {\n              _TIFFfree(buf); TIFFClose(tif);\n              throw CImgIOException(_cimg_instance\n                                    \"load_tiff(): Invalid tile in file '%s'.\",\n                                    cimg_instance,\n                                    TIFFFileName(tif));\n            }\n            const t *ptr = buf;\n            for (unsigned int rr = row; rr<cimg::min((unsigned int)(row + th),(unsigned int)ny); ++rr)\n              for (unsigned int cc = col; cc<cimg::min((unsigned int)(col + tw),(unsigned int)nx); ++cc)\n                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)\n                  (*this)(cc,rr,vv) = (T)(ptr[(rr - row)*th*samplesperpixel + (cc - col)*samplesperpixel + vv]);\n          }\n        _TIFFfree(buf);\n      }\n    }\n\n    template<typename t>\n    void _load_tiff_tiled_separate(TIFF *const tif, const uint16 samplesperpixel,\n                                   const uint32 nx, const uint32 ny, const uint32 tw, const uint32 th) {\n      t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif));\n      if (buf) {\n        for (unsigned int vv = 0; vv<samplesperpixel; ++vv)\n          for (unsigned int row = 0; row<ny; row+=th)\n            for (unsigned int col = 0; col<nx; col+=tw) {\n              if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {\n                _TIFFfree(buf); TIFFClose(tif);\n                throw CImgIOException(_cimg_instance\n                                      \"load_tiff(): Invalid tile in file '%s'.\",\n                                      cimg_instance,\n                                      TIFFFileName(tif));\n              }\n              const t *ptr = buf;\n              for (unsigned int rr = row; rr<cimg::min((unsigned int)(row + th),(unsigned int)ny); ++rr)\n                for (unsigned int cc = col; cc<cimg::min((unsigned int)(col + tw),(unsigned int)nx); ++cc)\n                  (*this)(cc,rr,vv) = (T)*(ptr++);\n            }\n        _TIFFfree(buf);\n      }\n    }\n\n    template<typename t>\n    void _load_tiff_contig(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny) {\n      t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif));\n      if (buf) {\n        uint32 row, rowsperstrip = (uint32)-1;\n        TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);\n        for (row = 0; row<ny; row+= rowsperstrip) {\n          uint32 nrow = (row + rowsperstrip>ny?ny - row:rowsperstrip);\n          tstrip_t strip = TIFFComputeStrip(tif, row, 0);\n          if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {\n            _TIFFfree(buf); TIFFClose(tif);\n            throw CImgIOException(_cimg_instance\n                                  \"load_tiff(): Invalid strip in file '%s'.\",\n                                  cimg_instance,\n                                  TIFFFileName(tif));\n          }\n          const t *ptr = buf;\n          for (unsigned int rr = 0; rr<nrow; ++rr)\n            for (unsigned int cc = 0; cc<nx; ++cc)\n              for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row + rr,vv) = (T)*(ptr++);\n        }\n        _TIFFfree(buf);\n      }\n    }\n\n    template<typename t>\n    void _load_tiff_separate(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny) {\n      t *buf = (t*)_TIFFmalloc(TIFFStripSize(tif));\n      if (buf) {\n        uint32 row, rowsperstrip = (uint32)-1;\n        TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);\n        for (unsigned int vv = 0; vv<samplesperpixel; ++vv)\n          for (row = 0; row<ny; row+= rowsperstrip) {\n            uint32 nrow = (row + rowsperstrip>ny?ny - row:rowsperstrip);\n            tstrip_t strip = TIFFComputeStrip(tif, row, vv);\n            if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {\n              _TIFFfree(buf); TIFFClose(tif);\n              throw CImgIOException(_cimg_instance\n                                    \"load_tiff(): Invalid strip in file '%s'.\",\n                                    cimg_instance,\n                                    TIFFFileName(tif));\n            }\n            const t *ptr = buf;\n            for (unsigned int rr = 0;rr<nrow; ++rr)\n              for (unsigned int cc = 0; cc<nx; ++cc)\n                (*this)(cc,row + rr,vv) = (T)*(ptr++);\n          }\n        _TIFFfree(buf);\n      }\n    }\n\n    CImg<T>& _load_tiff(TIFF *const tif, const unsigned int directory,\n                        float *const voxel_size, CImg<charT> *const description) {\n      if (!TIFFSetDirectory(tif,directory)) return assign();\n      uint16 samplesperpixel = 1, bitspersample = 8, photo = 0;\n      uint16 sampleformat = 1;\n      uint32 nx = 1, ny = 1;\n      const char *const filename = TIFFFileName(tif);\n      const bool is_spp = (bool)TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);\n      TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);\n      TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);\n      TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleformat);\n      TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample);\n      TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);\n      if (voxel_size) {\n        const char *s_description = 0;\n        float vx = 0, vy = 0, vz = 0;\n        if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) {\n          const char *s_desc = std::strstr(s_description,\"VX=\");\n          if (s_desc && cimg_sscanf(s_desc,\"VX=%f VY=%f VZ=%f\",&vx,&vy,&vz)==3) { // CImg format.\n            voxel_size[0] = vx; voxel_size[1] = vy; voxel_size[2] = vz;\n          }\n          s_desc = std::strstr(s_description,\"spacing=\");\n          if (s_desc && cimg_sscanf(s_desc,\"spacing=%f\",&vz)==1) { // fiji format.\n            voxel_size[2] = vz;\n          }\n        }\n        TIFFGetField(tif,TIFFTAG_XRESOLUTION,voxel_size);\n        TIFFGetField(tif,TIFFTAG_YRESOLUTION,voxel_size + 1);\n        voxel_size[0] = 1.0f/voxel_size[0];\n        voxel_size[1] = 1.0f/voxel_size[1];\n      }\n      if (description) {\n        const char *s_description = 0;\n        if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description)\n          CImg<charT>::string(s_description).move_to(*description);\n      }\n      const unsigned int spectrum = !is_spp || photo>=3?(photo>1?3:1):samplesperpixel;\n      assign(nx,ny,1,spectrum);\n\n      if ((photo>=3 && sampleformat==1 &&\n           (bitspersample==4 || bitspersample==8) &&\n           (samplesperpixel==1 || samplesperpixel==3 || samplesperpixel==4)) ||\n          (bitspersample==1 && samplesperpixel==1)) {\n        // Special case for unsigned color images.\n        uint32 *const raster = (uint32*)_TIFFmalloc(nx*ny*sizeof(uint32));\n        if (!raster) {\n          _TIFFfree(raster); TIFFClose(tif);\n          throw CImgException(_cimg_instance\n                              \"load_tiff(): Failed to allocate memory (%s) for file '%s'.\",\n                              cimg_instance,\n                              cimg::strbuffersize(nx*ny*sizeof(uint32)),filename);\n        }\n        TIFFReadRGBAImage(tif,nx,ny,raster,0);\n        switch (spectrum) {\n        case 1 :\n          cimg_forXY(*this,x,y)\n            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]);\n          break;\n        case 3 :\n          cimg_forXY(*this,x,y) {\n            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]);\n            (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 -y) + x]);\n            (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 -y) + x]);\n          }\n          break;\n        case 4 :\n          cimg_forXY(*this,x,y) {\n            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]);\n            (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]);\n            (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]);\n            (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny - 1 - y) + x]);\n          }\n          break;\n        }\n        _TIFFfree(raster);\n      } else { // Other cases.\n        uint16 config;\n        TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);\n        if (TIFFIsTiled(tif)) {\n          uint32 tw = 1, th = 1;\n          TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw);\n          TIFFGetField(tif,TIFFTAG_TILELENGTH,&th);\n          if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {\n            case 8 : {\n              if (sampleformat==SAMPLEFORMAT_UINT)\n                _load_tiff_tiled_contig<unsigned char>(tif,samplesperpixel,nx,ny,tw,th);\n              else _load_tiff_tiled_contig<signed char>(tif,samplesperpixel,nx,ny,tw,th);\n            } break;\n            case 16 :\n              if (sampleformat==SAMPLEFORMAT_UINT)\n                _load_tiff_tiled_contig<unsigned short>(tif,samplesperpixel,nx,ny,tw,th);\n              else _load_tiff_tiled_contig<short>(tif,samplesperpixel,nx,ny,tw,th);\n              break;\n            case 32 :\n              if (sampleformat==SAMPLEFORMAT_UINT)\n                _load_tiff_tiled_contig<unsigned int>(tif,samplesperpixel,nx,ny,tw,th);\n              else if (sampleformat==SAMPLEFORMAT_INT)\n                _load_tiff_tiled_contig<int>(tif,samplesperpixel,nx,ny,tw,th);\n              else _load_tiff_tiled_contig<float>(tif,samplesperpixel,nx,ny,tw,th);\n              break;\n            } else switch (bitspersample) {\n            case 8 :\n              if (sampleformat==SAMPLEFORMAT_UINT)\n                _load_tiff_tiled_separate<unsigned char>(tif,samplesperpixel,nx,ny,tw,th);\n              else _load_tiff_tiled_separate<signed char>(tif,samplesperpixel,nx,ny,tw,th);\n              break;\n            case 16 :\n              if (sampleformat==SAMPLEFORMAT_UINT)\n                _load_tiff_tiled_separate<unsigned short>(tif,samplesperpixel,nx,ny,tw,th);\n              else _load_tiff_tiled_separate<short>(tif,samplesperpixel,nx,ny,tw,th);\n              break;\n            case 32 :\n              if (sampleformat==SAMPLEFORMAT_UINT)\n                _load_tiff_tiled_separate<unsigned int>(tif,samplesperpixel,nx,ny,tw,th);\n              else if (sampleformat==SAMPLEFORMAT_INT)\n                _load_tiff_tiled_separate<int>(tif,samplesperpixel,nx,ny,tw,th);\n              else _load_tiff_tiled_separate<float>(tif,samplesperpixel,nx,ny,tw,th);\n              break;\n            }\n        } else {\n          if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {\n            case 8 :\n              if (sampleformat==SAMPLEFORMAT_UINT)\n                _load_tiff_contig<unsigned char>(tif,samplesperpixel,nx,ny);\n              else _load_tiff_contig<signed char>(tif,samplesperpixel,nx,ny);\n              break;\n            case 16 :\n              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig<unsigned short>(tif,samplesperpixel,nx,ny);\n              else _load_tiff_contig<short>(tif,samplesperpixel,nx,ny);\n              break;\n            case 32 :\n              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig<unsigned int>(tif,samplesperpixel,nx,ny);\n              else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_contig<int>(tif,samplesperpixel,nx,ny);\n              else _load_tiff_contig<float>(tif,samplesperpixel,nx,ny);\n              break;\n            } else switch (bitspersample) {\n            case 8 :\n              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<unsigned char>(tif,samplesperpixel,nx,ny);\n              else _load_tiff_separate<signed char>(tif,samplesperpixel,nx,ny);\n              break;\n            case 16 :\n              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<unsigned short>(tif,samplesperpixel,nx,ny);\n              else _load_tiff_separate<short>(tif,samplesperpixel,nx,ny);\n              break;\n            case 32 :\n              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<unsigned int>(tif,samplesperpixel,nx,ny);\n              else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_separate<int>(tif,samplesperpixel,nx,ny);\n              else _load_tiff_separate<float>(tif,samplesperpixel,nx,ny);\n              break;\n            }\n        }\n      }\n      return *this;\n    }\n#endif\n\n    //! Load image from a MINC2 file.\n    /**\n        \\param filename Filename, as a C-string.\n    **/\n    // (Original code by Haz-Edine Assemlal).\n    CImg<T>& load_minc2(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_minc2(): Specified filename is (null).\",\n                                    cimg_instance);\n#ifndef cimg_use_minc2\n      return load_other(filename);\n#else\n      minc::minc_1_reader rdr;\n      rdr.open(filename);\n      assign(rdr.ndim(1)?rdr.ndim(1):1,\n             rdr.ndim(2)?rdr.ndim(2):1,\n             rdr.ndim(3)?rdr.ndim(3):1,\n             rdr.ndim(4)?rdr.ndim(4):1);\n      if(typeid(T)==typeid(unsigned char))\n        rdr.setup_read_byte();\n      else if(typeid(T)==typeid(int))\n        rdr.setup_read_int();\n      else if(typeid(T)==typeid(double))\n        rdr.setup_read_double();\n      else\n        rdr.setup_read_float();\n      minc::load_standard_volume(rdr, this->_data);\n      return *this;\n#endif\n    }\n\n    //! Load image from a MINC2 file \\newinstance.\n    static CImg<T> get_load_minc2(const char *const filename) {\n      return CImg<T>().load_analyze(filename);\n    }\n\n    //! Load image from an ANALYZE7.5/NIFTI file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param[out] voxel_size Pointer to the three voxel sizes read from the file.\n    **/\n    CImg<T>& load_analyze(const char *const filename, float *const voxel_size=0) {\n      return _load_analyze(0,filename,voxel_size);\n    }\n\n    //! Load image from an ANALYZE7.5/NIFTI file \\newinstance.\n    static CImg<T> get_load_analyze(const char *const filename, float *const voxel_size=0) {\n      return CImg<T>().load_analyze(filename,voxel_size);\n    }\n\n    //! Load image from an ANALYZE7.5/NIFTI file \\overloading.\n    CImg<T>& load_analyze(std::FILE *const file, float *const voxel_size=0) {\n      return _load_analyze(file,0,voxel_size);\n    }\n\n    //! Load image from an ANALYZE7.5/NIFTI file \\newinstance.\n    static CImg<T> get_load_analyze(std::FILE *const file, float *const voxel_size=0) {\n      return CImg<T>().load_analyze(file,voxel_size);\n    }\n\n    CImg<T>& _load_analyze(std::FILE *const file, const char *const filename, float *const voxel_size=0) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_analyze(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      std::FILE *nfile_header = 0, *nfile = 0;\n      if (!file) {\n        CImg<charT> body(1024);\n        const char *const ext = cimg::split_filename(filename,body);\n        if (!cimg::strcasecmp(ext,\"hdr\")) { // File is an Analyze header file.\n          nfile_header = cimg::fopen(filename,\"rb\");\n          cimg_sprintf(body._data + std::strlen(body),\".img\");\n          nfile = cimg::fopen(body,\"rb\");\n        } else if (!cimg::strcasecmp(ext,\"img\")) { // File is an Analyze data file.\n          nfile = cimg::fopen(filename,\"rb\");\n          cimg_sprintf(body._data + std::strlen(body),\".hdr\");\n          nfile_header = cimg::fopen(body,\"rb\");\n        } else nfile_header = nfile = cimg::fopen(filename,\"rb\"); // File is a Niftii file.\n      } else nfile_header = nfile = file; // File is a Niftii file.\n      if (!nfile || !nfile_header)\n        throw CImgIOException(_cimg_instance\n                              \"load_analyze(): Invalid Analyze7.5 or NIFTI header in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n\n      // Read header.\n      bool endian = false;\n      unsigned int header_size;\n      cimg::fread(&header_size,1,nfile_header);\n      if (!header_size)\n        throw CImgIOException(_cimg_instance\n                              \"load_analyze(): Invalid zero-size header in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n\n      if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); }\n      unsigned char *const header = new unsigned char[header_size];\n      cimg::fread(header + 4,header_size - 4,nfile_header);\n      if (!file && nfile_header!=nfile) cimg::fclose(nfile_header);\n      if (endian) {\n        cimg::invert_endianness((short*)(header + 40),5);\n        cimg::invert_endianness((short*)(header + 70),1);\n        cimg::invert_endianness((short*)(header + 72),1);\n        cimg::invert_endianness((float*)(header + 76),4);\n        cimg::invert_endianness((float*)(header + 112),1);\n      }\n      unsigned short *dim = (unsigned short*)(header + 40), dimx = 1, dimy = 1, dimz = 1, dimv = 1;\n      if (!dim[0])\n        cimg::warn(_cimg_instance\n                   \"load_analyze(): File '%s' defines an image with zero dimensions.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n\n      if (dim[0]>4)\n        cimg::warn(_cimg_instance\n                   \"load_analyze(): File '%s' defines an image with %u dimensions, reading only the 4 first.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\",dim[0]);\n\n      if (dim[0]>=1) dimx = dim[1];\n      if (dim[0]>=2) dimy = dim[2];\n      if (dim[0]>=3) dimz = dim[3];\n      if (dim[0]>=4) dimv = dim[4];\n      float scalefactor = *(float*)(header + 112); if (scalefactor==0) scalefactor=1;\n      const unsigned short datatype = *(unsigned short*)(header + 70);\n      if (voxel_size) {\n        const float *vsize = (float*)(header + 76);\n        voxel_size[0] = vsize[1]; voxel_size[1] = vsize[2]; voxel_size[2] = vsize[3];\n      }\n      delete[] header;\n\n      // Read pixel data.\n      assign(dimx,dimy,dimz,dimv);\n      switch (datatype) {\n      case 2 : {\n        unsigned char *const buffer = new unsigned char[(size_t)dimx*dimy*dimz*dimv];\n        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);\n        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);\n        delete[] buffer;\n      } break;\n      case 4 : {\n        short *const buffer = new short[(size_t)dimx*dimy*dimz*dimv];\n        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);\n        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);\n        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);\n        delete[] buffer;\n      } break;\n      case 8 : {\n        int *const buffer = new int[(size_t)dimx*dimy*dimz*dimv];\n        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);\n        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);\n        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);\n        delete[] buffer;\n      } break;\n      case 16 : {\n        float *const buffer = new float[(size_t)dimx*dimy*dimz*dimv];\n        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);\n        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);\n        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);\n        delete[] buffer;\n      } break;\n      case 64 : {\n        double *const buffer = new double[(size_t)dimx*dimy*dimz*dimv];\n        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);\n        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);\n        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);\n        delete[] buffer;\n      } break;\n      default :\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_analyze(): Unable to load datatype %d in file '%s'\",\n                              cimg_instance,\n                              datatype,filename?filename:\"(FILE*)\");\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image from a .cimg[z] file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param axis Appending axis, if file contains multiple images. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n      \\param align Appending alignment.\n    **/\n    CImg<T>& load_cimg(const char *const filename, const char axis='z', const float align=0) {\n      CImgList<T> list;\n      list.load_cimg(filename);\n      if (list._width==1) return list[0].move_to(*this);\n      return assign(list.get_append(axis,align));\n    }\n\n    //! Load image from a .cimg[z] file \\newinstance\n    static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const float align=0) {\n      return CImg<T>().load_cimg(filename,axis,align);\n    }\n\n    //! Load image from a .cimg[z] file \\overloading.\n    CImg<T>& load_cimg(std::FILE *const file, const char axis='z', const float align=0) {\n      CImgList<T> list;\n      list.load_cimg(file);\n      if (list._width==1) return list[0].move_to(*this);\n      return assign(list.get_append(axis,align));\n    }\n\n    //! Load image from a .cimg[z] file \\newinstance\n    static CImg<T> get_load_cimg(std::FILE *const file, const char axis='z', const float align=0) {\n      return CImg<T>().load_cimg(file,axis,align);\n    }\n\n    //! Load sub-images of a .cimg file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param n0 Starting frame.\n      \\param n1 Ending frame (~0U for max).\n      \\param x0 X-coordinate of the starting sub-image vertex.\n      \\param y0 Y-coordinate of the starting sub-image vertex.\n      \\param z0 Z-coordinate of the starting sub-image vertex.\n      \\param c0 C-coordinate of the starting sub-image vertex.\n      \\param x1 X-coordinate of the ending sub-image vertex (~0U for max).\n      \\param y1 Y-coordinate of the ending sub-image vertex (~0U for max).\n      \\param z1 Z-coordinate of the ending sub-image vertex (~0U for max).\n      \\param c1 C-coordinate of the ending sub-image vertex (~0U for max).\n      \\param axis Appending axis, if file contains multiple images. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n      \\param align Appending alignment.\n    **/\n    CImg<T>& load_cimg(const char *const filename,\n                       const unsigned int n0, const unsigned int n1,\n                       const unsigned int x0, const unsigned int y0,\n                       const unsigned int z0, const unsigned int c0,\n                       const unsigned int x1, const unsigned int y1,\n                       const unsigned int z1, const unsigned int c1,\n                       const char axis='z', const float align=0) {\n      CImgList<T> list;\n      list.load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);\n      if (list._width==1) return list[0].move_to(*this);\n      return assign(list.get_append(axis,align));\n    }\n\n    //! Load sub-images of a .cimg file \\newinstance.\n    static CImg<T> get_load_cimg(const char *const filename,\n                                 const unsigned int n0, const unsigned int n1,\n                                 const unsigned int x0, const unsigned int y0,\n                                 const unsigned int z0, const unsigned int c0,\n                                 const unsigned int x1, const unsigned int y1,\n                                 const unsigned int z1, const unsigned int c1,\n                                 const char axis='z', const float align=0) {\n      return CImg<T>().load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1,axis,align);\n    }\n\n    //! Load sub-images of a .cimg file \\overloading.\n    CImg<T>& load_cimg(std::FILE *const file,\n                       const unsigned int n0, const unsigned int n1,\n                       const unsigned int x0, const unsigned int y0,\n                       const unsigned int z0, const unsigned int c0,\n                       const unsigned int x1, const unsigned int y1,\n                       const unsigned int z1, const unsigned int c1,\n                       const char axis='z', const float align=0) {\n      CImgList<T> list;\n      list.load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);\n      if (list._width==1) return list[0].move_to(*this);\n      return assign(list.get_append(axis,align));\n    }\n\n    //! Load sub-images of a .cimg file \\newinstance.\n    static CImg<T> get_load_cimg(std::FILE *const file,\n                                 const unsigned int n0, const unsigned int n1,\n                                 const unsigned int x0, const unsigned int y0,\n                                 const unsigned int z0, const unsigned int c0,\n                                 const unsigned int x1, const unsigned int y1,\n                                 const unsigned int z1, const unsigned int c1,\n                                 const char axis='z', const float align=0) {\n      return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1,axis,align);\n    }\n\n    //! Load image from an INRIMAGE-4 file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param[out] voxel_size Pointer to the three voxel sizes read from the file.\n    **/\n    CImg<T>& load_inr(const char *const filename, float *const voxel_size=0) {\n      return _load_inr(0,filename,voxel_size);\n    }\n\n    //! Load image from an INRIMAGE-4 file \\newinstance.\n    static CImg<T> get_load_inr(const char *const filename, float *const voxel_size=0) {\n      return CImg<T>().load_inr(filename,voxel_size);\n    }\n\n    //! Load image from an INRIMAGE-4 file \\overloading.\n    CImg<T>& load_inr(std::FILE *const file, float *const voxel_size=0) {\n      return _load_inr(file,0,voxel_size);\n    }\n\n    //! Load image from an INRIMAGE-4 file \\newinstance.\n    static CImg<T> get_load_inr(std::FILE *const file, float *voxel_size=0) {\n      return CImg<T>().load_inr(file,voxel_size);\n    }\n\n    static void _load_inr_header(std::FILE *file, int out[8], float *const voxel_size) {\n      CImg<charT> item(1024), tmp1(64), tmp2(64);\n      *item = *tmp1 = *tmp2 = 0;\n      out[0] = std::fscanf(file,\"%63s\",item._data);\n      out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;\n      if(cimg::strncasecmp(item,\"#INRIMAGE-4#{\",13)!=0)\n        throw CImgIOException(\"CImg<%s>::load_inr(): INRIMAGE-4 header not found.\",\n                              pixel_type());\n\n      while (std::fscanf(file,\" %63[^\\n]%*c\",item._data)!=EOF && std::strncmp(item,\"##}\",3)) {\n        cimg_sscanf(item,\" XDIM%*[^0-9]%d\",out);\n        cimg_sscanf(item,\" YDIM%*[^0-9]%d\",out + 1);\n        cimg_sscanf(item,\" ZDIM%*[^0-9]%d\",out + 2);\n        cimg_sscanf(item,\" VDIM%*[^0-9]%d\",out + 3);\n        cimg_sscanf(item,\" PIXSIZE%*[^0-9]%d\",out + 6);\n        if (voxel_size) {\n          cimg_sscanf(item,\" VX%*[^0-9.+-]%f\",voxel_size);\n          cimg_sscanf(item,\" VY%*[^0-9.+-]%f\",voxel_size + 1);\n          cimg_sscanf(item,\" VZ%*[^0-9.+-]%f\",voxel_size + 2);\n        }\n        if (cimg_sscanf(item,\" CPU%*[ =]%s\",tmp1._data)) out[7] = cimg::strncasecmp(tmp1,\"sun\",3)?0:1;\n        switch (cimg_sscanf(item,\" TYPE%*[ =]%s %s\",tmp1._data,tmp2._data)) {\n        case 0 : break;\n        case 2 : out[5] = cimg::strncasecmp(tmp1,\"unsigned\",8)?1:0; std::strncpy(tmp1,tmp2,tmp1._width - 1);\n        case 1 :\n          if (!cimg::strncasecmp(tmp1,\"int\",3) || !cimg::strncasecmp(tmp1,\"fixed\",5))  out[4] = 0;\n          if (!cimg::strncasecmp(tmp1,\"float\",5) || !cimg::strncasecmp(tmp1,\"double\",6)) out[4] = 1;\n          if (!cimg::strncasecmp(tmp1,\"packed\",6)) out[4] = 2;\n          if (out[4]>=0) break;\n        default :\n          throw CImgIOException(\"CImg<%s>::load_inr(): Invalid pixel type '%s' defined in header.\",\n                                pixel_type(),\n                                tmp2._data);\n        }\n      }\n      if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)\n        throw CImgIOException(\"CImg<%s>::load_inr(): Invalid dimensions (%d,%d,%d,%d) defined in header.\",\n                              pixel_type(),\n                              out[0],out[1],out[2],out[3]);\n      if(out[4]<0 || out[5]<0)\n        throw CImgIOException(\"CImg<%s>::load_inr(): Incomplete pixel type defined in header.\",\n                              pixel_type());\n      if(out[6]<0)\n        throw CImgIOException(\"CImg<%s>::load_inr(): Incomplete PIXSIZE field defined in header.\",\n                              pixel_type());\n      if(out[7]<0)\n        throw CImgIOException(\"CImg<%s>::load_inr(): Big/Little Endian coding type undefined in header.\",\n                              pixel_type());\n    }\n\n    CImg<T>& _load_inr(std::FILE *const file, const char *const filename, float *const voxel_size) {\n#define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \\\n     if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \\\n        Ts *xval, *const val = new Ts[(size_t)fopt[0]*fopt[3]]; \\\n        cimg_forYZ(*this,y,z) { \\\n            cimg::fread(val,fopt[0]*fopt[3],nfile); \\\n            if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \\\n            xval = val; cimg_forX(*this,x) cimg_forC(*this,c) (*this)(x,y,z,c) = (T)*(xval++); \\\n          } \\\n        delete[] val; \\\n        loaded = true; \\\n      }\n\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_inr(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      int fopt[8], endian=cimg::endianness()?1:0;\n      bool loaded = false;\n      if (voxel_size) voxel_size[0] = voxel_size[1] = voxel_size[2] = 1;\n      _load_inr_header(nfile,fopt,voxel_size);\n      assign(fopt[0],fopt[1],fopt[2],fopt[3]);\n      _cimg_load_inr_case(0,0,8,unsigned char);\n      _cimg_load_inr_case(0,1,8,char);\n      _cimg_load_inr_case(0,0,16,unsigned short);\n      _cimg_load_inr_case(0,1,16,short);\n      _cimg_load_inr_case(0,0,32,unsigned int);\n      _cimg_load_inr_case(0,1,32,int);\n      _cimg_load_inr_case(1,0,32,float);\n      _cimg_load_inr_case(1,1,32,float);\n      _cimg_load_inr_case(1,0,64,double);\n      _cimg_load_inr_case(1,1,64,double);\n      if (!loaded) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_inr(): Unknown pixel type defined in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image from a EXR file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_exr(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_exr(): Specified filename is (null).\",\n                                    cimg_instance);\n\n#ifndef cimg_use_openexr\n      return load_other(filename);\n#else\n      Imf::RgbaInputFile file(filename);\n      Imath::Box2i dw = file.dataWindow();\n      const int\n        inwidth = dw.max.x - dw.min.x + 1,\n        inheight = dw.max.y - dw.min.y + 1;\n      Imf::Array2D<Imf::Rgba> pixels;\n      pixels.resizeErase(inheight,inwidth);\n      file.setFrameBuffer(&pixels[0][0] - dw.min.x - dw.min.y*inwidth, 1, inwidth);\n      file.readPixels(dw.min.y, dw.max.y);\n      assign(inwidth,inheight,1,4);\n      T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3);\n      cimg_forXY(*this,x,y) {\n        *(ptr_r++) = (T)pixels[y][x].r;\n        *(ptr_g++) = (T)pixels[y][x].g;\n        *(ptr_b++) = (T)pixels[y][x].b;\n        *(ptr_a++) = (T)pixels[y][x].a;\n      }\n      return *this;\n#endif\n    }\n\n    //! Load image from a EXR file \\newinstance.\n    static CImg<T> get_load_exr(const char *const filename) {\n      return CImg<T>().load_exr(filename);\n    }\n\n    //! Load image from a PANDORE-5 file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_pandore(const char *const filename) {\n      return _load_pandore(0,filename);\n    }\n\n    //! Load image from a PANDORE-5 file \\newinstance.\n    static CImg<T> get_load_pandore(const char *const filename) {\n      return CImg<T>().load_pandore(filename);\n    }\n\n    //! Load image from a PANDORE-5 file \\overloading.\n    CImg<T>& load_pandore(std::FILE *const file) {\n      return _load_pandore(file,0);\n    }\n\n    //! Load image from a PANDORE-5 file \\newinstance.\n    static CImg<T> get_load_pandore(std::FILE *const file) {\n      return CImg<T>().load_pandore(file);\n    }\n\n    CImg<T>& _load_pandore(std::FILE *const file, const char *const filename) {\n#define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \\\n        cimg::fread(dims,nbdim,nfile); \\\n        if (endian) cimg::invert_endianness(dims,nbdim); \\\n        assign(nwidth,nheight,ndepth,ndim); \\\n        const size_t siz = size(); \\\n        stype *buffer = new stype[siz]; \\\n        cimg::fread(buffer,siz,nfile); \\\n        if (endian) cimg::invert_endianness(buffer,siz); \\\n        T *ptrd = _data; \\\n        cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \\\n        buffer-=siz; \\\n        delete[] buffer\n\n#define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \\\n        if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \\\n        else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \\\n        else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \\\n        else throw CImgIOException(_cimg_instance \\\n                                   \"load_pandore(): Unknown pixel datatype in file '%s'.\", \\\n                                   cimg_instance, \\\n                                   filename?filename:\"(FILE*)\"); }\n\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_pandore(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      CImg<charT> header(32);\n      cimg::fread(header._data,12,nfile);\n      if (cimg::strncasecmp(\"PANDORE\",header,7)) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_pandore(): PANDORE header not found in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      unsigned int imageid, dims[8] = { 0 };\n      int ptbuf[4] = { 0 };\n      cimg::fread(&imageid,1,nfile);\n      const bool endian = imageid>255;\n      if (endian) cimg::invert_endianness(imageid);\n      cimg::fread(header._data,20,nfile);\n\n      switch (imageid) {\n      case 2 : _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break;\n      case 3 : _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break;\n      case 4 : _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break;\n      case 5 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,unsigned char,unsigned char,unsigned char,1); break;\n      case 6 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break;\n      case 7 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break;\n      case 8 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,unsigned char,unsigned char,unsigned char,1); break;\n      case 9 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break;\n      case 10 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break;\n      case 11 : { // Region 1d\n        cimg::fread(dims,3,nfile);\n        if (endian) cimg::invert_endianness(dims,3);\n        assign(dims[1],1,1,1);\n        const unsigned siz = size();\n        if (dims[2]<256) {\n          unsigned char *buffer = new unsigned char[siz];\n          cimg::fread(buffer,siz,nfile);\n          T *ptrd = _data;\n          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);\n          buffer-=siz;\n          delete[] buffer;\n        } else {\n          if (dims[2]<65536) {\n            unsigned short *buffer = new unsigned short[siz];\n            cimg::fread(buffer,siz,nfile);\n            if (endian) cimg::invert_endianness(buffer,siz);\n            T *ptrd = _data;\n            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);\n            buffer-=siz;\n            delete[] buffer;\n          } else {\n            unsigned int *buffer = new unsigned int[siz];\n            cimg::fread(buffer,siz,nfile);\n            if (endian) cimg::invert_endianness(buffer,siz);\n            T *ptrd = _data;\n            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);\n            buffer-=siz;\n            delete[] buffer;\n          }\n        }\n      }\n        break;\n      case 12 : { // Region 2d\n        cimg::fread(dims,4,nfile);\n        if (endian) cimg::invert_endianness(dims,4);\n        assign(dims[2],dims[1],1,1);\n        const size_t siz = size();\n        if (dims[3]<256) {\n          unsigned char *buffer = new unsigned char[siz];\n          cimg::fread(buffer,siz,nfile);\n          T *ptrd = _data;\n          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);\n          buffer-=siz;\n          delete[] buffer;\n        } else {\n          if (dims[3]<65536) {\n            unsigned short *buffer = new unsigned short[siz];\n            cimg::fread(buffer,siz,nfile);\n            if (endian) cimg::invert_endianness(buffer,siz);\n            T *ptrd = _data;\n            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);\n            buffer-=siz;\n            delete[] buffer;\n          } else {\n            unsigned int *buffer = new unsigned int[siz];\n            cimg::fread(buffer,siz,nfile);\n            if (endian) cimg::invert_endianness(buffer,siz);\n            T *ptrd = _data;\n            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);\n            buffer-=siz;\n            delete[] buffer;\n          }\n        }\n      }\n        break;\n      case 13 : { // Region 3d\n        cimg::fread(dims,5,nfile);\n        if (endian) cimg::invert_endianness(dims,5);\n        assign(dims[3],dims[2],dims[1],1);\n        const size_t siz = size();\n        if (dims[4]<256) {\n          unsigned char *buffer = new unsigned char[siz];\n          cimg::fread(buffer,siz,nfile);\n          T *ptrd = _data;\n          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);\n          buffer-=siz;\n          delete[] buffer;\n        } else {\n          if (dims[4]<65536) {\n            unsigned short *buffer = new unsigned short[siz];\n            cimg::fread(buffer,siz,nfile);\n            if (endian) cimg::invert_endianness(buffer,siz);\n            T *ptrd = _data;\n            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);\n            buffer-=siz;\n            delete[] buffer;\n          } else {\n            unsigned int *buffer = new unsigned int[siz];\n            cimg::fread(buffer,siz,nfile);\n            if (endian) cimg::invert_endianness(buffer,siz);\n            T *ptrd = _data;\n            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);\n            buffer-=siz;\n            delete[] buffer;\n          }\n        }\n      }\n        break;\n      case 16 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,unsigned char,unsigned char,unsigned char,1); break;\n      case 17 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break;\n      case 18 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break;\n      case 19 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,unsigned char,unsigned char,unsigned char,1); break;\n      case 20 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break;\n      case 21 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break;\n      case 22 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned char,unsigned char,unsigned char,1); break;\n      case 23 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4);\n      case 24 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned long,unsigned int,unsigned short,4); break;\n      case 25 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break;\n      case 26 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned char,unsigned char,unsigned char,1); break;\n      case 27 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break;\n      case 28 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned long,unsigned int,unsigned short,4); break;\n      case 29 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break;\n      case 30 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned char,unsigned char,unsigned char,1);\n        break;\n      case 31 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break;\n      case 32 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned long,unsigned int,unsigned short,4);\n        break;\n      case 33 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;\n      case 34 : { // Points 1d\n        cimg::fread(ptbuf,1,nfile);\n        if (endian) cimg::invert_endianness(ptbuf,1);\n        assign(1); (*this)(0) = (T)ptbuf[0];\n      } break;\n      case 35 : { // Points 2d\n        cimg::fread(ptbuf,2,nfile);\n        if (endian) cimg::invert_endianness(ptbuf,2);\n        assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];\n      } break;\n      case 36 : { // Points 3d\n        cimg::fread(ptbuf,3,nfile);\n        if (endian) cimg::invert_endianness(ptbuf,3);\n        assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];\n      } break;\n      default :\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_pandore(): Unable to load data with ID_type %u in file '%s'.\",\n                              cimg_instance,\n                              imageid,filename?filename:\"(FILE*)\");\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image from a PAR-REC (Philips) file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param axis Appending axis, if file contains multiple images. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n      \\param align Appending alignment.\n    **/\n    CImg<T>& load_parrec(const char *const filename, const char axis='c', const float align=0) {\n      CImgList<T> list;\n      list.load_parrec(filename);\n      if (list._width==1) return list[0].move_to(*this);\n      return assign(list.get_append(axis,align));\n    }\n\n    //! Load image from a PAR-REC (Philips) file \\newinstance.\n    static CImg<T> get_load_parrec(const char *const filename, const char axis='c', const float align=0) {\n      return CImg<T>().load_parrec(filename,axis,align);\n    }\n\n    //! Load image from a raw binary file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param size_x Width of the image buffer.\n      \\param size_y Height of the image buffer.\n      \\param size_z Depth of the image buffer.\n      \\param size_c Spectrum of the image buffer.\n      \\param is_multiplexed Tells if the image values are multiplexed along the C-axis.\n      \\param invert_endianness Tells if the endianness of the image buffer must be inverted.\n      \\param offset Starting offset of the read in the specified file.\n    **/\n    CImg<T>& load_raw(const char *const filename,\n                      const unsigned int size_x=0, const unsigned int size_y=1,\n                      const unsigned int size_z=1, const unsigned int size_c=1,\n                      const bool is_multiplexed=false, const bool invert_endianness=false,\n                      const ulongT offset=0) {\n      return _load_raw(0,filename,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset);\n    }\n\n    //! Load image from a raw binary file \\newinstance.\n    static CImg<T> get_load_raw(const char *const filename,\n                                const unsigned int size_x=0, const unsigned int size_y=1,\n                                const unsigned int size_z=1, const unsigned int size_c=1,\n                                const bool is_multiplexed=false, const bool invert_endianness=false,\n                                const ulongT offset=0) {\n      return CImg<T>().load_raw(filename,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset);\n    }\n\n    //! Load image from a raw binary file \\overloading.\n    CImg<T>& load_raw(std::FILE *const file,\n                      const unsigned int size_x=0, const unsigned int size_y=1,\n                      const unsigned int size_z=1, const unsigned int size_c=1,\n                      const bool is_multiplexed=false, const bool invert_endianness=false,\n                      const ulongT offset=0) {\n      return _load_raw(file,0,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset);\n    }\n\n    //! Load image from a raw binary file \\newinstance.\n    static CImg<T> get_load_raw(std::FILE *const file,\n                                const unsigned int size_x=0, const unsigned int size_y=1,\n                                const unsigned int size_z=1, const unsigned int size_c=1,\n                                const bool is_multiplexed=false, const bool invert_endianness=false,\n                                const ulongT offset=0) {\n      return CImg<T>().load_raw(file,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset);\n    }\n\n    CImg<T>& _load_raw(std::FILE *const file, const char *const filename,\n                       const unsigned int size_x, const unsigned int size_y,\n                       const unsigned int size_z, const unsigned int size_c,\n                       const bool is_multiplexed, const bool invert_endianness,\n                       const ulongT offset) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_raw(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (cimg::is_directory(filename))\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_raw(): Specified filename '%s' is a directory.\",\n                                    cimg_instance,filename);\n\n      ulongT siz = (ulongT)size_x*size_y*size_z*size_c;\n      unsigned int\n        _size_x = size_x,\n        _size_y = size_y,\n        _size_z = size_z,\n        _size_c = size_c;\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      if (!siz) {  // Retrieve file size.\n        const longT fpos = cimg::ftell(nfile);\n        if (fpos<0) throw CImgArgumentException(_cimg_instance\n                                                \"load_raw(): Cannot determine size of input file '%s'.\",\n                                                cimg_instance,filename?filename:\"(FILE*)\");\n        cimg::fseek(nfile,0,SEEK_END);\n        siz = cimg::ftell(nfile)/sizeof(T);\n                _size_y = (unsigned int)siz;\n        _size_x = _size_z = _size_c = 1;\n        cimg::fseek(nfile,fpos,SEEK_SET);\n      }\n      cimg::fseek(nfile,offset,SEEK_SET);\n      assign(_size_x,_size_y,_size_z,_size_c,0);\n      if (siz && (!is_multiplexed || size_c==1)) {\n        cimg::fread(_data,siz,nfile);\n        if (invert_endianness) cimg::invert_endianness(_data,siz);\n      } else if (siz) {\n        CImg<T> buf(1,1,1,_size_c);\n        cimg_forXYZ(*this,x,y,z) {\n          cimg::fread(buf._data,_size_c,nfile);\n          if (invert_endianness) cimg::invert_endianness(buf._data,_size_c);\n          set_vector_at(buf,x,y,z);\n        }\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load image sequence from a YUV file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param size_x Width of the frames.\n      \\param size_y Height of the frames.\n      \\param first_frame Index of the first frame to read.\n      \\param last_frame Index of the last frame to read.\n      \\param step_frame Step value for frame reading.\n      \\param yuv2rgb Tells if the YUV to RGB transform must be applied.\n      \\param axis Appending axis, if file contains multiple images. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n    **/\n    CImg<T>& load_yuv(const char *const filename,\n                      const unsigned int size_x, const unsigned int size_y=1,\n                      const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                      const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') {\n      return get_load_yuv(filename,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb,axis).move_to(*this);\n    }\n\n    //! Load image sequence from a YUV file \\newinstance.\n    static CImg<T> get_load_yuv(const char *const filename,\n                                const unsigned int size_x, const unsigned int size_y=1,\n                                const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                                const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') {\n      return CImgList<T>().load_yuv(filename,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis);\n    }\n\n    //! Load image sequence from a YUV file \\overloading.\n    CImg<T>& load_yuv(std::FILE *const file,\n                      const unsigned int size_x, const unsigned int size_y=1,\n                      const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                      const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') {\n      return get_load_yuv(file,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb,axis).move_to(*this);\n    }\n\n    //! Load image sequence from a YUV file \\newinstance.\n    static CImg<T> get_load_yuv(std::FILE *const file,\n                                const unsigned int size_x, const unsigned int size_y=1,\n                                const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                                const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') {\n      return CImgList<T>().load_yuv(file,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis);\n    }\n\n    //! Load 3d object from a .OFF file.\n    /**\n        \\param[out] primitives Primitives data of the 3d object.\n        \\param[out] colors Colors data of the 3d object.\n        \\param filename Filename, as a C-string.\n    **/\n    template<typename tf, typename tc>\n    CImg<T>& load_off(CImgList<tf>& primitives, CImgList<tc>& colors, const char *const filename) {\n      return _load_off(primitives,colors,0,filename);\n    }\n\n    //! Load 3d object from a .OFF file \\newinstance.\n    template<typename tf, typename tc>\n    static CImg<T> get_load_off(CImgList<tf>& primitives, CImgList<tc>& colors, const char *const filename) {\n      return CImg<T>().load_off(primitives,colors,filename);\n    }\n\n    //! Load 3d object from a .OFF file \\overloading.\n    template<typename tf, typename tc>\n    CImg<T>& load_off(CImgList<tf>& primitives, CImgList<tc>& colors, std::FILE *const file) {\n      return _load_off(primitives,colors,file,0);\n    }\n\n    //! Load 3d object from a .OFF file \\newinstance.\n    template<typename tf, typename tc>\n    static CImg<T> get_load_off(CImgList<tf>& primitives, CImgList<tc>& colors, std::FILE *const file) {\n      return CImg<T>().load_off(primitives,colors,file);\n    }\n\n    template<typename tf, typename tc>\n    CImg<T>& _load_off(CImgList<tf>& primitives, CImgList<tc>& colors,\n                       std::FILE *const file, const char *const filename) {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_off(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"r\");\n      unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0;\n      CImg<charT> line(256); *line = 0;\n      int err;\n\n      // Skip comments, and read magic string OFF\n      do { err = std::fscanf(nfile,\"%255[^\\n] \",line._data); } while (!err || (err==1 && *line=='#'));\n      if (cimg::strncasecmp(line,\"OFF\",3) && cimg::strncasecmp(line,\"COFF\",4)) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_off(): OFF header not found in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      do { err = std::fscanf(nfile,\"%255[^\\n] \",line._data); } while (!err || (err==1 && *line=='#'));\n      if ((err = cimg_sscanf(line,\"%u%u%*[^\\n] \",&nb_points,&nb_primitives))!=2) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"load_off(): Invalid number of vertices or primitives specified in file '%s'.\",\n                              cimg_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n\n      // Read points data\n      assign(nb_points,3);\n      float X = 0, Y = 0, Z = 0;\n      cimg_forX(*this,l) {\n        do { err = std::fscanf(nfile,\"%255[^\\n] \",line._data); } while (!err || (err==1 && *line=='#'));\n        if ((err = cimg_sscanf(line,\"%f%f%f%*[^\\n] \",&X,&Y,&Z))!=3) {\n          if (!file) cimg::fclose(nfile);\n          throw CImgIOException(_cimg_instance\n                                \"load_off(): Failed to read vertex %u/%u in file '%s'.\",\n                                cimg_instance,\n                                l + 1,nb_points,filename?filename:\"(FILE*)\");\n        }\n        (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z;\n      }\n\n      // Read primitive data\n      primitives.assign();\n      colors.assign();\n      bool stop_flag = false;\n      while (!stop_flag) {\n        float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f;\n        unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;\n        *line = 0;\n        if ((err = std::fscanf(nfile,\"%u\",&prim))!=1) stop_flag = true;\n        else {\n          ++nb_read;\n          switch (prim) {\n          case 1 : {\n            if ((err = std::fscanf(nfile,\"%u%255[^\\n] \",&i0,line._data))<2) {\n              cimg::warn(_cimg_instance\n                         \"load_off(): Failed to read primitive %u/%u from file '%s'.\",\n                         cimg_instance,\n                         nb_read,nb_primitives,filename?filename:\"(FILE*)\");\n\n              err = std::fscanf(nfile,\"%*[^\\n] \");\n            } else {\n              err = cimg_sscanf(line,\"%f%f%f\",&c0,&c1,&c2);\n              CImg<tf>::vector(i0).move_to(primitives);\n              CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors);\n            }\n          } break;\n          case 2 : {\n            if ((err = std::fscanf(nfile,\"%u%u%255[^\\n] \",&i0,&i1,line._data))<2) {\n              cimg::warn(_cimg_instance\n                         \"load_off(): Failed to read primitive %u/%u from file '%s'.\",\n                         cimg_instance,\n                         nb_read,nb_primitives,filename?filename:\"(FILE*)\");\n\n              err = std::fscanf(nfile,\"%*[^\\n] \");\n            } else {\n              err = cimg_sscanf(line,\"%f%f%f\",&c0,&c1,&c2);\n              CImg<tf>::vector(i0,i1).move_to(primitives);\n              CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors);\n            }\n          } break;\n          case 3 : {\n            if ((err = std::fscanf(nfile,\"%u%u%u%255[^\\n] \",&i0,&i1,&i2,line._data))<3) {\n              cimg::warn(_cimg_instance\n                         \"load_off(): Failed to read primitive %u/%u from file '%s'.\",\n                         cimg_instance,\n                         nb_read,nb_primitives,filename?filename:\"(FILE*)\");\n\n              err = std::fscanf(nfile,\"%*[^\\n] \");\n            } else {\n              err = cimg_sscanf(line,\"%f%f%f\",&c0,&c1,&c2);\n              CImg<tf>::vector(i0,i2,i1).move_to(primitives);\n              CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors);\n            }\n          } break;\n          case 4 : {\n            if ((err = std::fscanf(nfile,\"%u%u%u%u%255[^\\n] \",&i0,&i1,&i2,&i3,line._data))<4) {\n              cimg::warn(_cimg_instance\n                         \"load_off(): Failed to read primitive %u/%u from file '%s'.\",\n                         cimg_instance,\n                         nb_read,nb_primitives,filename?filename:\"(FILE*)\");\n\n              err = std::fscanf(nfile,\"%*[^\\n] \");\n            } else {\n              err = cimg_sscanf(line,\"%f%f%f\",&c0,&c1,&c2);\n              CImg<tf>::vector(i0,i3,i2,i1).move_to(primitives);\n              CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors);\n            }\n          } break;\n          case 5 : {\n            if ((err = std::fscanf(nfile,\"%u%u%u%u%u%255[^\\n] \",&i0,&i1,&i2,&i3,&i4,line._data))<5) {\n              cimg::warn(_cimg_instance\n                         \"load_off(): Failed to read primitive %u/%u from file '%s'.\",\n                         cimg_instance,\n                         nb_read,nb_primitives,filename?filename:\"(FILE*)\");\n\n              err = std::fscanf(nfile,\"%*[^\\n] \");\n            } else {\n              err = cimg_sscanf(line,\"%f%f%f\",&c0,&c1,&c2);\n              CImg<tf>::vector(i0,i3,i2,i1).move_to(primitives);\n              CImg<tf>::vector(i0,i4,i3).move_to(primitives);\n              colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));\n              ++nb_primitives;\n            }\n          } break;\n          case 6 : {\n            if ((err = std::fscanf(nfile,\"%u%u%u%u%u%u%255[^\\n] \",&i0,&i1,&i2,&i3,&i4,&i5,line._data))<6) {\n              cimg::warn(_cimg_instance\n                         \"load_off(): Failed to read primitive %u/%u from file '%s'.\",\n                         cimg_instance,\n                         nb_read,nb_primitives,filename?filename:\"(FILE*)\");\n\n              err = std::fscanf(nfile,\"%*[^\\n] \");\n            } else {\n              err = cimg_sscanf(line,\"%f%f%f\",&c0,&c1,&c2);\n              CImg<tf>::vector(i0,i3,i2,i1).move_to(primitives);\n              CImg<tf>::vector(i0,i5,i4,i3).move_to(primitives);\n              colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));\n              ++nb_primitives;\n            }\n          } break;\n          case 7 : {\n            if ((err = std::fscanf(nfile,\"%u%u%u%u%u%u%u%255[^\\n] \",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line._data))<7) {\n              cimg::warn(_cimg_instance\n                         \"load_off(): Failed to read primitive %u/%u from file '%s'.\",\n                         cimg_instance,\n                         nb_read,nb_primitives,filename?filename:\"(FILE*)\");\n\n              err = std::fscanf(nfile,\"%*[^\\n] \");\n            } else {\n              err = cimg_sscanf(line,\"%f%f%f\",&c0,&c1,&c2);\n              CImg<tf>::vector(i0,i4,i3,i1).move_to(primitives);\n              CImg<tf>::vector(i0,i6,i5,i4).move_to(primitives);\n              CImg<tf>::vector(i3,i2,i1).move_to(primitives);\n              colors.insert(3,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));\n              ++(++nb_primitives);\n            }\n          } break;\n          case 8 : {\n            if ((err = std::fscanf(nfile,\"%u%u%u%u%u%u%u%u%255[^\\n] \",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line._data))<7) {\n              cimg::warn(_cimg_instance\n                         \"load_off(): Failed to read primitive %u/%u from file '%s'.\",\n                         cimg_instance,\n                         nb_read,nb_primitives,filename?filename:\"(FILE*)\");\n\n              err = std::fscanf(nfile,\"%*[^\\n] \");\n            } else {\n              err = cimg_sscanf(line,\"%f%f%f\",&c0,&c1,&c2);\n              CImg<tf>::vector(i0,i3,i2,i1).move_to(primitives);\n              CImg<tf>::vector(i0,i5,i4,i3).move_to(primitives);\n              CImg<tf>::vector(i0,i7,i6,i5).move_to(primitives);\n              colors.insert(3,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));\n              ++(++nb_primitives);\n            }\n          } break;\n          default :\n            cimg::warn(_cimg_instance\n                       \"load_off(): Failed to read primitive %u/%u (%u vertices) from file '%s'.\",\n                       cimg_instance,\n                       nb_read,nb_primitives,prim,filename?filename:\"(FILE*)\");\n\n            err = std::fscanf(nfile,\"%*[^\\n] \");\n          }\n        }\n      }\n      if (!file) cimg::fclose(nfile);\n      if (primitives._width!=nb_primitives)\n        cimg::warn(_cimg_instance\n                   \"load_off(): Only %u/%u primitives read from file '%s'.\",\n                   cimg_instance,\n                   primitives._width,nb_primitives,filename?filename:\"(FILE*)\");\n      return *this;\n    }\n\n    //! Load image sequence from a video file, using OpenCV library.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param first_frame Index of the first frame to read.\n      \\param last_frame Index of the last frame to read.\n      \\param step_frame Step value for frame reading.\n    **/\n    CImg<T>& load_video(const char *const filename,\n                        const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                        const unsigned int step_frame=1,\n                        const char axis='z', const float align=0) {\n      return get_load_video(filename,first_frame,last_frame,step_frame,axis,align).move_to(*this);\n    }\n\n    //! Load image sequence from a video file, using OpenCV library \\newinstance.\n    static CImg<T> get_load_video(const char *const filename,\n                                  const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                                  const unsigned int step_frame=1,\n                                  const char axis='z', const float align=0) {\n      return CImgList<T>().load_video(filename,first_frame,last_frame,step_frame).get_append(axis,align);\n    }\n\n    //! Load image sequence using FFMPEG's external tool 'ffmpeg'.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param axis Appending axis, if file contains multiple images. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n      \\param align Appending alignment.\n    **/\n    CImg<T>& load_ffmpeg_external(const char *const filename, const char axis='z', const float align=0) {\n      return get_load_ffmpeg_external(filename,axis,align).move_to(*this);\n    }\n\n    //! Load image sequence using FFMPEG's external tool 'ffmpeg' \\newinstance.\n    static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const float align=0) {\n      return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align);\n    }\n\n    //! Load gif file, using Imagemagick or GraphicsMagicks's external tools.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param use_graphicsmagick Tells if GraphicsMagick's tool 'gm' is used instead of ImageMagick's tool 'convert'.\n      \\param axis Appending axis, if file contains multiple images. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n      \\param align Appending alignment.\n    **/\n    CImg<T>& load_gif_external(const char *const filename,\n                               const char axis='z', const float align=0) {\n      return get_load_gif_external(filename,axis,align).move_to(*this);\n    }\n\n    //! Load gif file, using ImageMagick or GraphicsMagick's external tool 'convert' \\newinstance.\n    static CImg<T> get_load_gif_external(const char *const filename,\n                                         const char axis='z', const float align=0) {\n      return CImgList<T>().load_gif_external(filename).get_append(axis,align);\n    }\n\n    //! Load image using GraphicsMagick's external tool 'gm'.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_graphicsmagick_external(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_graphicsmagick_external(): Specified filename is (null).\",\n                                    cimg_instance);\n      std::fclose(cimg::fopen(filename,\"rb\"));            // Check if file exists.\n      CImg<charT> command(1024), filename_tmp(256);\n      std::FILE *file = 0;\n      const CImg<charT> s_filename = CImg<charT>::string(filename)._system_strescape();\n#if cimg_OS==1\n      cimg_snprintf(command,command._width,\"%s convert \\\"%s\\\" pnm:-\",\n                    cimg::graphicsmagick_path(),s_filename.data());\n      file = popen(command,\"r\");\n      if (file) {\n        const unsigned int omode = cimg::exception_mode();\n        cimg::exception_mode(0);\n        try { load_pnm(file); } catch (...) {\n          pclose(file);\n          cimg::exception_mode(omode);\n          throw CImgIOException(_cimg_instance\n                                \"load_graphicsmagick_external(): Failed to load file '%s' with external command 'gm'.\",\n                                cimg_instance,\n                                filename);\n        }\n        pclose(file);\n        return *this;\n      }\n#endif\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.pnm\",\n                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      cimg_snprintf(command,command._width,\"%s convert \\\"%s\\\" \\\"%s\\\"\",\n                    cimg::graphicsmagick_path(),s_filename.data(),\n                    CImg<charT>::string(filename_tmp)._system_strescape().data());\n      cimg::system(command,cimg::graphicsmagick_path());\n      if (!(file = std::fopen(filename_tmp,\"rb\"))) {\n        cimg::fclose(cimg::fopen(filename,\"r\"));\n        throw CImgIOException(_cimg_instance\n                              \"load_graphicsmagick_external(): Failed to load file '%s' with external command 'gm'.\",\n                              cimg_instance,\n                              filename);\n\n      } else cimg::fclose(file);\n      load_pnm(filename_tmp);\n      std::remove(filename_tmp);\n      return *this;\n    }\n\n    //! Load image using GraphicsMagick's external tool 'gm' \\newinstance.\n    static CImg<T> get_load_graphicsmagick_external(const char *const filename) {\n      return CImg<T>().load_graphicsmagick_external(filename);\n    }\n\n    //! Load gzipped image file, using external tool 'gunzip'.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_gzip_external(const char *const filename) {\n      if (!filename)\n        throw CImgIOException(_cimg_instance\n                              \"load_gzip_external(): Specified filename is (null).\",\n                              cimg_instance);\n      std::fclose(cimg::fopen(filename,\"rb\"));            // Check if file exists.\n      CImg<charT> command(1024), filename_tmp(256), body(256);\n      const char\n        *const ext = cimg::split_filename(filename,body),\n        *const ext2 = cimg::split_filename(body,0);\n\n      std::FILE *file = 0;\n      do {\n        if (!cimg::strcasecmp(ext,\"gz\")) {\n          if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",\n                                   cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);\n          else cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s\",\n                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        } else {\n          if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",\n                                  cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);\n          else cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s\",\n                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        }\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      cimg_snprintf(command,command._width,\"%s -c \\\"%s\\\" > \\\"%s\\\"\",\n                    cimg::gunzip_path(),\n                    CImg<charT>::string(filename)._system_strescape().data(),\n                    CImg<charT>::string(filename_tmp)._system_strescape().data());\n      cimg::system(command);\n      if (!(file = std::fopen(filename_tmp,\"rb\"))) {\n        cimg::fclose(cimg::fopen(filename,\"r\"));\n        throw CImgIOException(_cimg_instance\n                              \"load_gzip_external(): Failed to load file '%s' with external command 'gunzip'.\",\n                              cimg_instance,\n                              filename);\n\n      } else cimg::fclose(file);\n      load(filename_tmp);\n      std::remove(filename_tmp);\n      return *this;\n    }\n\n    //! Load gzipped image file, using external tool 'gunzip' \\newinstance.\n    static CImg<T> get_load_gzip_external(const char *const filename) {\n      return CImg<T>().load_gzip_external(filename);\n    }\n\n    //! Load image using ImageMagick's external tool 'convert'.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_imagemagick_external(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_imagemagick_external(): Specified filename is (null).\",\n                                    cimg_instance);\n      std::fclose(cimg::fopen(filename,\"rb\"));            // Check if file exists.\n      CImg<charT> command(1024), filename_tmp(256);\n      std::FILE *file = 0;\n      const CImg<charT> s_filename = CImg<charT>::string(filename)._system_strescape();\n#if cimg_OS==1\n      cimg_snprintf(command,command._width,\"%s%s \\\"%s\\\" pnm:-\",\n                    cimg::imagemagick_path(),\n                    !cimg::strcasecmp(cimg::split_filename(filename),\"pdf\")?\" -density 400x400\":\"\",\n                    s_filename.data());\n      file = popen(command,\"r\");\n      if (file) {\n        const unsigned int omode = cimg::exception_mode();\n        cimg::exception_mode(0);\n        try { load_pnm(file); } catch (...) {\n          pclose(file);\n          cimg::exception_mode(omode);\n          throw CImgIOException(_cimg_instance\n                                \"load_imagemagick_external(): Failed to load file '%s' with \"\n                                \"external command 'convert'.\",\n                                cimg_instance,\n                                filename);\n        }\n        pclose(file);\n        return *this;\n      }\n#endif\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.pnm\",\n                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      cimg_snprintf(command,command._width,\"%s%s \\\"%s\\\" \\\"%s\\\"\",\n                    cimg::imagemagick_path(),\n                    !cimg::strcasecmp(cimg::split_filename(filename),\"pdf\")?\" -density 400x400\":\"\",\n                    s_filename.data(),CImg<charT>::string(filename_tmp)._system_strescape().data());\n      cimg::system(command,cimg::imagemagick_path());\n      if (!(file = std::fopen(filename_tmp,\"rb\"))) {\n        cimg::fclose(cimg::fopen(filename,\"r\"));\n        throw CImgIOException(_cimg_instance\n                              \"load_imagemagick_external(): Failed to load file '%s' with external command 'convert'.\",\n                              cimg_instance,\n                              filename);\n\n      } else cimg::fclose(file);\n      load_pnm(filename_tmp);\n      std::remove(filename_tmp);\n      return *this;\n    }\n\n    //! Load image using ImageMagick's external tool 'convert' \\newinstance.\n    static CImg<T> get_load_imagemagick_external(const char *const filename) {\n      return CImg<T>().load_imagemagick_external(filename);\n    }\n\n    //! Load image from a DICOM file, using XMedcon's external tool 'medcon'.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_medcon_external(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_medcon_external(): Specified filename is (null).\",\n                                    cimg_instance);\n      std::fclose(cimg::fopen(filename,\"rb\"));            // Check if file exists.\n      CImg<charT> command(1024), filename_tmp(256), body(256);\n      cimg::fclose(cimg::fopen(filename,\"r\"));\n      std::FILE *file = 0;\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s.hdr\",cimg::filenamerand());\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      cimg_snprintf(command,command._width,\"%s -w -c anlz -o \\\"%s\\\" -f \\\"%s\\\"\",\n                    cimg::medcon_path(),\n                    CImg<charT>::string(filename_tmp)._system_strescape().data(),\n                    CImg<charT>::string(filename)._system_strescape().data());\n      cimg::system(command);\n      cimg::split_filename(filename_tmp,body);\n\n      cimg_snprintf(command,command._width,\"%s.hdr\",body._data);\n      file = std::fopen(command,\"rb\");\n      if (!file) {\n        cimg_snprintf(command,command._width,\"m000-%s.hdr\",body._data);\n        file = std::fopen(command,\"rb\");\n        if (!file) {\n          throw CImgIOException(_cimg_instance\n                                \"load_medcon_external(): Failed to load file '%s' with external command 'medcon'.\",\n                                cimg_instance,\n                                filename);\n        }\n      }\n      cimg::fclose(file);\n      load_analyze(command);\n      std::remove(command);\n      cimg::split_filename(command,body);\n      cimg_snprintf(command,command._width,\"%s.img\",body._data);\n      std::remove(command);\n      return *this;\n    }\n\n    //! Load image from a DICOM file, using XMedcon's external tool 'medcon' \\newinstance.\n    static CImg<T> get_load_medcon_external(const char *const filename) {\n      return CImg<T>().load_medcon_external(filename);\n    }\n\n    //! Load image from a RAW Color Camera file, using external tool 'dcraw'.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_dcraw_external(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_dcraw_external(): Specified filename is (null).\",\n                                    cimg_instance);\n      std::fclose(cimg::fopen(filename,\"rb\"));            // Check if file exists.\n      CImg<charT> command(1024), filename_tmp(256);\n      std::FILE *file = 0;\n      const CImg<charT> s_filename = CImg<charT>::string(filename)._system_strescape();\n#if cimg_OS==1\n      cimg_snprintf(command,command._width,\"%s -w -4 -c \\\"%s\\\"\",\n                    cimg::dcraw_path(),s_filename.data());\n      file = popen(command,\"r\");\n      if (file) {\n        const unsigned int omode = cimg::exception_mode();\n        cimg::exception_mode(0);\n        try { load_pnm(file); } catch (...) {\n          pclose(file);\n          cimg::exception_mode(omode);\n          throw CImgIOException(_cimg_instance\n                                \"load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.\",\n                                cimg_instance,\n                                filename);\n        }\n        pclose(file);\n        return *this;\n      }\n#endif\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.ppm\",\n                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      cimg_snprintf(command,command._width,\"%s -w -4 -c \\\"%s\\\" > \\\"%s\\\"\",\n                    cimg::dcraw_path(),s_filename.data(),CImg<charT>::string(filename_tmp)._system_strescape().data());\n      cimg::system(command,cimg::dcraw_path());\n      if (!(file = std::fopen(filename_tmp,\"rb\"))) {\n        cimg::fclose(cimg::fopen(filename,\"r\"));\n        throw CImgIOException(_cimg_instance\n                              \"load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.\",\n                              cimg_instance,\n                              filename);\n\n      } else cimg::fclose(file);\n      load_pnm(filename_tmp);\n      std::remove(filename_tmp);\n      return *this;\n    }\n\n    //! Load image from a RAW Color Camera file, using external tool 'dcraw' \\newinstance.\n    static CImg<T> get_load_dcraw_external(const char *const filename) {\n      return CImg<T>().load_dcraw_external(filename);\n    }\n\n    //! Load image from a camera stream, using OpenCV.\n    /**\n       \\param camera_index Index of the camera to capture images from.\n       \\param skip_frames Number of frames to skip before the capture.\n       \\param release_camera Tells if the camera ressource must be released at the end of the method.\n    **/\n    CImg<T>& load_camera(const unsigned int camera_index=0, const unsigned int skip_frames=0,\n                         const bool release_camera=true, const unsigned int capture_width=0,\n                         const unsigned int capture_height=0) {\n#ifdef cimg_use_opencv\n      if (camera_index>99)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_camera(): Invalid request for camera #%u \"\n                                    \"(no more than 100 cameras can be managed simultaneously).\",\n                                    cimg_instance,\n                                    camera_index);\n      static CvCapture *capture[100] = { 0 };\n      static unsigned int capture_w[100], capture_h[100];\n      if (release_camera) {\n        cimg::mutex(9);\n        if (capture[camera_index]) cvReleaseCapture(&(capture[camera_index]));\n        capture[camera_index] = 0;\n        capture_w[camera_index] = capture_h[camera_index] = 0;\n        cimg::mutex(9,0);\n        return *this;\n      }\n      if (!capture[camera_index]) {\n        cimg::mutex(9);\n        capture[camera_index] = cvCreateCameraCapture(camera_index);\n        capture_w[camera_index] = 0;\n        capture_h[camera_index] = 0;\n        cimg::mutex(9,0);\n        if (!capture[camera_index]) {\n          throw CImgIOException(_cimg_instance\n                                \"load_camera(): Failed to initialize camera #%u.\",\n                                cimg_instance,\n                                camera_index);\n        }\n      }\n      cimg::mutex(9);\n      if (capture_width!=capture_w[camera_index]) {\n        cvSetCaptureProperty(capture[camera_index],CV_CAP_PROP_FRAME_WIDTH,capture_width);\n        capture_w[camera_index] = capture_width;\n      }\n      if (capture_height!=capture_h[camera_index]) {\n        cvSetCaptureProperty(capture[camera_index],CV_CAP_PROP_FRAME_HEIGHT,capture_height);\n        capture_h[camera_index] = capture_height;\n      }\n      const IplImage *img = 0;\n      for (unsigned int i = 0; i<skip_frames; ++i) img = cvQueryFrame(capture[camera_index]);\n      img = cvQueryFrame(capture[camera_index]);\n      if (img) {\n        const int step = (int)(img->widthStep - 3*img->width);\n        assign(img->width,img->height,1,3);\n        const unsigned char* ptrs = (unsigned char*)img->imageData;\n        T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2);\n        if (step>0) cimg_forY(*this,y) {\n            cimg_forX(*this,x) { *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++); }\n            ptrs+=step;\n          } else for (ulongT siz = (ulongT)img->width*img->height; siz; --siz) {\n            *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++);\n          }\n      }\n      cimg::mutex(9,0);\n      return *this;\n#else\n      cimg::unused(camera_index,skip_frames,release_camera,capture_width,capture_height);\n      throw CImgIOException(_cimg_instance\n                            \"load_camera(): This function requires the OpenCV library to run \"\n                            \"(macro 'cimg_use_opencv' must be defined).\",\n                            cimg_instance);\n#endif\n    }\n\n    //! Load image from a camera stream, using OpenCV \\newinstance.\n    static CImg<T> get_load_camera(const unsigned int camera_index=0, const unsigned int skip_frames=0,\n                                   const bool release_camera=true,\n                                   const unsigned int capture_width=0, const unsigned int capture_height=0) {\n      return CImg<T>().load_camera(camera_index,skip_frames,release_camera,capture_width,capture_height);\n    }\n\n    //! Load image using various non-native ways.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    CImg<T>& load_other(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"load_other(): Specified filename is (null).\",\n                                    cimg_instance);\n\n      const unsigned int omode = cimg::exception_mode();\n      cimg::exception_mode(0);\n      try { load_magick(filename); }\n      catch (CImgException&) {\n        try { load_imagemagick_external(filename); }\n        catch (CImgException&) {\n          try { load_graphicsmagick_external(filename); }\n          catch (CImgException&) {\n            try { load_cimg(filename); }\n            catch (CImgException&) {\n              try {\n                std::fclose(cimg::fopen(filename,\"rb\"));\n              } catch (CImgException&) {\n                cimg::exception_mode(omode);\n                throw CImgIOException(_cimg_instance\n                                      \"load_other(): Failed to open file '%s'.\",\n                                      cimg_instance,\n                                      filename);\n              }\n              cimg::exception_mode(omode);\n              throw CImgIOException(_cimg_instance\n                                    \"load_other(): Failed to recognize format of file '%s'.\",\n                                    cimg_instance,\n                                    filename);\n            }\n          }\n        }\n      }\n      cimg::exception_mode(omode);\n      return *this;\n    }\n\n    //! Load image using various non-native ways \\newinstance.\n    static CImg<T> get_load_other(const char *const filename) {\n      return CImg<T>().load_other(filename);\n    }\n\n    //@}\n    //---------------------------\n    //\n    //! \\name Data Output\n    //@{\n    //---------------------------\n\n    //! Display information about the image data.\n    /**\n       \\param title Name for the considered image.\n       \\param display_stats Tells to compute and display image statistics.\n    **/\n    const CImg<T>& print(const char *const title=0, const bool display_stats=true) const {\n      int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0;\n      CImg<doubleT> st;\n      if (!is_empty() && display_stats) {\n        st = get_stats();\n        xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7];\n        xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11];\n      }\n      const ulongT siz = size(), msiz = siz*sizeof(T), siz1 = siz - 1,\n        mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U, width1 = _width - 1;\n\n      CImg<charT> _title(64);\n      if (!title) cimg_snprintf(_title,_title._width,\"CImg<%s>\",pixel_type());\n\n      std::fprintf(cimg::output(),\"%s%s%s%s: %sthis%s = %p, %ssize%s = (%u,%u,%u,%u) [%lu %s], %sdata%s = (%s*)%p\",\n                   cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal,\n                   cimg::t_bold,cimg::t_normal,(void*)this,\n                   cimg::t_bold,cimg::t_normal,_width,_height,_depth,_spectrum,\n                   mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),\n                   mdisp==0?\"b\":(mdisp==1?\"Kio\":\"Mio\"),\n                   cimg::t_bold,cimg::t_normal,pixel_type(),(void*)begin());\n      if (_data)\n        std::fprintf(cimg::output(),\"..%p (%s) = [ \",(void*)((char*)end() - 1),_is_shared?\"shared\":\"non-shared\");\n      else std::fprintf(cimg::output(),\" (%s) = [ \",_is_shared?\"shared\":\"non-shared\");\n\n      if (!is_empty()) cimg_foroff(*this,off) {\n        std::fprintf(cimg::output(),cimg::type<T>::format(),cimg::type<T>::format(_data[off]));\n        if (off!=siz1) std::fprintf(cimg::output(),\"%s\",off%_width==width1?\" ; \":\" \");\n        if (off==7 && siz>16) { off = siz1 - 8; std::fprintf(cimg::output(),\"... \"); }\n      }\n      if (!is_empty() && display_stats)\n        std::fprintf(cimg::output(),\n                     \" ], %smin%s = %g, %smax%s = %g, %smean%s = %g, %sstd%s = %g, %scoords_min%s = (%u,%u,%u,%u), \"\n                     \"%scoords_max%s = (%u,%u,%u,%u).\\n\",\n                     cimg::t_bold,cimg::t_normal,st[0],\n                     cimg::t_bold,cimg::t_normal,st[1],\n                     cimg::t_bold,cimg::t_normal,st[2],\n                     cimg::t_bold,cimg::t_normal,std::sqrt(st[3]),\n                     cimg::t_bold,cimg::t_normal,xm,ym,zm,vm,\n                     cimg::t_bold,cimg::t_normal,xM,yM,zM,vM);\n      else std::fprintf(cimg::output(),\"%s].\\n\",is_empty()?\"\":\" \");\n      std::fflush(cimg::output());\n      return *this;\n    }\n\n    //! Display image into a CImgDisplay window.\n    /**\n       \\param disp Display window.\n    **/\n    const CImg<T>& display(CImgDisplay& disp) const {\n      disp.display(*this);\n      return *this;\n    }\n\n    //! Display image into a CImgDisplay window, in an interactive way.\n    /**\n        \\param disp Display window.\n        \\param display_info Tells if image information are displayed on the standard output.\n    **/\n    const CImg<T>& display(CImgDisplay &disp, const bool display_info, unsigned int *const XYZ=0,\n                           const bool exit_on_anykey=false) const {\n      return _display(disp,0,display_info,XYZ,exit_on_anykey,false);\n    }\n\n    //! Display image into an interactive window.\n    /**\n        \\param title Window title\n        \\param display_info Tells if image information are displayed on the standard output.\n    **/\n    const CImg<T>& display(const char *const title=0, const bool display_info=true, unsigned int *const XYZ=0,\n                           const bool exit_on_anykey=false) const {\n      CImgDisplay disp;\n      return _display(disp,title,display_info,XYZ,exit_on_anykey,false);\n    }\n\n    const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info,\n                            unsigned int *const XYZ, const bool exit_on_anykey,\n                            const bool exit_on_simpleclick) const {\n      unsigned int oldw = 0, oldh = 0, _XYZ[3] = { 0 }, key = 0;\n      int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1,\n        old_mouse_x = -1, old_mouse_y = -1;\n\n      if (!disp) {\n        disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1);\n        if (!title) disp.set_title(\"CImg<%s> (%ux%ux%ux%u)\",pixel_type(),_width,_height,_depth,_spectrum);\n        else disp.set_title(\"%s\",title);\n      } else if (title) disp.set_title(\"%s\",title);\n      disp.show().flush();\n\n      const CImg<char> dtitle = CImg<char>::string(disp.title());\n      if (display_info) print(dtitle);\n\n      CImg<T> zoom;\n      for (bool reset_view = true, resize_disp = false, is_first_select = true; !key && !disp.is_closed(); ) {\n        if (reset_view) {\n          if (XYZ) { _XYZ[0] = XYZ[0]; _XYZ[1] = XYZ[1]; _XYZ[2] = XYZ[2]; }\n          else {\n            _XYZ[0] = (unsigned int)(x0 + x1)/2;\n            _XYZ[1] = (unsigned int)(y0 + y1)/2;\n            _XYZ[2] = (unsigned int)(z0 + z1)/2;\n          }\n          x0 = 0; y0 = 0; z0 = 0; x1 = width() - 1; y1 = height() - 1; z1 = depth() - 1;\n          oldw = disp._width; oldh = disp._height;\n          reset_view = false;\n        }\n        if (!x0 && !y0 && !z0 && x1==width() - 1 && y1==height() - 1 && z1==depth() - 1) {\n          if (is_empty()) zoom.assign(1,1,1,1,0); else zoom.assign();\n        } else zoom = get_crop(x0,y0,z0,x1,y1,z1);\n\n        const unsigned int\n          dx = 1U + x1 - x0, dy = 1U + y1 - y0, dz = 1U + z1 - z0,\n          tw = dx + (dz>1?dz:0U), th = dy + (dz>1?dz:0U);\n        if (!is_empty() && !disp.is_fullscreen() && resize_disp) {\n          const unsigned int\n            ttw = tw*disp.width()/oldw, tth = th*disp.height()/oldh,\n            dM = cimg::max(ttw,tth), diM = (unsigned int)cimg::max(disp.width(),disp.height()),\n            imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM);\n          disp.set_fullscreen(false).resize(cimg_fitscreen(imgw,imgh,1),false);\n          resize_disp = false;\n        }\n        oldw = tw; oldh = th;\n\n        bool\n          go_up = false, go_down = false, go_left = false, go_right = false,\n          go_inc = false, go_dec = false, go_in = false, go_out = false,\n          go_in_center = false;\n        const CImg<T>& visu = zoom?zoom:*this;\n\n        disp.set_title(\"%s\",dtitle._data);\n        if (_width>1 && visu._width==1) disp.set_title(\"%s | x=%u\",disp._title,x0);\n        if (_height>1 && visu._height==1) disp.set_title(\"%s | y=%u\",disp._title,y0);\n        if (_depth>1 && visu._depth==1) disp.set_title(\"%s | z=%u\",disp._title,z0);\n\n        if (!is_first_select) {\n          _XYZ[0] = (unsigned int)(x1 - x0)/2;\n          _XYZ[1] = (unsigned int)(y1 - y0)/2;\n          _XYZ[2] = (unsigned int)(z1 - z0)/2;\n        }\n\n        disp._mouse_x = old_mouse_x; disp._mouse_y = old_mouse_y;\n        const CImg<intT> selection = visu._get_select(disp,0,2,_XYZ,x0,y0,z0,true,is_first_select,_depth>1);\n        old_mouse_x = disp._mouse_x; old_mouse_y = disp._mouse_y;\n        is_first_select = false;\n\n        if (disp.wheel()) {\n          if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            go_down = !(go_up = disp.wheel()>0);\n          } else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) {\n            go_left = !(go_right = disp.wheel()>0);\n          }\n          else if (disp.is_keyALT() || disp.is_keyALTGR() || _depth==1) {\n            go_out = !(go_in = disp.wheel()>0); go_in_center = false;\n          }\n          disp.set_wheel();\n        }\n\n        const int\n          sx0 = selection(0), sy0 = selection(1), sz0 = selection(2),\n          sx1 = selection(3), sy1 = selection(4), sz1 = selection(5);\n        if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) {\n          x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1;\n          x0+=sx0; y0+=sy0; z0+=sz0;\n          if (sx0==sx1 && sy0==sy1 && sz0==sz1) {\n            if (exit_on_simpleclick && (!zoom || is_empty())) break; else reset_view = true;\n          }\n          resize_disp = true;\n        } else switch (key = disp.key()) {\n#if cimg_OS!=2\n          case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT :\n#endif\n          case 0 : case cimg::keyCTRLLEFT : case cimg::keyPAD5 : case cimg::keySHIFTLEFT :\n#if cimg_OS!=2\n          case cimg::keyALTGR :\n#endif\n          case cimg::keyALT : key = 0; break;\n          case cimg::keyP : if (visu._depth>1 && (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT())) {\n              // Special mode: play stack of frames\n              const unsigned int\n                w1 = visu._width*disp.width()/(visu._width + (visu._depth>1?visu._depth:0)),\n                h1 = visu._height*disp.height()/(visu._height + (visu._depth>1?visu._depth:0));\n              float frame_timing = 5;\n              bool is_stopped = false;\n              disp.set_key(key,false).set_wheel().resize(cimg_fitscreen(w1,h1,1),false); key = 0;\n              for (unsigned int timer = 0; !key && !disp.is_closed() && !disp.button(); ) {\n                if (disp.is_resized()) disp.resize(false);\n                if (!timer) {\n                  visu.get_slice((int)_XYZ[2]).display(disp.set_title(\"%s | z=%d\",dtitle.data(),_XYZ[2]));\n                  (++_XYZ[2])%=visu._depth;\n                }\n                if (!is_stopped) { if (++timer>(unsigned int)frame_timing) timer = 0; } else timer = ~0U;\n                if (disp.wheel()) { frame_timing-=disp.wheel()/3.0f; disp.set_wheel(); }\n                switch (key = disp.key()) {\n#if cimg_OS!=2\n                case cimg::keyCTRLRIGHT :\n#endif\n                case cimg::keyCTRLLEFT : key = 0; break;\n                case cimg::keyPAGEUP : frame_timing-=0.3f; key = 0; break;\n                case cimg::keyPAGEDOWN : frame_timing+=0.3f; key = 0; break;\n                case cimg::keySPACE : is_stopped = !is_stopped; disp.set_key(key,false); key = 0; break;\n                case cimg::keyARROWLEFT : case cimg::keyARROWUP : is_stopped = true; timer = 0; key = 0; break;\n                case cimg::keyARROWRIGHT : case cimg::keyARROWDOWN : is_stopped = true;\n                  (_XYZ[2]+=visu._depth - 2)%=visu._depth; timer = 0; key = 0; break;\n                case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n                    disp.set_fullscreen(false).\n                      resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false),\n                             CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false);\n                    disp.set_key(key,false); key = 0;\n                  } break;\n                case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n                    disp.set_fullscreen(false).\n                      resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false).set_key(key,false); key = 0;\n                  } break;\n                case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n                    disp.set_fullscreen(false).\n                      resize(cimg_fitscreen(_width,_height,_depth),false).set_key(key,false); key = 0;\n                  } break;\n                case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n                    disp.resize(disp.screen_width(),disp.screen_height(),false).\n                      toggle_fullscreen().set_key(key,false); key = 0;\n                  } break;\n                }\n                frame_timing = frame_timing<1?1:(frame_timing>39?39:frame_timing);\n                disp.wait(20);\n              }\n              const unsigned int\n                w2 = (visu._width + (visu._depth>1?visu._depth:0))*disp.width()/visu._width,\n                h2 = (visu._height + (visu._depth>1?visu._depth:0))*disp.height()/visu._height;\n              disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(dtitle.data()).set_key().set_button().set_wheel();\n              key = 0;\n            } break;\n          case cimg::keyHOME : reset_view = resize_disp = true; key = 0; break;\n          case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break;\n          case cimg::keyPADSUB : go_out = true; key = 0; break;\n          case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break;\n          case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break;\n          case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break;\n          case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break;\n          case cimg::keyPAD7 : go_up = go_left = true; key = 0; break;\n          case cimg::keyPAD9 : go_up = go_right = true; key = 0; break;\n          case cimg::keyPAD1 : go_down = go_left = true; key = 0; break;\n          case cimg::keyPAD3 : go_down = go_right = true; key = 0; break;\n          case cimg::keyPAGEUP : go_inc = true; key = 0; break;\n          case cimg::keyPAGEDOWN : go_dec = true; key = 0; break;\n          }\n        if (go_in) {\n          const int\n            mx = go_in_center?disp.width()/2:disp.mouse_x(),\n            my = go_in_center?disp.height()/2:disp.mouse_y(),\n            mX = mx*(width() + (depth()>1?depth():0))/disp.width(),\n            mY = my*(height() + (depth()>1?depth():0))/disp.height();\n          int X = (int)_XYZ[0], Y = (int)_XYZ[1], Z = (int)_XYZ[2];\n          if (mX<width() && mY<height())  {\n            X = x0 + mX*(1 + x1 - x0)/width(); Y = y0 + mY*(1 + y1 - y0)/height(); Z = (int)_XYZ[2];\n          }\n          if (mX<width() && mY>=height()) {\n            X = x0 + mX*(1 + x1 - x0)/width(); Z = z0 + (mY - height())*(1 + z1 - z0)/depth(); Y = (int)_XYZ[1];\n          }\n          if (mX>=width() && mY<height()) {\n            Y = y0 + mY*(1 + y1 - y0)/height(); Z = z0 + (mX - width())*(1 + z1 - z0)/depth(); X = (int)_XYZ[0];\n          }\n          if (x1 - x0>4) { x0 = X - 3*(X - x0)/4; x1 = X + 3*(x1 - X)/4; }\n          if (y1 - y0>4) { y0 = Y - 3*(Y - y0)/4; y1 = Y + 3*(y1 - Y)/4; }\n          if (z1 - z0>4) { z0 = Z - 3*(Z - z0)/4; z1 = Z + 3*(z1 - Z)/4; }\n        }\n        if (go_out) {\n          const int\n            delta_x = (x1 - x0)/8, delta_y = (y1 - y0)/8, delta_z = (z1 - z0)/8,\n            ndelta_x = delta_x?delta_x:(_width>1?1:0),\n            ndelta_y = delta_y?delta_y:(_height>1?1:0),\n            ndelta_z = delta_z?delta_z:(_depth>1?1:0);\n          x0-=ndelta_x; y0-=ndelta_y; z0-=ndelta_z;\n          x1+=ndelta_x; y1+=ndelta_y; z1+=ndelta_z;\n          if (x0<0) { x1-=x0; x0 = 0; if (x1>=width()) x1 = width() - 1; }\n          if (y0<0) { y1-=y0; y0 = 0; if (y1>=height()) y1 = height() - 1; }\n          if (z0<0) { z1-=z0; z0 = 0; if (z1>=depth()) z1 = depth() - 1; }\n          if (x1>=width()) { x0-=(x1 - width() + 1); x1 = width() - 1; if (x0<0) x0 = 0; }\n          if (y1>=height()) { y0-=(y1 - height() + 1); y1 = height() - 1; if (y0<0) y0 = 0; }\n          if (z1>=depth()) { z0-=(z1 - depth() + 1); z1 = depth() - 1; if (z0<0) z0 = 0; }\n        }\n        if (go_left) {\n          const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1?1:0);\n          if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; }\n          else { x1-=x0; x0 = 0; }\n        }\n        if (go_right) {\n          const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1?1:0);\n          if (x1+ndelta<width()) { x0+=ndelta; x1+=ndelta; }\n          else { x0+=(width() - 1 - x1); x1 = width() - 1; }\n        }\n        if (go_up) {\n          const int delta = (y1 - y0)/4, ndelta = delta?delta:(_height>1?1:0);\n          if (y0 - ndelta>=0) { y0-=ndelta; y1-=ndelta; }\n          else { y1-=y0; y0 = 0; }\n        }\n        if (go_down) {\n          const int delta = (y1 - y0)/4, ndelta = delta?delta:(_height>1?1:0);\n          if (y1+ndelta<height()) { y0+=ndelta; y1+=ndelta; }\n          else { y0+=(height() - 1 - y1); y1 = height() - 1; }\n        }\n        if (go_inc) {\n          const int delta = (z1 - z0)/4, ndelta = delta?delta:(_depth>1?1:0);\n          if (z0 - ndelta>=0) { z0-=ndelta; z1-=ndelta; }\n          else { z1-=z0; z0 = 0; }\n        }\n        if (go_dec) {\n          const int delta = (z1 - z0)/4, ndelta = delta?delta:(_depth>1?1:0);\n          if (z1+ndelta<depth()) { z0+=ndelta; z1+=ndelta; }\n          else { z0+=(depth() - 1 - z1); z1 = depth() - 1; }\n        }\n        disp.wait(100);\n        if (!exit_on_anykey && key && key!=cimg::keyESC &&\n            (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {\n          key = 0;\n        }\n      }\n      disp.set_key(key);\n      if (XYZ) { XYZ[0] = _XYZ[0]; XYZ[1] = _XYZ[1]; XYZ[2] = _XYZ[2]; }\n      return *this;\n    }\n\n    //! Display object 3d in an interactive window.\n    /**\n       \\param disp Display window.\n       \\param vertices Vertices data of the 3d object.\n       \\param primitives Primitives data of the 3d object.\n       \\param colors Colors data of the 3d object.\n       \\param opacities Opacities data of the 3d object.\n       \\param centering Tells if the 3d object must be centered for the display.\n       \\param render_static Rendering mode.\n       \\param render_motion Rendering mode, when the 3d object is moved.\n       \\param is_double_sided Tells if the object primitives are double-sided.\n       \\param focale Focale\n       \\param light_x X-coordinate of the light source.\n       \\param light_y Y-coordinate of the light source.\n       \\param light_z Z-coordinate of the light source.\n       \\param specular_lightness Amount of specular light.\n       \\param specular_shininess Shininess of the object material.\n       \\param display_axes Tells if the 3d axes are displayed.\n       \\param pose_matrix Pointer to 12 values, defining a 3d pose (as a 4x3 matrix).\n    **/\n    template<typename tp, typename tf, typename tc, typename to>\n    const CImg<T>& display_object3d(CImgDisplay& disp,\n                                    const CImg<tp>& vertices,\n                                    const CImgList<tf>& primitives,\n                                    const CImgList<tc>& colors,\n                                    const to& opacities,\n                                    const bool centering=true,\n                                    const int render_static=4, const int render_motion=1,\n                                    const bool is_double_sided=true, const float focale=700,\n                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,\n                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,\n                                    const bool display_axes=true, float *const pose_matrix=0,\n                                    const bool exit_on_anykey=false) const {\n      return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static,\n                               render_motion,is_double_sided,focale,\n                               light_x,light_y,light_z,specular_lightness,specular_shininess,\n                               display_axes,pose_matrix,exit_on_anykey);\n    }\n\n    //! Display object 3d in an interactive window \\simplification.\n    template<typename tp, typename tf, typename tc, typename to>\n    const CImg<T>& display_object3d(const char *const title,\n                                    const CImg<tp>& vertices,\n                                    const CImgList<tf>& primitives,\n                                    const CImgList<tc>& colors,\n                                    const to& opacities,\n                                    const bool centering=true,\n                                    const int render_static=4, const int render_motion=1,\n                                    const bool is_double_sided=true, const float focale=700,\n                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,\n                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,\n                                    const bool display_axes=true, float *const pose_matrix=0,\n                                    const bool exit_on_anykey=false) const {\n      CImgDisplay disp;\n      return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static,\n                               render_motion,is_double_sided,focale,\n                               light_x,light_y,light_z,specular_lightness,specular_shininess,\n                               display_axes,pose_matrix,exit_on_anykey);\n    }\n\n    //! Display object 3d in an interactive window \\simplification.\n    template<typename tp, typename tf, typename tc>\n    const CImg<T>& display_object3d(CImgDisplay &disp,\n                                    const CImg<tp>& vertices,\n                                    const CImgList<tf>& primitives,\n                                    const CImgList<tc>& colors,\n                                    const bool centering=true,\n                                    const int render_static=4, const int render_motion=1,\n                                    const bool is_double_sided=true, const float focale=700,\n                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,\n                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,\n                                    const bool display_axes=true, float *const pose_matrix=0,\n                                    const bool exit_on_anykey=false) const {\n      return display_object3d(disp,vertices,primitives,colors,CImgList<floatT>(),centering,\n                              render_static,render_motion,is_double_sided,focale,\n                              light_x,light_y,light_z,specular_lightness,specular_shininess,\n                              display_axes,pose_matrix,exit_on_anykey);\n    }\n\n    //! Display object 3d in an interactive window \\simplification.\n    template<typename tp, typename tf, typename tc>\n    const CImg<T>& display_object3d(const char *const title,\n                                    const CImg<tp>& vertices,\n                                    const CImgList<tf>& primitives,\n                                    const CImgList<tc>& colors,\n                                    const bool centering=true,\n                                    const int render_static=4, const int render_motion=1,\n                                    const bool is_double_sided=true, const float focale=700,\n                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,\n                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,\n                                    const bool display_axes=true, float *const pose_matrix=0,\n                                    const bool exit_on_anykey=false) const {\n      return display_object3d(title,vertices,primitives,colors,CImgList<floatT>(),centering,\n                              render_static,render_motion,is_double_sided,focale,\n                              light_x,light_y,light_z,specular_lightness,specular_shininess,\n                              display_axes,pose_matrix,exit_on_anykey);\n    }\n\n    //! Display object 3d in an interactive window \\simplification.\n    template<typename tp, typename tf>\n    const CImg<T>& display_object3d(CImgDisplay &disp,\n                                    const CImg<tp>& vertices,\n                                    const CImgList<tf>& primitives,\n                                    const bool centering=true,\n                                    const int render_static=4, const int render_motion=1,\n                                    const bool is_double_sided=true, const float focale=700,\n                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,\n                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,\n                                    const bool display_axes=true, float *const pose_matrix=0,\n                                    const bool exit_on_anykey=false) const {\n      return display_object3d(disp,vertices,primitives,CImgList<T>(),centering,\n                              render_static,render_motion,is_double_sided,focale,\n                              light_x,light_y,light_z,specular_lightness,specular_shininess,\n                              display_axes,pose_matrix,exit_on_anykey);\n    }\n\n\n    //! Display object 3d in an interactive window \\simplification.\n    template<typename tp, typename tf>\n    const CImg<T>& display_object3d(const char *const title,\n                                    const CImg<tp>& vertices,\n                                    const CImgList<tf>& primitives,\n                                    const bool centering=true,\n                                    const int render_static=4, const int render_motion=1,\n                                    const bool is_double_sided=true, const float focale=700,\n                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,\n                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,\n                                    const bool display_axes=true, float *const pose_matrix=0,\n                                    const bool exit_on_anykey=false) const {\n      return display_object3d(title,vertices,primitives,CImgList<T>(),centering,\n                              render_static,render_motion,is_double_sided,focale,\n                              light_x,light_y,light_z,specular_lightness,specular_shininess,\n                              display_axes,pose_matrix,exit_on_anykey);\n    }\n\n    //! Display object 3d in an interactive window \\simplification.\n    template<typename tp>\n    const CImg<T>& display_object3d(CImgDisplay &disp,\n                                    const CImg<tp>& vertices,\n                                    const bool centering=true,\n                                    const int render_static=4, const int render_motion=1,\n                                    const bool is_double_sided=true, const float focale=700,\n                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,\n                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,\n                                    const bool display_axes=true, float *const pose_matrix=0,\n                                    const bool exit_on_anykey=false) const {\n      return display_object3d(disp,vertices,CImgList<uintT>(),centering,\n                              render_static,render_motion,is_double_sided,focale,\n                              light_x,light_y,light_z,specular_lightness,specular_shininess,\n                              display_axes,pose_matrix,exit_on_anykey);\n    }\n\n    //! Display object 3d in an interactive window \\simplification.\n    template<typename tp>\n    const CImg<T>& display_object3d(const char *const title,\n                                    const CImg<tp>& vertices,\n                                    const bool centering=true,\n                                    const int render_static=4, const int render_motion=1,\n                                    const bool is_double_sided=true, const float focale=700,\n                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,\n                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,\n                                    const bool display_axes=true, float *const pose_matrix=0,\n                                    const bool exit_on_anykey=false) const {\n      return display_object3d(title,vertices,CImgList<uintT>(),centering,\n                              render_static,render_motion,is_double_sided,focale,\n                              light_x,light_y,light_z,specular_lightness,specular_shininess,\n                              display_axes,pose_matrix,exit_on_anykey);\n    }\n\n    template<typename tp, typename tf, typename tc, typename to>\n    const CImg<T>& _display_object3d(CImgDisplay& disp, const char *const title,\n                                     const CImg<tp>& vertices,\n                                     const CImgList<tf>& primitives,\n                                     const CImgList<tc>& colors,\n                                     const to& opacities,\n                                     const bool centering,\n                                     const int render_static, const int render_motion,\n                                     const bool is_double_sided, const float focale,\n                                     const float light_x, const float light_y, const float light_z,\n                                     const float specular_lightness, const float specular_shininess,\n                                     const bool display_axes, float *const pose_matrix,\n                                     const bool exit_on_anykey) const {\n      typedef typename cimg::superset<tp,float>::type tpfloat;\n\n      // Check input arguments\n      if (is_empty()) {\n        if (disp) return CImg<T>(disp.width(),disp.height(),1,(colors && colors[0].size()==1)?1:3,0).\n                    _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,\n                                      render_static,render_motion,is_double_sided,focale,\n                                      light_x,light_y,light_z,specular_lightness,specular_shininess,\n                                      display_axes,pose_matrix,exit_on_anykey);\n        else return CImg<T>(1,2,1,1,64,128).resize(cimg_fitscreen(CImgDisplay::screen_width()/2,\n                                                                  CImgDisplay::screen_height()/2,1),\n                                                   1,(colors && colors[0].size()==1)?1:3,3).\n               _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,\n                                 render_static,render_motion,is_double_sided,focale,\n                                 light_x,light_y,light_z,specular_lightness,specular_shininess,\n                                 display_axes,pose_matrix,exit_on_anykey);\n      } else { if (disp) disp.resize(*this,false); }\n      CImg<charT> error_message(1024);\n      if (!vertices.is_object3d(primitives,colors,opacities,true,error_message))\n        throw CImgArgumentException(_cimg_instance\n                                    \"display_object3d(): Invalid specified 3d object (%u,%u) (%s).\",\n                                    cimg_instance,vertices._width,primitives._width,error_message.data());\n      if (vertices._width && !primitives) {\n        CImgList<tf> nprimitives(vertices._width,1,1,1,1);\n        cimglist_for(nprimitives,l) nprimitives(l,0) = (tf)l;\n        return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering,\n                                 render_static,render_motion,is_double_sided,focale,\n                                 light_x,light_y,light_z,specular_lightness,specular_shininess,\n                                 display_axes,pose_matrix,exit_on_anykey);\n      }\n      if (!disp) {\n        disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3);\n        if (!title) disp.set_title(\"CImg<%s> (%u vertices, %u primitives)\",\n                                   pixel_type(),vertices._width,primitives._width);\n      } else if (title) disp.set_title(\"%s\",title);\n\n      // Init 3d objects and compute object statistics\n      CImg<floatT>\n        pose,\n        rotated_vertices(vertices._width,3),\n        bbox_vertices, rotated_bbox_vertices,\n        axes_vertices, rotated_axes_vertices,\n        bbox_opacities, axes_opacities;\n      CImgList<uintT> bbox_primitives, axes_primitives;\n      CImgList<tf> reverse_primitives;\n      CImgList<T> bbox_colors, bbox_colors2, axes_colors;\n      unsigned int ns_width = 0, ns_height = 0;\n      int _is_double_sided = (int)is_double_sided;\n      bool ndisplay_axes = display_axes;\n      const CImg<T>\n        background_color(1,1,1,_spectrum,0),\n        foreground_color(1,1,1,_spectrum,255);\n      float\n        Xoff = 0, Yoff = 0, Zoff = 0, sprite_scale = 1,\n        xm = 0, xM = vertices?vertices.get_shared_row(0).max_min(xm):0,\n        ym = 0, yM = vertices?vertices.get_shared_row(1).max_min(ym):0,\n        zm = 0, zM = vertices?vertices.get_shared_row(2).max_min(zm):0;\n      const float delta = cimg::max(xM - xm,yM - ym,zM - zm);\n\n      rotated_bbox_vertices = bbox_vertices.assign(8,3,1,1,\n                                                   xm,xM,xM,xm,xm,xM,xM,xm,\n                                                   ym,ym,yM,yM,ym,ym,yM,yM,\n                                                   zm,zm,zm,zm,zM,zM,zM,zM);\n      bbox_primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 1,2,6,5, 0,4,7,3, 0,1,5,4, 2,3,7,6);\n      bbox_colors.assign(6,_spectrum,1,1,1,background_color[0]);\n      bbox_colors2.assign(6,_spectrum,1,1,1,foreground_color[0]);\n      bbox_opacities.assign(bbox_colors._width,1,1,1,0.3f);\n\n      rotated_axes_vertices = axes_vertices.assign(7,3,1,1,\n                                                   0,20,0,0,22,-6,-6,\n                                                   0,0,20,0,-6,22,-6,\n                                                   0,0,0,20,0,0,22);\n      axes_opacities.assign(3,1,1,1,1);\n      axes_colors.assign(3,_spectrum,1,1,1,foreground_color[0]);\n      axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3);\n\n      // Begin user interaction loop\n      CImg<T> visu0(*this), visu;\n      CImg<tpfloat> zbuffer(visu0.width(),visu0.height(),1,1,0);\n      bool init_pose = true, clicked = false, redraw = true;\n      unsigned int key = 0;\n      int\n        x0 = 0, y0 = 0, x1 = 0, y1 = 0,\n        nrender_static = render_static,\n        nrender_motion = render_motion;\n      disp.show().flush();\n\n      while (!disp.is_closed() && !key) {\n\n        // Init object pose\n        if (init_pose) {\n          const float\n            ratio = delta>0?(2.0f*cimg::min(disp.width(),disp.height())/(3.0f*delta)):1,\n            dx = (xM + xm)/2, dy = (yM + ym)/2, dz = (zM + zm)/2;\n          if (centering)\n            CImg<floatT>(4,3,1,1, ratio,0.,0.,-ratio*dx, 0.,ratio,0.,-ratio*dy, 0.,0.,ratio,-ratio*dz).move_to(pose);\n          else CImg<floatT>(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0).move_to(pose);\n          if (pose_matrix) {\n            CImg<floatT> pose0(pose_matrix,4,3,1,1,false);\n            pose0.resize(4,4,1,1,0); pose.resize(4,4,1,1,0);\n            pose0(3,3) = pose(3,3) = 1;\n            (pose0*pose).get_crop(0,0,3,2).move_to(pose);\n            Xoff = pose_matrix[12]; Yoff = pose_matrix[13]; Zoff = pose_matrix[14]; sprite_scale = pose_matrix[15];\n          } else { Xoff = Yoff = Zoff = 0; sprite_scale = 1; }\n          init_pose = false;\n          redraw = true;\n        }\n\n        // Rotate and draw 3d object\n        if (redraw) {\n          const float\n            r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0),\n            r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1),\n            r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2);\n          if ((clicked && nrender_motion>=0) || (!clicked && nrender_static>=0))\n            cimg_forX(vertices,l) {\n              const float x = (float)vertices(l,0), y = (float)vertices(l,1), z = (float)vertices(l,2);\n              rotated_vertices(l,0) = r00*x + r10*y + r20*z + r30;\n              rotated_vertices(l,1) = r01*x + r11*y + r21*z + r31;\n              rotated_vertices(l,2) = r02*x + r12*y + r22*z + r32;\n            }\n          else cimg_forX(bbox_vertices,l) {\n              const float x = bbox_vertices(l,0), y = bbox_vertices(l,1), z = bbox_vertices(l,2);\n              rotated_bbox_vertices(l,0) = r00*x + r10*y + r20*z + r30;\n              rotated_bbox_vertices(l,1) = r01*x + r11*y + r21*z + r31;\n              rotated_bbox_vertices(l,2) = r02*x + r12*y + r22*z + r32;\n            }\n\n          // Draw objects\n          //#ifdef cimg_use_openmp\n          //          const bool render_with_zbuffer = true;\n          //#else\n          const bool render_with_zbuffer = !clicked && nrender_static>0;\n          //#endif\n          visu = visu0;\n          if ((clicked && nrender_motion<0) || (!clicked && nrender_static<0))\n            visu.draw_object3d(Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,\n                               rotated_bbox_vertices,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale).\n              draw_object3d(Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,\n                            rotated_bbox_vertices,bbox_primitives,bbox_colors2,1,false,focale);\n          else visu._draw_object3d((void*)0,render_with_zbuffer?zbuffer.fill(0):CImg<tpfloat>::empty(),\n                                   Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,\n                                   rotated_vertices,reverse_primitives?reverse_primitives:primitives,\n                                   colors,opacities,clicked?nrender_motion:nrender_static,_is_double_sided==1,focale,\n                                   width()/2.0f + light_x,height()/2.0f + light_y,light_z + Zoff,\n                                   specular_lightness,specular_shininess,sprite_scale);\n          // Draw axes\n          if (ndisplay_axes) {\n            const float\n              n = (float)std::sqrt(1e-8 + r00*r00 + r01*r01 + r02*r02),\n              _r00 = r00/n, _r10 = r10/n, _r20 = r20/n,\n              _r01 = r01/n, _r11 = r11/n, _r21 = r21/n,\n              _r02 = r01/n, _r12 = r12/n, _r22 = r22/n,\n              Xaxes = 25, Yaxes = visu._height - 38.0f;\n            cimg_forX(axes_vertices,l) {\n              const float\n                x = axes_vertices(l,0),\n                y = axes_vertices(l,1),\n                z = axes_vertices(l,2);\n              rotated_axes_vertices(l,0) = _r00*x + _r10*y + _r20*z;\n              rotated_axes_vertices(l,1) = _r01*x + _r11*y + _r21*z;\n              rotated_axes_vertices(l,2) = _r02*x + _r12*y + _r22*z;\n            }\n            axes_opacities(0,0) = (rotated_axes_vertices(1,2)>0)?0.5f:1.0f;\n            axes_opacities(1,0) = (rotated_axes_vertices(2,2)>0)?0.5f:1.0f;\n            axes_opacities(2,0) = (rotated_axes_vertices(3,2)>0)?0.5f:1.0f;\n            visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_vertices,axes_primitives,\n                               axes_colors,axes_opacities,1,false,focale).\n              draw_text((int)(Xaxes + rotated_axes_vertices(4,0)),\n                        (int)(Yaxes + rotated_axes_vertices(4,1)),\n                        \"X\",axes_colors[0]._data,0,axes_opacities(0,0),13).\n              draw_text((int)(Xaxes + rotated_axes_vertices(5,0)),\n                        (int)(Yaxes + rotated_axes_vertices(5,1)),\n                        \"Y\",axes_colors[1]._data,0,axes_opacities(1,0),13).\n              draw_text((int)(Xaxes + rotated_axes_vertices(6,0)),\n                        (int)(Yaxes + rotated_axes_vertices(6,1)),\n                        \"Z\",axes_colors[2]._data,0,axes_opacities(2,0),13);\n          }\n          visu.display(disp);\n          if (!clicked || nrender_motion==nrender_static) redraw = false;\n        }\n\n        // Handle user interaction\n        disp.wait();\n        if ((disp.button() || disp.wheel()) && disp.mouse_x()>=0 && disp.mouse_y()>=0) {\n          redraw = true;\n          if (!clicked) { x0 = x1 = disp.mouse_x(); y0 = y1 = disp.mouse_y(); if (!disp.wheel()) clicked = true; }\n          else { x1 = disp.mouse_x(); y1 = disp.mouse_y(); }\n          if (disp.button()&1) {\n            const float\n              R = 0.45f*cimg::min(disp.width(),disp.height()),\n              R2 = R*R,\n              u0 = (float)(x0 - disp.width()/2),\n              v0 = (float)(y0 - disp.height()/2),\n              u1 = (float)(x1 - disp.width()/2),\n              v1 = (float)(y1 - disp.height()/2),\n              n0 = (float)std::sqrt(u0*u0 + v0*v0),\n              n1 = (float)std::sqrt(u1*u1 + v1*v1),\n              nu0 = n0>R?(u0*R/n0):u0,\n              nv0 = n0>R?(v0*R/n0):v0,\n              nw0 = (float)std::sqrt(cimg::max(0,R2 - nu0*nu0 - nv0*nv0)),\n              nu1 = n1>R?(u1*R/n1):u1,\n              nv1 = n1>R?(v1*R/n1):v1,\n              nw1 = (float)std::sqrt(cimg::max(0,R2 - nu1*nu1 - nv1*nv1)),\n              u = nv0*nw1 - nw0*nv1,\n              v = nw0*nu1 - nu0*nw1,\n              w = nv0*nu1 - nu0*nv1,\n              n = (float)std::sqrt(u*u + v*v + w*w),\n              alpha = (float)std::asin(n/R2);\n            (CImg<floatT>::rotation_matrix(u,v,w,alpha)*pose).move_to(pose);\n            x0 = x1; y0 = y1;\n          }\n          if (disp.button()&2) {\n            if (focale>0) Zoff-=(y0 - y1)*focale/400;\n            else { const float s = std::exp((y0 - y1)/400.0f); pose*=s; sprite_scale*=s; }\n            x0 = x1; y0 = y1;\n          }\n          if (disp.wheel()) {\n            if (focale>0) Zoff-=disp.wheel()*focale/20;\n            else { const float s = std::exp(disp.wheel()/20.0f); pose*=s; sprite_scale*=s; }\n            disp.set_wheel();\n          }\n          if (disp.button()&4) { Xoff+=(x1 - x0); Yoff+=(y1 - y0); x0 = x1; y0 = y1; }\n          if ((disp.button()&1) && (disp.button()&2)) {\n            init_pose = true; disp.set_button(); x0 = x1; y0 = y1;\n            pose = CImg<floatT>(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0);\n          }\n        } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }\n\n        CImg<charT> filename(32);\n        switch (key = disp.key()) {\n#if cimg_OS!=2\n        case cimg::keyCTRLRIGHT :\n#endif\n        case 0 : case cimg::keyCTRLLEFT : key = 0; break;\n        case cimg::keyD: if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).\n              resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false),\n                     CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false).\n              _is_resized = true;\n            disp.set_key(key,false); key = 0;\n          } break;\n        case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).\n              resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true;\n            disp.set_key(key,false); key = 0;\n          } break;\n        case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true;\n            disp.set_key(key,false); key = 0;\n          } break;\n        case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            if (!ns_width || !ns_height ||\n                ns_width>(unsigned int)disp.screen_width() || ns_height>(unsigned int)disp.screen_height()) {\n              ns_width = disp.screen_width()*3U/4;\n              ns_height = disp.screen_height()*3U/4;\n            }\n            if (disp.is_fullscreen()) disp.resize(ns_width,ns_height,false);\n            else {\n              ns_width = disp._width; ns_height = disp._height;\n              disp.resize(disp.screen_width(),disp.screen_height(),false);\n            }\n            disp.toggle_fullscreen()._is_resized = true;\n            disp.set_key(key,false); key = 0;\n          } break;\n        case cimg::keyT : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            // Switch single/double-sided primitives.\n            if (--_is_double_sided==-2) _is_double_sided = 1;\n            if (_is_double_sided>=0) reverse_primitives.assign();\n            else primitives.get_reverse_object3d().move_to(reverse_primitives);\n            disp.set_key(key,false); key = 0; redraw = true;\n          } break;\n        case cimg::keyZ : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Enable/disable Z-buffer\n            if (zbuffer) zbuffer.assign();\n            else zbuffer.assign(visu0.width(),visu0.height(),1,1,0);\n            disp.set_key(key,false); key = 0; redraw = true;\n          } break;\n        case cimg::keyA : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Show/hide 3d axes.\n            ndisplay_axes = !ndisplay_axes;\n            disp.set_key(key,false); key = 0; redraw = true;\n          } break;\n        case cimg::keyF1 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to points.\n            nrender_motion = (nrender_static==0 && nrender_motion!=0)?0:-1; nrender_static = 0;\n            disp.set_key(key,false); key = 0; redraw = true;\n          } break;\n        case cimg::keyF2 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to lines.\n            nrender_motion = (nrender_static==1 && nrender_motion!=1)?1:-1; nrender_static = 1;\n            disp.set_key(key,false); key = 0; redraw = true;\n          } break;\n        case cimg::keyF3 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat.\n            nrender_motion = (nrender_static==2 && nrender_motion!=2)?2:-1; nrender_static = 2;\n            disp.set_key(key,false); key = 0; redraw = true;\n          } break;\n        case cimg::keyF4 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat-shaded.\n            nrender_motion = (nrender_static==3 && nrender_motion!=3)?3:-1; nrender_static = 3;\n            disp.set_key(key,false); key = 0; redraw = true;\n          } break;\n        case cimg::keyF5 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            // Set rendering mode to gouraud-shaded.\n            nrender_motion = (nrender_static==4 && nrender_motion!=4)?4:-1; nrender_static = 4;\n            disp.set_key(key,false); key = 0; redraw = true;\n          } break;\n        case cimg::keyF6 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to phong-shaded.\n            nrender_motion = (nrender_static==5 && nrender_motion!=5)?5:-1; nrender_static = 5;\n            disp.set_key(key,false); key = 0; redraw = true;\n          } break;\n        case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save snapshot\n            static unsigned int snap_number = 0;\n            std::FILE *file;\n            do {\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.bmp\",snap_number++);\n              if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n            } while (file);\n            (+visu).draw_text(0,0,\" Saving snapshot... \",\n                              foreground_color._data,background_color._data,0.7f,13).display(disp);\n            visu.save(filename);\n            (+visu).draw_text(0,0,\" Snapshot '%s' saved. \",\n                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);\n            disp.set_key(key,false); key = 0;\n          } break;\n        case cimg::keyG : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .off file\n            static unsigned int snap_number = 0;\n            std::FILE *file;\n            do {\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.off\",snap_number++);\n              if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n            } while (file);\n            (+visu).draw_text(0,0,\" Saving object... \",\n                              foreground_color._data,background_color._data,0.7f,13).display(disp);\n            vertices.save_off(reverse_primitives?reverse_primitives:primitives,colors,filename);\n            (+visu).draw_text(0,0,\" Object '%s' saved. \",\n                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);\n            disp.set_key(key,false); key = 0;\n          } break;\n        case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .cimg file\n            static unsigned int snap_number = 0;\n            std::FILE *file;\n            do {\n#ifdef cimg_use_zlib\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.cimgz\",snap_number++);\n#else\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.cimg\",snap_number++);\n#endif\n              if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n            } while (file);\n            (+visu).draw_text(0,0,\" Saving object... \",\n                              foreground_color._data,background_color._data,0.7f,13).display(disp);\n            vertices.get_object3dtoCImg3d(reverse_primitives?reverse_primitives:primitives,colors,opacities).\n              save(filename);\n            (+visu).draw_text(0,0,\" Object '%s' saved. \",\n                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);\n            disp.set_key(key,false); key = 0;\n          } break;\n#ifdef cimg_use_board\n        case cimg::keyP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .EPS file\n            static unsigned int snap_number = 0;\n            std::FILE *file;\n            do {\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.eps\",snap_number++);\n              if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n            } while (file);\n            (+visu).draw_text(0,0,\" Saving EPS snapshot... \",\n                              foreground_color._data,background_color._data,0.7f,13).display(disp);\n            LibBoard::Board board;\n            (+visu)._draw_object3d(&board,zbuffer.fill(0),\n                                   Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,\n                                   rotated_vertices,reverse_primitives?reverse_primitives:primitives,\n                                   colors,opacities,clicked?nrender_motion:nrender_static,\n                                   _is_double_sided==1,focale,\n                                   visu.width()/2.0f + light_x,visu.height()/2.0f + light_y,light_z + Zoff,\n                                   specular_lightness,specular_shininess,\n                                   sprite_scale);\n            board.saveEPS(filename);\n            (+visu).draw_text(0,0,\" Object '%s' saved. \",\n                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);\n            disp.set_key(key,false); key = 0;\n          } break;\n        case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .SVG file\n            static unsigned int snap_number = 0;\n            std::FILE *file;\n            do {\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.svg\",snap_number++);\n              if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n            } while (file);\n            (+visu).draw_text(0,0,\" Saving SVG snapshot... \",\n                              foreground_color._data,background_color._data,0.7f,13).display(disp);\n            LibBoard::Board board;\n            (+visu)._draw_object3d(&board,zbuffer.fill(0),\n                                   Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,\n                                   rotated_vertices,reverse_primitives?reverse_primitives:primitives,\n                                   colors,opacities,clicked?nrender_motion:nrender_static,\n                                   _is_double_sided==1,focale,\n                                   visu.width()/2.0f + light_x,visu.height()/2.0f + light_y,light_z + Zoff,\n                                   specular_lightness,specular_shininess,\n                                   sprite_scale);\n            board.saveSVG(filename);\n            (+visu).draw_text(0,0,\" Object '%s' saved. \",\n                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);\n            disp.set_key(key,false); key = 0;\n          } break;\n#endif\n        }\n        if (disp.is_resized()) {\n          disp.resize(false); visu0 = get_resize(disp,1);\n          if (zbuffer) zbuffer.assign(disp.width(),disp.height());\n          redraw = true;\n        }\n        if (!exit_on_anykey && key && key!=cimg::keyESC &&\n            (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {\n          key = 0;\n        }\n      }\n      if (pose_matrix) {\n        std::memcpy(pose_matrix,pose._data,12*sizeof(float));\n        pose_matrix[12] = Xoff; pose_matrix[13] = Yoff; pose_matrix[14] = Zoff; pose_matrix[15] = sprite_scale;\n      }\n      disp.set_button().set_key(key);\n      return *this;\n    }\n\n    //! Display 1d graph in an interactive window.\n    /**\n       \\param disp Display window.\n       \\param plot_type Plot type. Can be <tt>{ 0=points | 1=segments | 2=splines | 3=bars }</tt>.\n       \\param vertex_type Vertex type.\n       \\param labelx Title for the horizontal axis, as a C-string.\n       \\param xmin Minimum value along the X-axis.\n       \\param xmax Maximum value along the X-axis.\n       \\param labely Title for the vertical axis, as a C-string.\n       \\param ymin Minimum value along the X-axis.\n       \\param ymax Maximum value along the X-axis.\n    **/\n    const CImg<T>& display_graph(CImgDisplay &disp,\n                                 const unsigned int plot_type=1, const unsigned int vertex_type=1,\n                                 const char *const labelx=0, const double xmin=0, const double xmax=0,\n                                 const char *const labely=0, const double ymin=0, const double ymax=0,\n                                 const bool exit_on_anykey=false) const {\n      return _display_graph(disp,0,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey);\n    }\n\n    //! Display 1d graph in an interactive window \\overloading.\n    const CImg<T>& display_graph(const char *const title=0,\n                                 const unsigned int plot_type=1, const unsigned int vertex_type=1,\n                                 const char *const labelx=0, const double xmin=0, const double xmax=0,\n                                 const char *const labely=0, const double ymin=0, const double ymax=0,\n                                 const bool exit_on_anykey=false) const {\n      CImgDisplay disp;\n      return _display_graph(disp,title,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey);\n    }\n\n    const CImg<T>& _display_graph(CImgDisplay &disp, const char *const title=0,\n                                  const unsigned int plot_type=1, const unsigned int vertex_type=1,\n                                  const char *const labelx=0, const double xmin=0, const double xmax=0,\n                                  const char *const labely=0, const double ymin=0, const double ymax=0,\n                                  const bool exit_on_anykey=false) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"display_graph(): Empty instance.\",\n                                    cimg_instance);\n      if (!disp) disp.assign(cimg_fitscreen(CImgDisplay::screen_width()/2,CImgDisplay::screen_height()/2,1),0,0).\n                   set_title(title?\"%s\":\"CImg<%s>\",title?title:pixel_type());\n      const ulongT siz = (ulongT)_width*_height*_depth, siz1 = cimg::max(1U,siz - 1);\n      const unsigned int old_normalization = disp.normalization();\n      disp.show().flush()._normalization = 0;\n\n      double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax;\n      if (nxmin==nxmax) { nxmin = 0; nxmax = siz1; }\n      int x0 = 0, x1 = width()*height()*depth() - 1, key = 0;\n\n      for (bool reset_view = true; !key && !disp.is_closed(); ) {\n        if (reset_view) { x0 = 0; x1 = width()*height()*depth() - 1; y0 = ymin; y1 = ymax; reset_view = false; }\n        CImg<T> zoom(x1 - x0 + 1,1,1,spectrum());\n        cimg_forC(*this,c) zoom.get_shared_channel(c) = CImg<T>(data(x0,0,0,c),x1 - x0 + 1,1,1,1,true);\n        if (y0==y1) { y0 = zoom.min_max(y1); const double dy = y1 - y0; y0-=dy/20; y1+=dy/20; }\n        if (y0==y1) { --y0; ++y1; }\n\n        const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type,\n                                                           labelx,\n                                                           nxmin + x0*(nxmax - nxmin)/siz1,\n                                                           nxmin + x1*(nxmax - nxmin)/siz1,\n                                                           labely,y0,y1,true);\n        const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y();\n        if (selection[0]>=0) {\n          if (selection[2]<0) reset_view = true;\n          else {\n            x1 = x0 + selection[2]; x0+=selection[0];\n            if (selection[1]>=0 && selection[3]>=0) {\n              y0 = y1 - selection[3]*(y1 - y0)/(disp.height() - 32);\n              y1-=selection[1]*(y1 - y0)/(disp.height() - 32);\n            }\n          }\n        } else {\n          bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false;\n          switch (key = (int)disp.key()) {\n          case cimg::keyHOME : reset_view = true; key = 0; disp.set_key(); break;\n          case cimg::keyPADADD : go_in = true; go_out = false; key = 0; disp.set_key(); break;\n          case cimg::keyPADSUB : go_out = true; go_in = false; key = 0; disp.set_key(); break;\n          case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; go_right = false; key = 0; disp.set_key();\n            break;\n          case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; go_left = false; key = 0; disp.set_key();\n            break;\n          case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; go_down = false; key = 0; disp.set_key(); break;\n          case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; go_up = false; key = 0; disp.set_key(); break;\n          case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; disp.set_key(); break;\n          case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; disp.set_key(); break;\n          case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; disp.set_key(); break;\n          case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break;\n          }\n          if (disp.wheel()) {\n            if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_up = !(go_down = disp.wheel()<0);\n            else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) go_left = !(go_right = disp.wheel()>0);\n            else go_out = !(go_in = disp.wheel()>0);\n            key = 0;\n          }\n\n          if (go_in) {\n            const int\n              xsiz = x1 - x0,\n              mx = (mouse_x - 16)*xsiz/(disp.width() - 32),\n              cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx));\n            if (x1 - x0>4) {\n              x0 = cx - 7*(cx - x0)/8; x1 = cx + 7*(x1 - cx)/8;\n              if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n                const double\n                  ysiz = y1 - y0,\n                  my = (mouse_y - 16)*ysiz/(disp.height() - 32),\n                  cy = y1 - (my<0?0:(my>=ysiz?ysiz:my));\n                y0 = cy - 7*(cy - y0)/8; y1 = cy + 7*(y1 - cy)/8;\n              } else y0 = y1 = 0;\n            }\n          }\n          if (go_out) {\n            if (x0>0 || x1<(int)siz1) {\n              const int delta_x = (x1 - x0)/8, ndelta_x = delta_x?delta_x:(siz>1?1:0);\n              const double ndelta_y = (y1 - y0)/8;\n              x0-=ndelta_x; x1+=ndelta_x;\n              y0-=ndelta_y; y1+=ndelta_y;\n              if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz1; }\n              if (x1>=(int)siz) { x0-=(x1 - siz1); x1 = (int)siz1; if (x0<0) x0 = 0; }\n            }\n          }\n          if (go_left) {\n            const int delta = (x1 - x0)/5, ndelta = delta?delta:1;\n            if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; }\n            else { x1-=x0; x0 = 0; }\n            go_left = false;\n          }\n          if (go_right) {\n            const int delta = (x1 - x0)/5, ndelta = delta?delta:1;\n            if (x1 + ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; }\n            else { x0+=(siz1 - x1); x1 = (int)siz1; }\n            go_right = false;\n          }\n          if (go_up) {\n            const double delta = (y1 - y0)/10, ndelta = delta?delta:1;\n            y0+=ndelta; y1+=ndelta;\n            go_up = false;\n          }\n          if (go_down) {\n            const double delta = (y1 - y0)/10, ndelta = delta?delta:1;\n            y0-=ndelta; y1-=ndelta;\n            go_down = false;\n          }\n        }\n        if (!exit_on_anykey && key && key!=(int)cimg::keyESC &&\n            (key!=(int)cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {\n          disp.set_key(key,false);\n          key = 0;\n        }\n      }\n      disp._normalization = old_normalization;\n      return *this;\n    }\n\n    //! Save image as a file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param number When positive, represents an index added to the filename. Otherwise, no number is added.\n       \\param digits Number of digits used for adding the number to the filename.\n       \\note\n       - The used file format is defined by the file extension in the filename \\p filename.\n       - Parameter \\p number can be used to add a 6-digit number to the filename before saving.\n\n    **/\n    const CImg<T>& save(const char *const filename, const int number=-1, const unsigned int digits=6) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save(): Specified filename is (null).\",\n                                    cimg_instance);\n      // Do not test for empty instances, since .cimg format is able to manage empty instances.\n      const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.');\n      const char *const ext = cimg::split_filename(filename);\n      CImg<charT> nfilename(1024);\n      const char *const fn = is_stdout?filename:(number>=0)?cimg::number_filename(filename,number,digits,nfilename):\n        filename;\n\n#ifdef cimg_save_plugin\n      cimg_save_plugin(fn);\n#endif\n#ifdef cimg_save_plugin1\n      cimg_save_plugin1(fn);\n#endif\n#ifdef cimg_save_plugin2\n      cimg_save_plugin2(fn);\n#endif\n#ifdef cimg_save_plugin3\n      cimg_save_plugin3(fn);\n#endif\n#ifdef cimg_save_plugin4\n      cimg_save_plugin4(fn);\n#endif\n#ifdef cimg_save_plugin5\n      cimg_save_plugin5(fn);\n#endif\n#ifdef cimg_save_plugin6\n      cimg_save_plugin6(fn);\n#endif\n#ifdef cimg_save_plugin7\n      cimg_save_plugin7(fn);\n#endif\n#ifdef cimg_save_plugin8\n      cimg_save_plugin8(fn);\n#endif\n      // Ascii formats\n      if (!cimg::strcasecmp(ext,\"asc\")) return save_ascii(fn);\n      else if (!cimg::strcasecmp(ext,\"dlm\") ||\n               !cimg::strcasecmp(ext,\"txt\")) return save_dlm(fn);\n      else if (!cimg::strcasecmp(ext,\"cpp\") ||\n               !cimg::strcasecmp(ext,\"hpp\") ||\n               !cimg::strcasecmp(ext,\"h\") ||\n               !cimg::strcasecmp(ext,\"c\")) return save_cpp(fn);\n\n      // 2d binary formats\n      else if (!cimg::strcasecmp(ext,\"bmp\")) return save_bmp(fn);\n      else if (!cimg::strcasecmp(ext,\"jpg\") ||\n               !cimg::strcasecmp(ext,\"jpeg\") ||\n               !cimg::strcasecmp(ext,\"jpe\") ||\n               !cimg::strcasecmp(ext,\"jfif\") ||\n               !cimg::strcasecmp(ext,\"jif\")) return save_jpeg(fn);\n      else if (!cimg::strcasecmp(ext,\"rgb\")) return save_rgb(fn);\n      else if (!cimg::strcasecmp(ext,\"rgba\")) return save_rgba(fn);\n      else if (!cimg::strcasecmp(ext,\"png\")) return save_png(fn);\n      else if (!cimg::strcasecmp(ext,\"pgm\") ||\n               !cimg::strcasecmp(ext,\"ppm\") ||\n               !cimg::strcasecmp(ext,\"pnm\")) return save_pnm(fn);\n      else if (!cimg::strcasecmp(ext,\"pnk\")) return save_pnk(fn);\n      else if (!cimg::strcasecmp(ext,\"pfm\")) return save_pfm(fn);\n      else if (!cimg::strcasecmp(ext,\"exr\")) return save_exr(fn);\n      else if (!cimg::strcasecmp(ext,\"tif\") ||\n               !cimg::strcasecmp(ext,\"tiff\")) return save_tiff(fn);\n\n      // 3d binary formats\n      else if (!cimg::strcasecmp(ext,\"cimgz\")) return save_cimg(fn,true);\n      else if (!cimg::strcasecmp(ext,\"cimg\") || !*ext) return save_cimg(fn,false);\n      else if (!cimg::strcasecmp(ext,\"dcm\")) return save_medcon_external(fn);\n      else if (!cimg::strcasecmp(ext,\"hdr\") ||\n               !cimg::strcasecmp(ext,\"nii\")) return save_analyze(fn);\n      else if (!cimg::strcasecmp(ext,\"inr\")) return save_inr(fn);\n      else if (!cimg::strcasecmp(ext,\"mnc\")) return save_minc2(fn);\n      else if (!cimg::strcasecmp(ext,\"pan\")) return save_pandore(fn);\n      else if (!cimg::strcasecmp(ext,\"raw\")) return save_raw(fn);\n\n      // Archive files\n      else if (!cimg::strcasecmp(ext,\"gz\")) return save_gzip_external(fn);\n\n      // Image sequences\n      else if (!cimg::strcasecmp(ext,\"yuv\")) return save_yuv(fn,true);\n      else if (!cimg::strcasecmp(ext,\"avi\") ||\n               !cimg::strcasecmp(ext,\"mov\") ||\n               !cimg::strcasecmp(ext,\"asf\") ||\n               !cimg::strcasecmp(ext,\"divx\") ||\n               !cimg::strcasecmp(ext,\"flv\") ||\n               !cimg::strcasecmp(ext,\"mpg\") ||\n               !cimg::strcasecmp(ext,\"m1v\") ||\n               !cimg::strcasecmp(ext,\"m2v\") ||\n               !cimg::strcasecmp(ext,\"m4v\") ||\n               !cimg::strcasecmp(ext,\"mjp\") ||\n               !cimg::strcasecmp(ext,\"mp4\") ||\n               !cimg::strcasecmp(ext,\"mkv\") ||\n               !cimg::strcasecmp(ext,\"mpe\") ||\n               !cimg::strcasecmp(ext,\"movie\") ||\n               !cimg::strcasecmp(ext,\"ogm\") ||\n               !cimg::strcasecmp(ext,\"ogg\") ||\n               !cimg::strcasecmp(ext,\"ogv\") ||\n               !cimg::strcasecmp(ext,\"qt\") ||\n               !cimg::strcasecmp(ext,\"rm\") ||\n               !cimg::strcasecmp(ext,\"vob\") ||\n               !cimg::strcasecmp(ext,\"wmv\") ||\n               !cimg::strcasecmp(ext,\"xvid\") ||\n               !cimg::strcasecmp(ext,\"mpeg\")) return save_video(fn);\n      return save_other(fn);\n    }\n\n    //! Save image as an ascii file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    const CImg<T>& save_ascii(const char *const filename) const {\n      return _save_ascii(0,filename);\n    }\n\n    //! Save image as an ascii file \\overloading.\n    const CImg<T>& save_ascii(std::FILE *const file) const {\n      return _save_ascii(file,0);\n    }\n\n    const CImg<T>& _save_ascii(std::FILE *const file, const char *const filename) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_ascii(): Specified filename is (null).\",\n                                    cimg_instance);\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"w\");\n      std::fprintf(nfile,\"%u %u %u %u\\n\",_width,_height,_depth,_spectrum);\n      const T* ptrs = _data;\n      cimg_forYZC(*this,y,z,c) {\n        cimg_forX(*this,x) std::fprintf(nfile,\"%.16g \",(double)*(ptrs++));\n        std::fputc('\\n',nfile);\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as a .cpp source file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    const CImg<T>& save_cpp(const char *const filename) const {\n      return _save_cpp(0,filename);\n    }\n\n    //! Save image as a .cpp source file \\overloading.\n    const CImg<T>& save_cpp(std::FILE *const file) const {\n      return _save_cpp(file,0);\n    }\n\n    const CImg<T>& _save_cpp(std::FILE *const file, const char *const filename) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_cpp(): Specified filename is (null).\",\n                                    cimg_instance);\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"w\");\n      CImg<charT> varname(1024); *varname = 0;\n      if (filename) cimg_sscanf(cimg::basename(filename),\"%1023[a-zA-Z0-9_]\",varname._data);\n      if (!*varname) cimg_snprintf(varname,varname._width,\"unnamed\");\n      std::fprintf(nfile,\n                   \"/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\\n\"\n                   \"%s data_%s[] = { %s\\n  \",\n                   varname._data,_width,_height,_depth,_spectrum,pixel_type(),pixel_type(),varname._data,\n                   is_empty()?\"};\":\"\");\n      if (!is_empty()) for (ulongT off = 0, siz = size() - 1; off<=siz; ++off) {\n        std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off]));\n        if (off==siz) std::fprintf(nfile,\" };\\n\");\n        else if (!((off + 1)%16)) std::fprintf(nfile,\",\\n  \");\n        else std::fprintf(nfile,\", \");\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as a DLM file.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    const CImg<T>& save_dlm(const char *const filename) const {\n      return _save_dlm(0,filename);\n    }\n\n    //! Save image as a DLM file \\overloading.\n    const CImg<T>& save_dlm(std::FILE *const file) const {\n      return _save_dlm(file,0);\n    }\n\n    const CImg<T>& _save_dlm(std::FILE *const file, const char *const filename) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_dlm(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_dlm(): Instance is volumetric, values along Z will be unrolled in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n      if (_spectrum>1)\n        cimg::warn(_cimg_instance\n                   \"save_dlm(): Instance is multispectral, values along C will be unrolled in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"w\");\n      const T* ptrs = _data;\n      cimg_forYZC(*this,y,z,c) {\n        cimg_forX(*this,x) std::fprintf(nfile,\"%.16g%s\",(double)*(ptrs++),(x==width() - 1)?\"\":\",\");\n        std::fputc('\\n',nfile);\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as a BMP file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    const CImg<T>& save_bmp(const char *const filename) const {\n      return _save_bmp(0,filename);\n    }\n\n    //! Save image as a BMP file \\overloading.\n    const CImg<T>& save_bmp(std::FILE *const file) const {\n      return _save_bmp(file,0);\n    }\n\n    const CImg<T>& _save_bmp(std::FILE *const file, const char *const filename) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_bmp(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_bmp(): Instance is volumetric, only the first slice will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n      if (_spectrum>3)\n        cimg::warn(_cimg_instance\n                   \"save_bmp(): Instance is multispectral, only the three first channels will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      CImg<ucharT> header(54,1,1,1,0);\n      unsigned char align_buf[4] = { 0 };\n      const unsigned int\n        align = (4 - (3*_width)%4)%4,\n        buf_size = (3*_width + align)*height(),\n        file_size = 54 + buf_size;\n      header[0] = 'B'; header[1] = 'M';\n      header[0x02] = file_size&0xFF;\n      header[0x03] = (file_size>>8)&0xFF;\n      header[0x04] = (file_size>>16)&0xFF;\n      header[0x05] = (file_size>>24)&0xFF;\n      header[0x0A] = 0x36;\n      header[0x0E] = 0x28;\n      header[0x12] = _width&0xFF;\n      header[0x13] = (_width>>8)&0xFF;\n      header[0x14] = (_width>>16)&0xFF;\n      header[0x15] = (_width>>24)&0xFF;\n      header[0x16] = _height&0xFF;\n      header[0x17] = (_height>>8)&0xFF;\n      header[0x18] = (_height>>16)&0xFF;\n      header[0x19] = (_height>>24)&0xFF;\n      header[0x1A] = 1;\n      header[0x1B] = 0;\n      header[0x1C] = 24;\n      header[0x1D] = 0;\n      header[0x22] = buf_size&0xFF;\n      header[0x23] = (buf_size>>8)&0xFF;\n      header[0x24] = (buf_size>>16)&0xFF;\n      header[0x25] = (buf_size>>24)&0xFF;\n      header[0x27] = 0x1;\n      header[0x2B] = 0x1;\n      cimg::fwrite(header._data,54,nfile);\n\n      const T\n        *ptr_r = data(0,_height - 1,0,0),\n        *ptr_g = (_spectrum>=2)?data(0,_height - 1,0,1):0,\n        *ptr_b = (_spectrum>=3)?data(0,_height - 1,0,2):0;\n\n      switch (_spectrum) {\n      case 1 : {\n        cimg_forY(*this,y) {\n          cimg_forX(*this,x) {\n            const unsigned char val = (unsigned char)*(ptr_r++);\n            std::fputc(val,nfile); std::fputc(val,nfile); std::fputc(val,nfile);\n          }\n          cimg::fwrite(align_buf,align,nfile);\n          ptr_r-=2*_width;\n        }\n      } break;\n      case 2 : {\n        cimg_forY(*this,y) {\n          cimg_forX(*this,x) {\n            std::fputc(0,nfile);\n            std::fputc((unsigned char)(*(ptr_g++)),nfile);\n            std::fputc((unsigned char)(*(ptr_r++)),nfile);\n          }\n          cimg::fwrite(align_buf,align,nfile);\n          ptr_r-=2*_width; ptr_g-=2*_width;\n        }\n      } break;\n      default : {\n        cimg_forY(*this,y) {\n          cimg_forX(*this,x) {\n            std::fputc((unsigned char)(*(ptr_b++)),nfile);\n            std::fputc((unsigned char)(*(ptr_g++)),nfile);\n            std::fputc((unsigned char)(*(ptr_r++)),nfile);\n          }\n          cimg::fwrite(align_buf,align,nfile);\n          ptr_r-=2*_width; ptr_g-=2*_width; ptr_b-=2*_width;\n        }\n      }\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as a JPEG file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param quality Image quality (in %)\n    **/\n    const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const {\n      return _save_jpeg(0,filename,quality);\n    }\n\n    //! Save image as a JPEG file \\overloading.\n    const CImg<T>& save_jpeg(std::FILE *const file, const unsigned int quality=100) const {\n      return _save_jpeg(file,0,quality);\n    }\n\n    const CImg<T>& _save_jpeg(std::FILE *const file, const char *const filename, const unsigned int quality) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_jpeg(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_jpeg(): Instance is volumetric, only the first slice will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n\n#ifndef cimg_use_jpeg\n      if (!file) return save_other(filename,quality);\n      else throw CImgIOException(_cimg_instance\n                                 \"save_jpeg(): Unable to save data in '(*FILE)' unless libjpeg is enabled.\",\n                                 cimg_instance);\n#else\n      unsigned int dimbuf = 0;\n      J_COLOR_SPACE colortype = JCS_RGB;\n\n      switch (_spectrum) {\n      case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break;\n      case 2 : dimbuf = 3; colortype = JCS_RGB; break;\n      case 3 : dimbuf = 3; colortype = JCS_RGB; break;\n      default : dimbuf = 4; colortype = JCS_CMYK; break;\n      }\n\n      // Call libjpeg functions\n      struct jpeg_compress_struct cinfo;\n      struct jpeg_error_mgr jerr;\n      cinfo.err = jpeg_std_error(&jerr);\n      jpeg_create_compress(&cinfo);\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      jpeg_stdio_dest(&cinfo,nfile);\n      cinfo.image_width = _width;\n      cinfo.image_height = _height;\n      cinfo.input_components = dimbuf;\n      cinfo.in_color_space = colortype;\n      jpeg_set_defaults(&cinfo);\n      jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);\n      jpeg_start_compress(&cinfo,TRUE);\n\n      JSAMPROW row_pointer[1];\n      CImg<ucharT> buffer(_width*dimbuf);\n\n      while (cinfo.next_scanline<cinfo.image_height) {\n        unsigned char *ptrd = buffer._data;\n\n        // Fill pixel buffer\n        switch (_spectrum) {\n        case 1 : { // Greyscale images\n          const T *ptr_g = data(0, cinfo.next_scanline);\n          for (unsigned int b = 0; b<cinfo.image_width; b++)\n            *(ptrd++) = (unsigned char)*(ptr_g++);\n        } break;\n        case 2 : { // RG images\n          const T *ptr_r = data(0,cinfo.next_scanline,0,0),\n            *ptr_g = data(0,cinfo.next_scanline,0,1);\n          for (unsigned int b = 0; b<cinfo.image_width; ++b) {\n            *(ptrd++) = (unsigned char)*(ptr_r++);\n            *(ptrd++) = (unsigned char)*(ptr_g++);\n            *(ptrd++) = 0;\n          }\n        } break;\n        case 3 : { // RGB images\n          const T *ptr_r = data(0,cinfo.next_scanline,0,0),\n            *ptr_g = data(0,cinfo.next_scanline,0,1),\n            *ptr_b = data(0,cinfo.next_scanline,0,2);\n          for (unsigned int b = 0; b<cinfo.image_width; ++b) {\n            *(ptrd++) = (unsigned char)*(ptr_r++);\n            *(ptrd++) = (unsigned char)*(ptr_g++);\n            *(ptrd++) = (unsigned char)*(ptr_b++);\n          }\n        } break;\n        default : { // CMYK images\n          const T *ptr_r = data(0,cinfo.next_scanline,0,0),\n            *ptr_g = data(0,cinfo.next_scanline,0,1),\n            *ptr_b = data(0,cinfo.next_scanline,0,2),\n            *ptr_a = data(0,cinfo.next_scanline,0,3);\n          for (unsigned int b = 0; b<cinfo.image_width; ++b) {\n            *(ptrd++) = (unsigned char)*(ptr_r++);\n            *(ptrd++) = (unsigned char)*(ptr_g++);\n            *(ptrd++) = (unsigned char)*(ptr_b++);\n            *(ptrd++) = (unsigned char)*(ptr_a++);\n          }\n        }\n        }\n        *row_pointer = buffer._data;\n        jpeg_write_scanlines(&cinfo,row_pointer,1);\n      }\n      jpeg_finish_compress(&cinfo);\n      if (!file) cimg::fclose(nfile);\n      jpeg_destroy_compress(&cinfo);\n      return *this;\n#endif\n    }\n\n    //! Save image, using built-in ImageMagick++ library.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param bytes_per_pixel Force the number of bytes per pixel for the saving, when possible.\n    **/\n    const CImg<T>& save_magick(const char *const filename, const unsigned int bytes_per_pixel=0) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_magick(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n\n#ifdef cimg_use_magick\n      double stmin, stmax = (double)max_min(stmin);\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_magick(): Instance is volumetric, only the first slice will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename);\n\n      if (_spectrum>3)\n        cimg::warn(_cimg_instance\n                   \"save_magick(): Instance is multispectral, only the three first channels will be \"\n                   \"saved in file '%s'.\",\n                   cimg_instance,\n                   filename);\n\n      if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)\n        cimg::warn(_cimg_instance\n                   \"save_magick(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.\",\n                   cimg_instance,\n                   filename,stmin,stmax);\n\n      Magick::Image image(Magick::Geometry(_width,_height),\"black\");\n      image.type(Magick::TrueColorType);\n      image.depth(bytes_per_pixel?(8*bytes_per_pixel):(stmax>=256?16:8));\n      const T\n        *ptr_r = data(0,0,0,0),\n        *ptr_g = _spectrum>1?data(0,0,0,1):0,\n        *ptr_b = _spectrum>2?data(0,0,0,2):0;\n      Magick::PixelPacket *pixels = image.getPixels(0,0,_width,_height);\n      switch (_spectrum) {\n      case 1 : // Scalar images\n        for (ulongT off = (ulongT)_width*_height; off; --off) {\n          pixels->red = pixels->green = pixels->blue = (Magick::Quantum)*(ptr_r++);\n          ++pixels;\n        }\n        break;\n      case 2 : // RG images\n        for (ulongT off = (ulongT)_width*_height; off; --off) {\n          pixels->red = (Magick::Quantum)*(ptr_r++);\n          pixels->green = (Magick::Quantum)*(ptr_g++);\n          pixels->blue = 0; ++pixels;\n        }\n        break;\n      default : // RGB images\n        for (ulongT off = (ulongT)_width*_height; off; --off) {\n          pixels->red = (Magick::Quantum)*(ptr_r++);\n          pixels->green = (Magick::Quantum)*(ptr_g++);\n          pixels->blue = (Magick::Quantum)*(ptr_b++);\n          ++pixels;\n        }\n      }\n      image.syncPixels();\n      image.write(filename);\n      return *this;\n#else\n      cimg::unused(bytes_per_pixel);\n      throw CImgIOException(_cimg_instance\n                            \"save_magick(): Unable to save file '%s' unless libMagick++ is enabled.\",\n                            cimg_instance,\n                            filename);\n#endif\n    }\n\n    //! Save image as a PNG file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param bytes_per_pixel Force the number of bytes per pixels for the saving, when possible.\n    **/\n    const CImg<T>& save_png(const char *const filename, const unsigned int bytes_per_pixel=0) const {\n      return _save_png(0,filename,bytes_per_pixel);\n    }\n\n    //! Save image as a PNG file \\overloading.\n    const CImg<T>& save_png(std::FILE *const file, const unsigned int bytes_per_pixel=0) const {\n      return _save_png(file,0,bytes_per_pixel);\n    }\n\n    const CImg<T>& _save_png(std::FILE *const file, const char *const filename,\n                             const unsigned int bytes_per_pixel=0) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_png(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n\n#ifndef cimg_use_png\n      cimg::unused(bytes_per_pixel);\n      if (!file) return save_other(filename);\n      else throw CImgIOException(_cimg_instance\n                                 \"save_png(): Unable to save data in '(*FILE)' unless libpng is enabled.\",\n                                 cimg_instance);\n#else\n      const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.\n      std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,\"wb\");\n      volatile double stmin, stmax = (double)max_min(stmin);\n\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_png(): Instance is volumetric, only the first slice will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename);\n\n      if (_spectrum>4)\n        cimg::warn(_cimg_instance\n                   \"save_png(): Instance is multispectral, only the three first channels will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename);\n\n      if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)\n        cimg::warn(_cimg_instance\n                   \"save_png(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.\",\n                   cimg_instance,\n                   filename,stmin,stmax);\n\n      // Setup PNG structures for write\n      png_voidp user_error_ptr = 0;\n      png_error_ptr user_error_fn = 0, user_warning_fn = 0;\n      png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn,\n                                                    user_warning_fn);\n      if(!png_ptr){\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"save_png(): Failed to initialize 'png_ptr' structure when saving file '%s'.\",\n                              cimg_instance,\n                              nfilename?nfilename:\"(FILE*)\");\n      }\n      png_infop info_ptr = png_create_info_struct(png_ptr);\n      if (!info_ptr) {\n        png_destroy_write_struct(&png_ptr,(png_infopp)0);\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"save_png(): Failed to initialize 'info_ptr' structure when saving file '%s'.\",\n                              cimg_instance,\n                              nfilename?nfilename:\"(FILE*)\");\n      }\n      if (setjmp(png_jmpbuf(png_ptr))) {\n        png_destroy_write_struct(&png_ptr, &info_ptr);\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"save_png(): Encountered unknown fatal error in libpng when saving file '%s'.\",\n                              cimg_instance,\n                              nfilename?nfilename:\"(FILE*)\");\n      }\n      png_init_io(png_ptr, nfile);\n\n      const int bit_depth = bytes_per_pixel?(bytes_per_pixel*8):(stmax>=256?16:8);\n\n      int color_type;\n      switch (spectrum()) {\n      case 1 : color_type = PNG_COLOR_TYPE_GRAY; break;\n      case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;\n      case 3 : color_type = PNG_COLOR_TYPE_RGB; break;\n      default : color_type = PNG_COLOR_TYPE_RGB_ALPHA;\n      }\n      const int interlace_type = PNG_INTERLACE_NONE;\n      const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;\n      const int filter_method = PNG_FILTER_TYPE_DEFAULT;\n      png_set_IHDR(png_ptr,info_ptr,_width,_height,bit_depth,color_type,interlace_type,compression_type,filter_method);\n      png_write_info(png_ptr,info_ptr);\n      const int byte_depth = bit_depth>>3;\n      const int numChan = spectrum()>4?4:spectrum();\n      const int pixel_bit_depth_flag = numChan * (bit_depth - 1);\n\n      // Allocate Memory for Image Save and Fill pixel data\n      png_bytep *const imgData = new png_byte*[_height];\n      for (unsigned int row = 0; row<_height; ++row) imgData[row] = new png_byte[byte_depth*numChan*_width];\n      const T *pC0 = data(0,0,0,0);\n      switch (pixel_bit_depth_flag) {\n      case 7 :  { // Gray 8-bit\n        cimg_forY(*this,y) {\n          unsigned char *ptrd = imgData[y];\n          cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);\n        }\n      } break;\n      case 14 : { // Gray w/ Alpha 8-bit\n        const T *pC1 = data(0,0,0,1);\n        cimg_forY(*this,y) {\n          unsigned char *ptrd = imgData[y];\n          cimg_forX(*this,x) {\n            *(ptrd++) = (unsigned char)*(pC0++);\n            *(ptrd++) = (unsigned char)*(pC1++);\n          }\n        }\n      } break;\n      case 21 :  { // RGB 8-bit\n        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2);\n        cimg_forY(*this,y) {\n          unsigned char *ptrd = imgData[y];\n          cimg_forX(*this,x) {\n            *(ptrd++) = (unsigned char)*(pC0++);\n            *(ptrd++) = (unsigned char)*(pC1++);\n            *(ptrd++) = (unsigned char)*(pC2++);\n          }\n        }\n      } break;\n      case 28 : { // RGB x/ Alpha 8-bit\n        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3);\n        cimg_forY(*this,y){\n          unsigned char *ptrd = imgData[y];\n          cimg_forX(*this,x){\n            *(ptrd++) = (unsigned char)*(pC0++);\n            *(ptrd++) = (unsigned char)*(pC1++);\n            *(ptrd++) = (unsigned char)*(pC2++);\n            *(ptrd++) = (unsigned char)*(pC3++);\n          }\n        }\n      } break;\n      case 15 : { // Gray 16-bit\n        cimg_forY(*this,y){\n          unsigned short *ptrd = (unsigned short*)(imgData[y]);\n          cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);\n          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],_width);\n        }\n      } break;\n      case 30 : { // Gray w/ Alpha 16-bit\n        const T *pC1 = data(0,0,0,1);\n        cimg_forY(*this,y){\n          unsigned short *ptrd = (unsigned short*)(imgData[y]);\n          cimg_forX(*this,x) {\n            *(ptrd++) = (unsigned short)*(pC0++);\n            *(ptrd++) = (unsigned short)*(pC1++);\n          }\n          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*_width);\n        }\n      } break;\n      case 45 : { // RGB 16-bit\n        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2);\n        cimg_forY(*this,y) {\n          unsigned short *ptrd = (unsigned short*)(imgData[y]);\n          cimg_forX(*this,x) {\n            *(ptrd++) = (unsigned short)*(pC0++);\n            *(ptrd++) = (unsigned short)*(pC1++);\n            *(ptrd++) = (unsigned short)*(pC2++);\n          }\n          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*_width);\n        }\n      } break;\n      case 60 : { // RGB w/ Alpha 16-bit\n        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3);\n        cimg_forY(*this,y) {\n          unsigned short *ptrd = (unsigned short*)(imgData[y]);\n          cimg_forX(*this,x) {\n            *(ptrd++) = (unsigned short)*(pC0++);\n            *(ptrd++) = (unsigned short)*(pC1++);\n            *(ptrd++) = (unsigned short)*(pC2++);\n            *(ptrd++) = (unsigned short)*(pC3++);\n          }\n          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*_width);\n        }\n      } break;\n      default :\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimg_instance\n                              \"save_png(): Encountered unknown fatal error in libpng when saving file '%s'.\",\n                              cimg_instance,\n                              nfilename?nfilename:\"(FILE*)\");\n      }\n      png_write_image(png_ptr,imgData);\n      png_write_end(png_ptr,info_ptr);\n      png_destroy_write_struct(&png_ptr, &info_ptr);\n\n      // Deallocate Image Write Memory\n      cimg_forY(*this,n) delete[] imgData[n];\n      delete[] imgData;\n\n      if (!file) cimg::fclose(nfile);\n      return *this;\n#endif\n    }\n\n    //! Save image as a PNM file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param bytes_per_pixel Force the number of bytes per pixels for the saving.\n    **/\n    const CImg<T>& save_pnm(const char *const filename, const unsigned int bytes_per_pixel=0) const {\n      return _save_pnm(0,filename,bytes_per_pixel);\n    }\n\n    //! Save image as a PNM file \\overloading.\n    const CImg<T>& save_pnm(std::FILE *const file, const unsigned int bytes_per_pixel=0) const {\n      return _save_pnm(file,0,bytes_per_pixel);\n    }\n\n    const CImg<T>& _save_pnm(std::FILE *const file, const char *const filename,\n                             const unsigned int bytes_per_pixel=0) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_pnm(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n\n      double stmin, stmax = (double)max_min(stmin);\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_pnm(): Instance is volumetric, only the first slice will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n      if (_spectrum>3)\n        cimg::warn(_cimg_instance\n                   \"save_pnm(): Instance is multispectral, only the three first channels will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n      if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)\n        cimg::warn(_cimg_instance\n                   \"save_pnm(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.\",\n                   cimg_instance,\n                   stmin,stmax,filename?filename:\"(FILE*)\");\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      const T\n        *ptr_r = data(0,0,0,0),\n        *ptr_g = (_spectrum>=2)?data(0,0,0,1):0,\n        *ptr_b = (_spectrum>=3)?data(0,0,0,2):0;\n      const ulongT buf_size = cimg::min((ulongT)1024*1024,(ulongT)_width*_height*(_spectrum==1?1UL:3UL));\n\n      std::fprintf(nfile,\"P%c\\n%u %u\\n%u\\n\",\n                   (_spectrum==1?'5':'6'),_width,_height,stmax<256?255:(stmax<4096?4095:65535));\n\n      switch (_spectrum) {\n      case 1 : { // Scalar image\n        if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PGM 8 bits\n          CImg<ucharT> buf(buf_size);\n          for (longT to_write = (longT)width()*height(); to_write>0; ) {\n            const ulongT N = cimg::min((ulongT)to_write,buf_size);\n            unsigned char *ptrd = buf._data;\n            for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr_r++);\n            cimg::fwrite(buf._data,N,nfile);\n            to_write-=N;\n          }\n        } else { // Binary PGM 16 bits\n          CImg<ushortT> buf(buf_size);\n          for (longT to_write = (longT)width()*height(); to_write>0; ) {\n            const ulongT N = cimg::min((ulongT)to_write,buf_size);\n            unsigned short *ptrd = buf._data;\n            for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned short)*(ptr_r++);\n            if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size);\n            cimg::fwrite(buf._data,N,nfile);\n            to_write-=N;\n          }\n        }\n      } break;\n      case 2 : { // RG image\n        if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits\n          CImg<ucharT> buf(buf_size);\n          for (longT to_write = (longT)width()*height(); to_write>0; ) {\n            const ulongT N = cimg::min((ulongT)to_write,buf_size/3);\n            unsigned char *ptrd = buf._data;\n            for (ulongT i = N; i>0; --i) {\n              *(ptrd++) = (unsigned char)*(ptr_r++);\n              *(ptrd++) = (unsigned char)*(ptr_g++);\n              *(ptrd++) = 0;\n            }\n            cimg::fwrite(buf._data,3*N,nfile);\n            to_write-=N;\n          }\n        } else {             // Binary PPM 16 bits\n          CImg<ushortT> buf(buf_size);\n          for (longT to_write = (longT)width()*height(); to_write>0; ) {\n            const ulongT N = cimg::min((ulongT)to_write,buf_size/3);\n            unsigned short *ptrd = buf._data;\n            for (ulongT i = N; i>0; --i) {\n              *(ptrd++) = (unsigned short)*(ptr_r++);\n              *(ptrd++) = (unsigned short)*(ptr_g++);\n              *(ptrd++) = 0;\n            }\n            if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size);\n            cimg::fwrite(buf._data,3*N,nfile);\n            to_write-=N;\n          }\n        }\n      } break;\n      default : { // RGB image\n        if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits\n          CImg<ucharT> buf(buf_size);\n          for (longT to_write = (longT)width()*height(); to_write>0; ) {\n            const ulongT N = cimg::min((ulongT)to_write,buf_size/3);\n            unsigned char *ptrd = buf._data;\n            for (ulongT i = N; i>0; --i) {\n              *(ptrd++) = (unsigned char)*(ptr_r++);\n              *(ptrd++) = (unsigned char)*(ptr_g++);\n              *(ptrd++) = (unsigned char)*(ptr_b++);\n            }\n            cimg::fwrite(buf._data,3*N,nfile);\n            to_write-=N;\n          }\n        } else {             // Binary PPM 16 bits\n          CImg<ushortT> buf(buf_size);\n          for (longT to_write = (longT)width()*height(); to_write>0; ) {\n            const ulongT N = cimg::min((ulongT)to_write,buf_size/3);\n            unsigned short *ptrd = buf._data;\n            for (ulongT i = N; i>0; --i) {\n              *(ptrd++) = (unsigned short)*(ptr_r++);\n              *(ptrd++) = (unsigned short)*(ptr_g++);\n              *(ptrd++) = (unsigned short)*(ptr_b++);\n            }\n            if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size);\n            cimg::fwrite(buf._data,3*N,nfile);\n            to_write-=N;\n          }\n        }\n      }\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as a PNK file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    const CImg<T>& save_pnk(const char *const filename) const {\n      return _save_pnk(0,filename);\n    }\n\n    //! Save image as a PNK file \\overloading.\n    const CImg<T>& save_pnk(std::FILE *const file) const {\n      return _save_pnk(file,0);\n    }\n\n    const CImg<T>& _save_pnk(std::FILE *const file, const char *const filename) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_pnk(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n      if (_spectrum>1)\n        cimg::warn(_cimg_instance\n                   \"save_pnk(): Instance is multispectral, only the first channel will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n\n      const ulongT buf_size = cimg::min((ulongT)1024*1024,(ulongT)_width*_height*_depth);\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      const T *ptr = data(0,0,0,0);\n\n      if (!cimg::type<T>::is_float() && sizeof(T)==1 && _depth<2) // Can be saved as regular PNM file.\n        _save_pnm(file,filename,0);\n      else if (!cimg::type<T>::is_float() && sizeof(T)==1) { // Save as extended P5 file: Binary byte-valued 3d.\n        std::fprintf(nfile,\"P5\\n%u %u %u\\n255\\n\",_width,_height,_depth);\n        CImg<ucharT> buf(buf_size);\n        for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) {\n          const ulongT N = cimg::min((ulongT)to_write,buf_size);\n          unsigned char *ptrd = buf._data;\n          for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr++);\n          cimg::fwrite(buf._data,N,nfile);\n          to_write-=N;\n        }\n      } else if (!cimg::type<T>::is_float()) { // Save as P8: Binary int32-valued 3d.\n        if (_depth>1) std::fprintf(nfile,\"P8\\n%u %u %u\\n%d\\n\",_width,_height,_depth,(int)max());\n        else std::fprintf(nfile,\"P8\\n%u %u\\n%d\\n\",_width,_height,(int)max());\n        CImg<intT> buf(buf_size);\n        for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) {\n          const ulongT N = cimg::min((ulongT)to_write,buf_size);\n          int *ptrd = buf._data;\n          for (ulongT i = N; i>0; --i) *(ptrd++) = (int)*(ptr++);\n          cimg::fwrite(buf._data,N,nfile);\n          to_write-=N;\n        }\n      } else { // Save as P9: Binary float-valued 3d.\n        if (_depth>1) std::fprintf(nfile,\"P9\\n%u %u %u\\n%g\\n\",_width,_height,_depth,(double)max());\n        else std::fprintf(nfile,\"P9\\n%u %u\\n%g\\n\",_width,_height,(double)max());\n        CImg<floatT> buf(buf_size);\n        for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) {\n          const ulongT N = cimg::min((ulongT)to_write,buf_size);\n          float *ptrd = buf._data;\n          for (ulongT i = N; i>0; --i) *(ptrd++) = (float)*(ptr++);\n          cimg::fwrite(buf._data,N,nfile);\n          to_write-=N;\n        }\n      }\n\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as a PFM file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    const CImg<T>& save_pfm(const char *const filename) const {\n      get_mirror('y')._save_pfm(0,filename);\n      return *this;\n    }\n\n    //! Save image as a PFM file \\overloading.\n    const CImg<T>& save_pfm(std::FILE *const file) const {\n      get_mirror('y')._save_pfm(file,0);\n      return *this;\n    }\n\n    const CImg<T>& _save_pfm(std::FILE *const file, const char *const filename) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_pfm(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_pfm(): Instance is volumetric, only the first slice will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n      if (_spectrum>3)\n        cimg::warn(_cimg_instance\n                   \"save_pfm(): image instance is multispectral, only the three first channels will be saved \"\n                   \"in file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      const T\n        *ptr_r = data(0,0,0,0),\n        *ptr_g = (_spectrum>=2)?data(0,0,0,1):0,\n        *ptr_b = (_spectrum>=3)?data(0,0,0,2):0;\n      const unsigned int buf_size = cimg::min(1024*1024U,_width*_height*(_spectrum==1?1:3));\n\n      std::fprintf(nfile,\"P%c\\n%u %u\\n1.0\\n\",\n                   (_spectrum==1?'f':'F'),_width,_height);\n\n      switch (_spectrum) {\n      case 1 : { // Scalar image\n        CImg<floatT> buf(buf_size);\n        for (longT to_write = (longT)width()*height(); to_write>0; ) {\n          const ulongT N = cimg::min((ulongT)to_write,buf_size);\n          float *ptrd = buf._data;\n          for (ulongT i = N; i>0; --i) *(ptrd++) = (float)*(ptr_r++);\n          if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size);\n          cimg::fwrite(buf._data,N,nfile);\n          to_write-=N;\n        }\n      } break;\n      case 2 : { // RG image\n        CImg<floatT> buf(buf_size);\n        for (longT to_write = (longT)width()*height(); to_write>0; ) {\n          const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3);\n          float *ptrd = buf._data;\n          for (ulongT i = N; i>0; --i) {\n            *(ptrd++) = (float)*(ptr_r++);\n            *(ptrd++) = (float)*(ptr_g++);\n            *(ptrd++) = 0;\n          }\n          if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size);\n          cimg::fwrite(buf._data,3*N,nfile);\n          to_write-=N;\n        }\n      } break;\n      default : { // RGB image\n        CImg<floatT> buf(buf_size);\n        for (longT to_write = (longT)width()*height(); to_write>0; ) {\n          const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3);\n          float *ptrd = buf._data;\n          for (ulongT i = N; i>0; --i) {\n            *(ptrd++) = (float)*(ptr_r++);\n            *(ptrd++) = (float)*(ptr_g++);\n            *(ptrd++) = (float)*(ptr_b++);\n          }\n          if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size);\n          cimg::fwrite(buf._data,3*N,nfile);\n          to_write-=N;\n        }\n      }\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as a RGB file.\n    /**\n      \\param filename Filename, as a C-string.\n    **/\n    const CImg<T>& save_rgb(const char *const filename) const {\n      return _save_rgb(0,filename);\n    }\n\n    //! Save image as a RGB file \\overloading.\n    const CImg<T>& save_rgb(std::FILE *const file) const {\n      return _save_rgb(file,0);\n    }\n\n    const CImg<T>& _save_rgb(std::FILE *const file, const char *const filename) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_rgb(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n      if (_spectrum!=3)\n        cimg::warn(_cimg_instance\n                   \"save_rgb(): image instance has not exactly 3 channels, for file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      const ulongT wh = (ulongT)_width*_height;\n      unsigned char *const buffer = new unsigned char[3*wh], *nbuffer = buffer;\n      const T\n        *ptr1 = data(0,0,0,0),\n        *ptr2 = _spectrum>1?data(0,0,0,1):0,\n        *ptr3 = _spectrum>2?data(0,0,0,2):0;\n      switch (_spectrum) {\n      case 1 : { // Scalar image\n        for (ulongT k = 0; k<wh; ++k) {\n          const unsigned char val = (unsigned char)*(ptr1++);\n          *(nbuffer++) = val;\n          *(nbuffer++) = val;\n          *(nbuffer++) = val;\n        }\n      } break;\n      case 2 : { // RG image\n        for (ulongT k = 0; k<wh; ++k) {\n          *(nbuffer++) = (unsigned char)(*(ptr1++));\n          *(nbuffer++) = (unsigned char)(*(ptr2++));\n          *(nbuffer++) = 0;\n        }\n      } break;\n      default : { // RGB image\n        for (ulongT k = 0; k<wh; ++k) {\n          *(nbuffer++) = (unsigned char)(*(ptr1++));\n          *(nbuffer++) = (unsigned char)(*(ptr2++));\n          *(nbuffer++) = (unsigned char)(*(ptr3++));\n        }\n      }\n      }\n      cimg::fwrite(buffer,3*wh,nfile);\n      if (!file) cimg::fclose(nfile);\n      delete[] buffer;\n      return *this;\n    }\n\n    //! Save image as a RGBA file.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    const CImg<T>& save_rgba(const char *const filename) const {\n      return _save_rgba(0,filename);\n    }\n\n    //! Save image as a RGBA file \\overloading.\n    const CImg<T>& save_rgba(std::FILE *const file) const {\n      return _save_rgba(file,0);\n    }\n\n    const CImg<T>& _save_rgba(std::FILE *const file, const char *const filename) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_rgba(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n      if (_spectrum!=4)\n        cimg::warn(_cimg_instance\n                   \"save_rgba(): image instance has not exactly 4 channels, for file '%s'.\",\n                   cimg_instance,\n                   filename?filename:\"(FILE*)\");\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      const ulongT wh = (ulongT)_width*_height;\n      unsigned char *const buffer = new unsigned char[4*wh], *nbuffer = buffer;\n      const T\n        *ptr1 = data(0,0,0,0),\n        *ptr2 = _spectrum>1?data(0,0,0,1):0,\n        *ptr3 = _spectrum>2?data(0,0,0,2):0,\n        *ptr4 = _spectrum>3?data(0,0,0,3):0;\n      switch (_spectrum) {\n      case 1 : { // Scalar images\n        for (ulongT k = 0; k<wh; ++k) {\n          const unsigned char val = (unsigned char)*(ptr1++);\n          *(nbuffer++) = val;\n          *(nbuffer++) = val;\n          *(nbuffer++) = val;\n          *(nbuffer++) = 255;\n        }\n      } break;\n      case 2 : { // RG images\n        for (ulongT k = 0; k<wh; ++k) {\n          *(nbuffer++) = (unsigned char)(*(ptr1++));\n          *(nbuffer++) = (unsigned char)(*(ptr2++));\n          *(nbuffer++) = 0;\n          *(nbuffer++) = 255;\n        }\n      } break;\n      case 3 : { // RGB images\n        for (ulongT k = 0; k<wh; ++k) {\n          *(nbuffer++) = (unsigned char)(*(ptr1++));\n          *(nbuffer++) = (unsigned char)(*(ptr2++));\n          *(nbuffer++) = (unsigned char)(*(ptr3++));\n          *(nbuffer++) = 255;\n        }\n      } break;\n      default : { // RGBA images\n        for (ulongT k = 0; k<wh; ++k) {\n          *(nbuffer++) = (unsigned char)(*(ptr1++));\n          *(nbuffer++) = (unsigned char)(*(ptr2++));\n          *(nbuffer++) = (unsigned char)(*(ptr3++));\n          *(nbuffer++) = (unsigned char)(*(ptr4++));\n        }\n      }\n      }\n      cimg::fwrite(buffer,4*wh,nfile);\n      if (!file) cimg::fclose(nfile);\n      delete[] buffer;\n      return *this;\n    }\n\n    //! Save image as a TIFF file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param compression_type Type of data compression. Can be <tt>{ 0=None | 1=LZW | 2=JPEG }</tt>.\n       \\note\n       - libtiff support is enabled by defining the precompilation\n        directive \\c cimg_use_tif.\n       - When libtiff is enabled, 2D and 3D (multipage) several\n        channel per pixel are supported for\n        <tt>char,uchar,short,ushort,float</tt> and \\c double pixel types.\n       - If \\c cimg_use_tif is not defined at compile time the\n        function uses CImg<T>&save_other(const char*).\n     **/\n    const CImg<T>& save_tiff(const char *const filename, const unsigned int compression_type=0,\n                             const float *const voxel_size=0, const char *const description=0,\n                             const bool use_bigtiff=true) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_tiff(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n\n#ifdef cimg_use_tiff\n      const bool\n        _use_bigtiff = use_bigtiff && sizeof(ulongT)>=8 && size()*sizeof(T)>=1UL<<31; // No bigtiff for small images.\n      TIFF *tif = TIFFOpen(filename,_use_bigtiff?\"w8\":\"w4\");\n      if (tif) {\n        cimg_forZ(*this,z) _save_tiff(tif,z,z,compression_type,voxel_size,description);\n        TIFFClose(tif);\n      } else throw CImgIOException(_cimg_instance\n                                   \"save_tiff(): Failed to open file '%s' for writing.\",\n                                   cimg_instance,\n                                   filename);\n      return *this;\n#else\n      cimg::unused(compression_type,voxel_size,description,use_bigtiff);\n      return save_other(filename);\n#endif\n    }\n\n#ifdef cimg_use_tiff\n\n#define _cimg_save_tiff(types,typed,compression_type) if (!std::strcmp(types,pixel_type())) { \\\n      const typed foo = (typed)0; return _save_tiff(tif,directory,z,foo,compression_type,voxel_size,description); }\n\n    // [internal] Save a plane into a tiff file\n    template<typename t>\n    const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z, const t& pixel_t,\n                              const unsigned int compression_type, const float *const voxel_size,\n                              const char *const description) const {\n      if (is_empty() || !tif || pixel_t) return *this;\n      const char *const filename = TIFFFileName(tif);\n      uint32 rowsperstrip = (uint32)-1;\n      uint16 spp = _spectrum, bpp = sizeof(t)*8, photometric;\n      if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB;\n      else photometric = PHOTOMETRIC_MINISBLACK;\n      TIFFSetDirectory(tif,directory);\n      TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,_width);\n      TIFFSetField(tif,TIFFTAG_IMAGELENGTH,_height);\n      if (voxel_size) {\n        const float vx = voxel_size[0], vy = voxel_size[1], vz = voxel_size[2];\n        TIFFSetField(tif,TIFFTAG_RESOLUTIONUNIT,RESUNIT_NONE);\n        TIFFSetField(tif,TIFFTAG_XRESOLUTION,1.0f/vx);\n        TIFFSetField(tif,TIFFTAG_YRESOLUTION,1.0f/vy);\n        CImg<charT> s_description(256);\n        cimg_snprintf(s_description,s_description._width,\"VX=%g VY=%g VZ=%g spacing=%g\",vx,vy,vz,vz);\n        TIFFSetField(tif,TIFFTAG_IMAGEDESCRIPTION,s_description.data());\n      }\n      if (description) TIFFSetField(tif,TIFFTAG_IMAGEDESCRIPTION,description);\n      TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);\n      TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp);\n      if (cimg::type<t>::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3);\n      else if (cimg::type<t>::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1);\n      else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2);\n      TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp);\n      TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);\n      TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric);\n      TIFFSetField(tif,TIFFTAG_COMPRESSION,compression_type==2?COMPRESSION_JPEG:\n                   compression_type==1?COMPRESSION_LZW:COMPRESSION_NONE);\n      rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip);\n      TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip);\n      TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);\n      TIFFSetField(tif,TIFFTAG_SOFTWARE,\"CImg\");\n      t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif));\n      if (buf) {\n        for (unsigned int row = 0; row<_height; row+=rowsperstrip) {\n          uint32 nrow = (row + rowsperstrip>_height?_height - row:rowsperstrip);\n          tstrip_t strip = TIFFComputeStrip(tif,row,0);\n          tsize_t i = 0;\n          for (unsigned int rr = 0; rr<nrow; ++rr)\n            for (unsigned int cc = 0; cc<_width; ++cc)\n              for (unsigned int vv = 0; vv<spp; ++vv)\n                buf[i++] = (t)(*this)(cc,row + rr,z,vv);\n          if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(t))<0)\n            throw CImgIOException(_cimg_instance\n                                  \"save_tiff(): Invalid strip writing when saving file '%s'.\",\n                                  cimg_instance,\n                                  filename?filename:\"(FILE*)\");\n        }\n        _TIFFfree(buf);\n      }\n      TIFFWriteDirectory(tif);\n      return (*this);\n    }\n\n    const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z,\n                              const unsigned int compression_type, const float *const voxel_size,\n                              const char *const description) const {\n      _cimg_save_tiff(\"bool\",unsigned char,compression_type);\n      _cimg_save_tiff(\"unsigned char\",unsigned char,compression_type);\n      _cimg_save_tiff(\"char\",char,compression_type);\n      _cimg_save_tiff(\"unsigned short\",unsigned short,compression_type);\n      _cimg_save_tiff(\"short\",short,compression_type);\n      _cimg_save_tiff(\"unsigned int\",unsigned int,compression_type);\n      _cimg_save_tiff(\"int\",int,compression_type);\n      _cimg_save_tiff(\"unsigned int64\",unsigned int,compression_type);\n      _cimg_save_tiff(\"int64\",int,compression_type);\n      _cimg_save_tiff(\"float\",float,compression_type);\n      _cimg_save_tiff(\"double\",float,compression_type);\n      const char *const filename = TIFFFileName(tif);\n      throw CImgInstanceException(_cimg_instance\n                                  \"save_tiff(): Unsupported pixel type '%s' for file '%s'.\",\n                                  cimg_instance,\n                                  pixel_type(),filename?filename:\"(FILE*)\");\n      return *this;\n    }\n#endif\n\n    //! Save image as a MINC2 file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param imitate_file If non-zero, reference filename, as a C-string, to borrow header from.\n    **/\n    const CImg<T>& save_minc2(const char *const filename,\n                              const char *const imitate_file=0) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                   \"save_minc2(): Specified filename is (null).\",\n                                   cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n\n#ifndef cimg_use_minc2\n     cimg::unused(imitate_file);\n     return save_other(filename);\n#else\n     minc::minc_1_writer wtr;\n     if (imitate_file)\n       wtr.open(filename, imitate_file);\n     else {\n       minc::minc_info di;\n       if(width()) di.push_back(minc::dim_info(width(),width()*0.5,-1,minc::dim_info::DIM_X));\n       if(height()) di.push_back(minc::dim_info(height(),height()*0.5,-1,minc::dim_info::DIM_Y));\n       if(depth()) di.push_back(minc::dim_info(depth(),depth()*0.5,-1,minc::dim_info::DIM_Z));\n       if(spectrum()) di.push_back(minc::dim_info(spectrum(),spectrum()*0.5,-1,minc::dim_info::DIM_TIME));\n       wtr.open(filename,di,1,NC_FLOAT,0);\n     }\n     if(typeid(T)==typeid(unsigned char))\n       wtr.setup_write_byte();\n     else if(typeid(T)==typeid(int))\n       wtr.setup_write_int();\n     else if(typeid(T)==typeid(double))\n       wtr.setup_write_double();\n     else\n       wtr.setup_write_float();\n     minc::save_standard_volume(wtr, this->_data);\n     return *this;\n#endif\n    }\n\n    //! Save image as an ANALYZE7.5 or NIFTI file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param voxel_size Pointer to 3 consecutive values that tell about the voxel sizes along the X,Y and Z dimensions.\n    **/\n    const CImg<T>& save_analyze(const char *const filename, const float *const voxel_size=0) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_analyze(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n\n      std::FILE *file;\n      CImg<charT> header(348,1,1,1,0), hname(1024), iname(1024);\n      const char *const ext = cimg::split_filename(filename);\n      short datatype = -1;\n      if (!*ext) {\n        cimg_snprintf(hname,hname._width,\"%s.hdr\",filename);\n        cimg_snprintf(iname,iname._width,\"%s.img\",filename);\n      }\n      if (!cimg::strncasecmp(ext,\"hdr\",3)) {\n        std::strcpy(hname,filename);\n        std::strncpy(iname,filename,iname._width - 1);\n        cimg_sprintf(iname._data + std::strlen(iname) - 3,\"img\");\n      }\n      if (!cimg::strncasecmp(ext,\"img\",3)) {\n        std::strcpy(hname,filename);\n        std::strncpy(iname,filename,iname._width - 1);\n        cimg_sprintf(hname._data + std::strlen(iname) - 3,\"hdr\");\n      }\n      if (!cimg::strncasecmp(ext,\"nii\",3)) {\n        std::strncpy(hname,filename,hname._width - 1); *iname = 0;\n      }\n      int *const iheader = (int*)header._data;\n      *iheader = 348;\n      std::strcpy(header._data + 4,\"CImg\");\n      std::strcpy(header._data + 14,\" \");\n      ((short*)&(header[36]))[0] = 4096;\n      ((char*)&(header[38]))[0] = 114;\n      ((short*)&(header[40]))[0] = 4;\n      ((short*)&(header[40]))[1] = (short)_width;\n      ((short*)&(header[40]))[2] = (short)_height;\n      ((short*)&(header[40]))[3] = (short)_depth;\n      ((short*)&(header[40]))[4] = (short)_spectrum;\n      if (!cimg::strcasecmp(pixel_type(),\"bool\")) datatype = 2;\n      if (!cimg::strcasecmp(pixel_type(),\"unsigned char\")) datatype = 2;\n      if (!cimg::strcasecmp(pixel_type(),\"char\")) datatype = 2;\n      if (!cimg::strcasecmp(pixel_type(),\"unsigned short\")) datatype = 4;\n      if (!cimg::strcasecmp(pixel_type(),\"short\")) datatype = 4;\n      if (!cimg::strcasecmp(pixel_type(),\"unsigned int\")) datatype = 8;\n      if (!cimg::strcasecmp(pixel_type(),\"int\")) datatype = 8;\n      if (!cimg::strcasecmp(pixel_type(),\"unsigned int64\")) datatype = 8;\n      if (!cimg::strcasecmp(pixel_type(),\"int64\")) datatype = 8;\n      if (!cimg::strcasecmp(pixel_type(),\"float\")) datatype = 16;\n      if (!cimg::strcasecmp(pixel_type(),\"double\")) datatype = 64;\n      if (datatype<0)\n        throw CImgIOException(_cimg_instance\n                              \"save_analyze(): Unsupported pixel type '%s' for file '%s'.\",\n                              cimg_instance,\n                              pixel_type(),filename);\n\n      ((short*)&(header[70]))[0] = datatype;\n      ((short*)&(header[72]))[0] = sizeof(T);\n      ((float*)&(header[112]))[0] = 1;\n      ((float*)&(header[76]))[0] = 0;\n      if (voxel_size) {\n        ((float*)&(header[76]))[1] = voxel_size[0];\n        ((float*)&(header[76]))[2] = voxel_size[1];\n        ((float*)&(header[76]))[3] = voxel_size[2];\n      } else ((float*)&(header[76]))[1] = ((float*)&(header[76]))[2] = ((float*)&(header[76]))[3] = 1;\n      file = cimg::fopen(hname,\"wb\");\n      cimg::fwrite(header._data,348,file);\n      if (*iname) { cimg::fclose(file); file = cimg::fopen(iname,\"wb\"); }\n      cimg::fwrite(_data,size(),file);\n      cimg::fclose(file);\n      return *this;\n    }\n\n    //! Save image as a .cimg file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param is_compressed Tells if the file contains compressed image data.\n    **/\n    const CImg<T>& save_cimg(const char *const filename, const bool is_compressed=false) const {\n      CImgList<T>(*this,true).save_cimg(filename,is_compressed);\n      return *this;\n    }\n\n    //! Save image as a .cimg file \\overloading.\n    const CImg<T>& save_cimg(std::FILE *const file, const bool is_compressed=false) const {\n      CImgList<T>(*this,true).save_cimg(file,is_compressed);\n      return *this;\n    }\n\n    //! Save image as a sub-image into an existing .cimg file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param n0 Index of the image inside the file.\n      \\param x0 X-coordinate of the sub-image location.\n      \\param y0 Y-coordinate of the sub-image location.\n      \\param z0 Z-coordinate of the sub-image location.\n      \\param c0 C-coordinate of the sub-image location.\n    **/\n    const CImg<T>& save_cimg(const char *const filename,\n                             const unsigned int n0,\n                             const unsigned int x0, const unsigned int y0,\n                             const unsigned int z0, const unsigned int c0) const {\n      CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,c0);\n      return *this;\n    }\n\n    //! Save image as a sub-image into an existing .cimg file \\overloading.\n    const CImg<T>& save_cimg(std::FILE *const file,\n                             const unsigned int n0,\n                             const unsigned int x0, const unsigned int y0,\n                             const unsigned int z0, const unsigned int c0) const {\n      CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,c0);\n      return *this;\n    }\n\n    //! Save blank image as a .cimg file.\n    /**\n        \\param filename Filename, as a C-string.\n        \\param dx Width of the image.\n        \\param dy Height of the image.\n        \\param dz Depth of the image.\n        \\param dc Number of channels of the image.\n        \\note\n        - All pixel values of the saved image are set to \\c 0.\n        - Use this method to save large images without having to instanciate and allocate them.\n    **/\n    static void save_empty_cimg(const char *const filename,\n                                const unsigned int dx, const unsigned int dy=1,\n                                const unsigned int dz=1, const unsigned int dc=1) {\n      return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dc);\n    }\n\n    //! Save blank image as a .cimg file \\overloading.\n    /**\n       Same as save_empty_cimg(const char *,unsigned int,unsigned int,unsigned int,unsigned int)\n       with a file stream argument instead of a filename string.\n    **/\n    static void save_empty_cimg(std::FILE *const file,\n                                const unsigned int dx, const unsigned int dy=1,\n                                const unsigned int dz=1, const unsigned int dc=1) {\n      return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dc);\n    }\n\n    //! Save image as an INRIMAGE-4 file.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param voxel_size Pointer to 3 values specifying the voxel sizes along the X,Y and Z dimensions.\n    **/\n    const CImg<T>& save_inr(const char *const filename, const float *const voxel_size=0) const {\n      return _save_inr(0,filename,voxel_size);\n    }\n\n    //! Save image as an INRIMAGE-4 file \\overloading.\n    const CImg<T>& save_inr(std::FILE *const file, const float *const voxel_size=0) const {\n      return _save_inr(file,0,voxel_size);\n    }\n\n    const CImg<T>& _save_inr(std::FILE *const file, const char *const filename, const float *const voxel_size) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_inr(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n\n      int inrpixsize = -1;\n      const char *inrtype = \"unsigned fixed\\nPIXSIZE=8 bits\\nSCALE=2**0\";\n      if (!cimg::strcasecmp(pixel_type(),\"unsigned char\")) {\n        inrtype = \"unsigned fixed\\nPIXSIZE=8 bits\\nSCALE=2**0\"; inrpixsize = 1;\n      }\n      if (!cimg::strcasecmp(pixel_type(),\"char\")) {\n        inrtype = \"fixed\\nPIXSIZE=8 bits\\nSCALE=2**0\"; inrpixsize = 1;\n      }\n      if (!cimg::strcasecmp(pixel_type(),\"unsigned short\")) {\n        inrtype = \"unsigned fixed\\nPIXSIZE=16 bits\\nSCALE=2**0\";inrpixsize = 2;\n      }\n      if (!cimg::strcasecmp(pixel_type(),\"short\")) {\n        inrtype = \"fixed\\nPIXSIZE=16 bits\\nSCALE=2**0\"; inrpixsize = 2;\n      }\n      if (!cimg::strcasecmp(pixel_type(),\"unsigned int\")) {\n        inrtype = \"unsigned fixed\\nPIXSIZE=32 bits\\nSCALE=2**0\";inrpixsize = 4;\n      }\n      if (!cimg::strcasecmp(pixel_type(),\"int\")) {\n        inrtype = \"fixed\\nPIXSIZE=32 bits\\nSCALE=2**0\"; inrpixsize = 4;\n      }\n      if (!cimg::strcasecmp(pixel_type(),\"float\")) {\n        inrtype = \"float\\nPIXSIZE=32 bits\"; inrpixsize = 4;\n      }\n      if (!cimg::strcasecmp(pixel_type(),\"double\")) {\n        inrtype = \"float\\nPIXSIZE=64 bits\"; inrpixsize = 8;\n      }\n      if (inrpixsize<=0)\n        throw CImgIOException(_cimg_instance\n                              \"save_inr(): Unsupported pixel type '%s' for file '%s'\",\n                              cimg_instance,\n                              pixel_type(),filename?filename:\"(FILE*)\");\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      CImg<charT> header(257);\n      int err = cimg_snprintf(header,header._width,\"#INRIMAGE-4#{\\nXDIM=%u\\nYDIM=%u\\nZDIM=%u\\nVDIM=%u\\n\",\n                              _width,_height,_depth,_spectrum);\n      if (voxel_size) err+=cimg_sprintf(header._data + err,\"VX=%g\\nVY=%g\\nVZ=%g\\n\",\n                                        voxel_size[0],voxel_size[1],voxel_size[2]);\n      err+=cimg_sprintf(header._data + err,\"TYPE=%s\\nCPU=%s\\n\",inrtype,cimg::endianness()?\"sun\":\"decm\");\n      std::memset(header._data + err,'\\n',252 - err);\n      std::memcpy(header._data + 252,\"##}\\n\",4);\n      cimg::fwrite(header._data,256,nfile);\n      cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile);\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as an OpenEXR file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\note The OpenEXR file format is <a href=\"http://en.wikipedia.org/wiki/OpenEXR\">described here</a>.\n    **/\n    const CImg<T>& save_exr(const char *const filename) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_exr(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_exr(): Instance is volumetric, only the first slice will be saved in file '%s'.\",\n                   cimg_instance,\n                   filename);\n\n#ifndef cimg_use_openexr\n      return save_other(filename);\n#else\n      Imf::Rgba *const ptrd0 = new Imf::Rgba[(size_t)_width*_height], *ptrd = ptrd0, rgba;\n      switch (_spectrum) {\n      case 1 : { // Grayscale image.\n        for (const T *ptr_r = data(), *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_r<ptr_e;) {\n          rgba.r = rgba.g = rgba.b = (half)(*(ptr_r++));\n          rgba.a = (half)1;\n          *(ptrd++) = rgba;\n        }\n      } break;\n      case 2 : { // RG image.\n        for (const T *ptr_r = data(), *ptr_g = data(0,0,0,1),\n               *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_r<ptr_e; ) {\n          rgba.r = (half)(*(ptr_r++));\n          rgba.g = (half)(*(ptr_g++));\n          rgba.b = (half)0;\n          rgba.a = (half)1;\n          *(ptrd++) = rgba;\n        }\n      } break;\n      case 3 : { // RGB image.\n        for (const T *ptr_r = data(), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2),\n               *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_r<ptr_e;) {\n          rgba.r = (half)(*(ptr_r++));\n          rgba.g = (half)(*(ptr_g++));\n          rgba.b = (half)(*(ptr_b++));\n          rgba.a = (half)1;\n          *(ptrd++) = rgba;\n        }\n      } break;\n      default : { // RGBA image.\n        for (const T *ptr_r = data(), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3),\n               *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_r<ptr_e;) {\n          rgba.r = (half)(*(ptr_r++));\n          rgba.g = (half)(*(ptr_g++));\n          rgba.b = (half)(*(ptr_b++));\n          rgba.a = (half)(*(ptr_a++));\n          *(ptrd++) = rgba;\n        }\n      } break;\n      }\n      Imf::RgbaOutputFile outFile(filename,_width,_height,\n                                  _spectrum==1?Imf::WRITE_Y:_spectrum==2?Imf::WRITE_YA:_spectrum==3?\n                                  Imf::WRITE_RGB:Imf::WRITE_RGBA);\n      outFile.setFrameBuffer(ptrd0,1,_width);\n      outFile.writePixels(_height);\n      delete[] ptrd0;\n      return *this;\n#endif\n    }\n\n    //! Save image as a Pandore-5 file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param colorspace Colorspace data field in output file\n       (see <a href=\"http://www.greyc.ensicaen.fr/~regis/Pandore/#documentation\">Pandore file specifications</a>\n       for more information).\n    **/\n    const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const {\n      return _save_pandore(0,filename,colorspace);\n    }\n\n    //! Save image as a Pandore-5 file \\overloading.\n    /**\n        Same as save_pandore(const char *,unsigned int) const\n        with a file stream argument instead of a filename string.\n    **/\n    const CImg<T>& save_pandore(std::FILE *const file, const unsigned int colorspace=0) const {\n      return _save_pandore(file,0,colorspace);\n    }\n\n    unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {\n      unsigned int nbdims = 0;\n      if (id==2 || id==3 || id==4) {\n        dims[0] = 1; dims[1] = _width; nbdims = 2;\n      }\n      if (id==5 || id==6 || id==7) {\n        dims[0] = 1; dims[1] = _height; dims[2] = _width; nbdims=3;\n      }\n      if (id==8 || id==9 || id==10) {\n        dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4;\n      }\n      if (id==16 || id==17 || id==18) {\n        dims[0] = 3; dims[1] = _height; dims[2] = _width; dims[3] = colorspace; nbdims = 4;\n      }\n      if (id==19 || id==20 || id==21) {\n        dims[0] = 3; dims[1] = _depth; dims[2] = _height; dims[3] = _width; dims[4] = colorspace; nbdims = 5;\n      }\n      if (id==22 || id==23 || id==25) {\n        dims[0] = _spectrum; dims[1] = _width; nbdims = 2;\n      }\n      if (id==26 || id==27 || id==29) {\n        dims[0] = _spectrum; dims[1] = _height; dims[2] = _width; nbdims=3;\n      }\n      if (id==30 || id==31 || id==33) {\n        dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4;\n      }\n      return nbdims;\n    }\n\n    const CImg<T>& _save_pandore(std::FILE *const file, const char *const filename,\n                                 const unsigned int colorspace) const {\n\n#define __cimg_save_pandore_case(dtype) \\\n       dtype *buffer = new dtype[size()]; \\\n       const T *ptrs = _data; \\\n       cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \\\n       buffer-=size(); \\\n       cimg::fwrite(buffer,size(),nfile); \\\n       delete[] buffer\n\n#define _cimg_save_pandore_case(sy,sz,sv,stype,id) \\\n      if (!saved && (sy?(sy==_height):true) && (sz?(sz==_depth):true) && \\\n          (sv?(sv==_spectrum):true) && !std::strcmp(stype,pixel_type())) { \\\n        unsigned int *iheader = (unsigned int*)(header + 12); \\\n        nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \\\n        cimg::fwrite(header,36,nfile); \\\n        if (sizeof(unsigned long)==4) { CImg<ulongT> ndims(5); \\\n          for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \\\n        else if (sizeof(unsigned int)==4) { CImg<uintT> ndims(5); \\\n          for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \\\n        else if (sizeof(unsigned short)==4) { CImg<ushortT> ndims(5); \\\n          for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \\\n        else throw CImgIOException(_cimg_instance \\\n                                   \"save_pandore(): Unsupported datatype for file '%s'.\",\\\n                                   cimg_instance, \\\n                                   filename?filename:\"(FILE*)\"); \\\n        if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \\\n          __cimg_save_pandore_case(unsigned char); \\\n        } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \\\n          if (sizeof(unsigned long)==4) { __cimg_save_pandore_case(unsigned long); } \\\n          else if (sizeof(unsigned int)==4) { __cimg_save_pandore_case(unsigned int); } \\\n          else if (sizeof(unsigned short)==4) { __cimg_save_pandore_case(unsigned short); } \\\n          else throw CImgIOException(_cimg_instance \\\n                                     \"save_pandore(): Unsupported datatype for file '%s'.\",\\\n                                     cimg_instance, \\\n                                     filename?filename:\"(FILE*)\"); \\\n        } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \\\n          if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \\\n          else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \\\n          else throw CImgIOException(_cimg_instance \\\n                                     \"save_pandore(): Unsupported datatype for file '%s'.\",\\\n                                     cimg_instance, \\\n                                     filename?filename:\"(FILE*)\"); \\\n        } \\\n        saved = true; \\\n      }\n\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_pandore(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,\n                                   0,0,0,0,'C','I','m','g',0,0,0,0,0,\n                                   'N','o',' ','d','a','t','e',0,0,0,0 };\n      unsigned int nbdims, dims[5] = { 0 };\n      bool saved = false;\n      _cimg_save_pandore_case(1,1,1,\"unsigned char\",2);\n      _cimg_save_pandore_case(1,1,1,\"char\",3);\n      _cimg_save_pandore_case(1,1,1,\"unsigned short\",3);\n      _cimg_save_pandore_case(1,1,1,\"short\",3);\n      _cimg_save_pandore_case(1,1,1,\"unsigned int\",3);\n      _cimg_save_pandore_case(1,1,1,\"int\",3);\n      _cimg_save_pandore_case(1,1,1,\"unsigned int64\",3);\n      _cimg_save_pandore_case(1,1,1,\"int64\",3);\n      _cimg_save_pandore_case(1,1,1,\"float\",4);\n      _cimg_save_pandore_case(1,1,1,\"double\",4);\n\n      _cimg_save_pandore_case(0,1,1,\"unsigned char\",5);\n      _cimg_save_pandore_case(0,1,1,\"char\",6);\n      _cimg_save_pandore_case(0,1,1,\"unsigned short\",6);\n      _cimg_save_pandore_case(0,1,1,\"short\",6);\n      _cimg_save_pandore_case(0,1,1,\"unsigned int\",6);\n      _cimg_save_pandore_case(0,1,1,\"int\",6);\n      _cimg_save_pandore_case(0,1,1,\"unsigned int64\",6);\n      _cimg_save_pandore_case(0,1,1,\"int64\",6);\n      _cimg_save_pandore_case(0,1,1,\"float\",7);\n      _cimg_save_pandore_case(0,1,1,\"double\",7);\n\n      _cimg_save_pandore_case(0,0,1,\"unsigned char\",8);\n      _cimg_save_pandore_case(0,0,1,\"char\",9);\n      _cimg_save_pandore_case(0,0,1,\"unsigned short\",9);\n      _cimg_save_pandore_case(0,0,1,\"short\",9);\n      _cimg_save_pandore_case(0,0,1,\"unsigned int\",9);\n      _cimg_save_pandore_case(0,0,1,\"int\",9);\n      _cimg_save_pandore_case(0,0,1,\"unsigned int64\",9);\n      _cimg_save_pandore_case(0,0,1,\"int64\",9);\n      _cimg_save_pandore_case(0,0,1,\"float\",10);\n      _cimg_save_pandore_case(0,0,1,\"double\",10);\n\n      _cimg_save_pandore_case(0,1,3,\"unsigned char\",16);\n      _cimg_save_pandore_case(0,1,3,\"char\",17);\n      _cimg_save_pandore_case(0,1,3,\"unsigned short\",17);\n      _cimg_save_pandore_case(0,1,3,\"short\",17);\n      _cimg_save_pandore_case(0,1,3,\"unsigned int\",17);\n      _cimg_save_pandore_case(0,1,3,\"int\",17);\n      _cimg_save_pandore_case(0,1,3,\"unsigned int64\",17);\n      _cimg_save_pandore_case(0,1,3,\"int64\",17);\n      _cimg_save_pandore_case(0,1,3,\"float\",18);\n      _cimg_save_pandore_case(0,1,3,\"double\",18);\n\n      _cimg_save_pandore_case(0,0,3,\"unsigned char\",19);\n      _cimg_save_pandore_case(0,0,3,\"char\",20);\n      _cimg_save_pandore_case(0,0,3,\"unsigned short\",20);\n      _cimg_save_pandore_case(0,0,3,\"short\",20);\n      _cimg_save_pandore_case(0,0,3,\"unsigned int\",20);\n      _cimg_save_pandore_case(0,0,3,\"int\",20);\n      _cimg_save_pandore_case(0,0,3,\"unsigned int64\",20);\n      _cimg_save_pandore_case(0,0,3,\"int64\",20);\n      _cimg_save_pandore_case(0,0,3,\"float\",21);\n      _cimg_save_pandore_case(0,0,3,\"double\",21);\n\n      _cimg_save_pandore_case(1,1,0,\"unsigned char\",22);\n      _cimg_save_pandore_case(1,1,0,\"char\",23);\n      _cimg_save_pandore_case(1,1,0,\"unsigned short\",23);\n      _cimg_save_pandore_case(1,1,0,\"short\",23);\n      _cimg_save_pandore_case(1,1,0,\"unsigned int\",23);\n      _cimg_save_pandore_case(1,1,0,\"int\",23);\n      _cimg_save_pandore_case(1,1,0,\"unsigned int64\",23);\n      _cimg_save_pandore_case(1,1,0,\"int64\",23);\n      _cimg_save_pandore_case(1,1,0,\"float\",25);\n      _cimg_save_pandore_case(1,1,0,\"double\",25);\n\n      _cimg_save_pandore_case(0,1,0,\"unsigned char\",26);\n      _cimg_save_pandore_case(0,1,0,\"char\",27);\n      _cimg_save_pandore_case(0,1,0,\"unsigned short\",27);\n      _cimg_save_pandore_case(0,1,0,\"short\",27);\n      _cimg_save_pandore_case(0,1,0,\"unsigned int\",27);\n      _cimg_save_pandore_case(0,1,0,\"int\",27);\n      _cimg_save_pandore_case(0,1,0,\"unsigned int64\",27);\n      _cimg_save_pandore_case(0,1,0,\"int64\",27);\n      _cimg_save_pandore_case(0,1,0,\"float\",29);\n      _cimg_save_pandore_case(0,1,0,\"double\",29);\n\n      _cimg_save_pandore_case(0,0,0,\"unsigned char\",30);\n      _cimg_save_pandore_case(0,0,0,\"char\",31);\n      _cimg_save_pandore_case(0,0,0,\"unsigned short\",31);\n      _cimg_save_pandore_case(0,0,0,\"short\",31);\n      _cimg_save_pandore_case(0,0,0,\"unsigned int\",31);\n      _cimg_save_pandore_case(0,0,0,\"int\",31);\n      _cimg_save_pandore_case(0,0,0,\"unsigned int64\",31);\n      _cimg_save_pandore_case(0,0,0,\"int64\",31);\n      _cimg_save_pandore_case(0,0,0,\"float\",33);\n      _cimg_save_pandore_case(0,0,0,\"double\",33);\n\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as a raw data file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param is_multiplexed Tells if the image channels are stored in a multiplexed way (\\c true) or not (\\c false).\n       \\note The .raw format does not store the image dimensions in the output file,\n       so you have to keep track of them somewhere to be able to read the file correctly afterwards.\n    **/\n    const CImg<T>& save_raw(const char *const filename, const bool is_multiplexed=false) const {\n      return _save_raw(0,filename,is_multiplexed);\n    }\n\n    //! Save image as a raw data file \\overloading.\n    /**\n       Same as save_raw(const char *,bool) const\n       with a file stream argument instead of a filename string.\n    **/\n    const CImg<T>& save_raw(std::FILE *const file, const bool is_multiplexed=false) const {\n      return _save_raw(file,0,is_multiplexed);\n    }\n\n    const CImg<T>& _save_raw(std::FILE *const file, const char *const filename, const bool is_multiplexed) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_raw(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      if (!is_multiplexed) cimg::fwrite(_data,size(),nfile);\n      else {\n        CImg<T> buf(_spectrum);\n        cimg_forXYZ(*this,x,y,z) {\n          cimg_forC(*this,c) buf[c] = (*this)(x,y,z,c);\n          cimg::fwrite(buf._data,_spectrum,nfile);\n        }\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save image as a .yuv video file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param is_rgb Tells if pixel values of the instance image are RGB-coded (\\c true) or YUV-coded (\\c false).\n       \\note Each slice of the instance image is considered to be a single frame of the output video file.\n    **/\n    const CImg<T>& save_yuv(const char *const filename, const bool is_rgb=true) const {\n      get_split('z').save_yuv(filename,is_rgb);\n      return *this;\n    }\n\n    //! Save image as a .yuv video file \\overloading.\n    /**\n       Same as save_yuv(const char*,bool) const\n       with a file stream argument instead of a filename string.\n    **/\n    const CImg<T>& save_yuv(std::FILE *const file, const bool is_rgb=true) const {\n      get_split('z').save_yuv(file,is_rgb);\n      return *this;\n    }\n\n    //! Save 3d object as an Object File Format (.off) file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param primitives List of 3d object primitives.\n       \\param colors List of 3d object colors.\n       \\note\n       - Instance image contains the vertices data of the 3d object.\n       - Textured, transparent or sphere-shaped primitives cannot be managed by the .off file format.\n       Such primitives will be lost or simplified during file saving.\n       - The .off file format is <a href=\"http://people.sc.fsu.edu/~jburkardt/html/off_format.html\">described here</a>.\n    **/\n    template<typename tf, typename tc>\n    const CImg<T>& save_off(const CImgList<tf>& primitives, const CImgList<tc>& colors,\n                            const char *const filename) const {\n      return _save_off(primitives,colors,0,filename);\n    }\n\n    //! Save 3d object as an Object File Format (.off) file \\overloading.\n    /**\n       Same as save_off(const CImgList<tf>&,const CImgList<tc>&,const char*) const\n       with a file stream argument instead of a filename string.\n    **/\n    template<typename tf, typename tc>\n    const CImg<T>& save_off(const CImgList<tf>& primitives, const CImgList<tc>& colors,\n                            std::FILE *const file) const {\n      return _save_off(primitives,colors,file,0);\n    }\n\n    template<typename tf, typename tc>\n    const CImg<T>& _save_off(const CImgList<tf>& primitives, const CImgList<tc>& colors,\n                             std::FILE *const file, const char *const filename) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_off(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty())\n        throw CImgInstanceException(_cimg_instance\n                                    \"save_off(): Empty instance, for file '%s'.\",\n                                    cimg_instance,\n                                    filename?filename:\"(FILE*)\");\n\n      CImgList<T> opacities;\n      CImg<charT> error_message(1024);\n      if (!is_object3d(primitives,colors,opacities,true,error_message))\n        throw CImgInstanceException(_cimg_instance\n                                    \"save_off(): Invalid specified 3d object, for file '%s' (%s).\",\n                                    cimg_instance,\n                                    filename?filename:\"(FILE*)\",error_message.data());\n\n      const CImg<tc> default_color(1,3,1,1,200);\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"w\");\n      unsigned int supported_primitives = 0;\n      cimglist_for(primitives,l) if (primitives[l].size()!=5) ++supported_primitives;\n      std::fprintf(nfile,\"OFF\\n%u %u %u\\n\",_width,supported_primitives,3*primitives._width);\n      cimg_forX(*this,i) std::fprintf(nfile,\"%f %f %f\\n\",\n                                      (float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));\n      cimglist_for(primitives,l) {\n        const CImg<tc>& color = l<colors.width()?colors[l]:default_color;\n        const unsigned int psiz = primitives[l].size(), csiz = color.size();\n        const float r = color[0]/255.0f, g = (csiz>1?color[1]:r)/255.0f, b = (csiz>2?color[2]:g)/255.0f;\n        switch (psiz) {\n        case 1 : std::fprintf(nfile,\"1 %u %f %f %f\\n\",\n                              (unsigned int)primitives(l,0),r,g,b); break;\n        case 2 : std::fprintf(nfile,\"2 %u %u %f %f %f\\n\",\n                              (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break;\n        case 3 : std::fprintf(nfile,\"3 %u %u %u %f %f %f\\n\",\n                              (unsigned int)primitives(l,0),(unsigned int)primitives(l,2),\n                              (unsigned int)primitives(l,1),r,g,b); break;\n        case 4 : std::fprintf(nfile,\"4 %u %u %u %u %f %f %f\\n\",\n                              (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),\n                              (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b); break;\n        case 5 : std::fprintf(nfile,\"2 %u %u %f %f %f\\n\",\n                              (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break;\n        case 6 : {\n          const unsigned int xt = (unsigned int)primitives(l,2), yt = (unsigned int)primitives(l,3);\n          const float\n            rt = color.atXY(xt,yt,0)/255.0f,\n            gt = (csiz>1?color.atXY(xt,yt,1):r)/255.0f,\n            bt = (csiz>2?color.atXY(xt,yt,2):g)/255.0f;\n          std::fprintf(nfile,\"2 %u %u %f %f %f\\n\",\n                       (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),rt,gt,bt);\n        } break;\n        case 9 : {\n          const unsigned int xt = (unsigned int)primitives(l,3), yt = (unsigned int)primitives(l,4);\n          const float\n            rt = color.atXY(xt,yt,0)/255.0f,\n            gt = (csiz>1?color.atXY(xt,yt,1):r)/255.0f,\n            bt = (csiz>2?color.atXY(xt,yt,2):g)/255.0f;\n          std::fprintf(nfile,\"3 %u %u %u %f %f %f\\n\",\n                       (unsigned int)primitives(l,0),(unsigned int)primitives(l,2),\n                       (unsigned int)primitives(l,1),rt,gt,bt);\n        } break;\n        case 12 : {\n          const unsigned int xt = (unsigned int)primitives(l,4), yt = (unsigned int)primitives(l,5);\n          const float\n            rt = color.atXY(xt,yt,0)/255.0f,\n            gt = (csiz>1?color.atXY(xt,yt,1):r)/255.0f,\n            bt = (csiz>2?color.atXY(xt,yt,2):g)/255.0f;\n          std::fprintf(nfile,\"4 %u %u %u %u %f %f %f\\n\",\n                       (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),\n                       (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),rt,gt,bt);\n        } break;\n        }\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save volumetric image as a video, using the OpenCV library.\n    /**\n      \\param filename Filename to write data to.\n      \\param fps Number of frames per second.\n      \\param codec Type of compression (See http://www.fourcc.org/codecs.php to see available codecs).\n      \\param keep_open Tells if the video writer associated to the specified filename\n        must be kept open or not (to allow frames to be added in the same file afterwards).\n    **/\n    const CImg<T>& save_video(const char *const filename, const unsigned int fps=25,\n                              const char *codec=0, const bool keep_open=false) const {\n      if (is_empty()) { CImgList<T>().save_video(filename,fps,codec,keep_open); return *this; }\n      CImgList<T> list;\n      get_split('z').move_to(list);\n      list.save_video(filename,fps,codec,keep_open);\n      return *this;\n    }\n\n    //! Save volumetric image as a video, using ffmpeg external binary.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param fps Video framerate.\n       \\param codec Video codec, as a C-string.\n       \\param bitrate Video bitrate.\n       \\note\n       - Each slice of the instance image is considered to be a single frame of the output video file.\n       - This method uses \\c ffmpeg, an external executable binary provided by\n         <a href=\"http://www.ffmpeg.org\">FFmpeg</a>.\n       It must be installed for the method to succeed.\n    **/\n    const CImg<T>& save_ffmpeg_external(const char *const filename, const unsigned int fps=25,\n                                        const char *const codec=0, const unsigned int bitrate=2048) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_ffmpeg_external(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n\n      CImgList<T> list;\n      get_split('z').move_to(list);\n      list.save_ffmpeg_external(filename,fps,codec,bitrate);\n      return *this;\n    }\n\n    //! Save image using gzip external binary.\n    /**\n       \\param filename Filename, as a C-string.\n       \\note This method uses \\c gzip, an external executable binary provided by\n         <a href=\"//http://www.gzip.org\">gzip</a>.\n       It must be installed for the method to succeed.\n    **/\n    const CImg<T>& save_gzip_external(const char *const filename) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_gzip_external(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n\n      CImg<charT> command(1024), filename_tmp(256), body(256);\n      const char\n        *ext = cimg::split_filename(filename,body),\n        *ext2 = cimg::split_filename(body,0);\n      std::FILE *file;\n      do {\n        if (!cimg::strcasecmp(ext,\"gz\")) {\n          if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",\n                                   cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);\n          else cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.cimg\",\n                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        } else {\n          if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",\n                                  cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);\n          else cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.cimg\",\n                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        }\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      save(filename_tmp);\n      cimg_snprintf(command,command._width,\"%s -c \\\"%s\\\" > \\\"%s\\\"\",\n                    cimg::gzip_path(),\n                    CImg<charT>::string(filename_tmp)._system_strescape().data(),\n                    CImg<charT>::string(filename)._system_strescape().data());\n      cimg::system(command);\n      file = std::fopen(filename,\"rb\");\n      if (!file)\n        throw CImgIOException(_cimg_instance\n                              \"save_gzip_external(): Failed to save file '%s' with external command 'gzip'.\",\n                              cimg_instance,\n                              filename);\n\n      else cimg::fclose(file);\n      std::remove(filename_tmp);\n      return *this;\n    }\n\n    //! Save image using GraphicsMagick's external binary.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param quality Image quality (expressed in percent), when the file format supports it.\n       \\note This method uses \\c gm, an external executable binary provided by\n         <a href=\"http://www.graphicsmagick.org\">GraphicsMagick</a>.\n       It must be installed for the method to succeed.\n    **/\n    const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_graphicsmagick_external(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_other(): File '%s', saving a volumetric image with an external call to \"\n                   \"GraphicsMagick only writes the first image slice.\",\n                   cimg_instance,filename);\n\n#ifdef cimg_use_png\n#define _cimg_sge_ext1 \"png\"\n#define _cimg_sge_ext2 \"png\"\n#else\n#define _cimg_sge_ext1 \"pgm\"\n#define _cimg_sge_ext2 \"ppm\"\n#endif\n      CImg<charT> command(1024), filename_tmp(256);\n      std::FILE *file;\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",\n                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),\n                      _spectrum==1?_cimg_sge_ext1:_cimg_sge_ext2);\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n#ifdef cimg_use_png\n      save_png(filename_tmp);\n#else\n      save_pnm(filename_tmp);\n#endif\n      cimg_snprintf(command,command._width,\"%s convert -quality %u \\\"%s\\\" \\\"%s\\\"\",\n                    cimg::graphicsmagick_path(),quality,\n                    CImg<charT>::string(filename_tmp)._system_strescape().data(),\n                    CImg<charT>::string(filename)._system_strescape().data());\n      cimg::system(command);\n      file = std::fopen(filename,\"rb\");\n      if (!file)\n        throw CImgIOException(_cimg_instance\n                              \"save_graphicsmagick_external(): Failed to save file '%s' with external command 'gm'.\",\n                              cimg_instance,\n                              filename);\n\n      if (file) cimg::fclose(file);\n      std::remove(filename_tmp);\n      return *this;\n    }\n\n    //! Save image using ImageMagick's external binary.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param quality Image quality (expressed in percent), when the file format supports it.\n       \\note This method uses \\c convert, an external executable binary provided by\n       <a href=\"http://www.imagemagick.org\">ImageMagick</a>.\n       It must be installed for the method to succeed.\n    **/\n    const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_imagemagick_external(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_other(): File '%s', saving a volumetric image with an external call to \"\n                   \"ImageMagick only writes the first image slice.\",\n                   cimg_instance,filename);\n#ifdef cimg_use_png\n#define _cimg_sie_ext1 \"png\"\n#define _cimg_sie_ext2 \"png\"\n#else\n#define _cimg_sie_ext1 \"pgm\"\n#define _cimg_sie_ext2 \"ppm\"\n#endif\n      CImg<charT> command(1024), filename_tmp(256);\n      std::FILE *file;\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",cimg::temporary_path(),\n                      cimg_file_separator,cimg::filenamerand(),_spectrum==1?_cimg_sie_ext1:_cimg_sie_ext2);\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n#ifdef cimg_use_png\n      save_png(filename_tmp);\n#else\n      save_pnm(filename_tmp);\n#endif\n      cimg_snprintf(command,command._width,\"%s -quality %u \\\"%s\\\" \\\"%s\\\"\",\n                    cimg::imagemagick_path(),quality,\n                    CImg<charT>::string(filename_tmp)._system_strescape().data(),\n                    CImg<charT>::string(filename)._system_strescape().data());\n      cimg::system(command);\n      file = std::fopen(filename,\"rb\");\n      if (!file)\n        throw CImgIOException(_cimg_instance\n                              \"save_imagemagick_external(): Failed to save file '%s' with external command 'convert'.\",\n                              cimg_instance,\n                              filename);\n\n      if (file) cimg::fclose(file);\n      std::remove(filename_tmp);\n      return *this;\n    }\n\n    //! Save image as a Dicom file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\note This method uses \\c medcon, an external executable binary provided by\n         <a href=\"http://xmedcon.sourceforge.net\">(X)Medcon</a>.\n       It must be installed for the method to succeed.\n    **/\n    const CImg<T>& save_medcon_external(const char *const filename) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_medcon_external(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n\n      CImg<charT> command(1024), filename_tmp(256), body(256);\n      std::FILE *file;\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s.hdr\",cimg::filenamerand());\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      save_analyze(filename_tmp);\n      cimg_snprintf(command,command._width,\"%s -w -c dicom -o \\\"%s\\\" -f \\\"%s\\\"\",\n                    cimg::medcon_path(),\n                    CImg<charT>::string(filename)._system_strescape().data(),\n                    CImg<charT>::string(filename_tmp)._system_strescape().data());\n      cimg::system(command);\n      std::remove(filename_tmp);\n      cimg::split_filename(filename_tmp,body);\n      cimg_snprintf(filename_tmp,filename_tmp._width,\"%s.img\",body._data);\n      std::remove(filename_tmp);\n\n      file = std::fopen(filename,\"rb\");\n      if (!file) {\n        cimg_snprintf(command,command._width,\"m000-%s\",filename);\n        file = std::fopen(command,\"rb\");\n        if (!file) {\n          cimg::fclose(cimg::fopen(filename,\"r\"));\n          throw CImgIOException(_cimg_instance\n                                \"save_medcon_external(): Failed to save file '%s' with external command 'medcon'.\",\n                                cimg_instance,\n                                filename);\n        }\n      }\n      cimg::fclose(file);\n      std::rename(command,filename);\n      return *this;\n    }\n\n    // Save image for non natively supported formats.\n    /**\n       \\param filename Filename, as a C-string.\n       \\param quality Image quality (expressed in percent), when the file format supports it.\n       \\note\n       - The filename extension tells about the desired file format.\n       - This method tries to save the instance image as a file, using external tools from\n       <a href=\"http://www.imagemagick.org\">ImageMagick</a> or\n       <a href=\"http://www.graphicsmagick.org\">GraphicsMagick</a>.\n         At least one of these tool must be installed for the method to succeed.\n       - It is recommended to use the generic method save(const char*, int) const instead,\n         as it can handle some file formats natively.\n    **/\n    const CImg<T>& save_other(const char *const filename, const unsigned int quality=100) const {\n      if (!filename)\n        throw CImgArgumentException(_cimg_instance\n                                    \"save_other(): Specified filename is (null).\",\n                                    cimg_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n      if (_depth>1)\n        cimg::warn(_cimg_instance\n                   \"save_other(): File '%s', saving a volumetric image with an external call to \"\n                   \"ImageMagick or GraphicsMagick only writes the first image slice.\",\n                   cimg_instance,filename);\n\n      const unsigned int omode = cimg::exception_mode();\n      bool is_saved = true;\n      cimg::exception_mode(0);\n      try { save_magick(filename); }\n      catch (CImgException&) {\n        try { save_imagemagick_external(filename,quality); }\n        catch (CImgException&) {\n          try { save_graphicsmagick_external(filename,quality); }\n          catch (CImgException&) {\n            is_saved = false;\n          }\n        }\n      }\n      cimg::exception_mode(omode);\n      if (!is_saved)\n        throw CImgIOException(_cimg_instance\n                              \"save_other(): Failed to save file '%s'. Format is not natively supported, \"\n                              \"and no external commands succeeded.\",\n                              cimg_instance,\n                              filename);\n      return *this;\n    }\n\n    //! Serialize a CImg<T> instance into a raw CImg<unsigned char> buffer.\n    /**\n       \\param is_compressed tells if zlib compression must be used for serialization\n       (this requires 'cimg_use_zlib' been enabled).\n    **/\n    CImg<ucharT> get_serialize(const bool is_compressed=false) const {\n      return CImgList<T>(*this,true).get_serialize(is_compressed);\n    }\n\n    // [internal] Return a 40x38 color logo of a 'danger' item.\n    static CImg<T> _logo40x38() {\n      CImg<T> res(40,38,1,3);\n      const unsigned char *ptrs = cimg::logo40x38;\n      T *ptr1 = res.data(0,0,0,0), *ptr2 = res.data(0,0,0,1), *ptr3 = res.data(0,0,0,2);\n      for (ulongT off = 0; off<(ulongT)res._width*res._height;) {\n        const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);\n        for (unsigned int l = 0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }\n      }\n      return res;\n    }\n\n    //@}\n  };\n\n  /*\n   #-----------------------------------------\n   #\n   #\n   #\n   # Definition of the CImgList<T> structure\n   #\n   #\n   #\n   #------------------------------------------\n   */\n  //! Represent a list of images CImg<T>.\n  template<typename T>\n  struct CImgList {\n    unsigned int _width, _allocated_width;\n    CImg<T> *_data;\n\n    //! Simple iterator type, to loop through each image of a list.\n    /**\n       \\note\n       - The \\c CImgList<T>::iterator type is defined as a <tt>CImg<T>*</tt>.\n       - You may use it like this:\n       \\code\n       CImgList<> list;   // Assuming this image list is not empty.\n       for (CImgList<>::iterator it = list.begin(); it<list.end(); ++it) (*it).mirror('x');\n       \\endcode\n       - Using the loop macro \\c cimglist_for is another (more concise) alternative:\n       \\code\n       cimglist_for(list,l) list[l].mirror('x');\n       \\endcode\n    **/\n    typedef CImg<T>* iterator;\n\n    //! Simple const iterator type, to loop through each image of a \\c const list instance.\n    /**\n       \\note\n       - The \\c CImgList<T>::const_iterator type is defined to be a <tt>const CImg<T>*</tt>.\n       - Similar to CImgList<T>::iterator, but for constant list instances.\n    **/\n    typedef const CImg<T>* const_iterator;\n\n    //! Pixel value type.\n    /**\n       Refer to the pixels value type of the images in the list.\n       \\note\n       - The \\c CImgList<T>::value_type type of a \\c CImgList<T> is defined to be a \\c T.\n         It is then similar to CImg<T>::value_type.\n       - \\c CImgList<T>::value_type is actually not used in %CImg methods. It has been mainly defined for\n         compatibility with STL naming conventions.\n    **/\n    typedef T value_type;\n\n    // Define common types related to template type T.\n    typedef typename cimg::superset<T,bool>::type Tbool;\n    typedef typename cimg::superset<T,unsigned char>::type Tuchar;\n    typedef typename cimg::superset<T,char>::type Tchar;\n    typedef typename cimg::superset<T,unsigned short>::type Tushort;\n    typedef typename cimg::superset<T,short>::type Tshort;\n    typedef typename cimg::superset<T,unsigned int>::type Tuint;\n    typedef typename cimg::superset<T,int>::type Tint;\n    typedef typename cimg::superset<T,cimg_ulong>::type Tulong;\n    typedef typename cimg::superset<T,cimg_long>::type Tlong;\n    typedef typename cimg::superset<T,float>::type Tfloat;\n    typedef typename cimg::superset<T,double>::type Tdouble;\n    typedef typename cimg::last<T,bool>::type boolT;\n    typedef typename cimg::last<T,unsigned char>::type ucharT;\n    typedef typename cimg::last<T,char>::type charT;\n    typedef typename cimg::last<T,unsigned short>::type ushortT;\n    typedef typename cimg::last<T,short>::type shortT;\n    typedef typename cimg::last<T,unsigned int>::type uintT;\n    typedef typename cimg::last<T,int>::type intT;\n    typedef typename cimg::last<T,cimg_ulong>::type ulongT;\n    typedef typename cimg::last<T,cimg_long>::type longT;\n    typedef typename cimg::last<T,cimg_uint64>::type uint64T;\n    typedef typename cimg::last<T,cimg_int64>::type int64T;\n    typedef typename cimg::last<T,float>::type floatT;\n    typedef typename cimg::last<T,double>::type doubleT;\n\n    //@}\n    //---------------------------\n    //\n    //! \\name Plugins\n    //@{\n    //---------------------------\n#ifdef cimglist_plugin\n#include cimglist_plugin\n#endif\n#ifdef cimglist_plugin1\n#include cimglist_plugin1\n#endif\n#ifdef cimglist_plugin2\n#include cimglist_plugin2\n#endif\n#ifdef cimglist_plugin3\n#include cimglist_plugin3\n#endif\n#ifdef cimglist_plugin4\n#include cimglist_plugin4\n#endif\n#ifdef cimglist_plugin5\n#include cimglist_plugin5\n#endif\n#ifdef cimglist_plugin6\n#include cimglist_plugin6\n#endif\n#ifdef cimglist_plugin7\n#include cimglist_plugin7\n#endif\n#ifdef cimglist_plugin8\n#include cimglist_plugin8\n#endif\n\n    //@}\n    //--------------------------------------------------------\n    //\n    //! \\name Constructors / Destructor / Instance Management\n    //@{\n    //--------------------------------------------------------\n\n    //! Destructor.\n    /**\n       Destroy current list instance.\n       \\note\n       - Any allocated buffer is deallocated.\n       - Destroying an empty list does nothing actually.\n     **/\n    ~CImgList() {\n      delete[] _data;\n    }\n\n    //! Default constructor.\n    /**\n       Construct a new empty list instance.\n       \\note\n       - An empty list has no pixel data and its dimension width() is set to \\c 0, as well as its\n         image buffer pointer data().\n       - An empty list may be reassigned afterwards, with the family of the assign() methods.\n         In all cases, the type of pixels stays \\c T.\n     **/\n    CImgList():\n      _width(0),_allocated_width(0),_data(0) {}\n\n    //! Construct list containing empty images.\n    /**\n       \\param n Number of empty images.\n       \\note Useful when you know by advance the number of images you want to manage, as\n       it will allocate the right amount of memory for the list, without needs for reallocation\n       (that may occur when starting from an empty list and inserting several images in it).\n    **/\n    explicit CImgList(const unsigned int n):_width(n) {\n      if (n) _data = new CImg<T>[_allocated_width = cimg::max(16UL,cimg::nearest_pow2(n))];\n      else { _allocated_width = 0; _data = 0; }\n    }\n\n    //! Construct list containing images of specified size.\n    /**\n       \\param n Number of images.\n       \\param width Width of images.\n       \\param height Height of images.\n       \\param depth Depth of images.\n       \\param spectrum Number of channels of images.\n       \\note Pixel values are not initialized and may probably contain garbage.\n    **/\n    CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1,\n             const unsigned int depth=1, const unsigned int spectrum=1):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(n);\n      cimglist_apply(*this,assign)(width,height,depth,spectrum);\n    }\n\n    //! Construct list containing images of specified size, and initialize pixel values.\n    /**\n       \\param n Number of images.\n       \\param width Width of images.\n       \\param height Height of images.\n       \\param depth Depth of images.\n       \\param spectrum Number of channels of images.\n       \\param val Initialization value for images pixels.\n    **/\n    CImgList(const unsigned int n, const unsigned int width, const unsigned int height,\n             const unsigned int depth, const unsigned int spectrum, const T& val):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(n);\n      cimglist_apply(*this,assign)(width,height,depth,spectrum,val);\n    }\n\n    //! Construct list containing images of specified size, and initialize pixel values from a sequence of integers.\n    /**\n       \\param n Number of images.\n       \\param width Width of images.\n       \\param height Height of images.\n       \\param depth Depth of images.\n       \\param spectrum Number of channels of images.\n       \\param val0 First value of the initializing integers sequence.\n       \\param val1 Second value of the initializing integers sequence.\n       \\warning You must specify at least <tt>width*height*depth*spectrum</tt> values in your argument list,\n         or you will probably segfault.\n    **/\n    CImgList(const unsigned int n, const unsigned int width, const unsigned int height,\n             const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...):\n      _width(0),_allocated_width(0),_data(0) {\n#define _CImgList_stdarg(t) { \\\n        assign(n,width,height,depth,spectrum); \\\n        const ulongT siz = (ulongT)width*height*depth*spectrum, nsiz = siz*n; \\\n        T *ptrd = _data->_data; \\\n        va_list ap; \\\n        va_start(ap,val1); \\\n        for (ulongT l = 0, s = 0, i = 0; i<nsiz; ++i) { \\\n          *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \\\n          if ((++s)==siz) { ptrd = _data[++l]._data; s = 0; } \\\n        } \\\n        va_end(ap); \\\n      }\n      _CImgList_stdarg(int);\n    }\n\n    //! Construct list containing images of specified size, and initialize pixel values from a sequence of doubles.\n    /**\n       \\param n Number of images.\n       \\param width Width of images.\n       \\param height Height of images.\n       \\param depth Depth of images.\n       \\param spectrum Number of channels of images.\n       \\param val0 First value of the initializing doubles sequence.\n       \\param val1 Second value of the initializing doubles sequence.\n       \\warning You must specify at least <tt>width*height*depth*spectrum</tt> values in your argument list,\n         or you will probably segfault.\n    **/\n    CImgList(const unsigned int n, const unsigned int width, const unsigned int height,\n             const unsigned int depth, const unsigned int spectrum, const double val0, const double val1, ...):\n      _width(0),_allocated_width(0),_data(0) {\n      _CImgList_stdarg(double);\n    }\n\n    //! Construct list containing copies of an input image.\n    /**\n       \\param n Number of images.\n       \\param img Input image to copy in the constructed list.\n       \\param is_shared Tells if the elements of the list are shared or non-shared copies of \\c img.\n    **/\n    template<typename t>\n    CImgList(const unsigned int n, const CImg<t>& img, const bool is_shared=false):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(n);\n      cimglist_apply(*this,assign)(img,is_shared);\n    }\n\n    //! Construct list from one image.\n    /**\n       \\param img Input image to copy in the constructed list.\n       \\param is_shared Tells if the element of the list is a shared or non-shared copy of \\c img.\n     **/\n    template<typename t>\n    explicit CImgList(const CImg<t>& img, const bool is_shared=false):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(1);\n      _data[0].assign(img,is_shared);\n    }\n\n    //! Construct list from two images.\n    /**\n       \\param img1 First input image to copy in the constructed list.\n       \\param img2 Second input image to copy in the constructed list.\n       \\param is_shared Tells if the elements of the list are shared or non-shared copies of input images.\n     **/\n    template<typename t1, typename t2>\n    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool is_shared=false):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(2);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared);\n    }\n\n    //! Construct list from three images.\n    /**\n       \\param img1 First input image to copy in the constructed list.\n       \\param img2 Second input image to copy in the constructed list.\n       \\param img3 Third input image to copy in the constructed list.\n       \\param is_shared Tells if the elements of the list are shared or non-shared copies of input images.\n    **/\n    template<typename t1, typename t2, typename t3>\n    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool is_shared=false):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(3);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n    }\n\n    //! Construct list from four images.\n    /**\n       \\param img1 First input image to copy in the constructed list.\n       \\param img2 Second input image to copy in the constructed list.\n       \\param img3 Third input image to copy in the constructed list.\n       \\param img4 Fourth input image to copy in the constructed list.\n       \\param is_shared Tells if the elements of the list are shared or non-shared copies of input images.\n    **/\n    template<typename t1, typename t2, typename t3, typename t4>\n    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n             const bool is_shared=false):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(4);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared);\n    }\n\n    //! Construct list from five images.\n    /**\n       \\param img1 First input image to copy in the constructed list.\n       \\param img2 Second input image to copy in the constructed list.\n       \\param img3 Third input image to copy in the constructed list.\n       \\param img4 Fourth input image to copy in the constructed list.\n       \\param img5 Fifth input image to copy in the constructed list.\n       \\param is_shared Tells if the elements of the list are shared or non-shared copies of input images.\n    **/\n    template<typename t1, typename t2, typename t3, typename t4, typename t5>\n    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n             const CImg<t5>& img5, const bool is_shared=false):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(5);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared);\n    }\n\n    //! Construct list from six images.\n    /**\n       \\param img1 First input image to copy in the constructed list.\n       \\param img2 Second input image to copy in the constructed list.\n       \\param img3 Third input image to copy in the constructed list.\n       \\param img4 Fourth input image to copy in the constructed list.\n       \\param img5 Fifth input image to copy in the constructed list.\n       \\param img6 Sixth input image to copy in the constructed list.\n       \\param is_shared Tells if the elements of the list are shared or non-shared copies of input images.\n    **/\n    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>\n    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n             const CImg<t5>& img5, const CImg<t6>& img6, const bool is_shared=false):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(6);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared);\n    }\n\n    //! Construct list from seven images.\n    /**\n       \\param img1 First input image to copy in the constructed list.\n       \\param img2 Second input image to copy in the constructed list.\n       \\param img3 Third input image to copy in the constructed list.\n       \\param img4 Fourth input image to copy in the constructed list.\n       \\param img5 Fifth input image to copy in the constructed list.\n       \\param img6 Sixth input image to copy in the constructed list.\n       \\param img7 Seventh input image to copy in the constructed list.\n       \\param is_shared Tells if the elements of the list are shared or non-shared copies of input images.\n    **/\n    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>\n    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool is_shared=false):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(7);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared);\n      _data[6].assign(img7,is_shared);\n    }\n\n    //! Construct list from eight images.\n    /**\n       \\param img1 First input image to copy in the constructed list.\n       \\param img2 Second input image to copy in the constructed list.\n       \\param img3 Third input image to copy in the constructed list.\n       \\param img4 Fourth input image to copy in the constructed list.\n       \\param img5 Fifth input image to copy in the constructed list.\n       \\param img6 Sixth input image to copy in the constructed list.\n       \\param img7 Seventh input image to copy in the constructed list.\n       \\param img8 Eighth input image to copy in the constructed list.\n       \\param is_shared Tells if the elements of the list are shared or non-shared copies of input images.\n    **/\n    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>\n    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8,\n             const bool is_shared=false):\n      _width(0),_allocated_width(0),_data(0) {\n      assign(8);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared);\n      _data[6].assign(img7,is_shared); _data[7].assign(img8,is_shared);\n    }\n\n    //! Construct list copy.\n    /**\n       \\param list Input list to copy.\n       \\note The shared state of each element of the constructed list is kept the same as in \\c list.\n    **/\n    template<typename t>\n    CImgList(const CImgList<t>& list):_width(0),_allocated_width(0),_data(0) {\n      assign(list._width);\n      cimglist_for(*this,l) _data[l].assign(list[l],false);\n    }\n\n    //! Construct list copy \\specialization.\n    CImgList(const CImgList<T>& list):_width(0),_allocated_width(0),_data(0) {\n      assign(list._width);\n      cimglist_for(*this,l) _data[l].assign(list[l],list[l]._is_shared);\n    }\n\n    //! Construct list copy, and force the shared state of the list elements.\n    /**\n       \\param list Input list to copy.\n       \\param is_shared Tells if the elements of the list are shared or non-shared copies of input images.\n    **/\n    template<typename t>\n    CImgList(const CImgList<t>& list, const bool is_shared):_width(0),_allocated_width(0),_data(0) {\n      assign(list._width);\n      cimglist_for(*this,l) _data[l].assign(list[l],is_shared);\n    }\n\n    //! Construct list by reading the content of a file.\n    /**\n       \\param filename Filename, as a C-string.\n    **/\n    explicit CImgList(const char *const filename):_width(0),_allocated_width(0),_data(0) {\n      assign(filename);\n    }\n\n    //! Construct list from the content of a display window.\n    /**\n       \\param disp Display window to get content from.\n       \\note Constructed list contains a single image only.\n    **/\n    explicit CImgList(const CImgDisplay& disp):_width(0),_allocated_width(0),_data(0) {\n      assign(disp);\n    }\n\n    //! Return a list with elements being shared copies of images in the list instance.\n    /**\n      \\note <tt>list2 = list1.get_shared()</tt> is equivalent to <tt>list2.assign(list1,true)</tt>.\n    **/\n    CImgList<T> get_shared() {\n      CImgList<T> res(_width);\n      cimglist_for(*this,l) res[l].assign(_data[l],true);\n      return res;\n    }\n\n    //! Return a list with elements being shared copies of images in the list instance \\const.\n    const CImgList<T> get_shared() const {\n      CImgList<T> res(_width);\n      cimglist_for(*this,l) res[l].assign(_data[l],true);\n      return res;\n    }\n\n    //! Destructor \\inplace.\n    /**\n       \\see CImgList().\n    **/\n    CImgList<T>& assign() {\n      delete[] _data;\n      _width = _allocated_width = 0;\n      _data = 0;\n      return *this;\n    }\n\n    //! Destructor \\inplace.\n    /**\n       Equivalent to assign().\n       \\note Only here for compatibility with STL naming conventions.\n    **/\n    CImgList<T>& clear() {\n      return assign();\n    }\n\n    //! Construct list containing empty images \\inplace.\n    /**\n       \\see CImgList(unsigned int).\n    **/\n    CImgList<T>& assign(const unsigned int n) {\n      if (!n) return assign();\n      if (_allocated_width<n || _allocated_width>(n<<2)) {\n        delete[] _data;\n        _data = new CImg<T>[_allocated_width=cimg::max(16UL,cimg::nearest_pow2(n))];\n      }\n      _width = n;\n      return *this;\n    }\n\n    //! Construct list containing images of specified size \\inplace.\n    /**\n       \\see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int).\n    **/\n    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height=1,\n                        const unsigned int depth=1, const unsigned int spectrum=1) {\n      assign(n);\n      cimglist_apply(*this,assign)(width,height,depth,spectrum);\n      return *this;\n    }\n\n    //! Construct list containing images of specified size, and initialize pixel values \\inplace.\n    /**\n       \\see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, const T).\n    **/\n    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,\n                        const unsigned int depth, const unsigned int spectrum, const T& val) {\n      assign(n);\n      cimglist_apply(*this,assign)(width,height,depth,spectrum,val);\n      return *this;\n    }\n\n    //! Construct list with images of specified size, and initialize pixel values from a sequence of integers \\inplace.\n    /**\n       \\see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, const int, const int, ...).\n    **/\n    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,\n                        const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...) {\n      _CImgList_stdarg(int);\n      return *this;\n    }\n\n    //! Construct list with images of specified size, and initialize pixel values from a sequence of doubles \\inplace.\n    /**\n       \\see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, const double, const double, ...).\n    **/\n    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,\n                        const unsigned int depth, const unsigned int spectrum,\n                        const double val0, const double val1, ...) {\n      _CImgList_stdarg(double);\n      return *this;\n    }\n\n    //! Construct list containing copies of an input image \\inplace.\n    /**\n       \\see CImgList(unsigned int, const CImg<t>&, bool).\n    **/\n    template<typename t>\n    CImgList<T>& assign(const unsigned int n, const CImg<t>& img, const bool is_shared=false) {\n      assign(n);\n      cimglist_apply(*this,assign)(img,is_shared);\n      return *this;\n    }\n\n    //! Construct list from one image \\inplace.\n    /**\n       \\see CImgList(const CImg<t>&, bool).\n    **/\n    template<typename t>\n    CImgList<T>& assign(const CImg<t>& img, const bool is_shared=false) {\n      assign(1);\n      _data[0].assign(img,is_shared);\n      return *this;\n    }\n\n    //! Construct list from two images \\inplace.\n    /**\n       \\see CImgList(const CImg<t>&, const CImg<t>&, bool).\n    **/\n    template<typename t1, typename t2>\n    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool is_shared=false) {\n      assign(2);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared);\n      return *this;\n    }\n\n    //! Construct list from three images \\inplace.\n    /**\n       \\see CImgList(const CImg<t>&, const CImg<t>&, const CImg<t>&, bool).\n    **/\n    template<typename t1, typename t2, typename t3>\n    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool is_shared=false) {\n      assign(3);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      return *this;\n    }\n\n    //! Construct list from four images \\inplace.\n    /**\n       \\see CImgList(const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, bool).\n    **/\n    template<typename t1, typename t2, typename t3, typename t4>\n    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n                        const bool is_shared=false) {\n      assign(4);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared);\n      return *this;\n    }\n\n    //! Construct list from five images \\inplace.\n    /**\n       \\see CImgList(const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, bool).\n    **/\n    template<typename t1, typename t2, typename t3, typename t4, typename t5>\n    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n                        const CImg<t5>& img5, const bool is_shared=false) {\n      assign(5);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared);\n      return *this;\n    }\n\n    //! Construct list from six images \\inplace.\n    /**\n       \\see CImgList(const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, bool).\n    **/\n    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>\n    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n                        const CImg<t5>& img5, const CImg<t6>& img6, const bool is_shared=false) {\n      assign(6);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared);\n      return *this;\n    }\n\n    //! Construct list from seven images \\inplace.\n    /**\n       \\see CImgList(const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, bool).\n    **/\n    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>\n    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n                        const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool is_shared=false) {\n      assign(7);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared);\n      _data[6].assign(img7,is_shared);\n      return *this;\n    }\n\n    //! Construct list from eight images \\inplace.\n    /**\n       \\see CImgList(const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, const CImg<t>&, bool).\n    **/\n    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>\n    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,\n                        const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8,\n                        const bool is_shared=false) {\n      assign(8);\n      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);\n      _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared);\n      _data[6].assign(img7,is_shared); _data[7].assign(img8,is_shared);\n      return *this;\n    }\n\n    //! Construct list as a copy of an existing list and force the shared state of the list elements \\inplace.\n    /**\n      \\see CImgList(const CImgList<t>&, bool is_shared).\n    **/\n    template<typename t>\n    CImgList<T>& assign(const CImgList<t>& list, const bool is_shared=false) {\n      cimg::unused(is_shared);\n      assign(list._width);\n      cimglist_for(*this,l) _data[l].assign(list[l],false);\n      return *this;\n    }\n\n    //! Construct list as a copy of an existing list and force shared state of elements \\inplace \\specialization.\n    CImgList<T>& assign(const CImgList<T>& list, const bool is_shared=false) {\n      if (this==&list) return *this;\n      CImgList<T> res(list._width);\n      cimglist_for(res,l) res[l].assign(list[l],is_shared);\n      return res.move_to(*this);\n    }\n\n    //! Construct list by reading the content of a file \\inplace.\n    /**\n      \\see CImgList(const char *const).\n    **/\n    CImgList<T>& assign(const char *const filename) {\n      return load(filename);\n    }\n\n    //! Construct list from the content of a display window \\inplace.\n    /**\n      \\see CImgList(const CImgDisplay&).\n    **/\n    CImgList<T>& assign(const CImgDisplay &disp) {\n      return assign(CImg<T>(disp));\n    }\n\n    //! Transfer the content of the list instance to another list.\n    /**\n       \\param list Destination list.\n       \\note When returning, the current list instance is empty and the initial content of \\c list is destroyed.\n    **/\n    template<typename t>\n    CImgList<t>& move_to(CImgList<t>& list) {\n      list.assign(_width);\n      bool is_one_shared_element = false;\n      cimglist_for(*this,l) is_one_shared_element|=_data[l]._is_shared;\n      if (is_one_shared_element) cimglist_for(*this,l) list[l].assign(_data[l]);\n      else cimglist_for(*this,l) _data[l].move_to(list[l]);\n      assign();\n      return list;\n    }\n\n    //! Transfer the content of the list instance at a specified position in another list.\n    /**\n       \\param list Destination list.\n       \\param pos Index of the insertion in the list.\n       \\note When returning, the list instance is empty and the initial content of \\c list is preserved\n       (only images indexes may be modified).\n     **/\n    template<typename t>\n    CImgList<t>& move_to(CImgList<t>& list, const unsigned int pos) {\n      if (is_empty()) return list;\n      const unsigned int npos = pos>list._width?list._width:pos;\n      list.insert(_width,npos);\n      bool is_one_shared_element = false;\n      cimglist_for(*this,l) is_one_shared_element|=_data[l]._is_shared;\n      if (is_one_shared_element) cimglist_for(*this,l) list[npos + l].assign(_data[l]);\n      else cimglist_for(*this,l) _data[l].move_to(list[npos + l]);\n      assign();\n      return list;\n    }\n\n    //! Swap all fields between two list instances.\n    /**\n       \\param list List to swap fields with.\n       \\note Can be used to exchange the content of two lists in a fast way.\n    **/\n    CImgList<T>& swap(CImgList<T>& list) {\n      cimg::swap(_width,list._width,_allocated_width,list._allocated_width);\n      cimg::swap(_data,list._data);\n      return list;\n    }\n\n    //! Return a reference to an empty list.\n    /**\n      \\note Can be used to define default values in a function taking a CImgList<T> as an argument.\n      \\code\n      void f(const CImgList<char>& list=CImgList<char>::empty());\n      \\endcode\n    **/\n    static CImgList<T>& empty() {\n      static CImgList<T> _empty;\n      return _empty.assign();\n    }\n\n    //! Return a reference to an empty list \\const.\n    static const CImgList<T>& const_empty() {\n      static const CImgList<T> _empty;\n      return _empty;\n    }\n\n    //@}\n    //------------------------------------------\n    //\n    //! \\name Overloaded Operators\n    //@{\n    //------------------------------------------\n\n    //! Return a reference to one image element of the list.\n    /**\n       \\param pos Indice of the image element.\n    **/\n    CImg<T>& operator()(const unsigned int pos) {\n#if cimg_verbosity>=3\n      if (pos>=_width) {\n        cimg::warn(_cimglist_instance\n                   \"operator(): Invalid image request, at position [%u].\",\n                   cimglist_instance,\n                   pos);\n        return *_data;\n      }\n#endif\n      return _data[pos];\n    }\n\n    //! Return a reference to one image of the list.\n    /**\n       \\param pos Indice of the image element.\n    **/\n    const CImg<T>& operator()(const unsigned int pos) const {\n      return const_cast<CImgList<T>*>(this)->operator()(pos);\n    }\n\n    //! Return a reference to one pixel value of one image of the list.\n    /**\n       \\param pos Indice of the image element.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note <tt>list(n,x,y,z,c)</tt> is equivalent to <tt>list[n](x,y,z,c)</tt>.\n    **/\n    T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,\n                  const unsigned int z=0, const unsigned int c=0) {\n      return (*this)[pos](x,y,z,c);\n    }\n\n    //! Return a reference to one pixel value of one image of the list \\const.\n    const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,\n                        const unsigned int z=0, const unsigned int c=0) const {\n      return (*this)[pos](x,y,z,c);\n    }\n\n    //! Return pointer to the first image of the list.\n    /**\n       \\note Images in a list are stored as a buffer of \\c CImg<T>.\n    **/\n    operator CImg<T>*() {\n      return _data;\n    }\n\n    //! Return pointer to the first image of the list \\const.\n    operator const CImg<T>*() const {\n      return _data;\n    }\n\n    //! Construct list from one image \\inplace.\n    /**\n        \\param img Input image to copy in the constructed list.\n        \\note <tt>list = img;</tt> is equivalent to <tt>list.assign(img);</tt>.\n    **/\n    template<typename t>\n    CImgList<T>& operator=(const CImg<t>& img) {\n      return assign(img);\n    }\n\n    //! Construct list from another list.\n    /**\n       \\param list Input list to copy.\n       \\note <tt>list1 = list2</tt> is equivalent to <tt>list1.assign(list2);</tt>.\n    **/\n    template<typename t>\n    CImgList<T>& operator=(const CImgList<t>& list) {\n      return assign(list);\n    }\n\n    //! Construct list from another list \\specialization.\n    CImgList<T>& operator=(const CImgList<T>& list) {\n      return assign(list);\n    }\n\n    //! Construct list by reading the content of a file \\inplace.\n    /**\n       \\see CImgList(const char *const).\n    **/\n    CImgList<T>& operator=(const char *const filename) {\n      return assign(filename);\n    }\n\n    //! Construct list from the content of a display window \\inplace.\n    /**\n        \\see CImgList(const CImgDisplay&).\n    **/\n    CImgList<T>& operator=(const CImgDisplay& disp) {\n      return assign(disp);\n    }\n\n    //! Return a non-shared copy of a list.\n    /**\n        \\note <tt>+list</tt> is equivalent to <tt>CImgList<T>(list,false)</tt>.\n          It forces the copy to have non-shared elements.\n    **/\n    CImgList<T> operator+() const {\n      return CImgList<T>(*this,false);\n    }\n\n    //! Return a copy of the list instance, where image \\c img has been inserted at the end.\n    /**\n       \\param img Image inserted at the end of the instance copy.\n       \\note Define a convenient way to create temporary lists of images, as in the following code:\n       \\code\n       (img1,img2,img3,img4).display(\"My four images\");\n       \\endcode\n    **/\n    template<typename t>\n    CImgList<T>& operator,(const CImg<t>& img) {\n      return insert(img);\n    }\n\n    //! Return a copy of the list instance, where image \\c img has been inserted at the end \\const.\n    template<typename t>\n    CImgList<T> operator,(const CImg<t>& img) const {\n      return (+*this).insert(img);\n    }\n\n    //! Return a copy of the list instance, where all elements of input list \\c list have been inserted at the end.\n    /**\n       \\param list List inserted at the end of the instance copy.\n    **/\n    template<typename t>\n    CImgList<T>& operator,(const CImgList<t>& list) {\n      return insert(list);\n    }\n\n    //! Return a copy of the list instance, where all elements of input \\c list have been inserted at the end \\const.\n    template<typename t>\n    CImgList<T>& operator,(const CImgList<t>& list) const {\n      return (+*this).insert(list);\n    }\n\n    //! Return image corresponding to the appending of all images of the instance list along specified axis.\n    /**\n      \\param axis Appending axis. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n      \\note <tt>list>'x'</tt> is equivalent to <tt>list.get_append('x')</tt>.\n    **/\n    CImg<T> operator>(const char axis) const {\n      return get_append(axis,0);\n    }\n\n    //! Return list corresponding to the splitting of all images of the instance list along specified axis.\n    /**\n      \\param axis Axis used for image splitting.\n      \\note <tt>list<'x'</tt> is equivalent to <tt>list.get_split('x')</tt>.\n    **/\n    CImgList<T> operator<(const char axis) const {\n      return get_split(axis);\n    }\n\n    //@}\n    //-------------------------------------\n    //\n    //! \\name Instance Characteristics\n    //@{\n    //-------------------------------------\n\n    //! Return the type of image pixel values as a C string.\n    /**\n       Return a \\c char* string containing the usual type name of the image pixel values\n       (i.e. a stringified version of the template parameter \\c T).\n       \\note\n       - The returned string may contain spaces (as in \\c \"unsigned char\").\n       - If the pixel type \\c T does not correspond to a registered type, the string <tt>\"unknown\"</tt> is returned.\n    **/\n    static const char* pixel_type() {\n      return cimg::type<T>::string();\n    }\n\n    //! Return the size of the list, i.e. the number of images contained in it.\n    /**\n      \\note Similar to size() but returns result as a (signed) integer.\n    **/\n    int width() const {\n      return (int)_width;\n    }\n\n    //! Return the size of the list, i.e. the number of images contained in it.\n    /**\n      \\note Similar to width() but returns result as an unsigned integer.\n    **/\n    unsigned int size() const {\n      return _width;\n    }\n\n    //! Return pointer to the first image of the list.\n    /**\n       \\note Images in a list are stored as a buffer of \\c CImg<T>.\n    **/\n    CImg<T> *data() {\n      return _data;\n    }\n\n    //! Return pointer to the first image of the list \\const.\n    const CImg<T> *data() const {\n      return _data;\n    }\n\n    //! Return pointer to the pos-th image of the list.\n    /**\n       \\param pos Indice of the image element to access.\n       \\note <tt>list.data(n);</tt> is equivalent to <tt>list.data + n;</tt>.\n    **/\n#if cimg_verbosity>=3\n    CImg<T> *data(const unsigned int pos) {\n      if (pos>=size())\n        cimg::warn(_cimglist_instance\n                   \"data(): Invalid pointer request, at position [%u].\",\n                   cimglist_instance,\n                   pos);\n      return _data + pos;\n    }\n\n    const CImg<T> *data(const unsigned int l) const {\n      return const_cast<CImgList<T>*>(this)->data(l);\n    }\n#else\n    CImg<T> *data(const unsigned int l) {\n      return _data + l;\n    }\n\n    //! Return pointer to the pos-th image of the list \\const.\n    const CImg<T> *data(const unsigned int l) const {\n      return _data + l;\n    }\n#endif\n\n    //! Return iterator to the first image of the list.\n    /**\n    **/\n    iterator begin() {\n      return _data;\n    }\n\n    //! Return iterator to the first image of the list \\const.\n    const_iterator begin() const {\n      return _data;\n    }\n\n    //! Return iterator to one position after the last image of the list.\n    /**\n    **/\n    iterator end() {\n      return _data + _width;\n    }\n\n    //! Return iterator to one position after the last image of the list \\const.\n    const_iterator end() const {\n      return _data + _width;\n    }\n\n    //! Return reference to the first image of the list.\n    /**\n    **/\n    CImg<T>& front() {\n      return *_data;\n    }\n\n    //! Return reference to the first image of the list \\const.\n    const CImg<T>& front() const {\n      return *_data;\n    }\n\n    //! Return a reference to the last image of the list.\n    /**\n    **/\n    const CImg<T>& back() const {\n      return *(_data + _width - 1);\n    }\n\n    //! Return a reference to the last image of the list \\const.\n    CImg<T>& back() {\n      return *(_data + _width - 1);\n    }\n\n    //! Return pos-th image of the list.\n    /**\n       \\param pos Indice of the image element to access.\n    **/\n    CImg<T>& at(const int pos) {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"at(): Empty instance.\",\n                                    cimglist_instance);\n\n      return _data[pos<0?0:pos>=(int)_width?(int)_width - 1:pos];\n    }\n\n    //! Access to pixel value with Dirichlet boundary conditions.\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param out_value Default value returned if \\c offset is outside image bounds.\n       \\note <tt>list.atNXYZC(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZC(x,y,z,c);</tt>.\n    **/\n    T& atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T& out_value) {\n      return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):_data[pos].atXYZC(x,y,z,c,out_value);\n    }\n\n    //! Access to pixel value with Dirichlet boundary conditions \\const.\n    T atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const {\n      return (pos<0 || pos>=(int)_width)?out_value:_data[pos].atXYZC(x,y,z,c,out_value);\n    }\n\n    //! Access to pixel value with Neumann boundary conditions.\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note <tt>list.atNXYZC(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZC(x,y,z,c);</tt>.\n    **/\n    T& atNXYZC(const int pos, const int x, const int y, const int z, const int c) {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atNXYZC(): Empty instance.\",\n                                    cimglist_instance);\n\n      return _atNXYZC(pos,x,y,z,c);\n    }\n\n    //! Access to pixel value with Neumann boundary conditions \\const.\n    T atNXYZC(const int pos, const int x, const int y, const int z, const int c) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atNXYZC(): Empty instance.\",\n                                    cimglist_instance);\n\n      return _atNXYZC(pos,x,y,z,c);\n    }\n\n    T& _atNXYZC(const int pos, const int x, const int y, const int z, const int c) {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZC(x,y,z,c);\n    }\n\n    T _atNXYZC(const int pos, const int x, const int y, const int z, const int c) const {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZC(x,y,z,c);\n    }\n\n    //! Access pixel value with Dirichlet boundary conditions for the 3 first coordinates (\\c pos, \\c x,\\c y,\\c z).\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param out_value Default value returned if \\c offset is outside image bounds.\n       \\note <tt>list.atNXYZ(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZ(x,y,z,c);</tt>.\n    **/\n    T& atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T& out_value) {\n      return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):_data[pos].atXYZ(x,y,z,c,out_value);\n    }\n\n    //! Access pixel value with Dirichlet boundary conditions for the 3 first coordinates (\\c pos, \\c x,\\c y,\\c z) \\const.\n    T atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const {\n      return (pos<0 || pos>=(int)_width)?out_value:_data[pos].atXYZ(x,y,z,c,out_value);\n    }\n\n    //! Access to pixel value with Neumann boundary conditions for the 4 first coordinates (\\c pos, \\c x,\\c y,\\c z).\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note <tt>list.atNXYZ(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZ(x,y,z,c);</tt>.\n    **/\n   T& atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atNXYZ(): Empty instance.\",\n                                    cimglist_instance);\n\n      return _atNXYZ(pos,x,y,z,c);\n    }\n\n    //! Access to pixel value with Neumann boundary conditions for the 4 first coordinates (\\c pos, \\c x,\\c y,\\c z) \\const.\n    T atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atNXYZ(): Empty instance.\",\n                                    cimglist_instance);\n\n      return _atNXYZ(pos,x,y,z,c);\n    }\n\n    T& _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZ(x,y,z,c);\n    }\n\n    T _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZ(x,y,z,c);\n    }\n\n    //! Access to pixel value with Dirichlet boundary conditions for the 3 first coordinates (\\c pos, \\c x,\\c y).\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param out_value Default value returned if \\c offset is outside image bounds.\n       \\note <tt>list.atNXYZ(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZ(x,y,z,c);</tt>.\n    **/\n    T& atNXY(const int pos, const int x, const int y, const int z, const int c, const T& out_value) {\n      return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):_data[pos].atXY(x,y,z,c,out_value);\n    }\n\n    //! Access to pixel value with Dirichlet boundary conditions for the 3 first coordinates (\\c pos, \\c x,\\c y) \\const.\n    T atNXY(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const {\n      return (pos<0 || pos>=(int)_width)?out_value:_data[pos].atXY(x,y,z,c,out_value);\n    }\n\n    //! Access to pixel value with Neumann boundary conditions for the 3 first coordinates (\\c pos, \\c x,\\c y).\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note <tt>list.atNXYZ(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZ(x,y,z,c);</tt>.\n    **/\n    T& atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atNXY(): Empty instance.\",\n                                    cimglist_instance);\n\n      return _atNXY(pos,x,y,z,c);\n    }\n\n    //! Access to pixel value with Neumann boundary conditions for the 3 first coordinates (\\c pos, \\c x,\\c y) \\const.\n    T atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atNXY(): Empty instance.\",\n                                    cimglist_instance);\n\n      return _atNXY(pos,x,y,z,c);\n    }\n\n    T& _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXY(x,y,z,c);\n    }\n\n    T _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) const {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXY(x,y,z,c);\n    }\n\n    //! Access to pixel value with Dirichlet boundary conditions for the 2 first coordinates (\\c pos,\\c x).\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param out_value Default value returned if \\c offset is outside image bounds.\n       \\note <tt>list.atNXYZ(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZ(x,y,z,c);</tt>.\n    **/\n    T& atNX(const int pos, const int x, const int y, const int z, const int c, const T& out_value) {\n      return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):_data[pos].atX(x,y,z,c,out_value);\n    }\n\n    //! Access to pixel value with Dirichlet boundary conditions for the 2 first coordinates (\\c pos,\\c x) \\const.\n    T atNX(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const {\n      return (pos<0 || pos>=(int)_width)?out_value:_data[pos].atX(x,y,z,c,out_value);\n    }\n\n    //! Access to pixel value with Neumann boundary conditions for the 2 first coordinates (\\c pos, \\c x).\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note <tt>list.atNXYZ(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZ(x,y,z,c);</tt>.\n    **/\n    T& atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atNX(): Empty instance.\",\n                                    cimglist_instance);\n\n      return _atNX(pos,x,y,z,c);\n    }\n\n    //! Access to pixel value with Neumann boundary conditions for the 2 first coordinates (\\c pos, \\c x) \\const.\n    T atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atNX(): Empty instance.\",\n                                    cimglist_instance);\n\n      return _atNX(pos,x,y,z,c);\n    }\n\n    T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atX(x,y,z,c);\n    }\n\n    T _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) const {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atX(x,y,z,c);\n    }\n\n    //! Access to pixel value with Dirichlet boundary conditions for the first coordinate (\\c pos).\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\param out_value Default value returned if \\c offset is outside image bounds.\n       \\note <tt>list.atNXYZ(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZ(x,y,z,c);</tt>.\n    **/\n    T& atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) {\n      return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):(*this)(pos,x,y,z,c);\n    }\n\n    //! Access to pixel value with Dirichlet boundary conditions for the first coordinate (\\c pos) \\const.\n    T atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const {\n      return (pos<0 || pos>=(int)_width)?out_value:(*this)(pos,x,y,z,c);\n    }\n\n    //! Return pixel value with Neumann boundary conditions for the first coordinate (\\c pos).\n    /**\n       \\param pos Indice of the image element to access.\n       \\param x X-coordinate of the pixel value.\n       \\param y Y-coordinate of the pixel value.\n       \\param z Z-coordinate of the pixel value.\n       \\param c C-coordinate of the pixel value.\n       \\note <tt>list.atNXYZ(p,x,y,z,c);</tt> is equivalent to <tt>list[p].atXYZ(x,y,z,c);</tt>.\n    **/\n    T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atN(): Empty instance.\",\n                                    cimglist_instance);\n      return _atN(pos,x,y,z,c);\n    }\n\n    //! Return pixel value with Neumann boundary conditions for the first coordinate (\\c pos) \\const.\n    T atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"atN(): Empty instance.\",\n                                    cimglist_instance);\n      return _atN(pos,x,y,z,c);\n    }\n\n    T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)](x,y,z,c);\n    }\n\n    T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) const {\n      return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)](x,y,z,c);\n    }\n\n    //! Return a C-string containing the values of all images in the instance list.\n    /**\n       \\param separator Character separator set between consecutive pixel values.\n       \\param max_size Maximum size of the returned string.\n       \\note The result is returne as a <tt>CImg<char></tt> image whose pixel buffer contains the desired C-string.\n    **/\n    CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {\n      if (is_empty()) return CImg<ucharT>(1,1,1,1,0);\n      CImgList<charT> items;\n      for (unsigned int l = 0; l<_width - 1; ++l) {\n        CImg<charT> item = _data[l].value_string(separator,0);\n        item.back() = separator;\n        item.move_to(items);\n      }\n      _data[_width - 1].value_string(separator,0).move_to(items);\n      CImg<charT> res; (items>'x').move_to(res);\n      if (max_size) { res.crop(0,max_size); res(max_size) = 0; }\n      return res;\n    }\n\n    //@}\n    //-------------------------------------\n    //\n    //! \\name Instance Checking\n    //@{\n    //-------------------------------------\n\n    //! Return \\c true if list is empty.\n    /**\n    **/\n    bool is_empty() const {\n      return (!_data || !_width);\n    }\n\n    //! Test if number of image elements is equal to specified value.\n    /**\n        \\param size_n Number of image elements to test.\n    **/\n    bool is_sameN(const unsigned int size_n) const {\n      return _width==size_n;\n    }\n\n    //! Test if number of image elements is equal between two images lists.\n    /**\n        \\param list Input list to compare with.\n    **/\n    template<typename t>\n    bool is_sameN(const CImgList<t>& list) const {\n      return is_sameN(list._width);\n    }\n\n    // Define useful functions to check list dimensions.\n    // (cannot be documented because macro-generated).\n#define _cimglist_def_is_same1(axis) \\\n    bool is_same##axis(const unsigned int val) const { \\\n      bool res = true; \\\n      for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis(val); return res; \\\n    } \\\n    bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \\\n      return is_sameN(n) && is_same##axis(val); \\\n    } \\\n\n#define _cimglist_def_is_same2(axis1,axis2) \\\n    bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \\\n      bool res = true; \\\n      for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis1##axis2(val1,val2); return res; \\\n    } \\\n    bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \\\n      return is_sameN(n) && is_same##axis1##axis2(val1,val2); \\\n    } \\\n\n#define _cimglist_def_is_same3(axis1,axis2,axis3) \\\n    bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, \\\n                                      const unsigned int val3) const { \\\n      bool res = true; \\\n      for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis1##axis2##axis3(val1,val2,val3); \\\n      return res; \\\n    } \\\n    bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, \\\n                                       const unsigned int val2, const unsigned int val3) const { \\\n      return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \\\n    } \\\n\n#define _cimglist_def_is_same(axis) \\\n    template<typename t> bool is_same##axis(const CImg<t>& img) const { \\\n      bool res = true; for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis(img); return res; \\\n    } \\\n    template<typename t> bool is_same##axis(const CImgList<t>& list) const { \\\n      const unsigned int lmin = cimg::min(_width,list._width); \\\n      bool res = true; for (unsigned int l = 0; l<lmin && res; ++l) res = _data[l].is_same##axis(list[l]); return res; \\\n    } \\\n    template<typename t> bool is_sameN##axis(const unsigned int n, const CImg<t>& img) const { \\\n      return (is_sameN(n) && is_same##axis(img)); \\\n    } \\\n    template<typename t> bool is_sameN##axis(const CImgList<t>& list) const { \\\n      return (is_sameN(list) && is_same##axis(list)); \\\n    }\n\n    _cimglist_def_is_same(XY)\n    _cimglist_def_is_same(XZ)\n    _cimglist_def_is_same(XC)\n    _cimglist_def_is_same(YZ)\n    _cimglist_def_is_same(YC)\n    _cimglist_def_is_same(XYZ)\n    _cimglist_def_is_same(XYC)\n    _cimglist_def_is_same(YZC)\n    _cimglist_def_is_same(XYZC)\n    _cimglist_def_is_same1(X)\n    _cimglist_def_is_same1(Y)\n    _cimglist_def_is_same1(Z)\n    _cimglist_def_is_same1(C)\n    _cimglist_def_is_same2(X,Y)\n    _cimglist_def_is_same2(X,Z)\n    _cimglist_def_is_same2(X,C)\n    _cimglist_def_is_same2(Y,Z)\n    _cimglist_def_is_same2(Y,C)\n    _cimglist_def_is_same2(Z,C)\n    _cimglist_def_is_same3(X,Y,Z)\n    _cimglist_def_is_same3(X,Y,C)\n    _cimglist_def_is_same3(X,Z,C)\n    _cimglist_def_is_same3(Y,Z,C)\n\n    //! Test if dimensions of each image of the list match specified arguments.\n    /**\n      \\param dx Checked image width.\n      \\param dy Checked image height.\n      \\param dz Checked image depth.\n      \\param dc Checked image spectrum.\n    **/\n    bool is_sameXYZC(const unsigned int dx, const unsigned int dy,\n                     const unsigned int dz, const unsigned int dc) const {\n      bool res = true;\n      for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_sameXYZC(dx,dy,dz,dc);\n      return res;\n    }\n\n    //! Test if list dimensions match specified arguments.\n    /**\n       \\param n Number of images in the list.\n       \\param dx Checked image width.\n       \\param dy Checked image height.\n       \\param dz Checked image depth.\n       \\param dc Checked image spectrum.\n    **/\n    bool is_sameNXYZC(const unsigned int n,\n                      const unsigned int dx, const unsigned int dy,\n                      const unsigned int dz, const unsigned int dc) const {\n      return is_sameN(n) && is_sameXYZC(dx,dy,dz,dc);\n    }\n\n    //! Test if list contains one particular pixel location.\n    /**\n       \\param n Index of the image whom checked pixel value belong to.\n       \\param x X-coordinate of the checked pixel value.\n       \\param y Y-coordinate of the checked pixel value.\n       \\param z Z-coordinate of the checked pixel value.\n       \\param c C-coordinate of the checked pixel value.\n    **/\n    bool containsNXYZC(const int n, const int x=0, const int y=0, const int z=0, const int c=0) const {\n      if (is_empty()) return false;\n      return n>=0 && n<(int)_width && x>=0 && x<_data[n].width() && y>=0 && y<_data[n].height() &&\n        z>=0 && z<_data[n].depth() && c>=0 && c<_data[n].spectrum();\n    }\n\n    //! Test if list contains image with specified indice.\n    /**\n       \\param n Index of the checked image.\n    **/\n    bool containsN(const int n) const {\n      if (is_empty()) return false;\n      return n>=0 && n<(int)_width;\n    }\n\n    //! Test if one image of the list contains the specified referenced value.\n    /**\n       \\param pixel Reference to pixel value to test.\n       \\param[out] n Index of image containing the pixel value, if test succeeds.\n       \\param[out] x X-coordinate of the pixel value, if test succeeds.\n       \\param[out] y Y-coordinate of the pixel value, if test succeeds.\n       \\param[out] z Z-coordinate of the pixel value, if test succeeds.\n       \\param[out] c C-coordinate of the pixel value, if test succeeds.\n       \\note If true, set coordinates (n,x,y,z,c).\n    **/\n    template<typename t>\n    bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& c) const {\n      if (is_empty()) return false;\n      cimglist_for(*this,l) if (_data[l].contains(pixel,x,y,z,c)) { n = (t)l; return true; }\n      return false;\n    }\n\n    //! Test if one of the image list contains the specified referenced value.\n    /**\n       \\param pixel Reference to pixel value to test.\n       \\param[out] n Index of image containing the pixel value, if test succeeds.\n       \\param[out] x X-coordinate of the pixel value, if test succeeds.\n       \\param[out] y Y-coordinate of the pixel value, if test succeeds.\n       \\param[out] z Z-coordinate of the pixel value, if test succeeds.\n       \\note If true, set coordinates (n,x,y,z).\n    **/\n    template<typename t>\n    bool contains(const T& pixel, t& n, t& x, t&y, t& z) const {\n      t c;\n      return contains(pixel,n,x,y,z,c);\n    }\n\n    //! Test if one of the image list contains the specified referenced value.\n    /**\n       \\param pixel Reference to pixel value to test.\n       \\param[out] n Index of image containing the pixel value, if test succeeds.\n       \\param[out] x X-coordinate of the pixel value, if test succeeds.\n       \\param[out] y Y-coordinate of the pixel value, if test succeeds.\n       \\note If true, set coordinates (n,x,y).\n    **/\n    template<typename t>\n    bool contains(const T& pixel, t& n, t& x, t&y) const {\n      t z, c;\n      return contains(pixel,n,x,y,z,c);\n    }\n\n    //! Test if one of the image list contains the specified referenced value.\n    /**\n       \\param pixel Reference to pixel value to test.\n       \\param[out] n Index of image containing the pixel value, if test succeeds.\n       \\param[out] x X-coordinate of the pixel value, if test succeeds.\n       \\note If true, set coordinates (n,x).\n    **/\n    template<typename t>\n    bool contains(const T& pixel, t& n, t& x) const {\n      t y, z, c;\n      return contains(pixel,n,x,y,z,c);\n    }\n\n    //! Test if one of the image list contains the specified referenced value.\n    /**\n       \\param pixel Reference to pixel value to test.\n       \\param[out] n Index of image containing the pixel value, if test succeeds.\n       \\note If true, set coordinates (n).\n    **/\n    template<typename t>\n    bool contains(const T& pixel, t& n) const {\n      t x, y, z, c;\n      return contains(pixel,n,x,y,z,c);\n    }\n\n    //! Test if one of the image list contains the specified referenced value.\n    /**\n       \\param pixel Reference to pixel value to test.\n    **/\n    bool contains(const T& pixel) const {\n      unsigned int n, x, y, z, c;\n      return contains(pixel,n,x,y,z,c);\n    }\n\n    //! Test if the list contains the image 'img'.\n    /**\n       \\param img Reference to image to test.\n       \\param[out] n Index of image in the list, if test succeeds.\n       \\note If true, returns the position (n) of the image in the list.\n    **/\n    template<typename t>\n    bool contains(const CImg<T>& img, t& n) const {\n      if (is_empty()) return false;\n      const CImg<T> *const ptr = &img;\n      cimglist_for(*this,i) if (_data + i==ptr) { n = (t)i; return true; }\n      return false;\n    }\n\n    //! Test if the list contains the image img.\n    /**\n       \\param img Reference to image to test.\n    **/\n    bool contains(const CImg<T>& img) const {\n      unsigned int n;\n      return contains(img,n);\n    }\n\n    //@}\n    //-------------------------------------\n    //\n    //! \\name Mathematical Functions\n    //@{\n    //-------------------------------------\n\n    //! Return a reference to the minimum pixel value of the instance list.\n    /**\n    **/\n    T& min() {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"min(): Empty instance.\",\n                                    cimglist_instance);\n      T *ptr_min = _data->_data;\n      T min_value = *ptr_min;\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        cimg_for(img,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs);\n      }\n      return *ptr_min;\n    }\n\n    //! Return a reference to the minimum pixel value of the instance list \\const.\n    const T& min() const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"min(): Empty instance.\",\n                                    cimglist_instance);\n      const T *ptr_min = _data->_data;\n      T min_value = *ptr_min;\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        cimg_for(img,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs);\n      }\n      return *ptr_min;\n    }\n\n    //! Return a reference to the maximum pixel value of the instance list.\n    /**\n    **/\n    T& max() {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"max(): Empty instance.\",\n                                    cimglist_instance);\n      T *ptr_max = _data->_data;\n      T max_value = *ptr_max;\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        cimg_for(img,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);\n      }\n      return *ptr_max;\n    }\n\n    //! Return a reference to the maximum pixel value of the instance list \\const.\n    const T& max() const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"max(): Empty instance.\",\n                                    cimglist_instance);\n      const T *ptr_max = _data->_data;\n      T max_value = *ptr_max;\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        cimg_for(img,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);\n      }\n      return *ptr_max;\n    }\n\n    //! Return a reference to the minimum pixel value of the instance list and return the maximum vvalue as well.\n    /**\n       \\param[out] max_val Value of the maximum value found.\n    **/\n    template<typename t>\n    T& min_max(t& max_val) {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"min_max(): Empty instance.\",\n                                    cimglist_instance);\n      T *ptr_min = _data->_data;\n      T min_value = *ptr_min, max_value = min_value;\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        cimg_for(img,ptrs,T) {\n          const T val = *ptrs;\n          if (val<min_value) { min_value = val; ptr_min = ptrs; }\n          if (val>max_value) max_value = val;\n        }\n      }\n      max_val = (t)max_value;\n      return *ptr_min;\n    }\n\n    //! Return a reference to the minimum pixel value of the instance list and return the maximum vvalue as well \\const.\n    /**\n       \\param[out] max_val Value of the maximum value found.\n    **/\n    template<typename t>\n    const T& min_max(t& max_val) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"min_max(): Empty instance.\",\n                                    cimglist_instance);\n      const T *ptr_min = _data->_data;\n      T min_value = *ptr_min, max_value = min_value;\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        cimg_for(img,ptrs,T) {\n          const T val = *ptrs;\n          if (val<min_value) { min_value = val; ptr_min = ptrs; }\n          if (val>max_value) max_value = val;\n        }\n      }\n      max_val = (t)max_value;\n      return *ptr_min;\n    }\n\n    //! Return a reference to the minimum pixel value of the instance list and return the minimum value as well.\n    /**\n       \\param[out] min_val Value of the minimum value found.\n    **/\n    template<typename t>\n    T& max_min(t& min_val) {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"max_min(): Empty instance.\",\n                                    cimglist_instance);\n      T *ptr_max = _data->_data;\n      T min_value = *ptr_max, max_value = min_value;\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        cimg_for(img,ptrs,T) {\n          const T val = *ptrs;\n          if (val>max_value) { max_value = val; ptr_max = ptrs; }\n          if (val<min_value) min_value = val;\n        }\n      }\n      min_val = (t)min_value;\n      return *ptr_max;\n    }\n\n    //! Return a reference to the minimum pixel value of the instance list and return the minimum value as well \\const.\n    template<typename t>\n    const T& max_min(t& min_val) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"max_min(): Empty instance.\",\n                                    cimglist_instance);\n      const T *ptr_max = _data->_data;\n      T min_value = *ptr_max, max_value = min_value;\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        cimg_for(img,ptrs,T) {\n          const T val = *ptrs;\n          if (val>max_value) { max_value = val; ptr_max = ptrs; }\n          if (val<min_value) min_value = val;\n        }\n      }\n      min_val = (t)min_value;\n      return *ptr_max;\n    }\n\n    //@}\n    //---------------------------\n    //\n    //! \\name List Manipulation\n    //@{\n    //---------------------------\n\n    //! Insert a copy of the image \\c img into the current image list, at position \\c pos.\n    /**\n        \\param img Image to insert a copy to the list.\n        \\param pos Index of the insertion.\n        \\param is_shared Tells if the inserted image is a shared copy of \\c img or not.\n    **/\n    template<typename t>\n    CImgList<T>& insert(const CImg<t>& img, const unsigned int pos=~0U, const bool is_shared=false) {\n      const unsigned int npos = pos==~0U?_width:pos;\n      if (npos>_width)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"insert(): Invalid insertion request of specified image (%u,%u,%u,%u,%p) \"\n                                    \"at position %u.\",\n                                    cimglist_instance,\n                                    img._width,img._height,img._depth,img._spectrum,img._data,npos);\n      if (is_shared)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"insert(): Invalid insertion request of specified shared image \"\n                                    \"CImg<%s>(%u,%u,%u,%u,%p) at position %u (pixel types are different).\",\n                                    cimglist_instance,\n                                    img.pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data,npos);\n\n      CImg<T> *const new_data = (++_width>_allocated_width)?new CImg<T>[_allocated_width?(_allocated_width<<=1):\n                                                                        (_allocated_width=16)]:0;\n      if (!_data) { // Insert new element into empty list.\n        _data = new_data;\n        *_data = img;\n      } else {\n        if (new_data) { // Insert with re-allocation.\n          if (npos) std::memcpy(new_data,_data,sizeof(CImg<T>)*npos);\n          if (npos!=_width - 1) std::memcpy(new_data + npos + 1,_data + npos,sizeof(CImg<T>)*(_width - 1 - npos));\n          std::memset(_data,0,sizeof(CImg<T>)*(_width - 1));\n          delete[] _data;\n          _data = new_data;\n        } else if (npos!=_width - 1) // Insert without re-allocation.\n          std::memmove(_data + npos + 1,_data + npos,sizeof(CImg<T>)*(_width - 1 - npos));\n        _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0;\n        _data[npos]._data = 0;\n        _data[npos] = img;\n      }\n      return *this;\n    }\n\n    //! Insert a copy of the image \\c img into the current image list, at position \\c pos \\specialization.\n    CImgList<T>& insert(const CImg<T>& img, const unsigned int pos=~0U, const bool is_shared=false) {\n      const unsigned int npos = pos==~0U?_width:pos;\n      if (npos>_width)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"insert(): Invalid insertion request of specified image (%u,%u,%u,%u,%p) \"\n                                    \"at position %u.\",\n                                    cimglist_instance,\n                                    img._width,img._height,img._depth,img._spectrum,img._data,npos);\n      CImg<T> *const new_data = (++_width>_allocated_width)?new CImg<T>[_allocated_width?(_allocated_width<<=1):\n                                                                        (_allocated_width=16)]:0;\n      if (!_data) { // Insert new element into empty list.\n        _data = new_data;\n        if (is_shared && img) {\n          _data->_width = img._width;\n          _data->_height = img._height;\n          _data->_depth = img._depth;\n          _data->_spectrum = img._spectrum;\n          _data->_is_shared = true;\n          _data->_data = img._data;\n        } else *_data = img;\n      }\n      else {\n        if (new_data) { // Insert with re-allocation.\n          if (npos) std::memcpy(new_data,_data,sizeof(CImg<T>)*npos);\n          if (npos!=_width - 1) std::memcpy(new_data + npos + 1,_data + npos,sizeof(CImg<T>)*(_width - 1 - npos));\n          if (is_shared && img) {\n            new_data[npos]._width = img._width;\n            new_data[npos]._height = img._height;\n            new_data[npos]._depth = img._depth;\n            new_data[npos]._spectrum = img._spectrum;\n            new_data[npos]._is_shared = true;\n            new_data[npos]._data = img._data;\n          } else {\n            new_data[npos]._width = new_data[npos]._height = new_data[npos]._depth = new_data[npos]._spectrum = 0;\n            new_data[npos]._data = 0;\n            new_data[npos] = img;\n          }\n          std::memset(_data,0,sizeof(CImg<T>)*(_width - 1));\n          delete[] _data;\n          _data = new_data;\n        } else { // Insert without re-allocation.\n          if (npos!=_width - 1) std::memmove(_data + npos + 1,_data + npos,sizeof(CImg<T>)*(_width - 1 - npos));\n          if (is_shared && img) {\n            _data[npos]._width = img._width;\n            _data[npos]._height = img._height;\n            _data[npos]._depth = img._depth;\n            _data[npos]._spectrum = img._spectrum;\n            _data[npos]._is_shared = true;\n            _data[npos]._data = img._data;\n          } else {\n            _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0;\n            _data[npos]._data = 0;\n            _data[npos] = img;\n          }\n        }\n      }\n      return *this;\n    }\n\n    //! Insert a copy of the image \\c img into the current image list, at position \\c pos \\newinstance.\n    template<typename t>\n    CImgList<T> get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool is_shared=false) const {\n      return (+*this).insert(img,pos,is_shared);\n    }\n\n    //! Insert n empty images img into the current image list, at position \\p pos.\n    /**\n       \\param n Number of empty images to insert.\n       \\param pos Index of the insertion.\n    **/\n    CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) {\n      CImg<T> empty;\n      if (!n) return *this;\n      const unsigned int npos = pos==~0U?_width:pos;\n      for (unsigned int i = 0; i<n; ++i) insert(empty,npos+i);\n      return *this;\n    }\n\n    //! Insert n empty images img into the current image list, at position \\p pos \\newinstance.\n    CImgList<T> get_insert(const unsigned int n, const unsigned int pos=~0U) const {\n      return (+*this).insert(n,pos);\n    }\n\n    //! Insert \\c n copies of the image \\c img into the current image list, at position \\c pos.\n    /**\n       \\param n Number of image copies to insert.\n       \\param img Image to insert by copy.\n       \\param pos Index of the insertion.\n       \\param is_shared Tells if inserted images are shared copies of \\c img or not.\n    **/\n    template<typename t>\n    CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U,\n                        const bool is_shared=false) {\n      if (!n) return *this;\n      const unsigned int npos = pos==~0U?_width:pos;\n      insert(img,npos,is_shared);\n      for (unsigned int i = 1; i<n; ++i) insert(_data[npos],npos + i,is_shared);\n      return *this;\n    }\n\n    //! Insert \\c n copies of the image \\c img into the current image list, at position \\c pos \\newinstance.\n    template<typename t>\n    CImgList<T> get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U,\n                           const bool is_shared=false) const {\n      return (+*this).insert(n,img,pos,is_shared);\n    }\n\n    //! Insert a copy of the image list \\c list into the current image list, starting from position \\c pos.\n    /**\n      \\param list Image list to insert.\n      \\param pos Index of the insertion.\n      \\param is_shared Tells if inserted images are shared copies of images of \\c list or not.\n    **/\n    template<typename t>\n    CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool is_shared=false) {\n      const unsigned int npos = pos==~0U?_width:pos;\n      if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos + l,is_shared);\n      else insert(CImgList<T>(list),npos,is_shared);\n      return *this;\n    }\n\n    //! Insert a copy of the image list \\c list into the current image list, starting from position \\c pos \\newinstance.\n    template<typename t>\n    CImgList<T> get_insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool is_shared=false) const {\n      return (+*this).insert(list,pos,is_shared);\n    }\n\n    //! Insert n copies of the list \\c list at position \\c pos of the current list.\n    /**\n      \\param n Number of list copies to insert.\n      \\param list Image list to insert.\n      \\param pos Index of the insertion.\n      \\param is_shared Tells if inserted images are shared copies of images of \\c list or not.\n    **/\n    template<typename t>\n    CImgList<T>& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U,\n                        const bool is_shared=false) {\n      if (!n) return *this;\n      const unsigned int npos = pos==~0U?_width:pos;\n      for (unsigned int i = 0; i<n; ++i) insert(list,npos,is_shared);\n      return *this;\n    }\n\n    //! Insert n copies of the list \\c list at position \\c pos of the current list \\newinstance.\n    template<typename t>\n    CImgList<T> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U,\n                           const bool is_shared=false) const {\n      return (+*this).insert(n,list,pos,is_shared);\n    }\n\n    //! Remove all images between from indexes.\n    /**\n      \\param pos1 Starting index of the removal.\n      \\param pos2 Ending index of the removal.\n    **/\n    CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) {\n      const unsigned int\n        npos1 = pos1<pos2?pos1:pos2,\n        tpos2 = pos1<pos2?pos2:pos1,\n        npos2 = tpos2<_width?tpos2:_width - 1;\n      if (npos1>=_width)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"remove(): Invalid remove request at positions %u->%u.\",\n                                    cimglist_instance,\n                                    npos1,tpos2);\n      else {\n        if (tpos2>=_width)\n          throw CImgArgumentException(_cimglist_instance\n                                      \"remove(): Invalid remove request at positions %u->%u.\",\n                                      cimglist_instance,\n                                      npos1,tpos2);\n\n        for (unsigned int k = npos1; k<=npos2; ++k) _data[k].assign();\n        const unsigned int nb = 1 + npos2 - npos1;\n        if (!(_width-=nb)) return assign();\n        if (_width>(_allocated_width>>2) || _allocated_width<=16) { // Removing items without reallocation.\n          if (npos1!=_width) std::memmove(_data + npos1,_data + npos2 + 1,sizeof(CImg<T>)*(_width - npos1));\n          std::memset(_data + _width,0,sizeof(CImg<T>)*nb);\n        } else { // Removing items with reallocation.\n          _allocated_width>>=2;\n          while (_allocated_width>16 && _width<(_allocated_width>>1)) _allocated_width>>=1;\n          CImg<T> *const new_data = new CImg<T>[_allocated_width];\n          if (npos1) std::memcpy(new_data,_data,sizeof(CImg<T>)*npos1);\n          if (npos1!=_width) std::memcpy(new_data + npos1,_data + npos2 + 1,sizeof(CImg<T>)*(_width - npos1));\n          if (_width!=_allocated_width) std::memset(new_data + _width,0,sizeof(CImg<T>)*(_allocated_width - _width));\n          std::memset(_data,0,sizeof(CImg<T>)*(_width + nb));\n          delete[] _data;\n          _data = new_data;\n        }\n      }\n      return *this;\n    }\n\n    //! Remove all images between from indexes \\newinstance.\n    CImgList<T> get_remove(const unsigned int pos1, const unsigned int pos2) const {\n      return (+*this).remove(pos1,pos2);\n    }\n\n    //! Remove image at index \\c pos from the image list.\n    /**\n      \\param pos Index of the image to remove.\n    **/\n    CImgList<T>& remove(const unsigned int pos) {\n      return remove(pos,pos);\n    }\n\n    //! Remove image at index \\c pos from the image list \\newinstance.\n    CImgList<T> get_remove(const unsigned int pos) const {\n      return (+*this).remove(pos);\n    }\n\n    //! Remove last image.\n    /**\n    **/\n    CImgList<T>& remove() {\n      return remove(_width - 1);\n    }\n\n    //! Remove last image \\newinstance.\n    CImgList<T> get_remove() const {\n      return (+*this).remove();\n    }\n\n    //! Reverse list order.\n    CImgList<T>& reverse() {\n      for (unsigned int l = 0; l<_width/2; ++l) (*this)[l].swap((*this)[_width - 1 - l]);\n      return *this;\n    }\n\n    //! Reverse list order \\newinstance.\n    CImgList<T> get_reverse() const {\n      return (+*this).reverse();\n    }\n\n    //! Return a sublist.\n    /**\n      \\param pos0 Starting index of the sublist.\n      \\param pos1 Ending index of the sublist.\n    **/\n    CImgList<T>& images(const unsigned int pos0, const unsigned int pos1) {\n      return get_images(pos0,pos1).move_to(*this);\n    }\n\n    //! Return a sublist \\newinstance.\n    CImgList<T> get_images(const unsigned int pos0, const unsigned int pos1) const {\n      if (pos0>pos1 || pos1>=_width)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"images(): Specified sub-list indices (%u->%u) are out of bounds.\",\n                                    cimglist_instance,\n                                    pos0,pos1);\n      CImgList<T> res(pos1 - pos0 + 1);\n      cimglist_for(res,l) res[l].assign(_data[pos0 + l]);\n      return res;\n    }\n\n    //! Return a shared sublist.\n    /**\n      \\param pos0 Starting index of the sublist.\n      \\param pos1 Ending index of the sublist.\n    **/\n    CImgList<T> get_shared_images(const unsigned int pos0, const unsigned int pos1) {\n      if (pos0>pos1 || pos1>=_width)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"get_shared_images(): Specified sub-list indices (%u->%u) are out of bounds.\",\n                                    cimglist_instance,\n                                    pos0,pos1);\n      CImgList<T> res(pos1 - pos0 + 1);\n      cimglist_for(res,l) res[l].assign(_data[pos0 + l],_data[pos0 + l]?true:false);\n      return res;\n    }\n\n    //! Return a shared sublist \\newinstance.\n    const CImgList<T> get_shared_images(const unsigned int pos0, const unsigned int pos1) const {\n      if (pos0>pos1 || pos1>=_width)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"get_shared_images(): Specified sub-list indices (%u->%u) are out of bounds.\",\n                                    cimglist_instance,\n                                    pos0,pos1);\n      CImgList<T> res(pos1 - pos0 + 1);\n      cimglist_for(res,l) res[l].assign(_data[pos0 + l],_data[pos0 + l]?true:false);\n      return res;\n    }\n\n    //! Return a single image which is the appending of all images of the current CImgList instance.\n    /**\n       \\param axis Appending axis. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n       \\param align Appending alignment.\n    **/\n    CImg<T> get_append(const char axis, const float align=0) const {\n      if (is_empty()) return CImg<T>();\n      if (_width==1) return +((*this)[0]);\n      unsigned int dx = 0, dy = 0, dz = 0, dc = 0, pos = 0;\n      CImg<T> res;\n      switch (cimg::uncase(axis)) {\n      case 'x' : { // Along the X-axis.\n        cimglist_for(*this,l) {\n          const CImg<T>& img = (*this)[l];\n          if (img) {\n            dx+=img._width;\n            dy = cimg::max(dy,img._height);\n            dz = cimg::max(dz,img._depth);\n            dc = cimg::max(dc,img._spectrum);\n          }\n        }\n        res.assign(dx,dy,dz,dc,0);\n        if (res) cimglist_for(*this,l) {\n            const CImg<T>& img = (*this)[l];\n            if (img) res.draw_image(pos,\n                                    (int)(align*(dy - img._height)),\n                                    (int)(align*(dz - img._depth)),\n                                    (int)(align*(dc - img._spectrum)),\n                                    img);\n            pos+=img._width;\n          }\n      } break;\n      case 'y' : { // Along the Y-axis.\n        cimglist_for(*this,l) {\n          const CImg<T>& img = (*this)[l];\n          if (img) {\n            dx = cimg::max(dx,img._width);\n            dy+=img._height;\n            dz = cimg::max(dz,img._depth);\n            dc = cimg::max(dc,img._spectrum);\n          }\n        }\n        res.assign(dx,dy,dz,dc,0);\n        if (res) cimglist_for(*this,l) {\n            const CImg<T>& img = (*this)[l];\n            if (img) res.draw_image((int)(align*(dx - img._width)),\n                                    pos,\n                                    (int)(align*(dz - img._depth)),\n                                    (int)(align*(dc - img._spectrum)),\n                                    img);\n            pos+=img._height;\n          }\n      } break;\n      case 'z' : { // Along the Z-axis.\n        cimglist_for(*this,l) {\n          const CImg<T>& img = (*this)[l];\n          if (img) {\n            dx = cimg::max(dx,img._width);\n            dy = cimg::max(dy,img._height);\n            dz+=img._depth;\n            dc = cimg::max(dc,img._spectrum);\n          }\n        }\n        res.assign(dx,dy,dz,dc,0);\n        if (res) cimglist_for(*this,l) {\n            const CImg<T>& img = (*this)[l];\n            if (img) res.draw_image((int)(align*(dx - img._width)),\n                                    (int)(align*(dy - img._height)),\n                                    pos,\n                                    (int)(align*(dc - img._spectrum)),\n                                    img);\n            pos+=img._depth;\n          }\n      } break;\n      default : { // Along the C-axis.\n        cimglist_for(*this,l) {\n          const CImg<T>& img = (*this)[l];\n          if (img) {\n            dx = cimg::max(dx,img._width);\n            dy = cimg::max(dy,img._height);\n            dz = cimg::max(dz,img._depth);\n            dc+=img._spectrum;\n          }\n        }\n        res.assign(dx,dy,dz,dc,0);\n        if (res) cimglist_for(*this,l) {\n            const CImg<T>& img = (*this)[l];\n            if (img) res.draw_image((int)(align*(dx - img._width)),\n                                    (int)(align*(dy - img._height)),\n                                    (int)(align*(dz - img._depth)),\n                                    pos,\n                                    img);\n            pos+=img._spectrum;\n          }\n      }\n      }\n      return res;\n    }\n\n    //! Return a list where each image has been split along the specified axis.\n    /**\n        \\param axis Axis to split images along.\n        \\param nb Number of spliting parts for each image.\n    **/\n    CImgList<T>& split(const char axis, const int nb=-1) {\n      return get_split(axis,nb).move_to(*this);\n    }\n\n    //! Return a list where each image has been split along the specified axis \\newinstance.\n    CImgList<T> get_split(const char axis, const int nb=-1) const {\n      CImgList<T> res;\n      cimglist_for(*this,l) _data[l].get_split(axis,nb).move_to(res,~0U);\n      return res;\n    }\n\n    //! Insert image at the end of the list.\n    /**\n      \\param img Image to insert.\n    **/\n    template<typename t>\n    CImgList<T>& push_back(const CImg<t>& img) {\n      return insert(img);\n    }\n\n    //! Insert image at the front of the list.\n    /**\n      \\param img Image to insert.\n    **/\n    template<typename t>\n    CImgList<T>& push_front(const CImg<t>& img) {\n      return insert(img,0);\n    }\n\n    //! Insert list at the end of the current list.\n    /**\n      \\param list List to insert.\n    **/\n    template<typename t>\n    CImgList<T>& push_back(const CImgList<t>& list) {\n      return insert(list);\n    }\n\n    //! Insert list at the front of the current list.\n    /**\n      \\param list List to insert.\n    **/\n    template<typename t>\n    CImgList<T>& push_front(const CImgList<t>& list) {\n      return insert(list,0);\n    }\n\n    //! Remove last image.\n    /**\n    **/\n    CImgList<T>& pop_back() {\n      return remove(_width - 1);\n    }\n\n    //! Remove first image.\n    /**\n    **/\n    CImgList<T>& pop_front() {\n      return remove(0);\n    }\n\n    //! Remove image pointed by iterator.\n    /**\n      \\param iter Iterator pointing to the image to remove.\n    **/\n    CImgList<T>& erase(const iterator iter) {\n      return remove(iter - _data);\n    }\n\n    //@}\n    //----------------------------------\n    //\n    //! \\name Data Input\n    //@{\n    //----------------------------------\n\n    //! Display a simple interactive interface to select images or sublists.\n    /**\n       \\param disp Window instance to display selection and user interface.\n       \\param feature_type Can be \\c false to select a single image, or \\c true to select a sublist.\n       \\param axis Axis along whom images are appended for visualization.\n       \\param align Alignment setting when images have not all the same size.\n       \\return A one-column vector containing the selected image indexes.\n    **/\n    CImg<intT> get_select(CImgDisplay &disp, const bool feature_type=true,\n                          const char axis='x', const float align=0,\n                          const bool exit_on_anykey=false) const {\n      return _get_select(disp,0,feature_type,axis,align,exit_on_anykey,0,false,false,false);\n    }\n\n    //! Display a simple interactive interface to select images or sublists.\n    /**\n       \\param title Title of a new window used to display selection and user interface.\n       \\param feature_type Can be \\c false to select a single image, or \\c true to select a sublist.\n       \\param axis Axis along whom images are appended for visualization.\n       \\param align Alignment setting when images have not all the same size.\n       \\return A one-column vector containing the selected image indexes.\n    **/\n    CImg<intT> get_select(const char *const title, const bool feature_type=true,\n                          const char axis='x', const float align=0,\n                          const bool exit_on_anykey=false) const {\n      CImgDisplay disp;\n      return _get_select(disp,title,feature_type,axis,align,exit_on_anykey,0,false,false,false);\n    }\n\n    CImg<intT> _get_select(CImgDisplay &disp, const char *const title, const bool feature_type,\n                           const char axis, const float align, const bool exit_on_anykey,\n                           const unsigned int orig, const bool resize_disp,\n                           const bool exit_on_rightbutton, const bool exit_on_wheel) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"select(): Empty instance.\",\n                                    cimglist_instance);\n\n      // Create image correspondence table and get list dimensions for visualization.\n      CImgList<uintT> _indices;\n      unsigned int max_width = 0, max_height = 0, sum_width = 0, sum_height = 0;\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        const unsigned int\n          w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false),\n          h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true);\n        if (w>max_width) max_width = w;\n        if (h>max_height) max_height = h;\n        sum_width+=w; sum_height+=h;\n        if (axis=='x') CImg<uintT>(w,1,1,1,(unsigned int)l).move_to(_indices);\n        else CImg<uintT>(h,1,1,1,(unsigned int)l).move_to(_indices);\n      }\n      const CImg<uintT> indices0 = _indices>'x';\n\n      // Create display window.\n      if (!disp) {\n        if (axis=='x') disp.assign(cimg_fitscreen(sum_width,max_height,1),title?title:0,1);\n        else disp.assign(cimg_fitscreen(max_width,sum_height,1),title?title:0,1);\n        if (!title) disp.set_title(\"CImgList<%s> (%u)\",pixel_type(),_width);\n      } else if (title) disp.set_title(\"%s\",title);\n      if (resize_disp) {\n        if (axis=='x') disp.resize(cimg_fitscreen(sum_width,max_height,1),false);\n        else disp.resize(cimg_fitscreen(max_width,sum_height,1),false);\n      }\n\n      const unsigned int old_normalization = disp.normalization();\n      bool old_is_resized = disp.is_resized();\n      disp._normalization = 0;\n      disp.show().set_key(0);\n      static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 };\n\n      // Enter event loop.\n      CImg<ucharT> visu0, visu;\n      CImg<uintT> indices;\n      CImg<intT> positions(_width,4,1,1,-1);\n      int oindice0 = -1, oindice1 = -1, indice0 = -1, indice1 = -1;\n      bool is_clicked = false, is_selected = false, text_down = false, update_display = true;\n      unsigned int key = 0;\n\n      while (!is_selected && !disp.is_closed() && !key) {\n\n        // Create background image.\n        if (!visu0) {\n          visu0.assign(disp._width,disp._height,1,3,0); visu.assign();\n          (indices0.get_resize(axis=='x'?visu0._width:visu0._height,1)).move_to(indices);\n          unsigned int ind = 0;\n          if (axis=='x') for (unsigned int x = 0; x<visu0._width; ) {\n              const unsigned int x0 = x;\n              ind = indices[x];\n              while (x<indices._width && indices[x++]==ind) {}\n              const CImg<T>\n                onexone(1,1,1,1,0),\n                &src = _data[ind]?_data[ind]:onexone;\n              CImg<ucharT> res;\n              src.__get_select(disp,old_normalization,(src._width - 1)/2,(src._height - 1)/2,(src._depth - 1)/2).\n                move_to(res);\n              const unsigned int h = CImgDisplay::_fitscreen(res._width,res._height,1,128,-85,true);\n              res.resize(x - x0,cimg::max(32U,h*disp._height/max_height),1,res._spectrum==1?3:-100);\n              positions(ind,0) = positions(ind,2) = (int)x0;\n              positions(ind,1) = positions(ind,3) = (int)(align*(visu0.height() - res.height()));\n              positions(ind,2)+=res._width;\n              positions(ind,3)+=res._height - 1;\n              visu0.draw_image(positions(ind,0),positions(ind,1),res);\n            } else for (unsigned int y = 0; y<visu0._height; ) {\n              const unsigned int y0 = y;\n              ind = indices[y];\n              while (y<visu0._height && indices[++y]==ind) {}\n              const CImg<T> &src = _data[ind];\n              const CImg<Tuchar>\n                img2d = src._depth>1?src.get_projections2d((src._width - 1)/2,(src._height - 1)/2,(src._depth - 1)/2):\n                cimg::type<Tuchar>::string()==cimg::type<T>::string()?src.get_shared():src;\n              CImg<ucharT> res = old_normalization==1 ||\n                (old_normalization==3 && cimg::type<T>::string()!=cimg::type<unsigned char>::string())?\n                CImg<ucharT>(img2d.get_normalize(0,255)):\n                CImg<ucharT>(img2d);\n              if (res._spectrum>3) res.channels(0,2);\n              const unsigned int w = CImgDisplay::_fitscreen(res._width,res._height,1,128,-85,false);\n              res.resize(cimg::max(32U,w*disp._width/max_width),y - y0,1,res._spectrum==1?3:-100);\n              positions(ind,0) = positions(ind,2) = (int)(align*(visu0.width() - res.width()));\n              positions(ind,1) = positions(ind,3) = (int)y0;\n              positions(ind,2)+=res._width - 1;\n              positions(ind,3)+=res._height;\n              visu0.draw_image(positions(ind,0),positions(ind,1),res);\n            }\n          if (axis=='x') --positions(ind,2); else --positions(ind,3);\n          update_display = true;\n        }\n\n        if (!visu || oindice0!=indice0 || oindice1!=indice1) {\n          if (indice0>=0 && indice1>=0) {\n            visu.assign(visu0,false);\n            const int indm = cimg::min(indice0,indice1), indM = cimg::max(indice0,indice1);\n            for (int ind = indm; ind<=indM; ++ind) if (positions(ind,0)>=0) {\n                visu.draw_rectangle(positions(ind,0),positions(ind,1),positions(ind,2),positions(ind,3),\n                                    background_color,0.2f);\n                if ((axis=='x' && positions(ind,2) - positions(ind,0)>=8) ||\n                    (axis!='x' && positions(ind,3) - positions(ind,1)>=8))\n                  visu.draw_rectangle(positions(ind,0),positions(ind,1),positions(ind,2),positions(ind,3),\n                                      foreground_color,0.9f,0xAAAAAAAA);\n              }\n            const int yt = (int)text_down?visu.height() - 13:0;\n            if (is_clicked) visu.draw_text(0,yt,\" Images #%u - #%u, Size = %u\",\n                                           foreground_color,background_color,0.7f,13,\n                                           orig + indm,orig + indM,indM - indm + 1);\n            else visu.draw_text(0,yt,\" Image #%u (%u,%u,%u,%u)\",foreground_color,background_color,0.7f,13,\n                                orig + indice0,\n                                _data[indice0]._width,\n                                _data[indice0]._height,\n                                _data[indice0]._depth,\n                                _data[indice0]._spectrum);\n            update_display = true;\n          } else visu.assign();\n        }\n        if (!visu) { visu.assign(visu0,true); update_display = true; }\n        if (update_display) { visu.display(disp); update_display = false; }\n        disp.wait();\n\n        // Manage user events.\n        const int xm = disp.mouse_x(), ym = disp.mouse_y();\n        int indice = -1;\n\n        if (xm>=0) {\n          indice = (int)indices(axis=='x'?xm:ym);\n          if (disp.button()&1) {\n            if (!is_clicked) { is_clicked = true; oindice0 = indice0; indice0 = indice; }\n            oindice1 = indice1; indice1 = indice;\n            if (!feature_type) is_selected = true;\n          } else {\n            if (!is_clicked) { oindice0 = oindice1 = indice0; indice0 = indice1 = indice; }\n            else is_selected = true;\n          }\n        } else {\n          if (is_clicked) {\n            if (!(disp.button()&1)) { is_clicked = is_selected = false; indice0 = indice1 = -1; }\n            else indice1 = -1;\n          } else indice0 = indice1 = -1;\n        }\n\n        if (disp.button()&4) { is_clicked = is_selected = false; indice0 = indice1 = -1; }\n        if (disp.button()&2 && exit_on_rightbutton) { is_selected = true; indice1 = indice0 = -1; }\n        if (disp.wheel() && exit_on_wheel) is_selected = true;\n\n        CImg<charT> filename(32);\n        switch (key = disp.key()) {\n#if cimg_OS!=2\n        case cimg::keyCTRLRIGHT :\n#endif\n        case 0 : case cimg::keyCTRLLEFT : key = 0; break;\n        case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).\n              resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false),\n                     CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false).\n              _is_resized = true;\n            disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).\n              resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true;\n            disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.set_fullscreen(false).\n              resize(cimg_fitscreen(axis=='x'?sum_width:max_width,axis=='x'?max_height:sum_height,1),false).\n              _is_resized = true;\n            disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true;\n            disp.set_key(key,false); key = 0; visu0.assign();\n          } break;\n        case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            static unsigned int snap_number = 0;\n            std::FILE *file;\n            do {\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.bmp\",snap_number++);\n              if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n            } while (file);\n            if (visu0) {\n              (+visu0).draw_text(0,0,\" Saving snapshot... \",\n                                 foreground_color,background_color,0.7f,13).display(disp);\n              visu0.save(filename);\n              (+visu0).draw_text(0,0,\" Snapshot '%s' saved. \",\n                                 foreground_color,background_color,0.7f,13,filename._data).display(disp);\n            }\n            disp.set_key(key,false).wait(); key = 0;\n          } break;\n        case cimg::keyO :\n          if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {\n            static unsigned int snap_number = 0;\n            std::FILE *file;\n            do {\n#ifdef cimg_use_zlib\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.cimgz\",snap_number++);\n#else\n              cimg_snprintf(filename,filename._width,cimg_appname \"_%.4u.cimg\",snap_number++);\n#endif\n              if ((file=std::fopen(filename,\"r\"))!=0) cimg::fclose(file);\n            } while (file);\n            (+visu0).draw_text(0,0,\" Saving instance... \",\n                               foreground_color,background_color,0.7f,13).display(disp);\n            save(filename);\n            (+visu0).draw_text(0,0,\" Instance '%s' saved. \",\n                               foreground_color,background_color,0.7f,13,filename._data).display(disp);\n            disp.set_key(key,false).wait(); key = 0;\n          } break;\n        }\n        if (disp.is_resized()) { disp.resize(false); visu0.assign(); }\n        if (ym>=0 && ym<13) { if (!text_down) { visu.assign(); text_down = true; }}\n        else if (ym>=visu.height() - 13) { if(text_down) { visu.assign(); text_down = false; }}\n        if (!exit_on_anykey && key && key!=cimg::keyESC &&\n            (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {\n          key = 0;\n        }\n      }\n      CImg<intT> res(1,2,1,1,-1);\n      if (is_selected) {\n        if (feature_type) res.fill(cimg::min(indice0,indice1),cimg::max(indice0,indice1));\n        else res.fill(indice0);\n      }\n      if (!(disp.button()&2)) disp.set_button();\n      disp._normalization = old_normalization;\n      disp._is_resized = old_is_resized;\n      disp.set_key(key);\n      return res;\n    }\n\n    //! Load a list from a file.\n    /**\n     \\param filename Filename to read data from.\n    **/\n    CImgList<T>& load(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load(): Specified filename is (null).\",\n                                    cimglist_instance);\n\n      if (!cimg::strncasecmp(filename,\"http://\",7) || !cimg::strncasecmp(filename,\"https://\",8)) {\n        CImg<charT> filename_local(256);\n        load(cimg::load_network(filename,filename_local));\n        std::remove(filename_local);\n        return *this;\n      }\n\n      const bool is_stdin = *filename=='-' && (!filename[1] || filename[1]=='.');\n      const char *const ext = cimg::split_filename(filename);\n      const unsigned int omode = cimg::exception_mode();\n      cimg::exception_mode(0);\n      try {\n#ifdef cimglist_load_plugin\n        cimglist_load_plugin(filename);\n#endif\n#ifdef cimglist_load_plugin1\n        cimglist_load_plugin1(filename);\n#endif\n#ifdef cimglist_load_plugin2\n        cimglist_load_plugin2(filename);\n#endif\n#ifdef cimglist_load_plugin3\n        cimglist_load_plugin3(filename);\n#endif\n#ifdef cimglist_load_plugin4\n        cimglist_load_plugin4(filename);\n#endif\n#ifdef cimglist_load_plugin5\n        cimglist_load_plugin5(filename);\n#endif\n#ifdef cimglist_load_plugin6\n        cimglist_load_plugin6(filename);\n#endif\n#ifdef cimglist_load_plugin7\n        cimglist_load_plugin7(filename);\n#endif\n#ifdef cimglist_load_plugin8\n        cimglist_load_plugin8(filename);\n#endif\n        if (!cimg::strcasecmp(ext,\"tif\") ||\n            !cimg::strcasecmp(ext,\"tiff\")) load_tiff(filename);\n        else if (!cimg::strcasecmp(ext,\"gif\")) load_gif_external(filename);\n        else if (!cimg::strcasecmp(ext,\"cimg\") ||\n                 !cimg::strcasecmp(ext,\"cimgz\") ||\n                 !*ext) load_cimg(filename);\n        else if (!cimg::strcasecmp(ext,\"rec\") ||\n                 !cimg::strcasecmp(ext,\"par\")) load_parrec(filename);\n        else if (!cimg::strcasecmp(ext,\"avi\") ||\n                 !cimg::strcasecmp(ext,\"mov\") ||\n                 !cimg::strcasecmp(ext,\"asf\") ||\n                 !cimg::strcasecmp(ext,\"divx\") ||\n                 !cimg::strcasecmp(ext,\"flv\") ||\n                 !cimg::strcasecmp(ext,\"mpg\") ||\n                 !cimg::strcasecmp(ext,\"m1v\") ||\n                 !cimg::strcasecmp(ext,\"m2v\") ||\n                 !cimg::strcasecmp(ext,\"m4v\") ||\n                 !cimg::strcasecmp(ext,\"mjp\") ||\n                 !cimg::strcasecmp(ext,\"mp4\") ||\n                 !cimg::strcasecmp(ext,\"mkv\") ||\n                 !cimg::strcasecmp(ext,\"mpe\") ||\n                 !cimg::strcasecmp(ext,\"movie\") ||\n                 !cimg::strcasecmp(ext,\"ogm\") ||\n                 !cimg::strcasecmp(ext,\"ogg\") ||\n                 !cimg::strcasecmp(ext,\"ogv\") ||\n                 !cimg::strcasecmp(ext,\"qt\") ||\n                 !cimg::strcasecmp(ext,\"rm\") ||\n                 !cimg::strcasecmp(ext,\"vob\") ||\n                 !cimg::strcasecmp(ext,\"wmv\") ||\n                 !cimg::strcasecmp(ext,\"xvid\") ||\n                 !cimg::strcasecmp(ext,\"mpeg\")) load_video(filename);\n        else if (!cimg::strcasecmp(ext,\"gz\")) load_gzip_external(filename);\n        else throw CImgIOException(\"CImgList<%s>::load()\",\n                                   pixel_type());\n      } catch (CImgIOException&) {\n        std::FILE *file = 0;\n        if (!is_stdin) try {\n            file = cimg::fopen(filename,\"rb\");\n          } catch (CImgIOException&) {\n            cimg::exception_mode(omode);\n            throw CImgIOException(_cimglist_instance\n                                  \"load(): Failed to open file '%s'.\",\n                                  cimglist_instance,\n                                  filename);\n          }\n\n        try {\n          if (!is_stdin) {\n            const char *const f_type = cimg::ftype(file,filename);\n            std::fclose(file);\n            if (!cimg::strcasecmp(f_type,\"gif\")) load_gif_external(filename);\n            else if (!cimg::strcasecmp(f_type,\"tif\")) load_tiff(filename);\n            else throw CImgIOException(\"CImgList<%s>::load()\",\n                                       pixel_type());\n          } else throw CImgIOException(\"CImgList<%s>::load()\",\n                                       pixel_type());\n        } catch (CImgIOException&) {\n          assign(1);\n          try {\n            _data->load(filename);\n          } catch (CImgIOException&) {\n            cimg::exception_mode(omode);\n          throw CImgIOException(_cimglist_instance\n                                \"load(): Failed to recognize format of file '%s'.\",\n                                cimglist_instance,\n                                filename);\n          }\n        }\n      }\n      cimg::exception_mode(omode);\n      return *this;\n    }\n\n    //! Load a list from a file \\newinstance.\n    static CImgList<T> get_load(const char *const filename) {\n      return CImgList<T>().load(filename);\n    }\n\n    //! Load a list from a .cimg file.\n    /**\n      \\param filename Filename to read data from.\n    **/\n    CImgList<T>& load_cimg(const char *const filename) {\n      return _load_cimg(0,filename);\n    }\n\n    //! Load a list from a .cimg file \\newinstance.\n    static CImgList<T> get_load_cimg(const char *const filename) {\n      return CImgList<T>().load_cimg(filename);\n    }\n\n    //! Load a list from a .cimg file.\n    /**\n      \\param file File to read data from.\n    **/\n    CImgList<T>& load_cimg(std::FILE *const file) {\n      return _load_cimg(file,0);\n    }\n\n    //! Load a list from a .cimg file \\newinstance.\n    static CImgList<T> get_load_cimg(std::FILE *const file) {\n      return CImgList<T>().load_cimg(file);\n    }\n\n    CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename) {\n#ifdef cimg_use_zlib\n#define _cimgz_load_cimg_case(Tss) { \\\n   Bytef *const cbuf = new Bytef[csiz]; \\\n   cimg::fread(cbuf,csiz,nfile); \\\n   raw.assign(W,H,D,C); \\\n   uLongf destlen = (ulongT)raw.size()*sizeof(Tss); \\\n   uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \\\n   delete[] cbuf; \\\n   if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \\\n   raw.move_to(img); \\\n}\n#else\n#define _cimgz_load_cimg_case(Tss) \\\n   throw CImgIOException(_cimglist_instance \\\n                         \"load_cimg(): Unable to load compressed data from file '%s' unless zlib is enabled.\", \\\n                         cimglist_instance, \\\n                         filename?filename:\"(FILE*)\");\n#endif\n\n#define _cimg_load_cimg_case(Ts,Tss) \\\n      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \\\n        for (unsigned int l = 0; l<N; ++l) { \\\n          j = 0; while ((i=std::fgetc(nfile))!='\\n' && i>=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0; \\\n          W = H = D = C = 0; csiz = 0; \\\n          if ((err = cimg_sscanf(tmp,\"%u %u %u %u #%lu\",&W,&H,&D,&C,&csiz))<4) \\\n            throw CImgIOException(_cimglist_instance \\\n                                  \"load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'.\", \\\n                                  cimglist_instance, \\\n                                  W,H,D,C,l,filename?filename:(\"(FILE*)\")); \\\n          if (W*H*D*C>0) { \\\n            CImg<Tss> raw; \\\n            CImg<T> &img = _data[l]; \\\n            if (err==5) _cimgz_load_cimg_case(Tss) \\\n            else { \\\n              img.assign(W,H,D,C); \\\n              T *ptrd = img._data; \\\n              for (ulongT to_read = img.size(); to_read; ) { \\\n                raw.assign((unsigned int)cimg::min(to_read,cimg_iobuffer)); \\\n                cimg::fread(raw._data,raw._width,nfile); \\\n                if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \\\n                const Tss *ptrs = raw._data; \\\n                for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \\\n                to_read-=raw._width; \\\n              } \\\n            } \\\n          } \\\n        } \\\n        loaded = true; \\\n      }\n\n      if (!filename && !file)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_cimg(): Specified filename is (null).\",\n                                    cimglist_instance);\n\n      const ulongT cimg_iobuffer = (ulongT)24*1024*1024;\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      bool loaded = false, endian = cimg::endianness();\n      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);\n      *tmp = *str_pixeltype = *str_endian = 0;\n      unsigned int j, N = 0, W, H, D, C;\n      ulongT csiz;\n      int i, err;\n      do {\n        j = 0; while ((i=std::fgetc(nfile))!='\\n' && i>=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0;\n      } while (*tmp=='#' && i>=0);\n      err = cimg_sscanf(tmp,\"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]\",\n                        &N,str_pixeltype._data,str_endian._data);\n      if (err<2) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimglist_instance\n                              \"load_cimg(): CImg header not found in file '%s'.\",\n                              cimglist_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      if (!cimg::strncasecmp(\"little\",str_endian,6)) endian = false;\n      else if (!cimg::strncasecmp(\"big\",str_endian,3)) endian = true;\n      assign(N);\n      _cimg_load_cimg_case(\"bool\",bool);\n      _cimg_load_cimg_case(\"unsigned_char\",unsigned char);\n      _cimg_load_cimg_case(\"uchar\",unsigned char);\n      _cimg_load_cimg_case(\"char\",char);\n      _cimg_load_cimg_case(\"unsigned_short\",unsigned short);\n      _cimg_load_cimg_case(\"ushort\",unsigned short);\n      _cimg_load_cimg_case(\"short\",short);\n      _cimg_load_cimg_case(\"unsigned_int\",unsigned int);\n      _cimg_load_cimg_case(\"uint\",unsigned int);\n      _cimg_load_cimg_case(\"int\",int);\n      _cimg_load_cimg_case(\"unsigned_long\",ulongT);\n      _cimg_load_cimg_case(\"ulong\",ulongT);\n      _cimg_load_cimg_case(\"long\",longT);\n      _cimg_load_cimg_case(\"unsigned_int64\",uint64T);\n      _cimg_load_cimg_case(\"uint64\",uint64T);\n      _cimg_load_cimg_case(\"int64\",int64T);\n      _cimg_load_cimg_case(\"float\",float);\n      _cimg_load_cimg_case(\"double\",double);\n\n      if (!loaded) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimglist_instance\n                              \"load_cimg(): Unsupported pixel type '%s' for file '%s'.\",\n                              cimglist_instance,\n                              str_pixeltype._data,filename?filename:\"(FILE*)\");\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load a sublist list from a (non compressed) .cimg file.\n    /**\n      \\param filename Filename to read data from.\n      \\param n0 Starting index of images to read (~0U for max).\n      \\param n1 Ending index of images to read (~0U for max).\n      \\param x0 Starting X-coordinates of image regions to read.\n      \\param y0 Starting Y-coordinates of image regions to read.\n      \\param z0 Starting Z-coordinates of image regions to read.\n      \\param c0 Starting C-coordinates of image regions to read.\n      \\param x1 Ending X-coordinates of image regions to read (~0U for max).\n      \\param y1 Ending Y-coordinates of image regions to read (~0U for max).\n      \\param z1 Ending Z-coordinates of image regions to read (~0U for max).\n      \\param c1 Ending C-coordinates of image regions to read (~0U for max).\n    **/\n    CImgList<T>& load_cimg(const char *const filename,\n                           const unsigned int n0, const unsigned int n1,\n                           const unsigned int x0, const unsigned int y0,\n                           const unsigned int z0, const unsigned int c0,\n                           const unsigned int x1, const unsigned int y1,\n                           const unsigned int z1, const unsigned int c1) {\n      return _load_cimg(0,filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);\n    }\n\n    //! Load a sublist list from a (non compressed) .cimg file \\newinstance.\n    static CImgList<T> get_load_cimg(const char *const filename,\n                                     const unsigned int n0, const unsigned int n1,\n                                     const unsigned int x0, const unsigned int y0,\n                                     const unsigned int z0, const unsigned int c0,\n                                     const unsigned int x1, const unsigned int y1,\n                                     const unsigned int z1, const unsigned int c1) {\n      return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);\n    }\n\n    //! Load a sub-image list from a (non compressed) .cimg file \\overloading.\n    CImgList<T>& load_cimg(std::FILE *const file,\n                           const unsigned int n0, const unsigned int n1,\n                           const unsigned int x0, const unsigned int y0,\n                           const unsigned int z0, const unsigned int c0,\n                           const unsigned int x1, const unsigned int y1,\n                           const unsigned int z1, const unsigned int c1) {\n      return _load_cimg(file,0,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);\n    }\n\n    //! Load a sub-image list from a (non compressed) .cimg file \\newinstance.\n    static CImgList<T> get_load_cimg(std::FILE *const file,\n                                     const unsigned int n0, const unsigned int n1,\n                                     const unsigned int x0, const unsigned int y0,\n                                     const unsigned int z0, const unsigned int c0,\n                                     const unsigned int x1, const unsigned int y1,\n                                     const unsigned int z1, const unsigned int c1) {\n      return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);\n    }\n\n    CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename,\n                            const unsigned int n0, const unsigned int n1,\n                            const unsigned int x0, const unsigned int y0,\n                            const unsigned int z0, const unsigned int c0,\n                            const unsigned int x1, const unsigned int y1,\n                            const unsigned int z1, const unsigned int c1) {\n#define _cimg_load_cimg_case2(Ts,Tss) \\\n      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \\\n        for (unsigned int l = 0; l<=nn1; ++l) { \\\n          j = 0; while ((i=std::fgetc(nfile))!='\\n' && i>=0) tmp[j++] = (char)i; tmp[j] = 0; \\\n          W = H = D = C = 0; \\\n          if (cimg_sscanf(tmp,\"%u %u %u %u\",&W,&H,&D,&C)!=4) \\\n            throw CImgIOException(_cimglist_instance \\\n                                  \"load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'\", \\\n                                  cimglist_instance, \\\n                                  W,H,D,C,l,filename?filename:\"(FILE*)\"); \\\n          if (W*H*D*C>0) { \\\n            if (l<nn0 || nx0>=W || ny0>=H || nz0>=D || nc0>=C) cimg::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \\\n            else { \\\n              const unsigned int \\\n                _nx1 = nx1==~0U?W - 1:nx1, \\\n                _ny1 = ny1==~0U?H - 1:ny1, \\\n                _nz1 = nz1==~0U?D - 1:nz1, \\\n                _nc1 = nc1==~0U?C - 1:nc1; \\\n              if (_nx1>=W || _ny1>=H || _nz1>=D || _nc1>=C) \\\n                throw CImgArgumentException(_cimglist_instance \\\n                                            \"load_cimg(): Invalid specified coordinates \" \\\n                                            \"[%u](%u,%u,%u,%u) -> [%u](%u,%u,%u,%u) \" \\\n                                            \"because image [%u] in file '%s' has size (%u,%u,%u,%u).\", \\\n                                            cimglist_instance, \\\n                                            n0,x0,y0,z0,c0,n1,x1,y1,z1,c1,l,filename?filename:\"(FILE*)\",W,H,D,C); \\\n              CImg<Tss> raw(1 + _nx1 - nx0); \\\n              CImg<T> &img = _data[l - nn0]; \\\n              img.assign(1 + _nx1 - nx0,1 + _ny1 - ny0,1 + _nz1 - nz0,1 + _nc1 - nc0); \\\n              T *ptrd = img._data; \\\n              ulongT skipvb = nc0*W*H*D*sizeof(Tss); \\\n              if (skipvb) cimg::fseek(nfile,skipvb,SEEK_CUR); \\\n              for (unsigned int c = 1 + _nc1 - nc0; c; --c) { \\\n                const ulongT skipzb = nz0*W*H*sizeof(Tss); \\\n                if (skipzb) cimg::fseek(nfile,skipzb,SEEK_CUR); \\\n                for (unsigned int z = 1 + _nz1 - nz0; z; --z) { \\\n                  const ulongT skipyb = ny0*W*sizeof(Tss); \\\n                  if (skipyb) cimg::fseek(nfile,skipyb,SEEK_CUR); \\\n                  for (unsigned int y = 1 + _ny1 - ny0; y; --y) { \\\n                    const ulongT skipxb = nx0*sizeof(Tss); \\\n                    if (skipxb) cimg::fseek(nfile,skipxb,SEEK_CUR); \\\n                    cimg::fread(raw._data,raw._width,nfile); \\\n                    if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); \\\n                    const Tss *ptrs = raw._data; \\\n                    for (unsigned int off = raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \\\n                    const ulongT skipxe = (W - 1 - _nx1)*sizeof(Tss); \\\n                    if (skipxe) cimg::fseek(nfile,skipxe,SEEK_CUR); \\\n                  } \\\n                  const ulongT skipye = (H - 1 - _ny1)*W*sizeof(Tss); \\\n                  if (skipye) cimg::fseek(nfile,skipye,SEEK_CUR); \\\n                } \\\n                const ulongT skipze = (D - 1 - _nz1)*W*H*sizeof(Tss); \\\n                if (skipze) cimg::fseek(nfile,skipze,SEEK_CUR); \\\n              } \\\n              const ulongT skipve = (C - 1 - _nc1)*W*H*D*sizeof(Tss); \\\n              if (skipve) cimg::fseek(nfile,skipve,SEEK_CUR); \\\n            } \\\n          } \\\n        } \\\n        loaded = true; \\\n      }\n\n      if (!filename && !file)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_cimg(): Specified filename is (null).\",\n                                    cimglist_instance);\n      unsigned int\n        nn0 = cimg::min(n0,n1), nn1 = cimg::max(n0,n1),\n        nx0 = cimg::min(x0,x1), nx1 = cimg::max(x0,x1),\n        ny0 = cimg::min(y0,y1), ny1 = cimg::max(y0,y1),\n        nz0 = cimg::min(z0,z1), nz1 = cimg::max(z0,z1),\n        nc0 = cimg::min(c0,c1), nc1 = cimg::max(c0,c1);\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      bool loaded = false, endian = cimg::endianness();\n      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);\n      *tmp = *str_pixeltype = *str_endian = 0;\n      unsigned int j, N, W, H, D, C;\n      int i, err;\n      j = 0; while ((i=std::fgetc(nfile))!='\\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;\n      err = cimg_sscanf(tmp,\"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]\",\n                        &N,str_pixeltype._data,str_endian._data);\n      if (err<2) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimglist_instance\n                              \"load_cimg(): CImg header not found in file '%s'.\",\n                              cimglist_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      if (!cimg::strncasecmp(\"little\",str_endian,6)) endian = false;\n      else if (!cimg::strncasecmp(\"big\",str_endian,3)) endian = true;\n      nn1 = n1==~0U?N - 1:n1;\n      if (nn1>=N)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_cimg(): Invalid specified coordinates [%u](%u,%u,%u,%u) -> [%u](%u,%u,%u,%u) \"\n                                    \"because file '%s' contains only %u images.\",\n                                    cimglist_instance,\n                                    n0,x0,y0,z0,c0,n1,x1,y1,z1,c1,filename?filename:\"(FILE*)\",N);\n      assign(1 + nn1 - n0);\n      _cimg_load_cimg_case2(\"bool\",bool);\n      _cimg_load_cimg_case2(\"unsigned_char\",unsigned char);\n      _cimg_load_cimg_case2(\"uchar\",unsigned char);\n      _cimg_load_cimg_case2(\"char\",char);\n      _cimg_load_cimg_case2(\"unsigned_short\",unsigned short);\n      _cimg_load_cimg_case2(\"ushort\",unsigned short);\n      _cimg_load_cimg_case2(\"short\",short);\n      _cimg_load_cimg_case2(\"unsigned_int\",unsigned int);\n      _cimg_load_cimg_case2(\"uint\",unsigned int);\n      _cimg_load_cimg_case2(\"int\",int);\n      _cimg_load_cimg_case2(\"unsigned_long\",ulongT);\n      _cimg_load_cimg_case2(\"ulong\",ulongT);\n      _cimg_load_cimg_case2(\"long\",longT);\n      _cimg_load_cimg_case2(\"unsigned_int64\",uint64T);\n      _cimg_load_cimg_case2(\"uint64\",uint64T);\n      _cimg_load_cimg_case2(\"int64\",int64T);\n      _cimg_load_cimg_case2(\"float\",float);\n      _cimg_load_cimg_case2(\"double\",double);\n      if (!loaded) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimglist_instance\n                              \"load_cimg(): Unsupported pixel type '%s' for file '%s'.\",\n                              cimglist_instance,\n                              str_pixeltype._data,filename?filename:\"(FILE*)\");\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load a list from a PAR/REC (Philips) file.\n    /**\n      \\param filename Filename to read data from.\n    **/\n    CImgList<T>& load_parrec(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_parrec(): Specified filename is (null).\",\n                                    cimglist_instance);\n\n      CImg<charT> body(1024), filenamepar(1024), filenamerec(1024);\n      *body = *filenamepar = *filenamerec = 0;\n      const char *const ext = cimg::split_filename(filename,body);\n      if (!std::strcmp(ext,\"par\")) {\n        std::strncpy(filenamepar,filename,filenamepar._width - 1);\n        cimg_snprintf(filenamerec,filenamerec._width,\"%s.rec\",body._data);\n      }\n      if (!std::strcmp(ext,\"PAR\")) {\n        std::strncpy(filenamepar,filename,filenamepar._width - 1);\n        cimg_snprintf(filenamerec,filenamerec._width,\"%s.REC\",body._data);\n      }\n      if (!std::strcmp(ext,\"rec\")) {\n        std::strncpy(filenamerec,filename,filenamerec._width - 1);\n        cimg_snprintf(filenamepar,filenamepar._width,\"%s.par\",body._data);\n      }\n      if (!std::strcmp(ext,\"REC\")) {\n        std::strncpy(filenamerec,filename,filenamerec._width - 1);\n        cimg_snprintf(filenamepar,filenamepar._width,\"%s.PAR\",body._data);\n      }\n      std::FILE *file = cimg::fopen(filenamepar,\"r\");\n\n      // Parse header file\n      CImgList<floatT> st_slices;\n      CImgList<uintT> st_global;\n      CImg<charT> line(256); *line = 0;\n      int err;\n      do { err = std::fscanf(file,\"%255[^\\n]%*c\",line._data); } while (err!=EOF && (*line=='#' || *line=='.'));\n      do {\n        unsigned int sn,size_x,size_y,pixsize;\n        float rs,ri,ss;\n        err = std::fscanf(file,\"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\\n]\",&sn,&pixsize,&size_x,&size_y,&ri,&rs,&ss);\n        if (err==7) {\n          CImg<floatT>::vector((float)sn,(float)pixsize,(float)size_x,(float)size_y,ri,rs,ss,0).move_to(st_slices);\n          unsigned int i; for (i = 0; i<st_global._width && sn<=st_global[i][2]; ++i) {}\n          if (i==st_global._width) CImg<uintT>::vector(size_x,size_y,sn).move_to(st_global);\n          else {\n            CImg<uintT> &vec = st_global[i];\n            if (size_x>vec[0]) vec[0] = size_x;\n            if (size_y>vec[1]) vec[1] = size_y;\n            vec[2] = sn;\n          }\n          st_slices[st_slices._width - 1][7] = (float)i;\n        }\n      } while (err==7);\n\n      // Read data\n      std::FILE *file2 = cimg::fopen(filenamerec,\"rb\");\n      cimglist_for(st_global,l) {\n        const CImg<uintT>& vec = st_global[l];\n        CImg<T>(vec[0],vec[1],vec[2]).move_to(*this);\n      }\n\n      cimglist_for(st_slices,l) {\n        const CImg<floatT>& vec = st_slices[l];\n        const unsigned int\n          sn = (unsigned int)vec[0] - 1,\n          pixsize = (unsigned int)vec[1],\n          size_x = (unsigned int)vec[2],\n          size_y = (unsigned int)vec[3],\n          imn = (unsigned int)vec[7];\n        const float ri = vec[4], rs = vec[5], ss = vec[6];\n        switch (pixsize) {\n        case 8 : {\n          CImg<ucharT> buf(size_x,size_y);\n          cimg::fread(buf._data,size_x*size_y,file2);\n          if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y);\n          CImg<T>& img = (*this)[imn];\n          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));\n        } break;\n        case 16 : {\n          CImg<ushortT> buf(size_x,size_y);\n          cimg::fread(buf._data,size_x*size_y,file2);\n          if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y);\n          CImg<T>& img = (*this)[imn];\n          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));\n        } break;\n        case 32 : {\n          CImg<uintT> buf(size_x,size_y);\n          cimg::fread(buf._data,size_x*size_y,file2);\n          if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y);\n          CImg<T>& img = (*this)[imn];\n          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));\n        } break;\n        default :\n          cimg::fclose(file);\n          cimg::fclose(file2);\n          throw CImgIOException(_cimglist_instance\n                                \"load_parrec(): Unsupported %d-bits pixel type for file '%s'.\",\n                                cimglist_instance,\n                                pixsize,filename);\n        }\n      }\n      cimg::fclose(file);\n      cimg::fclose(file2);\n      if (!_width)\n        throw CImgIOException(_cimglist_instance\n                              \"load_parrec(): Failed to recognize valid PAR-REC data in file '%s'.\",\n                              cimglist_instance,\n                              filename);\n      return *this;\n    }\n\n    //! Load a list from a PAR/REC (Philips) file \\newinstance.\n    static CImgList<T> get_load_parrec(const char *const filename) {\n      return CImgList<T>().load_parrec(filename);\n    }\n\n    //! Load a list from a YUV image sequence file.\n    /**\n        \\param filename Filename to read data from.\n        \\param size_x Width of the images.\n        \\param size_y Height of the images.\n        \\param first_frame Index of first image frame to read.\n        \\param last_frame Index of last image frame to read.\n        \\param step_frame Step applied between each frame.\n        \\param yuv2rgb Apply YUV to RGB transformation during reading.\n    **/\n    CImgList<T>& load_yuv(const char *const filename,\n                          const unsigned int size_x, const unsigned int size_y,\n                          const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                          const unsigned int step_frame=1, const bool yuv2rgb=true) {\n      return _load_yuv(0,filename,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb);\n    }\n\n    //! Load a list from a YUV image sequence file \\newinstance.\n    static CImgList<T> get_load_yuv(const char *const filename,\n                                    const unsigned int size_x, const unsigned int size_y=1,\n                                    const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                                    const unsigned int step_frame=1, const bool yuv2rgb=true) {\n      return CImgList<T>().load_yuv(filename,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb);\n    }\n\n    //! Load a list from an image sequence YUV file \\overloading.\n    CImgList<T>& load_yuv(std::FILE *const file,\n                          const unsigned int size_x, const unsigned int size_y,\n                          const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                          const unsigned int step_frame=1, const bool yuv2rgb=true) {\n      return _load_yuv(file,0,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb);\n    }\n\n    //! Load a list from an image sequence YUV file \\newinstance.\n    static CImgList<T> get_load_yuv(std::FILE *const file,\n                                    const unsigned int size_x, const unsigned int size_y=1,\n                                    const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                                    const unsigned int step_frame=1, const bool yuv2rgb=true) {\n      return CImgList<T>().load_yuv(file,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb);\n    }\n\n    CImgList<T>& _load_yuv(std::FILE *const file, const char *const filename,\n                           const unsigned int size_x, const unsigned int size_y,\n                           const unsigned int first_frame, const unsigned int last_frame,\n                           const unsigned int step_frame, const bool yuv2rgb) {\n      if (!filename && !file)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_yuv(): Specified filename is (null).\",\n                                    cimglist_instance);\n      if (size_x%2 || size_y%2)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_yuv(): Invalid odd XY dimensions %ux%u in file '%s'.\",\n                                    cimglist_instance,\n                                    size_x,size_y,filename?filename:\"(FILE*)\");\n      if (!size_x || !size_y)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_yuv(): Invalid sequence size (%u,%u) in file '%s'.\",\n                                    cimglist_instance,\n                                    size_x,size_y,filename?filename:\"(FILE*)\");\n\n      const unsigned int\n        nfirst_frame = first_frame<last_frame?first_frame:last_frame,\n        nlast_frame = first_frame<last_frame?last_frame:first_frame,\n        nstep_frame = step_frame?step_frame:1;\n\n      CImg<ucharT> tmp(size_x,size_y,1,3), UV(size_x/2,size_y/2,1,2);\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb\");\n      bool stop_flag = false;\n      int err;\n      if (nfirst_frame) {\n        err = cimg::fseek(nfile,nfirst_frame*(size_x*size_y + size_x*size_y/2),SEEK_CUR);\n        if (err) {\n          if (!file) cimg::fclose(nfile);\n          throw CImgIOException(_cimglist_instance\n                                \"load_yuv(): File '%s' doesn't contain frame number %u.\",\n                                cimglist_instance,\n                                filename?filename:\"(FILE*)\",nfirst_frame);\n        }\n      }\n      unsigned int frame;\n      for (frame = nfirst_frame; !stop_flag && frame<=nlast_frame; frame+=nstep_frame) {\n        tmp.fill(0);\n        // *TRY* to read the luminance part, do not replace by cimg::fread!\n        err = (int)std::fread((void*)(tmp._data),1,(ulongT)tmp._width*tmp._height,nfile);\n        if (err!=(int)(tmp._width*tmp._height)) {\n          stop_flag = true;\n          if (err>0)\n            cimg::warn(_cimglist_instance\n                       \"load_yuv(): File '%s' contains incomplete data or given image dimensions \"\n                       \"(%u,%u) are incorrect.\",\n                       cimglist_instance,\n                       filename?filename:\"(FILE*)\",size_x,size_y);\n        } else {\n          UV.fill(0);\n          // *TRY* to read the luminance part, do not replace by cimg::fread!\n          err = (int)std::fread((void*)(UV._data),1,(size_t)(UV.size()),nfile);\n          if (err!=(int)(UV.size())) {\n            stop_flag = true;\n            if (err>0)\n              cimg::warn(_cimglist_instance\n                         \"load_yuv(): File '%s' contains incomplete data or given image dimensions (%u,%u) \"\n                         \"are incorrect.\",\n                         cimglist_instance,\n                         filename?filename:\"(FILE*)\",size_x,size_y);\n          } else {\n            cimg_forXY(UV,x,y) {\n              const int x2 = x*2, y2 = y*2;\n              tmp(x2,y2,1) = tmp(x2 + 1,y2,1) = tmp(x2,y2 + 1,1) = tmp(x2 + 1,y2 + 1,1) = UV(x,y,0);\n              tmp(x2,y2,2) = tmp(x2 + 1,y2,2) = tmp(x2,y2 + 1,2) = tmp(x2 + 1,y2 + 1,2) = UV(x,y,1);\n            }\n            if (yuv2rgb) tmp.YCbCrtoRGB();\n            insert(tmp);\n            if (nstep_frame>1) cimg::fseek(nfile,(nstep_frame - 1)*(size_x*size_y + size_x*size_y/2),SEEK_CUR);\n          }\n        }\n      }\n      if (stop_flag && nlast_frame!=~0U && frame!=nlast_frame)\n        cimg::warn(_cimglist_instance\n                   \"load_yuv(): Frame %d not reached since only %u frames were found in file '%s'.\",\n                   cimglist_instance,\n                   nlast_frame,frame - 1,filename?filename:\"(FILE*)\");\n\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Load an image from a video file, using OpenCV library.\n    /**\n      \\param filename Filename, as a C-string.\n      \\param first_frame Index of the first frame to read.\n      \\param last_frame Index of the last frame to read.\n      \\param step_frame Step value for frame reading.\n      \\note If step_frame==0, the current video stream is forced to be released (without any frames read).\n    **/\n    CImgList<T>& load_video(const char *const filename,\n                            const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                            const unsigned int step_frame=1) {\n#ifndef cimg_use_opencv\n      if (first_frame || last_frame!=~0U || step_frame>1)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_video() : File '%s', arguments 'first_frame', 'last_frame' \"\n                                    \"and 'step_frame' can be only set when using OpenCV \"\n                                    \"(-Dcimg_use_opencv must be enabled).\",\n                                    cimglist_instance,filename);\n      return load_ffmpeg_external(filename);\n#else\n      static CvCapture *captures[32] = { 0 };\n      static CImgList<charT> filenames(32);\n      static CImg<uintT> positions(32,1,1,1,0);\n      static int last_used_index = -1;\n\n      // Detect if a video capture already exists for the specified filename.\n      cimg::mutex(9);\n      int index = -1;\n      if (filename) {\n        if (last_used_index>=0 && !std::strcmp(filename,filenames[last_used_index])) {\n          index = last_used_index;\n        } else cimglist_for(filenames,l) if (filenames[l] && !std::strcmp(filename,filenames[l])) {\n            index = l; break;\n          }\n      } else index = last_used_index;\n      cimg::mutex(9,0);\n\n      // Release stream if needed.\n      if (!step_frame || (index>=0 && positions[index]>first_frame)) {\n        if (index>=0) {\n          cimg::mutex(9);\n          cvReleaseCapture(&captures[index]);\n          captures[index] = 0; filenames[index].assign(); positions[index] = 0;\n          if (last_used_index==index) last_used_index = -1;\n          index = -1;\n          cimg::mutex(9,0);\n        } else\n          if (filename)\n            cimg::warn(_cimglist_instance\n                       \"load_video() : File '%s', no opened video stream associated with filename found.\",\n                       cimglist_instance,filename);\n          else\n            cimg::warn(_cimglist_instance\n                       \"load_video() : No opened video stream found.\",\n                       cimglist_instance,filename);\n        if (!step_frame) return *this;\n      }\n\n      // Find empty slot for capturing video stream.\n      if (index<0) {\n        if (!filename)\n          throw CImgArgumentException(_cimglist_instance\n                                      \"load_video(): No already open video reader found. You must specify a \"\n                                      \"non-(null) filename argument for the first call.\",\n                                      cimglist_instance);\n        else { cimg::mutex(9); cimglist_for(filenames,l) if (!filenames[l]) { index = l; break; } cimg::mutex(9,0); }\n        if (index<0)\n          throw CImgIOException(_cimglist_instance\n                                \"load_video(): File '%s', no video reader slots available. \"\n                                \"You have to release some of your previously opened videos.\",\n                                cimglist_instance,filename);\n        cimg::mutex(9);\n        captures[index] = cvCaptureFromFile(filename);\n        CImg<charT>::string(filename).move_to(filenames[index]);\n        positions[index] = 0;\n        cimg::mutex(9,0);\n        if (!captures[index]) {\n          filenames[index].assign();\n          std::fclose(cimg::fopen(filename,\"rb\"));  // Check file availability.\n          throw CImgIOException(_cimglist_instance\n                                \"load_video(): File '%s', unable to detect format of video file.\",\n                                cimglist_instance,filename);\n        }\n      }\n\n      cimg::mutex(9);\n      const unsigned int nb_frames = (unsigned int)cimg::max(0.,cvGetCaptureProperty(captures[index],\n                                                                                     CV_CAP_PROP_FRAME_COUNT));\n      cimg::mutex(9,0);\n      assign();\n\n      // Skip frames if necessary.\n      unsigned int &pos = positions[index];\n      while (pos<first_frame) {\n        cimg::mutex(9);\n        if (!cvGrabFrame(captures[index])) {\n          cimg::mutex(9,0);\n          throw CImgIOException(_cimglist_instance\n                                \"load_video(): File '%s', unable to locate frame %u.\",\n                                cimglist_instance,filename,first_frame);\n        }\n        cimg::mutex(9,0);\n        ++pos;\n      }\n\n      // Read and convert frames.\n      const unsigned int _last_frame = cimg::min(nb_frames?nb_frames - 1:~0U,last_frame);\n      const IplImage *src = 0;\n      while (pos<=_last_frame) {\n        cimg::mutex(9);\n        src = cvQueryFrame(captures[index]);\n        if (src) {\n          CImg<T> frame(src->width,src->height,1,3);\n          const int step = (int)(src->widthStep - 3*src->width);\n          const unsigned char* ptrs = (unsigned char*)src->imageData;\n          T *ptr_r = frame.data(0,0,0,0), *ptr_g = frame.data(0,0,0,1), *ptr_b = frame.data(0,0,0,2);\n          if (step>0) cimg_forY(frame,y) {\n              cimg_forX(frame,x) { *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++); }\n              ptrs+=step;\n            } else for (ulongT siz = (ulongT)src->width*src->height; siz; --siz) {\n              *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++);\n            }\n          frame.move_to(*this);\n          ++pos;\n\n          bool skip_failed = false;\n          for (unsigned int i = 1; i<step_frame && pos<=_last_frame; ++i, ++pos)\n            if (!cvGrabFrame(captures[index])) { skip_failed = true; break; }\n          if (skip_failed) src = 0;\n        }\n        cimg::mutex(9,0);\n        if (!src) break;\n      }\n\n      if (!src || (nb_frames && pos>=nb_frames)) { // Close video stream when necessary.\n        cimg::mutex(9);\n        cvReleaseCapture(&captures[index]);\n        captures[index] = 0;\n        filenames[index].assign();\n        positions[index] = 0;\n        index = -1;\n        cimg::mutex(9,0);\n      }\n\n      cimg::mutex(9);\n      last_used_index = index;\n      cimg::mutex(9,0);\n      return *this;\n#endif\n    }\n\n    //! Load an image from a video file, using OpenCV library \\newinstance.\n    static CImgList<T> get_load_video(const char *const filename,\n                           const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                           const unsigned int step_frame=1) {\n      return CImgList<T>().load_video(filename,first_frame,last_frame,step_frame);\n    }\n\n    //! Load an image from a video file using the external tool 'ffmpeg'.\n    /**\n      \\param filename Filename to read data from.\n    **/\n    CImgList<T>& load_ffmpeg_external(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_ffmpeg_external(): Specified filename is (null).\",\n                                    cimglist_instance);\n      std::fclose(cimg::fopen(filename,\"rb\"));            // Check if file exists.\n      CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256);\n      std::FILE *file = 0;\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s\",\n                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s_000001.ppm\",filename_tmp._data);\n        if ((file=std::fopen(filename_tmp2,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s_%%6d.ppm\",filename_tmp._data);\n#if cimg_OS!=2\n      cimg_snprintf(command,command._width,\"%s -i \\\"%s\\\" \\\"%s\\\" >/dev/null 2>&1\",\n                    cimg::ffmpeg_path(),\n                    CImg<charT>::string(filename)._system_strescape().data(),\n                    CImg<charT>::string(filename_tmp2)._system_strescape().data());\n#else\n      cimg_snprintf(command,command._width,\"\\\"%s -i \\\"%s\\\" \\\"%s\\\"\\\" >NUL 2>&1\",\n                    cimg::ffmpeg_path(),\n                    CImg<charT>::string(filename)._system_strescape().data(),\n                    CImg<charT>::string(filename_tmp2)._system_strescape().data());\n#endif\n      cimg::system(command,0);\n      const unsigned int omode = cimg::exception_mode();\n      cimg::exception_mode(0);\n      assign();\n      unsigned int i = 1;\n      for (bool stop_flag = false; !stop_flag; ++i) {\n        cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s_%.6u.ppm\",filename_tmp._data,i);\n        CImg<T> img;\n        try { img.load_pnm(filename_tmp2); }\n        catch (CImgException&) { stop_flag = true; }\n        if (img) { img.move_to(*this); std::remove(filename_tmp2); }\n      }\n      cimg::exception_mode(omode);\n      if (is_empty())\n        throw CImgIOException(_cimglist_instance\n                              \"load_ffmpeg_external(): Failed to open file '%s' with external command 'ffmpeg'.\",\n                              cimglist_instance,\n                              filename);\n      return *this;\n    }\n\n    //! Load an image from a video file using the external tool 'ffmpeg' \\newinstance.\n    static CImgList<T> get_load_ffmpeg_external(const char *const filename) {\n      return CImgList<T>().load_ffmpeg_external(filename);\n    }\n\n    //! Load gif file, using ImageMagick or GraphicsMagick's external tools.\n    /**\n      \\param filename Filename to read data from.\n      \\param use_graphicsmagick Tells if GraphicsMagick's tool 'gm' is used instead of ImageMagick's tool 'convert'.\n    **/\n    CImgList<T>& load_gif_external(const char *const filename) {\n      if (!filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_gif_external(): Specified filename is (null).\",\n                                    cimglist_instance);\n      std::fclose(cimg::fopen(filename,\"rb\"));            // Check if file exists.\n      if (!_load_gif_external(filename,false))\n        if (!_load_gif_external(filename,true))\n          try { assign(CImg<T>().load_other(filename)); } catch (CImgException&) { assign(); }\n      if (is_empty())\n        throw CImgIOException(_cimglist_instance\n                              \"load_gif_external(): Failed to open file '%s'.\",\n                              cimglist_instance,filename);\n      return *this;\n    }\n\n    CImgList<T>& _load_gif_external(const char *const filename, const bool use_graphicsmagick=false) {\n      CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256);\n      std::FILE *file = 0;\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s\",\n                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s.png.0\",filename_tmp._data);\n        else cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s-0.png\",filename_tmp._data);\n        if ((file=std::fopen(filename_tmp2,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n#if cimg_OS!=2\n      if (use_graphicsmagick) cimg_snprintf(command,command._width,\"%s convert \\\"%s\\\" \\\"%s.png\\\" >/dev/null 2>&1\",\n                                            cimg::graphicsmagick_path(),\n                                            CImg<charT>::string(filename)._system_strescape().data(),\n                                            CImg<charT>::string(filename_tmp)._system_strescape().data());\n      else cimg_snprintf(command,command._width,\"%s \\\"%s\\\" \\\"%s.png\\\" >/dev/null 2>&1\",\n                         cimg::imagemagick_path(),\n                         CImg<charT>::string(filename)._system_strescape().data(),\n                         CImg<charT>::string(filename_tmp)._system_strescape().data());\n#else\n      if (use_graphicsmagick) cimg_snprintf(command,command._width,\"\\\"%s convert \\\"%s\\\" \\\"%s.png\\\"\\\" >NUL 2>&1\",\n                                            cimg::graphicsmagick_path(),\n                                            CImg<charT>::string(filename)._system_strescape().data(),\n                                            CImg<charT>::string(filename_tmp)._system_strescape().data());\n      else cimg_snprintf(command,command._width,\"\\\"%s \\\"%s\\\" \\\"%s.png\\\"\\\" >NUL 2>&1\",\n                         cimg::imagemagick_path(),\n                         CImg<charT>::string(filename)._system_strescape().data(),\n                         CImg<charT>::string(filename_tmp)._system_strescape().data());\n#endif\n      cimg::system(command,0);\n      const unsigned int omode = cimg::exception_mode();\n      cimg::exception_mode(0);\n      assign();\n\n      // Try to read a single frame gif.\n      cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s.png\",filename_tmp._data);\n      CImg<T> img;\n      try { img.load_png(filename_tmp2); }\n      catch (CImgException&) { }\n      if (img) { img.move_to(*this); std::remove(filename_tmp2); }\n      else { // Try to read animated gif.\n        unsigned int i = 0;\n        for (bool stop_flag = false; !stop_flag; ++i) {\n          if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s.png.%u\",filename_tmp._data,i);\n          else cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s-%u.png\",filename_tmp._data,i);\n          CImg<T> img;\n          try { img.load_png(filename_tmp2); }\n          catch (CImgException&) { stop_flag = true; }\n          if (img) { img.move_to(*this); std::remove(filename_tmp2); }\n        }\n      }\n      cimg::exception_mode(omode);\n      return *this;\n    }\n\n    //! Load gif file, using ImageMagick or GraphicsMagick's external tools \\newinstance.\n    static CImgList<T> get_load_gif_external(const char *const filename) {\n      return CImgList<T>().load_gif_external(filename);\n    }\n\n    //! Load a gzipped list, using external tool 'gunzip'.\n    /**\n      \\param filename Filename to read data from.\n    **/\n    CImgList<T>& load_gzip_external(const char *const filename) {\n      if (!filename)\n        throw CImgIOException(_cimglist_instance\n                              \"load_gzip_external(): Specified filename is (null).\",\n                              cimglist_instance);\n      std::fclose(cimg::fopen(filename,\"rb\"));            // Check if file exists.\n      CImg<charT> command(1024), filename_tmp(256), body(256);\n      const char\n        *ext = cimg::split_filename(filename,body),\n        *ext2 = cimg::split_filename(body,0);\n      std::FILE *file = 0;\n      do {\n        if (!cimg::strcasecmp(ext,\"gz\")) {\n          if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",\n                                   cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);\n          else cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s\",\n                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        } else {\n          if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",\n                                  cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);\n          else cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s\",\n                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        }\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      cimg_snprintf(command,command._width,\"%s -c \\\"%s\\\" > \\\"%s\\\"\",\n                    cimg::gunzip_path(),\n                    CImg<charT>::string(filename)._system_strescape().data(),\n                    CImg<charT>::string(filename_tmp)._system_strescape().data());\n      cimg::system(command);\n      if (!(file = std::fopen(filename_tmp,\"rb\"))) {\n        cimg::fclose(cimg::fopen(filename,\"r\"));\n        throw CImgIOException(_cimglist_instance\n                              \"load_gzip_external(): Failed to open file '%s'.\",\n                              cimglist_instance,\n                              filename);\n\n      } else cimg::fclose(file);\n      load(filename_tmp);\n      std::remove(filename_tmp);\n      return *this;\n    }\n\n    //! Load a gzipped list, using external tool 'gunzip' \\newinstance.\n    static CImgList<T> get_load_gzip_external(const char *const filename) {\n      return CImgList<T>().load_gzip_external(filename);\n    }\n\n    //! Load a 3d object from a .OFF file.\n    /**\n      \\param filename Filename to read data from.\n      \\param[out] primitives At return, contains the list of 3d object primitives.\n      \\param[out] colors At return, contains the list of 3d object colors.\n      \\return List of 3d object vertices.\n    **/\n    template<typename tf, typename tc>\n    CImgList<T>& load_off(const char *const filename,\n                          CImgList<tf>& primitives, CImgList<tc>& colors) {\n      return get_load_off(filename,primitives,colors).move_to(*this);\n    }\n\n    //! Load a 3d object from a .OFF file \\newinstance.\n    template<typename tf, typename tc>\n      static CImgList<T> get_load_off(const char *const filename,\n                                      CImgList<tf>& primitives, CImgList<tc>& colors) {\n      return CImg<T>().load_off(filename,primitives,colors)<'x';\n    }\n\n    //! Load images from a TIFF file.\n    /**\n        \\param filename Filename to read data from.\n        \\param first_frame Index of first image frame to read.\n        \\param last_frame Index of last image frame to read.\n        \\param step_frame Step applied between each frame.\n    **/\n    CImgList<T>& load_tiff(const char *const filename,\n                           const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                           const unsigned int step_frame=1,\n                           float *const voxel_size=0,\n                           CImg<charT> *const description=0) {\n      const unsigned int\n        nfirst_frame = first_frame<last_frame?first_frame:last_frame,\n        nstep_frame = step_frame?step_frame:1;\n      unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;\n#ifndef cimg_use_tiff\n      cimg::unused(voxel_size,description);\n      if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"load_tiff(): Unable to load sub-images from file '%s' unless libtiff is enabled.\",\n                                    cimglist_instance,\n                                    filename);\n\n      return assign(CImg<T>::get_load_tiff(filename));\n#else\n      TIFF *tif = TIFFOpen(filename,\"r\");\n      if (tif) {\n        unsigned int nb_images = 0;\n        do ++nb_images; while (TIFFReadDirectory(tif));\n        if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))\n          cimg::warn(_cimglist_instance\n                     \"load_tiff(): Invalid specified frame range is [%u,%u] (step %u) since \"\n                     \"file '%s' contains %u image(s).\",\n                     cimglist_instance,\n                     nfirst_frame,nlast_frame,nstep_frame,filename,nb_images);\n\n        if (nfirst_frame>=nb_images) return assign();\n        if (nlast_frame>=nb_images) nlast_frame = nb_images - 1;\n        assign(1 + (nlast_frame - nfirst_frame)/nstep_frame);\n        TIFFSetDirectory(tif,0);\n#if cimg_verbosity>=3\n        TIFFSetWarningHandler(0);\n        TIFFSetErrorHandler(0);\n#endif\n        cimglist_for(*this,l) _data[l]._load_tiff(tif,nfirst_frame + l*nstep_frame,voxel_size,description);\n        TIFFClose(tif);\n      } else throw CImgIOException(_cimglist_instance\n                                   \"load_tiff(): Failed to open file '%s'.\",\n                                   cimglist_instance,\n                                   filename);\n      return *this;\n#endif\n    }\n\n    //! Load a multi-page TIFF file \\newinstance.\n    static CImgList<T> get_load_tiff(const char *const filename,\n                                     const unsigned int first_frame=0, const unsigned int last_frame=~0U,\n                                     const unsigned int step_frame=1,\n                                     float *const voxel_size=0,\n                                     CImg<charT> *const description=0) {\n      return CImgList<T>().load_tiff(filename,first_frame,last_frame,step_frame,voxel_size,description);\n    }\n\n    //@}\n    //----------------------------------\n    //\n    //! \\name Data Output\n    //@{\n    //----------------------------------\n\n    //! Print information about the list on the standard output.\n    /**\n      \\param title Label set to the information displayed.\n      \\param display_stats Tells if image statistics must be computed and displayed.\n    **/\n    const CImgList<T>& print(const char *const title=0, const bool display_stats=true) const {\n      unsigned int msiz = 0;\n      cimglist_for(*this,l) msiz+=_data[l].size();\n      msiz*=sizeof(T);\n      const unsigned int mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U;\n      CImg<charT> _title(64);\n      if (!title) cimg_snprintf(_title,_title._width,\"CImgList<%s>\",pixel_type());\n      std::fprintf(cimg::output(),\"%s%s%s%s: %sthis%s = %p, %ssize%s = %u/%u [%u %s], %sdata%s = (CImg<%s>*)%p\",\n                   cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal,\n                   cimg::t_bold,cimg::t_normal,(void*)this,\n                   cimg::t_bold,cimg::t_normal,_width,_allocated_width,\n                   mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),\n                   mdisp==0?\"b\":(mdisp==1?\"Kio\":\"Mio\"),\n                   cimg::t_bold,cimg::t_normal,pixel_type(),(void*)begin());\n      if (_data) std::fprintf(cimg::output(),\"..%p.\\n\",(void*)((char*)end() - 1));\n      else std::fprintf(cimg::output(),\".\\n\");\n\n      char tmp[16] = { 0 };\n      cimglist_for(*this,ll) {\n        cimg_snprintf(tmp,sizeof(tmp),\"[%d]\",ll);\n        std::fprintf(cimg::output(),\"  \");\n        _data[ll].print(tmp,display_stats);\n        if (ll==3 && width()>8) { ll = width() - 5; std::fprintf(cimg::output(),\"  ...\\n\"); }\n      }\n      std::fflush(cimg::output());\n      return *this;\n    }\n\n    //! Display the current CImgList instance in an existing CImgDisplay window (by reference).\n    /**\n       \\param disp Reference to an existing CImgDisplay instance, where the current image list will be displayed.\n       \\param axis Appending axis. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n       \\param align Appending alignmenet.\n       \\note This function displays the list images of the current CImgList instance into an existing\n         CImgDisplay window.\n       Images of the list are appended in a single temporarly image for visualization purposes.\n       The function returns immediately.\n    **/\n    const CImgList<T>& display(CImgDisplay &disp, const char axis='x', const float align=0) const {\n      disp.display(*this,axis,align);\n      return *this;\n    }\n\n    //! Display the current CImgList instance in a new display window.\n    /**\n        \\param disp Display window.\n        \\param display_info Tells if image information are displayed on the standard output.\n       \\param axis Alignment axis for images viewing.\n       \\param align Apending alignment.\n       \\note This function opens a new window with a specific title and displays the list images of the\n         current CImgList instance into it.\n       Images of the list are appended in a single temporarly image for visualization purposes.\n       The function returns when a key is pressed or the display window is closed by the user.\n    **/\n    const CImgList<T>& display(CImgDisplay &disp, const bool display_info,\n                               const char axis='x', const float align=0,\n                               unsigned int *const XYZ=0, const bool exit_on_anykey=false) const {\n      bool is_exit = false;\n      return _display(disp,0,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit);\n    }\n\n    //! Display the current CImgList instance in a new display window.\n    /**\n      \\param title Title of the opening display window.\n      \\param display_info Tells if list information must be written on standard output.\n      \\param axis Appending axis. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.\n      \\param align Appending alignment.\n    **/\n    const CImgList<T>& display(const char *const title=0, const bool display_info=true,\n                               const char axis='x', const float align=0,\n                               unsigned int *const XYZ=0, const bool exit_on_anykey=false) const {\n      CImgDisplay disp;\n      bool is_exit = false;\n      return _display(disp,title,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit);\n    }\n\n    const CImgList<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info,\n                                const char axis, const float align, unsigned int *const XYZ,\n                                const bool exit_on_anykey, const unsigned int orig, const bool is_first_call,\n                                bool &is_exit) const {\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"display(): Empty instance.\",\n                                    cimglist_instance);\n      if (!disp) {\n        if (axis=='x') {\n          unsigned int sum_width = 0, max_height = 0;\n          cimglist_for(*this,l) {\n            const CImg<T> &img = _data[l];\n            const unsigned int\n              w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false),\n              h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true);\n            sum_width+=w;\n            if (h>max_height) max_height = h;\n          }\n          disp.assign(cimg_fitscreen(sum_width,max_height,1),title?title:0,1);\n        } else {\n          unsigned int max_width = 0, sum_height = 0;\n          cimglist_for(*this,l) {\n            const CImg<T> &img = _data[l];\n            const unsigned int\n              w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false),\n              h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true);\n            if (w>max_width) max_width = w;\n            sum_height+=h;\n          }\n          disp.assign(cimg_fitscreen(max_width,sum_height,1),title?title:0,1);\n        }\n        if (!title) disp.set_title(\"CImgList<%s> (%u)\",pixel_type(),_width);\n      } else if (title) disp.set_title(\"%s\",title);\n      const CImg<char> dtitle = CImg<char>::string(disp.title());\n      if (display_info) print(disp.title());\n      disp.show().flush();\n\n      if (_width==1) {\n        const unsigned int dw = disp._width, dh = disp._height;\n        if (!is_first_call)\n          disp.resize(cimg_fitscreen(_data[0]._width,_data[0]._height,_data[0]._depth),false).\n            set_title(\"%s (%ux%ux%ux%u)\",\n                      dtitle.data(),_data[0]._width,_data[0]._height,_data[0]._depth,_data[0]._spectrum);\n        _data[0]._display(disp,0,false,XYZ,exit_on_anykey,!is_first_call);\n        if (disp.key()) is_exit = true;\n        disp.resize(cimg_fitscreen(dw,dh,1),false).set_title(\"%s\",dtitle.data());\n      } else {\n        bool disp_resize = !is_first_call;\n        while (!disp.is_closed() && !is_exit) {\n          const CImg<intT> s = _get_select(disp,0,true,axis,align,exit_on_anykey,orig,disp_resize,!is_first_call,true);\n          disp_resize = true;\n          if (s[0]<0) { // No selections done.\n            if (disp.button()&2) { disp.flush(); break; }\n            is_exit = true;\n          } else if (disp.wheel()) { // Zoom in/out.\n            const int wheel = disp.wheel();\n            disp.set_wheel();\n            if (!is_first_call && wheel<0) break;\n            if (wheel>0 && _width>=4) {\n              const unsigned int\n                delta = cimg::max(1U,(unsigned int)cimg::round(0.3*_width)),\n                ind0 = (unsigned int)cimg::max(0,s[0] - (int)delta),\n                ind1 = (unsigned int)cimg::min(width() - 1,s[0] + (int)delta);\n              if ((ind0!=0 || ind1!=_width - 1) && ind1 - ind0>=3)\n                get_shared_images(ind0,ind1)._display(disp,0,false,axis,align,XYZ,exit_on_anykey,\n                                                      orig + ind0,false,is_exit);\n            }\n          } else if (s[0]!=0 || s[1]!=width() - 1)\n            get_shared_images(s[0],s[1])._display(disp,0,false,axis,align,XYZ,exit_on_anykey,\n                                                  orig + s[0],false,is_exit);\n        }\n      }\n      return *this;\n    }\n\n    //! Save list into a file.\n    /**\n      \\param filename Filename to write data to.\n      \\param number When positive, represents an index added to the filename. Otherwise, no number is added.\n      \\param digits Number of digits used for adding the number to the filename.\n    **/\n    const CImgList<T>& save(const char *const filename, const int number=-1, const unsigned int digits=6) const {\n      if (!filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"save(): Specified filename is (null).\",\n                                    cimglist_instance);\n      // Do not test for empty instances, since .cimg format is able to manage empty instances.\n      const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.');\n      const char *const ext = cimg::split_filename(filename);\n      CImg<charT> nfilename(1024);\n      const char *const fn = is_stdout?filename:number>=0?cimg::number_filename(filename,number,digits,nfilename):\n        filename;\n\n#ifdef cimglist_save_plugin\n      cimglist_save_plugin(fn);\n#endif\n#ifdef cimglist_save_plugin1\n      cimglist_save_plugin1(fn);\n#endif\n#ifdef cimglist_save_plugin2\n      cimglist_save_plugin2(fn);\n#endif\n#ifdef cimglist_save_plugin3\n      cimglist_save_plugin3(fn);\n#endif\n#ifdef cimglist_save_plugin4\n      cimglist_save_plugin4(fn);\n#endif\n#ifdef cimglist_save_plugin5\n      cimglist_save_plugin5(fn);\n#endif\n#ifdef cimglist_save_plugin6\n      cimglist_save_plugin6(fn);\n#endif\n#ifdef cimglist_save_plugin7\n      cimglist_save_plugin7(fn);\n#endif\n#ifdef cimglist_save_plugin8\n      cimglist_save_plugin8(fn);\n#endif\n      if (!cimg::strcasecmp(ext,\"cimgz\")) return save_cimg(fn,true);\n      else if (!cimg::strcasecmp(ext,\"cimg\") || !*ext) return save_cimg(fn,false);\n      else if (!cimg::strcasecmp(ext,\"yuv\")) return save_yuv(fn,true);\n      else if (!cimg::strcasecmp(ext,\"avi\") ||\n               !cimg::strcasecmp(ext,\"mov\") ||\n               !cimg::strcasecmp(ext,\"asf\") ||\n               !cimg::strcasecmp(ext,\"divx\") ||\n               !cimg::strcasecmp(ext,\"flv\") ||\n               !cimg::strcasecmp(ext,\"mpg\") ||\n               !cimg::strcasecmp(ext,\"m1v\") ||\n               !cimg::strcasecmp(ext,\"m2v\") ||\n               !cimg::strcasecmp(ext,\"m4v\") ||\n               !cimg::strcasecmp(ext,\"mjp\") ||\n               !cimg::strcasecmp(ext,\"mp4\") ||\n               !cimg::strcasecmp(ext,\"mkv\") ||\n               !cimg::strcasecmp(ext,\"mpe\") ||\n               !cimg::strcasecmp(ext,\"movie\") ||\n               !cimg::strcasecmp(ext,\"ogm\") ||\n               !cimg::strcasecmp(ext,\"ogg\") ||\n               !cimg::strcasecmp(ext,\"ogv\") ||\n               !cimg::strcasecmp(ext,\"qt\") ||\n               !cimg::strcasecmp(ext,\"rm\") ||\n               !cimg::strcasecmp(ext,\"vob\") ||\n               !cimg::strcasecmp(ext,\"wmv\") ||\n               !cimg::strcasecmp(ext,\"xvid\") ||\n               !cimg::strcasecmp(ext,\"mpeg\")) return save_video(fn);\n#ifdef cimg_use_tiff\n      else if (!cimg::strcasecmp(ext,\"tif\") ||\n          !cimg::strcasecmp(ext,\"tiff\")) return save_tiff(fn);\n#endif\n      else if (!cimg::strcasecmp(ext,\"gz\")) return save_gzip_external(fn);\n      else {\n        if (_width==1) _data[0].save(fn,-1);\n        else cimglist_for(*this,l) { _data[l].save(fn,is_stdout?-1:l); if (is_stdout) std::fputc(EOF,stdout); }\n      }\n      return *this;\n    }\n\n    //! Tell if an image list can be saved as one single file.\n    /**\n       \\param filename Filename, as a C-string.\n       \\return \\c true if the file format supports multiple images, \\c false otherwise.\n    **/\n    static bool is_saveable(const char *const filename) {\n      const char *const ext = cimg::split_filename(filename);\n      if (!cimg::strcasecmp(ext,\"cimgz\") ||\n#ifdef cimg_use_tiff\n          !cimg::strcasecmp(ext,\"tif\") ||\n          !cimg::strcasecmp(ext,\"tiff\") ||\n#endif\n          !cimg::strcasecmp(ext,\"yuv\") ||\n          !cimg::strcasecmp(ext,\"avi\") ||\n          !cimg::strcasecmp(ext,\"mov\") ||\n          !cimg::strcasecmp(ext,\"asf\") ||\n          !cimg::strcasecmp(ext,\"divx\") ||\n          !cimg::strcasecmp(ext,\"flv\") ||\n          !cimg::strcasecmp(ext,\"mpg\") ||\n          !cimg::strcasecmp(ext,\"m1v\") ||\n          !cimg::strcasecmp(ext,\"m2v\") ||\n          !cimg::strcasecmp(ext,\"m4v\") ||\n          !cimg::strcasecmp(ext,\"mjp\") ||\n          !cimg::strcasecmp(ext,\"mp4\") ||\n          !cimg::strcasecmp(ext,\"mkv\") ||\n          !cimg::strcasecmp(ext,\"mpe\") ||\n          !cimg::strcasecmp(ext,\"movie\") ||\n          !cimg::strcasecmp(ext,\"ogm\") ||\n          !cimg::strcasecmp(ext,\"ogg\") ||\n          !cimg::strcasecmp(ext,\"ogv\") ||\n          !cimg::strcasecmp(ext,\"qt\") ||\n          !cimg::strcasecmp(ext,\"rm\") ||\n          !cimg::strcasecmp(ext,\"vob\") ||\n          !cimg::strcasecmp(ext,\"wmv\") ||\n          !cimg::strcasecmp(ext,\"xvid\") ||\n          !cimg::strcasecmp(ext,\"mpeg\")) return true;\n      return false;\n    }\n\n    //! Save image sequence as a GIF animated file.\n    /**\n       \\param filename Filename to write data to.\n       \\param fps Number of desired frames per second.\n       \\param nb_loops Number of loops (\\c 0 for infinite looping).\n    **/\n    const CImgList<T>& save_gif_external(const char *const filename, const float fps=25,\n                                         const unsigned int nb_loops=0) {\n      CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256);\n      CImgList<charT> filenames;\n      std::FILE *file = 0;\n\n#ifdef cimg_use_png\n#define _cimg_save_gif_ext \"png\"\n#else\n#define _cimg_save_gif_ext \"ppm\"\n#endif\n\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s\",\n                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s_000001.\" _cimg_save_gif_ext,filename_tmp._data);\n        if ((file=std::fopen(filename_tmp2,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      cimglist_for(*this,l) {\n        cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s_%.6u.\" _cimg_save_gif_ext,filename_tmp._data,l + 1);\n        CImg<charT>::string(filename_tmp2).move_to(filenames);\n        if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save(filename_tmp2);\n        else _data[l].save(filename_tmp2);\n      }\n\n#if cimg_OS!=2\n      cimg_snprintf(command,command._width,\"%s -delay %u -loop %u\",\n                    cimg::imagemagick_path(),(unsigned int)cimg::max(0.0f,cimg::round(100/fps)),nb_loops);\n      CImg<ucharT>::string(command).move_to(filenames,0);\n      cimg_snprintf(command,command._width,\"\\\"%s\\\" >/dev/null 2>&1\",\n                    CImg<charT>::string(filename)._system_strescape().data());\n      CImg<ucharT>::string(command).move_to(filenames);\n#else\n      cimg_snprintf(command,command._width,\"\\\"%s -delay %u -loop %u\",\n                    cimg::imagemagick_path(),(unsigned int)cimg::max(0.0f,cimg::round(100/fps)),nb_loops);\n      CImg<ucharT>::string(command).move_to(filenames,0);\n      cimg_snprintf(command,command._width,\"\\\"%s\\\"\\\" >NUL 2>&1\",\n                    CImg<charT>::string(filename)._system_strescape().data());\n      CImg<ucharT>::string(command).move_to(filenames);\n#endif\n      CImg<charT> _command = filenames>'x';\n      cimg_for(_command,p,char) if (!*p) *p = ' ';\n      _command.back() = 0;\n\n      cimg::system(_command);\n      file = std::fopen(filename,\"rb\");\n      if (!file)\n        throw CImgIOException(_cimglist_instance\n                              \"save_gif_external(): Failed to save file '%s' with external command 'convert'.\",\n                              cimglist_instance,\n                              filename);\n      else cimg::fclose(file);\n      cimglist_for_in(*this,1,filenames._width - 1,l) std::remove(filenames[l]);\n      return *this;\n    }\n\n    const CImgList<T>& _save_yuv(std::FILE *const file, const char *const filename, const bool is_rgb) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"save_yuv(): Specified filename is (null).\",\n                                    cimglist_instance);\n      if (is_empty()) { cimg::fempty(file,filename); return *this; }\n      if ((*this)[0].width()%2 || (*this)[0].height()%2)\n        throw CImgInstanceException(_cimglist_instance\n                                    \"save_yuv(): Invalid odd instance dimensions (%u,%u) for file '%s'.\",\n                                    cimglist_instance,\n                                    (*this)[0].width(),(*this)[0].height(),\n                                    filename?filename:\"(FILE*)\");\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      cimglist_for(*this,l) {\n        CImg<ucharT> YCbCr((*this)[l]);\n        if (is_rgb) YCbCr.RGBtoYCbCr();\n        cimg::fwrite(YCbCr._data,(size_t)YCbCr._width*YCbCr._height,nfile);\n        cimg::fwrite(YCbCr.get_resize(YCbCr._width/2, YCbCr._height/2,1,3,3).data(0,0,0,1),\n                     (size_t)YCbCr._width*YCbCr._height/2,nfile);\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save list as a YUV image sequence file.\n    /**\n      \\param filename Filename to write data to.\n      \\param is_rgb Tells if the RGB to YUV conversion must be done for saving.\n    **/\n    const CImgList<T>& save_yuv(const char *const filename=0, const bool is_rgb=true) const {\n      return _save_yuv(0,filename,is_rgb);\n    }\n\n    //! Save image sequence into a YUV file.\n    /**\n      \\param file File to write data to.\n      \\param is_rgb Tells if the RGB to YUV conversion must be done for saving.\n    **/\n    const CImgList<T>& save_yuv(std::FILE *const file, const bool is_rgb=true) const {\n      return _save_yuv(file,0,is_rgb);\n    }\n\n    const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename, const bool is_compressed) const {\n      if (!file && !filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"save_cimg(): Specified filename is (null).\",\n                                    cimglist_instance);\n#ifndef cimg_use_zlib\n      if (is_compressed)\n        cimg::warn(_cimglist_instance\n                   \"save_cimg(): Unable to save compressed data in file '%s' unless zlib is enabled, \"\n                   \"saving them uncompressed.\",\n                   cimglist_instance,\n                   filename?filename:\"(FILE*)\");\n#endif\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      const char *const ptype = pixel_type(), *const etype = cimg::endianness()?\"big\":\"little\";\n      if (std::strstr(ptype,\"unsigned\")==ptype) std::fprintf(nfile,\"%u unsigned_%s %s_endian\\n\",_width,ptype + 9,etype);\n      else std::fprintf(nfile,\"%u %s %s_endian\\n\",_width,ptype,etype);\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        std::fprintf(nfile,\"%u %u %u %u\",img._width,img._height,img._depth,img._spectrum);\n        if (img._data) {\n          CImg<T> tmp;\n          if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); }\n          const CImg<T>& ref = cimg::endianness()?tmp:img;\n          bool failed_to_compress = true;\n          if (is_compressed) {\n#ifdef cimg_use_zlib\n            const ulongT siz = sizeof(T)*ref.size();\n            uLongf csiz = siz + siz/100 + 16;\n            Bytef *const cbuf = new Bytef[csiz];\n            if (compress(cbuf,&csiz,(Bytef*)ref._data,siz))\n              cimg::warn(_cimglist_instance\n                         \"save_cimg(): Failed to save compressed data for file '%s', saving them uncompressed.\",\n                         cimglist_instance,\n                         filename?filename:\"(FILE*)\");\n            else {\n              std::fprintf(nfile,\" #%lu\\n\",csiz);\n              cimg::fwrite(cbuf,csiz,nfile);\n              delete[] cbuf;\n              failed_to_compress = false;\n            }\n#endif\n          }\n          if (failed_to_compress) { // Write in a non-compressed way.\n            std::fputc('\\n',nfile);\n            cimg::fwrite(ref._data,ref.size(),nfile);\n          }\n        } else std::fputc('\\n',nfile);\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Save list into a .cimg file.\n    /**\n       \\param filename Filename to write data to.\n       \\param is_compressed Tells if data compression must be enabled.\n    **/\n    const CImgList<T>& save_cimg(const char *const filename, const bool is_compressed=false) const {\n      return _save_cimg(0,filename,is_compressed);\n    }\n\n    //! Save list into a .cimg file.\n    /**\n       \\param file File to write data to.\n       \\param is_compressed Tells if data compression must be enabled.\n    **/\n    const CImgList<T>& save_cimg(std::FILE *file, const bool is_compressed=false) const {\n      return _save_cimg(file,0,is_compressed);\n    }\n\n    const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename,\n                                 const unsigned int n0,\n                                 const unsigned int x0, const unsigned int y0,\n                                 const unsigned int z0, const unsigned int c0) const {\n#define _cimg_save_cimg_case(Ts,Tss) \\\n      if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \\\n        for (unsigned int l = 0; l<lmax; ++l) { \\\n          j = 0; while ((i=std::fgetc(nfile))!='\\n') tmp[j++]=(char)i; tmp[j] = 0; \\\n          W = H = D = C = 0; \\\n          if (cimg_sscanf(tmp,\"%u %u %u %u\",&W,&H,&D,&C)!=4) \\\n            throw CImgIOException(_cimglist_instance \\\n                                  \"save_cimg(): Invalid size (%u,%u,%u,%u) of image[%u], for file '%s'.\", \\\n                                  cimglist_instance, \\\n                                  W,H,D,C,l,filename?filename:\"(FILE*)\"); \\\n          if (W*H*D*C>0) { \\\n            if (l<n0 || x0>=W || y0>=H || z0>=D || c0>=D) cimg::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \\\n            else { \\\n              const CImg<T>& img = (*this)[l - n0]; \\\n              const T *ptrs = img._data; \\\n              const unsigned int \\\n                x1 = x0 + img._width - 1, \\\n                y1 = y0 + img._height - 1, \\\n                z1 = z0 + img._depth - 1, \\\n                c1 = c0 + img._spectrum - 1, \\\n                nx1 = x1>=W?W - 1:x1, \\\n                ny1 = y1>=H?H - 1:y1, \\\n                nz1 = z1>=D?D - 1:z1, \\\n                nc1 = c1>=C?C - 1:c1; \\\n              CImg<Tss> raw(1 + nx1 - x0); \\\n              const unsigned int skipvb = c0*W*H*D*sizeof(Tss); \\\n              if (skipvb) cimg::fseek(nfile,skipvb,SEEK_CUR); \\\n              for (unsigned int v = 1 + nc1 - c0; v; --v) { \\\n                const unsigned int skipzb = z0*W*H*sizeof(Tss); \\\n                if (skipzb) cimg::fseek(nfile,skipzb,SEEK_CUR); \\\n                for (unsigned int z = 1 + nz1 - z0; z; --z) { \\\n                  const unsigned int skipyb = y0*W*sizeof(Tss); \\\n                  if (skipyb) cimg::fseek(nfile,skipyb,SEEK_CUR); \\\n                  for (unsigned int y = 1 + ny1 - y0; y; --y) { \\\n                    const unsigned int skipxb = x0*sizeof(Tss); \\\n                    if (skipxb) cimg::fseek(nfile,skipxb,SEEK_CUR); \\\n                    raw.assign(ptrs, raw._width); \\\n                    ptrs+=img._width; \\\n                    if (endian) cimg::invert_endianness(raw._data,raw._width); \\\n                    cimg::fwrite(raw._data,raw._width,nfile); \\\n                    const unsigned int skipxe = (W - 1 - nx1)*sizeof(Tss); \\\n                    if (skipxe) cimg::fseek(nfile,skipxe,SEEK_CUR); \\\n                  } \\\n                  const unsigned int skipye = (H - 1 - ny1)*W*sizeof(Tss); \\\n                  if (skipye) cimg::fseek(nfile,skipye,SEEK_CUR); \\\n                } \\\n                const unsigned int skipze = (D - 1 - nz1)*W*H*sizeof(Tss); \\\n                if (skipze) cimg::fseek(nfile,skipze,SEEK_CUR); \\\n              } \\\n              const unsigned int skipve = (C - 1 - nc1)*W*H*D*sizeof(Tss); \\\n              if (skipve) cimg::fseek(nfile,skipve,SEEK_CUR); \\\n            } \\\n          } \\\n        } \\\n        saved = true; \\\n      }\n\n      if (!file && !filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"save_cimg(): Specified filename is (null).\",\n                                    cimglist_instance);\n      if (is_empty())\n        throw CImgInstanceException(_cimglist_instance\n                                    \"save_cimg(): Empty instance, for file '%s'.\",\n                                    cimglist_instance,\n                                    filename?filename:\"(FILE*)\");\n\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"rb+\");\n      bool saved = false, endian = cimg::endianness();\n      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);\n      *tmp = *str_pixeltype = *str_endian = 0;\n      unsigned int j, N, W, H, D, C;\n      int i, err;\n      j = 0; while ((i=std::fgetc(nfile))!='\\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;\n      err = cimg_sscanf(tmp,\"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]\",&N,str_pixeltype._data,str_endian._data);\n      if (err<2) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimglist_instance\n                              \"save_cimg(): CImg header not found in file '%s'.\",\n                              cimglist_instance,\n                              filename?filename:\"(FILE*)\");\n      }\n      if (!cimg::strncasecmp(\"little\",str_endian,6)) endian = false;\n      else if (!cimg::strncasecmp(\"big\",str_endian,3)) endian = true;\n      const unsigned int lmax = cimg::min(N,n0 + _width);\n      _cimg_save_cimg_case(\"bool\",bool);\n      _cimg_save_cimg_case(\"unsigned_char\",unsigned char);\n      _cimg_save_cimg_case(\"uchar\",unsigned char);\n      _cimg_save_cimg_case(\"char\",char);\n      _cimg_save_cimg_case(\"unsigned_short\",unsigned short);\n      _cimg_save_cimg_case(\"ushort\",unsigned short);\n      _cimg_save_cimg_case(\"short\",short);\n      _cimg_save_cimg_case(\"unsigned_int\",unsigned int);\n      _cimg_save_cimg_case(\"uint\",unsigned int);\n      _cimg_save_cimg_case(\"int\",int);\n      _cimg_save_cimg_case(\"unsigned_int64\",uint64T);\n      _cimg_save_cimg_case(\"uint64\",uint64T);\n      _cimg_save_cimg_case(\"int64\",int64T);\n      _cimg_save_cimg_case(\"float\",float);\n      _cimg_save_cimg_case(\"double\",double);\n      if (!saved) {\n        if (!file) cimg::fclose(nfile);\n        throw CImgIOException(_cimglist_instance\n                              \"save_cimg(): Unsupported data type '%s' for file '%s'.\",\n                              cimglist_instance,\n                              filename?filename:\"(FILE*)\",str_pixeltype._data);\n      }\n      if (!file) cimg::fclose(nfile);\n      return *this;\n    }\n\n    //! Insert the image instance into into an existing .cimg file, at specified coordinates.\n    /**\n      \\param filename Filename to write data to.\n      \\param n0 Starting index of images to write.\n      \\param x0 Starting X-coordinates of image regions to write.\n      \\param y0 Starting Y-coordinates of image regions to write.\n      \\param z0 Starting Z-coordinates of image regions to write.\n      \\param c0 Starting C-coordinates of image regions to write.\n    **/\n    const CImgList<T>& save_cimg(const char *const filename,\n                                 const unsigned int n0,\n                                 const unsigned int x0, const unsigned int y0,\n                                 const unsigned int z0, const unsigned int c0) const {\n      return _save_cimg(0,filename,n0,x0,y0,z0,c0);\n    }\n\n    //! Insert the image instance into into an existing .cimg file, at specified coordinates.\n    /**\n      \\param file File to write data to.\n      \\param n0 Starting index of images to write.\n      \\param x0 Starting X-coordinates of image regions to write.\n      \\param y0 Starting Y-coordinates of image regions to write.\n      \\param z0 Starting Z-coordinates of image regions to write.\n      \\param c0 Starting C-coordinates of image regions to write.\n    **/\n    const CImgList<T>& save_cimg(std::FILE *const file,\n                                 const unsigned int n0,\n                                 const unsigned int x0, const unsigned int y0,\n                                 const unsigned int z0, const unsigned int c0) const {\n      return _save_cimg(file,0,n0,x0,y0,z0,c0);\n    }\n\n    static void _save_empty_cimg(std::FILE *const file, const char *const filename,\n                                const unsigned int nb,\n                                const unsigned int dx, const unsigned int dy,\n                                const unsigned int dz, const unsigned int dc) {\n      std::FILE *const nfile = file?file:cimg::fopen(filename,\"wb\");\n      const ulongT siz = (ulongT)dx*dy*dz*dc*sizeof(T);\n      std::fprintf(nfile,\"%u %s\\n\",nb,pixel_type());\n      for (unsigned int i=nb; i; --i) {\n        std::fprintf(nfile,\"%u %u %u %u\\n\",dx,dy,dz,dc);\n        for (ulongT off = siz; off; --off) std::fputc(0,nfile);\n      }\n      if (!file) cimg::fclose(nfile);\n    }\n\n    //! Save empty (non-compressed) .cimg file with specified dimensions.\n    /**\n        \\param filename Filename to write data to.\n        \\param nb Number of images to write.\n        \\param dx Width of images in the written file.\n        \\param dy Height of images in the written file.\n        \\param dz Depth of images in the written file.\n        \\param dc Spectrum of images in the written file.\n    **/\n    static void save_empty_cimg(const char *const filename,\n                                const unsigned int nb,\n                                const unsigned int dx, const unsigned int dy=1,\n                                const unsigned int dz=1, const unsigned int dc=1) {\n      return _save_empty_cimg(0,filename,nb,dx,dy,dz,dc);\n    }\n\n    //! Save empty .cimg file with specified dimensions.\n    /**\n        \\param file File to write data to.\n        \\param nb Number of images to write.\n        \\param dx Width of images in the written file.\n        \\param dy Height of images in the written file.\n        \\param dz Depth of images in the written file.\n        \\param dc Spectrum of images in the written file.\n    **/\n    static void save_empty_cimg(std::FILE *const file,\n                                const unsigned int nb,\n                                const unsigned int dx, const unsigned int dy=1,\n                                const unsigned int dz=1, const unsigned int dc=1) {\n      return _save_empty_cimg(file,0,nb,dx,dy,dz,dc);\n    }\n\n    //! Save list as a TIFF file.\n    /**\n      \\param filename Filename to write data to.\n      \\param compression_type Compression mode used to write data.\n    **/\n    const CImgList<T>& save_tiff(const char *const filename, const unsigned int compression_type=0,\n                                 const float *const voxel_size=0, const char *const description=0,\n                                 const bool use_bigtiff=true) const {\n      if (!filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"save_tiff(): Specified filename is (null).\",\n                                    cimglist_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n\n#ifndef cimg_use_tiff\n      if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description,use_bigtiff);\n      else cimglist_for(*this,l) {\n          CImg<charT> nfilename(1024);\n          cimg::number_filename(filename,l,6,nfilename);\n          _data[l].save_tiff(nfilename,compression_type,voxel_size,description,use_bigtiff);\n        }\n#else\n      ulongT siz = 0;\n      cimglist_for(*this,l) siz+=_data[l].size();\n      const bool _use_bigtiff = use_bigtiff && sizeof(siz)>=8 && siz*sizeof(T)>=1UL<<31; // No bigtiff for small images.\n      TIFF *tif = TIFFOpen(filename,_use_bigtiff?\"w8\":\"w4\");\n      if (tif) {\n        for (unsigned int dir = 0, l = 0; l<_width; ++l) {\n          const CImg<T>& img = (*this)[l];\n          cimg_forZ(img,z) img._save_tiff(tif,dir++,z,compression_type,voxel_size,description);\n        }\n        TIFFClose(tif);\n      } else\n        throw CImgIOException(_cimglist_instance\n                              \"save_tiff(): Failed to open stream for file '%s'.\",\n                              cimglist_instance,\n                              filename);\n#endif\n      return *this;\n    }\n\n    //! Save list as a gzipped file, using external tool 'gzip'.\n    /**\n      \\param filename Filename to write data to.\n    **/\n    const CImgList<T>& save_gzip_external(const char *const filename) const {\n      if (!filename)\n        throw CImgIOException(_cimglist_instance\n                              \"save_gzip_external(): Specified filename is (null).\",\n                              cimglist_instance);\n\n      CImg<charT> command(1024), filename_tmp(256), body(256);\n      const char\n        *ext = cimg::split_filename(filename,body),\n        *ext2 = cimg::split_filename(body,0);\n      std::FILE *file;\n      do {\n        if (!cimg::strcasecmp(ext,\"gz\")) {\n          if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",\n                                   cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);\n          else cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.cimg\",\n                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        } else {\n          if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.%s\",\n                                  cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);\n          else cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s.cimg\",\n                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        }\n        if ((file=std::fopen(filename_tmp,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n\n      if (is_saveable(body)) {\n        save(filename_tmp);\n        cimg_snprintf(command,command._width,\"%s -c \\\"%s\\\" > \\\"%s\\\"\",\n                      cimg::gzip_path(),\n                      CImg<charT>::string(filename_tmp)._system_strescape().data(),\n                      CImg<charT>::string(filename)._system_strescape().data());\n        cimg::system(command);\n        file = std::fopen(filename,\"rb\");\n        if (!file)\n          throw CImgIOException(_cimglist_instance\n                                \"save_gzip_external(): Failed to save file '%s' with external command 'gzip'.\",\n                                cimglist_instance,\n                                filename);\n        else cimg::fclose(file);\n        std::remove(filename_tmp);\n      } else {\n        CImg<charT> nfilename(1024);\n        cimglist_for(*this,l) {\n          cimg::number_filename(body,l,6,nfilename);\n          if (*ext) cimg_sprintf(nfilename._data + std::strlen(nfilename),\".%s\",ext);\n          _data[l].save_gzip_external(nfilename);\n        }\n      }\n      return *this;\n    }\n\n    //! Save image sequence, using the OpenCV library.\n    /**\n       \\param filename Filename to write data to.\n       \\param fps Number of frames per second.\n       \\param codec Type of compression (See http://www.fourcc.org/codecs.php to see available codecs).\n       \\param keep_open Tells if the video writer associated to the specified filename\n       must be kept open or not (to allow frames to be added in the same file afterwards).\n    **/\n    const CImgList<T>& save_video(const char *const filename, const unsigned int fps=25,\n                                  const char *codec=0, const bool keep_open=false) const {\n#ifndef cimg_use_opencv\n      cimg::unused(codec,keep_open);\n      return save_ffmpeg_external(filename,fps);\n#else\n      static CvVideoWriter *writers[32] = { 0 };\n      static CImgList<charT> filenames(32);\n      static CImg<intT> sizes(32,2,1,1,0);\n      static int last_used_index = -1;\n\n      // Detect if a video writer already exists for the specified filename.\n      cimg::mutex(9);\n      int index = -1;\n      if (filename) {\n        if (last_used_index>=0 && !std::strcmp(filename,filenames[last_used_index])) {\n          index = last_used_index;\n        } else cimglist_for(filenames,l) if (filenames[l] && !std::strcmp(filename,filenames[l])) {\n            index = l; break;\n          }\n      } else index = last_used_index;\n      cimg::mutex(9,0);\n\n      // Find empty slot for capturing video stream.\n      if (index<0) {\n        if (!filename)\n          throw CImgArgumentException(_cimglist_instance\n                                      \"save_video(): No already open video writer found. You must specify a \"\n                                      \"non-(null) filename argument for the first call.\",\n                                      cimglist_instance);\n        else { cimg::mutex(9); cimglist_for(filenames,l) if (!filenames[l]) { index = l; break; } cimg::mutex(9,0); }\n        if (index<0)\n          throw CImgIOException(_cimglist_instance\n                                \"save_video(): File '%s', no video writer slots available. \"\n                                \"You have to release some of your previously opened videos.\",\n                                cimglist_instance,filename);\n        if (is_empty())\n          throw CImgInstanceException(_cimglist_instance\n                                      \"save_video(): Instance list is empty.\",\n                                      cimglist_instance);\n        const unsigned int W = _data?_data[0]._width:0, H = _data?_data[0]._height:0;\n        if (!W || !H)\n          throw CImgInstanceException(_cimglist_instance\n                                      \"save_video(): Frame [0] is an empty image.\",\n                                      cimglist_instance);\n\n#define _cimg_docase(x) ((x)>='a'&&(x)<='z'?(x) + 'A' - 'a':(x))\n        const char\n          *const _codec = codec && *codec?codec:\"mp4v\",\n          codec0 = _cimg_docase(_codec[0]),\n          codec1 = _codec[0]?_cimg_docase(_codec[1]):0,\n          codec2 = _codec[1]?_cimg_docase(_codec[2]):0,\n          codec3 = _codec[2]?_cimg_docase(_codec[3]):0;\n        cimg::mutex(9);\n        writers[index] = cvCreateVideoWriter(filename,CV_FOURCC(codec0,codec1,codec2,codec3),\n                                             fps,cvSize(W,H));\n        CImg<charT>::string(filename).move_to(filenames[index]);\n        sizes(index,0) = W; sizes(index,1) = H;\n        cimg::mutex(9,0);\n        if (!writers[index])\n          throw CImgIOException(_cimglist_instance\n                                \"save_video(): File '%s', unable to initialize video writer with codec '%c%c%c%c'.\",\n                                cimglist_instance,filename,\n                                codec0,codec1,codec2,codec3);\n      }\n\n      if (!is_empty()) {\n        const unsigned int W = sizes(index,0), H = sizes(index,1);\n        cimg::mutex(9);\n        IplImage *ipl = cvCreateImage(cvSize(W,H),8,3);\n        cimglist_for(*this,l) {\n          CImg<T> &src = _data[l];\n          if (src.is_empty())\n            cimg::warn(_cimglist_instance\n                       \"save_video(): Skip empty frame %d for file '%s'.\",\n                       cimglist_instance,l,filename);\n          if (src._depth>1 || src._spectrum>3)\n            cimg::warn(_cimglist_instance\n                       \"save_video(): Frame %u has incompatible dimension (%u,%u,%u,%u). \"\n                       \"Some image data may be ignored when writing frame into video file '%s'.\",\n                       cimglist_instance,l,src._width,src._height,src._depth,src._spectrum,filename);\n          if (src._width==W && src._height==H && src._spectrum==3) {\n            const T *ptr_r = src.data(0,0,0,0), *ptr_g = src.data(0,0,0,1), *ptr_b = src.data(0,0,0,2);\n            char *ptrd = ipl->imageData;\n            cimg_forXY(src,x,y) {\n              *(ptrd++) = (char)*(ptr_b++); *(ptrd++) = (char)*(ptr_g++); *(ptrd++) = (char)*(ptr_r++);\n            }\n          } else {\n            CImg<unsigned char> _src(src,false);\n            _src.channels(0,cimg::min(_src._spectrum - 1,2U)).resize(W,H);\n            _src.resize(W,H,1,3,_src._spectrum==1?1:0);\n            const unsigned char *ptr_r = _src.data(0,0,0,0), *ptr_g = _src.data(0,0,0,1), *ptr_b = _src.data(0,0,0,2);\n            char *ptrd = ipl->imageData;\n            cimg_forXY(_src,x,y) {\n              *(ptrd++) = (char)*(ptr_b++); *(ptrd++) = (char)*(ptr_g++); *(ptrd++) = (char)*(ptr_r++);\n            }\n          }\n          cvWriteFrame(writers[index],ipl);\n        }\n        cvReleaseImage(&ipl);\n        cimg::mutex(9,0);\n      }\n\n      cimg::mutex(9);\n      if (!keep_open) {\n        cvReleaseVideoWriter(&writers[index]);\n        writers[index] = 0;\n        filenames[index].assign();\n        sizes(index,0) = sizes(index,1) = 0;\n        last_used_index = -1;\n      } else last_used_index = index;\n      cimg::mutex(9,0);\n\n      return *this;\n#endif\n    }\n\n    //! Save image sequence, using the external tool 'ffmpeg'.\n    /**\n      \\param filename Filename to write data to.\n      \\param fps Number of frames per second.\n      \\param codec Type of compression.\n      \\param bitrate Output bitrate\n    **/\n    const CImgList<T>& save_ffmpeg_external(const char *const filename, const unsigned int fps=25,\n                                            const char *const codec=0, const unsigned int bitrate=2048) const {\n      if (!filename)\n        throw CImgArgumentException(_cimglist_instance\n                                    \"save_ffmpeg_external(): Specified filename is (null).\",\n                                    cimglist_instance);\n      if (is_empty()) { cimg::fempty(0,filename); return *this; }\n\n      const char\n        *const ext = cimg::split_filename(filename),\n        *const _codec = codec?codec:!cimg::strcasecmp(ext,\"flv\")?\"flv\":\"mpeg2video\";\n\n      CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256);\n      CImgList<charT> filenames;\n      std::FILE *file = 0;\n      cimglist_for(*this,l) if (!_data[l].is_sameXYZ(_data[0]))\n        throw CImgInstanceException(_cimglist_instance\n                                    \"save_ffmpeg_external(): Invalid instance dimensions for file '%s'.\",\n                                    cimglist_instance,\n                                    filename);\n      do {\n        cimg_snprintf(filename_tmp,filename_tmp._width,\"%s%c%s\",\n                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());\n        cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s_000001.ppm\",filename_tmp._data);\n        if ((file=std::fopen(filename_tmp2,\"rb\"))!=0) cimg::fclose(file);\n      } while (file);\n      cimglist_for(*this,l) {\n        cimg_snprintf(filename_tmp2,filename_tmp2._width,\"%s_%.6u.ppm\",filename_tmp._data,l + 1);\n        CImg<charT>::string(filename_tmp2).move_to(filenames);\n        if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save_pnm(filename_tmp2);\n        else _data[l].save_pnm(filename_tmp2);\n      }\n#if cimg_OS!=2\n      cimg_snprintf(command,command._width,\"%s -i \\\"%s_%%6d.ppm\\\" -vcodec %s -b %uk -r %u -y \\\"%s\\\" >/dev/null 2>&1\",\n                    cimg::ffmpeg_path(),\n                    CImg<charT>::string(filename_tmp)._system_strescape().data(),\n                    _codec,bitrate,fps,\n                    CImg<charT>::string(filename)._system_strescape().data());\n#else\n      cimg_snprintf(command,command._width,\"\\\"%s -i \\\"%s_%%6d.ppm\\\" -vcodec %s -b %uk -r %u -y \\\"%s\\\"\\\" >NUL 2>&1\",\n                    cimg::ffmpeg_path(),\n                    CImg<charT>::string(filename_tmp)._system_strescape().data(),\n                    _codec,bitrate,fps,\n                    CImg<charT>::string(filename)._system_strescape().data());\n#endif\n      cimg::system(command);\n      file = std::fopen(filename,\"rb\");\n      if (!file)\n        throw CImgIOException(_cimglist_instance\n                              \"save_ffmpeg_external(): Failed to save file '%s' with external command 'ffmpeg'.\",\n                              cimglist_instance,\n                              filename);\n      else cimg::fclose(file);\n      cimglist_for(*this,l) std::remove(filenames[l]);\n      return *this;\n    }\n\n    //! Serialize a CImgList<T> instance into a raw CImg<unsigned char> buffer.\n    /**\n       \\param is_compressed tells if zlib compression must be used for serialization\n       (this requires 'cimg_use_zlib' been enabled).\n    **/\n    CImg<ucharT> get_serialize(const bool is_compressed=false) const {\n#ifndef cimg_use_zlib\n      if (is_compressed)\n        cimg::warn(_cimglist_instance\n                   \"get_serialize(): Unable to compress data unless zlib is enabled, \"\n                   \"storing them uncompressed.\",\n                   cimglist_instance);\n#endif\n      CImgList<ucharT> stream;\n      CImg<charT> tmpstr(128);\n      const char *const ptype = pixel_type(), *const etype = cimg::endianness()?\"big\":\"little\";\n      if (std::strstr(ptype,\"unsigned\")==ptype)\n        cimg_snprintf(tmpstr,tmpstr._width,\"%u unsigned_%s %s_endian\\n\",_width,ptype + 9,etype);\n      else\n        cimg_snprintf(tmpstr,tmpstr._width,\"%u %s %s_endian\\n\",_width,ptype,etype);\n      CImg<ucharT>::string(tmpstr,false).move_to(stream);\n      cimglist_for(*this,l) {\n        const CImg<T>& img = _data[l];\n        cimg_snprintf(tmpstr,tmpstr._width,\"%u %u %u %u\",img._width,img._height,img._depth,img._spectrum);\n        CImg<ucharT>::string(tmpstr,false).move_to(stream);\n        if (img._data) {\n          CImg<T> tmp;\n          if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); }\n          const CImg<T>& ref = cimg::endianness()?tmp:img;\n          bool failed_to_compress = true;\n          if (is_compressed) {\n#ifdef cimg_use_zlib\n            const ulongT siz = sizeof(T)*ref.size();\n            uLongf csiz = (ulongT)compressBound(siz);\n            Bytef *const cbuf = new Bytef[csiz];\n            if (compress(cbuf,&csiz,(Bytef*)ref._data,siz))\n              cimg::warn(_cimglist_instance\n                         \"get_serialize(): Failed to save compressed data, saving them uncompressed.\",\n                         cimglist_instance);\n            else {\n              cimg_snprintf(tmpstr,tmpstr._width,\" #%lu\\n\",csiz);\n              CImg<ucharT>::string(tmpstr,false).move_to(stream);\n              CImg<ucharT>(cbuf,csiz).move_to(stream);\n              delete[] cbuf;\n              failed_to_compress = false;\n            }\n#endif\n          }\n          if (failed_to_compress) { // Write in a non-compressed way.\n            CImg<charT>::string(\"\\n\",false).move_to(stream);\n            stream.insert(1);\n            stream.back().assign((unsigned char*)ref._data,ref.size()*sizeof(T),1,1,1,true);\n          }\n        } else CImg<charT>::string(\"\\n\",false).move_to(stream);\n      }\n      cimglist_apply(stream,unroll)('y');\n      return stream>'y';\n    }\n\n    //! Unserialize a CImg<unsigned char> serialized buffer into a CImgList<T> list.\n    template<typename t>\n    static CImgList<T> get_unserialize(const CImg<t>& buffer) {\n#ifdef cimg_use_zlib\n#define _cimgz_unserialize_case(Tss) { \\\n        Bytef *cbuf = (Bytef*)stream; \\\n        if (sizeof(t)!=1 || cimg::type<t>::string()==cimg::type<bool>::string()) { \\\n          cbuf = new Bytef[csiz]; Bytef *_cbuf = cbuf; \\\n          for (ulongT i = 0; i<csiz; ++i) *(_cbuf++) = (Bytef)*(stream++); \\\n          is_bytef = false; \\\n        } else { stream+=csiz; is_bytef = true; } \\\n        CImg<Tss> raw(W,H,D,C); \\\n        uLongf destlen = raw.size()*sizeof(Tss); \\\n        uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \\\n        if (!is_bytef) delete[] cbuf; \\\n        if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \\\n        raw.move_to(img); \\\n      }\n#else\n#define _cimgz_unserialize_case(Tss) \\\n      throw CImgArgumentException(\"CImgList<%s>::get_unserialize(): Unable to unserialize compressed data \" \\\n                                  \"unless zlib is enabled.\", \\\n                                  pixel_type());\n#endif\n\n#define _cimg_unserialize_case(Ts,Tss) \\\n      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \\\n        for (unsigned int l = 0; l<N; ++l) { \\\n          j = 0; while ((i=(int)*stream)!='\\n' && stream<estream && j<255) { ++stream; tmp[j++] = (char)i; } \\\n          ++stream; tmp[j] = 0; \\\n          W = H = D = C = 0; csiz = 0; \\\n          if ((err = cimg_sscanf(tmp,\"%u %u %u %u #%lu\",&W,&H,&D,&C,&csiz))<4) \\\n            throw CImgArgumentException(\"CImgList<%s>::unserialize(): Invalid specified size (%u,%u,%u,%u) for \" \\\n                                        \"image #%u in serialized buffer.\", \\\n                                        pixel_type(),W,H,D,C,l); \\\n          if (W*H*D*C>0) { \\\n            CImg<T> &img = res._data[l]; \\\n            if (err==5) _cimgz_unserialize_case(Tss) \\\n            else { \\\n              if (sizeof(t)!=1) { \\\n                CImg<ucharT> raw(W*sizeof(Tss),H,D,C);  \\\n                cimg_for(raw,p,unsigned char) *p = (unsigned char)*(stream++); \\\n                img.assign((Tss*)raw._data,W,H,D,C); \\\n              } else img.assign((Tss*)stream,W,H,D,C); \\\n              if (endian!=cimg::endianness()) cimg::invert_endianness(img._data,img.size()); \\\n            } \\\n          } \\\n        } \\\n        loaded = true; \\\n      }\n\n      if (buffer.is_empty())\n        throw CImgArgumentException(\"CImgList<%s>::get_unserialize(): Specified serialized buffer is (null).\",\n                                    pixel_type());\n      CImgList<T> res;\n      const t *stream = buffer._data, *const estream = buffer._data + buffer.size();\n      bool loaded = false, endian = cimg::endianness(), is_bytef = false;\n      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);\n      *tmp = *str_pixeltype = *str_endian = 0;\n      unsigned int j, N = 0, W, H, D, C;\n      ulongT csiz;\n      int i, err;\n      cimg::unused(is_bytef);\n      do {\n        j = 0; while ((i=(int)*stream)!='\\n' && stream<estream && j<255) { ++stream; tmp[j++] = (char)i; }\n        ++stream; tmp[j] = 0;\n      } while (*tmp=='#' && stream<estream);\n      err = cimg_sscanf(tmp,\"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]\",\n                        &N,str_pixeltype._data,str_endian._data);\n      if (err<2)\n        throw CImgArgumentException(\"CImgList<%s>::get_unserialize(): CImg header not found in serialized buffer.\",\n                                    pixel_type());\n      if (!cimg::strncasecmp(\"little\",str_endian,6)) endian = false;\n      else if (!cimg::strncasecmp(\"big\",str_endian,3)) endian = true;\n      res.assign(N);\n      _cimg_unserialize_case(\"bool\",bool);\n      _cimg_unserialize_case(\"unsigned_char\",unsigned char);\n      _cimg_unserialize_case(\"uchar\",unsigned char);\n      _cimg_unserialize_case(\"char\",char);\n      _cimg_unserialize_case(\"unsigned_short\",unsigned short);\n      _cimg_unserialize_case(\"ushort\",unsigned short);\n      _cimg_unserialize_case(\"short\",short);\n      _cimg_unserialize_case(\"unsigned_int\",unsigned int);\n      _cimg_unserialize_case(\"uint\",unsigned int);\n      _cimg_unserialize_case(\"int\",int);\n      _cimg_unserialize_case(\"unsigned_int64\",uint64T);\n      _cimg_unserialize_case(\"uint64\",uint64T);\n      _cimg_unserialize_case(\"int64\",int64T);\n      _cimg_unserialize_case(\"float\",float);\n      _cimg_unserialize_case(\"double\",double);\n      if (!loaded)\n        throw CImgArgumentException(\"CImgList<%s>::get_unserialize(): Unsupported pixel type '%s' defined \"\n                                    \"in serialized buffer.\",\n                                    pixel_type(),str_pixeltype._data);\n      return res;\n    }\n\n    //@}\n    //----------------------------------\n    //\n    //! \\name Others\n    //@{\n    //----------------------------------\n\n    //! Crop font along the X-axis.\n    /**\n    **/\n    CImgList<T>& crop_font() {\n      return get_crop_font().move_to(*this);\n    }\n\n    //! Crop font along the X-axis \\newinstance.\n    /**\n    **/\n    CImgList<T> get_crop_font() const {\n      CImgList<T> res;\n      cimglist_for(*this,l) {\n        const CImg<T>& letter = (*this)[l];\n        int xmin = letter.width(), xmax = 0;\n        cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin = x; if (x>xmax) xmax = x; }\n        if (xmin>xmax) CImg<T>(letter._width,letter._height,1,letter._spectrum,0).move_to(res);\n        else letter.get_crop(xmin,0,xmax,letter._height - 1).move_to(res);\n      }\n      res[' '].resize(res['f']._width,-100,-100,-100,0);\n      if (' ' + 256<res.size()) res[' ' + 256].resize(res['f']._width,-100,-100,-100,0);\n      return res;\n    }\n\n    //! Return a CImg pre-defined font with desired size.\n    /**\n       \\param font_height Height of the desired font (exact match for 13,23,53,103).\n       \\param is_variable_width Decide if the font has a variable (\\c true) or fixed (\\c false) width.\n    **/\n    static const CImgList<ucharT>& font(const unsigned int font_height, const bool is_variable_width=true) {\n      if (!font_height) return CImgList<ucharT>::const_empty();\n      cimg::mutex(11);\n\n      // Decompress nearest base font data if needed.\n      static const char *data_fonts[] = { cimg::data_font12x13, cimg::data_font20x23, cimg::data_font47x53, 0 };\n      static const unsigned int data_widths[] = { 12,20,47,90 }, data_heights[] = { 13,23,53,103 },\n                                data_Ms[] = { 86,79,57,47 };\n      const unsigned int data_ind = font_height<=13U?0U:font_height<=23U?1U:font_height<=53U?2U:3U;\n      static CImg<ucharT> base_fonts[4];\n      CImg<ucharT> &base_font = base_fonts[data_ind];\n      if (!base_font) {\n        const unsigned int w = data_widths[data_ind], h = data_heights[data_ind], M = data_Ms[data_ind];\n        base_font.assign(256*w,h);\n        const char *data_font = data_fonts[data_ind];\n        unsigned char *ptrd = base_font;\n        const unsigned char *const ptrde = base_font.end();\n\n        // Special case needed for 90x103 to avoid MS compiler limit with big strings.\n        CImg<char> data90x103;\n        if (!data_font) {\n          ((CImg<char>(cimg::_data_font90x103[0],\n                       (unsigned int)std::strlen(cimg::_data_font90x103[0]),1,1,1,true),\n            CImg<char>(cimg::_data_font90x103[1],\n                       (unsigned int)std::strlen(cimg::_data_font90x103[1]) + 1,1,1,1,true))>'x').\n            move_to(data90x103);\n          data_font = data90x103.data();\n        }\n\n        // Uncompress font data (decode RLE).\n        for (const char *ptrs = data_font; *ptrs; ++ptrs) {\n          const int c = (int)(*ptrs - M - 32), v = c>=0?255:0, n = c>=0?c:-c;\n          if (ptrd + n<=ptrde) { std::memset(ptrd,v,n); ptrd+=n; }\n          else { std::memset(ptrd,v,ptrde - ptrd); break; }\n        }\n      }\n\n      // Find optimal font cache location to return.\n      static CImgList<ucharT> fonts[16];\n      static bool is_variable_widths[16] = { 0 };\n      unsigned int ind = ~0U;\n      for (int i = 0; i<16; ++i)\n        if (!fonts[i] || (is_variable_widths[i]==is_variable_width && font_height==fonts[i][0]._height)) {\n          ind = (unsigned int)i; break; // Found empty slot or cached font.\n        }\n      if (ind==~0U) { // No empty slots nor existing font in cache.\n        std::memmove(fonts,fonts + 1,15*sizeof(CImgList<ucharT>));\n        std::memmove(is_variable_widths,is_variable_widths + 1,15*sizeof(bool));\n        std::memset(fonts + (ind=15),0,sizeof(CImgList<ucharT>));  // Free a slot in cache for new font.\n      }\n      CImgList<ucharT> &font = fonts[ind];\n\n      // Render requested font.\n      if (!font) {\n        const unsigned int padding_x = font_height<33U?1U:font_height<53U?2U:font_height<103U?3U:4U;\n        is_variable_widths[ind] = is_variable_width;\n        font = base_font.get_split('x',256);\n        if (font_height!=font[0]._height)\n          cimglist_for(font,l)\n            font[l].resize(cimg::max(1U,font[l]._width*font_height/font[l]._height),font_height,-100,-100,\n                           font[0]._height>font_height?2:5);\n        if (is_variable_width) font.crop_font();\n        cimglist_for(font,l) font[l].resize(font[l]._width + padding_x,-100,1,1,0,0,0.5);\n        font.insert(256,0);\n        cimglist_for_in(font,0,255,l) font[l].assign(font[l + 256]._width,font[l + 256]._height,1,3,1);\n      }\n      cimg::mutex(11,0);\n      return font;\n    }\n\n    //! Compute a 1d Fast Fourier Transform, along specified axis.\n    /**\n       \\param axis Axis along which the Fourier transform is computed.\n       \\param invert Tells if the direct (\\c false) or inverse transform (\\c true) is computed.\n    **/\n    CImgList<T>& FFT(const char axis, const bool invert=false) {\n      if (is_empty()) return *this;\n      if (_width==1) insert(1);\n      if (_width>2)\n        cimg::warn(_cimglist_instance\n                   \"FFT(): Instance has more than 2 images\",\n                   cimglist_instance);\n\n      CImg<T>::FFT(_data[0],_data[1],axis,invert);\n      return *this;\n    }\n\n    //! Compute a 1-D Fast Fourier Transform, along specified axis \\newinstance.\n    CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {\n      return CImgList<Tfloat>(*this,false).FFT(axis,invert);\n    }\n\n    //! Compute a n-d Fast Fourier Transform.\n    /**\n      \\param invert Tells if the direct (\\c false) or inverse transform (\\c true) is computed.\n    **/\n    CImgList<T>& FFT(const bool invert=false) {\n      if (is_empty()) return *this;\n      if (_width==1) insert(1);\n      if (_width>2)\n        cimg::warn(_cimglist_instance\n                   \"FFT(): Instance has more than 2 images\",\n                   cimglist_instance);\n\n      CImg<T>::FFT(_data[0],_data[1],invert);\n      return *this;\n    }\n\n    //! Compute a n-d Fast Fourier Transform \\newinstance.\n    CImgList<Tfloat> get_FFT(const bool invert=false) const {\n      return CImgList<Tfloat>(*this,false).FFT(invert);\n    }\n\n    //! Reverse primitives orientations of a 3d object.\n    /**\n    **/\n    CImgList<T>& reverse_object3d() {\n      cimglist_for(*this,l) {\n        CImg<T>& p = _data[l];\n        switch (p.size()) {\n        case 2 : case 3: cimg::swap(p[0],p[1]); break;\n        case 6 : cimg::swap(p[0],p[1],p[2],p[4],p[3],p[5]); break;\n        case 9 : cimg::swap(p[0],p[1],p[3],p[5],p[4],p[6]); break;\n        case 4 : cimg::swap(p[0],p[1],p[2],p[3]); break;\n        case 12 : cimg::swap(p[0],p[1],p[2],p[3],p[4],p[6],p[5],p[7],p[8],p[10],p[9],p[11]); break;\n        }\n      }\n      return *this;\n    }\n\n    //! Reverse primitives orientations of a 3d object \\newinstance.\n    CImgList<T> get_reverse_object3d() const {\n      return (+*this).reverse_object3d();\n    }\n\n    //@}\n  }; // struct CImgList<T> { ...\n\n  /*\n    #---------------------------------------------\n    #\n    # Completion of previously declared functions\n    #\n    #----------------------------------------------\n  */\n\nnamespace cimg {\n\n  //! Get/set path to store temporary files.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path where temporary files can be saved.\n  **/\n  inline const char* temporary_path(const char *const user_path, const bool reinit_path) {\n#define _cimg_test_temporary_path(p)                                    \\\n    if (!path_found) {                                                  \\\n      cimg_snprintf(s_path,s_path.width(),\"%s\",p);                      \\\n      cimg_snprintf(tmp,tmp._width,\"%s%c%s\",s_path.data(),cimg_file_separator,filename_tmp._data); \\\n      if ((file=std::fopen(tmp,\"wb\"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; } \\\n    }\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      CImg<char> tmp(1024), filename_tmp(256);\n      std::FILE *file = 0;\n      cimg_snprintf(filename_tmp,filename_tmp._width,\"%s.tmp\",cimg::filenamerand());\n      char *tmpPath = std::getenv(\"TMP\");\n      if (!tmpPath) { tmpPath = std::getenv(\"TEMP\"); winformat_string(tmpPath); }\n      if (tmpPath) _cimg_test_temporary_path(tmpPath);\n#if cimg_OS==2\n      _cimg_test_temporary_path(\"C:\\\\WINNT\\\\Temp\");\n      _cimg_test_temporary_path(\"C:\\\\WINDOWS\\\\Temp\");\n      _cimg_test_temporary_path(\"C:\\\\Temp\");\n      _cimg_test_temporary_path(\"C:\");\n      _cimg_test_temporary_path(\"D:\\\\WINNT\\\\Temp\");\n      _cimg_test_temporary_path(\"D:\\\\WINDOWS\\\\Temp\");\n      _cimg_test_temporary_path(\"D:\\\\Temp\");\n      _cimg_test_temporary_path(\"D:\");\n#else\n      _cimg_test_temporary_path(\"/tmp\");\n      _cimg_test_temporary_path(\"/var/tmp\");\n#endif\n      if (!path_found) {\n        *s_path = 0;\n        std::strncpy(tmp,filename_tmp,tmp._width - 1);\n        if ((file=std::fopen(tmp,\"wb\"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; }\n      }\n      if (!path_found) {\n        cimg::mutex(7,0);\n        throw CImgIOException(\"cimg::temporary_path(): Failed to locate path for writing temporary files.\\n\");\n      }\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  //! Get/set path to the <i>Program Files/</i> directory (Windows only).\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the program files.\n  **/\n#if cimg_OS==2\n  inline const char* programfiles_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(MAX_PATH);\n      *s_path = 0;\n      // Note: in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler).\n#if !defined(__INTEL_COMPILER)\n      if (!SHGetSpecialFolderPathA(0,s_path,0x0026,false)) {\n        const char *const pfPath = std::getenv(\"PROGRAMFILES\");\n        if (pfPath) std::strncpy(s_path,pfPath,MAX_PATH - 1);\n        else std::strcpy(s_path,\"C:\\\\PROGRA~1\");\n      }\n#else\n      std::strcpy(s_path,\"C:\\\\PROGRA~1\");\n#endif\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n#endif\n\n  //! Get/set path to the ImageMagick's \\c convert binary.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the \\c convert binary.\n  **/\n  inline const char* imagemagick_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      std::FILE *file = 0;\n#if cimg_OS==2\n      const char *const pf_path = programfiles_path();\n      if (!path_found) {\n        std::strcpy(s_path,\".\\\\convert.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\IMAGEM~1.%.2d-\\\\convert.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\IMAGEM~1.%d-Q\\\\convert.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\IMAGEM~1.%d\\\\convert.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\IMAGEM~1.%.2d-\\\\VISUA~1\\\\BIN\\\\convert.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\IMAGEM~1.%d-Q\\\\VISUA~1\\\\BIN\\\\convert.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\IMAGEM~1.%d\\\\VISUA~1\\\\BIN\\\\convert.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\IMAGEM~1.%.2d-\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\IMAGEM~1.%d-Q\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\IMAGEM~1.%d\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\IMAGEM~1.%.2d-\\\\VISUA~1\\\\BIN\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\IMAGEM~1.%d-Q\\\\VISUA~1\\\\BIN\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\IMAGEM~1.%d\\\\VISUA~1\\\\BIN\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\IMAGEM~1.%.2d-\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\IMAGEM~1.%d-Q\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\IMAGEM~1.%d\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\IMAGEM~1.%.2d-\\\\VISUA~1\\\\BIN\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\IMAGEM~1.%d-Q\\\\VISUA~1\\\\BIN\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\IMAGEM~1.%d\\\\VISUA~1\\\\BIN\\\\convert.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"convert.exe\");\n#else\n      if (!path_found) {\n        std::strcpy(s_path,\"./convert\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"convert\");\n#endif\n      winformat_string(s_path);\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  //! Get/set path to the GraphicsMagick's \\c gm binary.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the \\c gm binary.\n  **/\n  inline const char* graphicsmagick_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      std::FILE *file = 0;\n#if cimg_OS==2\n      const char *const pf_path = programfiles_path();\n      if (!path_found) {\n        std::strcpy(s_path,\".\\\\gm.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\GRAPHI~1.%.2d-\\\\gm.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\GRAPHI~1.%d-Q\\\\gm.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\GRAPHI~1.%d\\\\gm.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\GRAPHI~1.%.2d-\\\\VISUA~1\\\\BIN\\\\gm.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\GRAPHI~1.%d-Q\\\\VISUA~1\\\\BIN\\\\gm.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\GRAPHI~1.%d\\\\VISUA~1\\\\BIN\\\\gm.exe\",pf_path,k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\GRAPHI~1.%.2d-\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\GRAPHI~1.%d-Q\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\GRAPHI~1.%d\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\GRAPHI~1.%.2d-\\\\VISUA~1\\\\BIN\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\GRAPHI~1.%d-Q\\\\VISUA~1\\\\BIN\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"C:\\\\GRAPHI~1.%d\\\\VISUA~1\\\\BIN\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\GRAPHI~1.%.2d-\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\GRAPHI~1.%d-Q\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\GRAPHI~1.%d\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=10 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\GRAPHI~1.%.2d-\\\\VISUA~1\\\\BIN\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 9; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\GRAPHI~1.%d-Q\\\\VISUA~1\\\\BIN\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      for (int k = 32; k>=0 && !path_found; --k) {\n        cimg_snprintf(s_path,s_path._width,\"D:\\\\GRAPHI~1.%d\\\\VISUA~1\\\\BIN\\\\gm.exe\",k);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"gm.exe\");\n#else\n      if (!path_found) {\n        std::strcpy(s_path,\"./gm\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"gm\");\n#endif\n      winformat_string(s_path);\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  //! Get/set path to the XMedcon's \\c medcon binary.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the \\c medcon binary.\n  **/\n  inline const char* medcon_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      std::FILE *file = 0;\n#if cimg_OS==2\n      const char *const pf_path = programfiles_path();\n      if (!path_found) {\n        std::strcpy(s_path,\".\\\\medcon.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\XMedCon\\\\bin\\\\medcon.bat\",pf_path);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) {\n        cimg_snprintf(s_path,s_path._width,\"%s\\\\XMedCon\\\\bin\\\\medcon.exe\",pf_path);\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) {\n        std::strcpy(s_path,\"C:\\\\XMedCon\\\\bin\\\\medcon.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"medcon.exe\");\n#else\n      if (!path_found) {\n        std::strcpy(s_path,\"./medcon\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"medcon\");\n#endif\n      winformat_string(s_path);\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  //! Get/set path to the FFMPEG's \\c ffmpeg binary.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the \\c ffmpeg binary.\n  **/\n  inline const char *ffmpeg_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      std::FILE *file = 0;\n#if cimg_OS==2\n      if (!path_found) {\n        std::strcpy(s_path,\".\\\\ffmpeg.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"ffmpeg.exe\");\n#else\n      if (!path_found) {\n        std::strcpy(s_path,\"./ffmpeg\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"ffmpeg\");\n#endif\n      winformat_string(s_path);\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  //! Get/set path to the \\c gzip binary.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the \\c gzip binary.\n  **/\n  inline const char *gzip_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      std::FILE *file = 0;\n#if cimg_OS==2\n      if (!path_found) {\n        std::strcpy(s_path,\".\\\\gzip.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"gzip.exe\");\n#else\n      if (!path_found) {\n        std::strcpy(s_path,\"./gzip\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"gzip\");\n#endif\n      winformat_string(s_path);\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  //! Get/set path to the \\c gunzip binary.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the \\c gunzip binary.\n  **/\n  inline const char *gunzip_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      std::FILE *file = 0;\n#if cimg_OS==2\n      if (!path_found) {\n        std::strcpy(s_path,\".\\\\gunzip.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"gunzip.exe\");\n#else\n      if (!path_found) {\n        std::strcpy(s_path,\"./gunzip\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"gunzip\");\n#endif\n      winformat_string(s_path);\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  //! Get/set path to the \\c dcraw binary.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the \\c dcraw binary.\n  **/\n  inline const char *dcraw_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      std::FILE *file = 0;\n#if cimg_OS==2\n      if (!path_found) {\n        std::strcpy(s_path,\".\\\\dcraw.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"dcraw.exe\");\n#else\n      if (!path_found) {\n        std::strcpy(s_path,\"./dcraw\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"dcraw\");\n#endif\n      winformat_string(s_path);\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  //! Get/set path to the \\c wget binary.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the \\c wget binary.\n  **/\n  inline const char *wget_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      std::FILE *file = 0;\n#if cimg_OS==2\n      if (!path_found) {\n        std::strcpy(s_path,\".\\\\wget.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"wget.exe\");\n#else\n      if (!path_found) {\n        std::strcpy(s_path,\"./wget\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"wget\");\n#endif\n      winformat_string(s_path);\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  //! Get/set path to the \\c curl binary.\n  /**\n     \\param user_path Specified path, or \\c 0 to get the path currently used.\n     \\param reinit_path Force path to be recalculated (may take some time).\n     \\return Path containing the \\c curl binary.\n  **/\n  inline const char *curl_path(const char *const user_path, const bool reinit_path) {\n    static CImg<char> s_path;\n    cimg::mutex(7);\n    if (reinit_path) s_path.assign();\n    if (user_path) {\n      if (!s_path) s_path.assign(1024);\n      std::strncpy(s_path,user_path,1023);\n    } else if (!s_path) {\n      s_path.assign(1024);\n      bool path_found = false;\n      std::FILE *file = 0;\n#if cimg_OS==2\n      if (!path_found) {\n        std::strcpy(s_path,\".\\\\curl.exe\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"curl.exe\");\n#else\n      if (!path_found) {\n        std::strcpy(s_path,\"./curl\");\n        if ((file=std::fopen(s_path,\"r\"))!=0) { cimg::fclose(file); path_found = true; }\n      }\n      if (!path_found) std::strcpy(s_path,\"curl\");\n#endif\n      winformat_string(s_path);\n    }\n    cimg::mutex(7,0);\n    return s_path;\n  }\n\n  // [internal] Sorting function, used by cimg::files().\n  inline int _sort_files(const void* a, const void* b) {\n    const CImg<char> &sa = *(CImg<char>*)a, &sb = *(CImg<char>*)b;\n    return std::strcmp(sa._data,sb._data);\n  }\n\n  //! Return list of files/directories in specified directory.\n  /**\n     \\param path Path to the directory. Set to 0 for current directory.\n     \\param is_pattern Tell if specified path has a matching pattern in it.\n     \\param mode Output type, can be primary { 0=files only | 1=folders only | 2=files + folders }.\n     \\param include_path Tell if \\c path must be included in resulting filenames.\n     \\return A list of filenames.\n  **/\n  inline CImgList<char> files(const char *const path, const bool is_pattern=false,\n                              const unsigned int mode=2, const bool include_path=false) {\n    if (!path || !*path) return files(\"*\",true,mode,include_path);\n    CImgList<char> res;\n\n    // If path is a valid folder name, ignore argument 'is_pattern'.\n    const bool _is_pattern = is_pattern && !cimg::is_directory(path);\n    bool is_root = false, is_current = false;\n    cimg::unused(is_root,is_current);\n\n    // Clean format of input path.\n    CImg<char> pattern, _path = CImg<char>::string(path);\n#if cimg_OS==2\n    for (char *ps = _path; *ps; ++ps) if (*ps=='\\\\') *ps='/';\n#endif\n    char *pd = _path;\n    for (char *ps = pd; *ps; ++ps) { if (*ps!='/' || *ps!=*(ps+1)) *(pd++) = *ps; }\n    *pd = 0;\n    unsigned int lp = (unsigned int)std::strlen(_path);\n    if (!_is_pattern && lp && _path[lp - 1]=='/') {\n      _path[lp - 1] = 0; --lp;\n#if cimg_OS!=2\n      is_root = !*_path;\n#endif\n    }\n\n    // Separate folder path and matching pattern.\n    if (_is_pattern) {\n      const unsigned int bpos = (unsigned int)(cimg::basename(_path,'/') - _path.data());\n      CImg<char>::string(_path).move_to(pattern);\n      if (bpos) {\n        _path[bpos - 1] = 0; // End 'path' at last slash.\n#if cimg_OS!=2\n        is_root = !*_path;\n#endif\n      } else { // No path to folder specified, assuming current folder.\n        is_current = true; *_path = 0;\n      }\n      lp = (unsigned int)std::strlen(_path);\n    }\n\n    // Windows version.\n#if cimg_OS==2\n    if (!_is_pattern) {\n      pattern.assign(lp + 3);\n      std::memcpy(pattern,_path,lp);\n      pattern[lp] = '/'; pattern[lp + 1] = '*'; pattern[lp + 2] = 0;\n    }\n    WIN32_FIND_DATAA file_data;\n    const HANDLE dir = FindFirstFileA(pattern.data(),&file_data);\n    if (dir==INVALID_HANDLE_VALUE) return CImgList<char>::const_empty();\n    do {\n      const char *const filename = file_data.cFileName;\n      if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) {\n        const unsigned int lf = (unsigned int)std::strlen(filename);\n        const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0;\n        if ((!mode && !is_directory) || (mode==1 && is_directory) || mode>=2) {\n          if (include_path) {\n            CImg<char> full_filename((lp?lp+1:0) + lf + 1);\n            if (lp) { std::memcpy(full_filename,_path,lp); full_filename[lp] = '/'; }\n            std::memcpy(full_filename._data + (lp?lp + 1:0),filename,lf + 1);\n            full_filename.move_to(res);\n          } else CImg<char>(filename,lf + 1).move_to(res);\n        }\n      }\n    } while (FindNextFileA(dir,&file_data));\n    FindClose(dir);\n\n    // Unix version (posix).\n#else\n    DIR *const dir = opendir(is_root?\"/\":is_current?\".\":_path.data());\n    if (!dir) return CImgList<char>::const_empty();\n    struct dirent *ent;\n    while ((ent=readdir(dir))!=0) {\n      const char *const filename = ent->d_name;\n      if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) {\n        const unsigned int lf = (unsigned int)std::strlen(filename);\n        CImg<char> full_filename(lp + lf + 2);\n\n        if (!is_current) {\n          full_filename.assign(lp + lf + 2);\n          if (lp) std::memcpy(full_filename,_path,lp);\n          full_filename[lp] = '/';\n          std::memcpy(full_filename._data + lp + 1,filename,lf + 1);\n        } else full_filename.assign(filename,lf + 1);\n\n        struct stat st;\n        if (stat(full_filename,&st)==-1) continue;\n        const bool is_directory = (st.st_mode & S_IFDIR)!=0;\n        if ((!mode && !is_directory) || (mode==1 && is_directory) || mode==2) {\n          if (include_path) {\n            if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0)))\n              full_filename.move_to(res);\n          } else {\n            if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0)))\n              CImg<char>(filename,lf + 1).move_to(res);\n          }\n        }\n      }\n    }\n    closedir(dir);\n#endif\n\n    // Sort resulting list by lexicographic order.\n  if (res._width>=2) std::qsort(res._data,res._width,sizeof(CImg<char>),_sort_files);\n\n    return res;\n  }\n\n  //! Try to guess format from an image file.\n  /**\n     \\param file Input file (can be \\c 0 if \\c filename is set).\n     \\param filename Filename, as a C-string (can be \\c 0 if \\c file is set).\n     \\return C-string containing the guessed file format, or \\c 0 if nothing has been guessed.\n  **/\n  inline const char *ftype(std::FILE *const file, const char *const filename) {\n    if (!file && !filename)\n      throw CImgArgumentException(\"cimg::ftype(): Specified filename is (null).\");\n    static const char\n      *const _pnm = \"pnm\",\n      *const _pfm = \"pfm\",\n      *const _bmp = \"bmp\",\n      *const _gif = \"gif\",\n      *const _jpg = \"jpg\",\n      *const _off = \"off\",\n      *const _pan = \"pan\",\n      *const _png = \"png\",\n      *const _tif = \"tif\",\n      *const _inr = \"inr\",\n      *const _dcm = \"dcm\";\n    const char *f_type = 0;\n    CImg<char> header;\n    const unsigned int omode = cimg::exception_mode();\n    cimg::exception_mode(0);\n    try {\n      header._load_raw(file,filename,512,1,1,1,false,false,0);\n      const unsigned char *const uheader = (unsigned char*)header._data;\n      if (!std::strncmp(header,\"OFF\\n\",4)) f_type = _off; // OFF.\n      else if (!std::strncmp(header,\"#INRIMAGE\",9)) f_type = _inr; // INRIMAGE.\n      else if (!std::strncmp(header,\"PANDORE\",7)) f_type = _pan; // PANDORE.\n      else if (!std::strncmp(header.data() + 128,\"DICM\",4)) f_type = _dcm; // DICOM.\n      else if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) f_type = _jpg;  // JPEG.\n      else if (header[0]=='B' && header[1]=='M') f_type = _bmp;  // BMP.\n      else if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' && // GIF.\n               (header[4]=='7' || header[4]=='9')) f_type = _gif;\n      else if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 &&  // PNG.\n               uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) f_type = _png;\n      else if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) f_type = _tif; // TIFF.\n      else { // PNM or PFM.\n        CImgList<char> _header = header.get_split(CImg<char>::vector('\\n'),0,false);\n        cimglist_for(_header,l) {\n          if (_header(l,0)=='#') continue;\n          if (_header[l]._height==2 && _header(l,0)=='P') {\n            const char c = _header(l,1);\n            if (c=='f' || c=='F') { f_type = _pfm; break; }\n            if (c>='1' && c<='9') { f_type = _pnm; break; }\n          }\n          f_type = 0; break;\n        }\n      }\n    } catch (CImgIOException&) { }\n    cimg::exception_mode(omode);\n    return f_type;\n  }\n\n  //! Load file from network as a local temporary file.\n  /**\n     \\param filename Filename, as a C-string.\n     \\param[out] filename_local C-string containing the path to a local copy of \\c filename.\n     \\param timeout Maximum time (in seconds) authorized for downloading the file from the URL.\n     \\param try_fallback When using libcurl, tells using system calls as fallbacks in case of libcurl failure.\n     \\return Value of \\c filename_local.\n     \\note Use the \\c libcurl library, or the external binaries \\c wget or \\c curl to perform the download.\n  **/\n  inline char *load_network(const char *const url, char *const filename_local,\n                            const unsigned int timeout, const bool try_fallback,\n                            const char *const referer) {\n    if (!url)\n      throw CImgArgumentException(\"cimg::load_network(): Specified URL is (null).\");\n    if (!filename_local)\n      throw CImgArgumentException(\"cimg::load_network(): Specified destination string is (null).\");\n\n    const char *const __ext = cimg::split_filename(url), *const _ext = (*__ext && __ext>url)?__ext - 1:__ext;\n    CImg<char> ext = CImg<char>::string(_ext);\n    std::FILE *file = 0;\n    *filename_local = 0;\n    if (ext._width>16 || !cimg::strncasecmp(ext,\"cgi\",3)) *ext = 0;\n    else cimg::strwindows_reserved(ext);\n    do {\n      cimg_snprintf(filename_local,256,\"%s%c%s%s\",\n                    cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext._data);\n      if ((file=std::fopen(filename_local,\"rb\"))!=0) cimg::fclose(file);\n    } while (file);\n\n#ifdef cimg_use_curl\n    const unsigned int omode = cimg::exception_mode();\n    cimg::exception_mode(0);\n    try {\n      CURL *curl = 0;\n      CURLcode res;\n      curl = curl_easy_init();\n      if (curl) {\n        file = cimg::fopen(filename_local,\"wb\");\n        curl_easy_setopt(curl,CURLOPT_URL,url);\n        curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,0);\n        curl_easy_setopt(curl,CURLOPT_WRITEDATA,file);\n        curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L);\n        curl_easy_setopt(curl,CURLOPT_SSL_VERIFYHOST,0L);\n        curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L);\n        if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout);\n        if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L);\n        if (referer) curl_easy_setopt(curl,CURLOPT_REFERER,referer);\n        res = curl_easy_perform(curl);\n        curl_easy_cleanup(curl);\n        cimg::fseek(file,0,SEEK_END); // Check if file size is 0.\n        const cimg_ulong siz = cimg::ftell(file);\n        cimg::fclose(file);\n        if (siz>0 && res==CURLE_OK) {\n          cimg::exception_mode(omode);\n          return filename_local;\n        } else std::remove(filename_local);\n      }\n    } catch (...) { }\n    cimg::exception_mode(omode);\n    if (!try_fallback) throw CImgIOException(\"cimg::load_network(): Failed to load file '%s' with libcurl.\",url);\n#endif\n\n    CImg<char> command((unsigned int)std::strlen(url) + 64);\n    cimg::unused(try_fallback);\n\n    // Try with 'curl' first.\n    if (timeout) {\n      if (referer)\n        cimg_snprintf(command,command._width,\"%s -e %s -m %u -f --silent --compressed -o \\\"%s\\\" \\\"%s\\\"\",\n                      cimg::curl_path(),referer,timeout,filename_local,url);\n      else\n        cimg_snprintf(command,command._width,\"%s -m %u -f --silent --compressed -o \\\"%s\\\" \\\"%s\\\"\",\n                      cimg::curl_path(),timeout,filename_local,url);\n    } else {\n      if (referer)\n        cimg_snprintf(command,command._width,\"%s -e %s -f --silent --compressed -o \\\"%s\\\" \\\"%s\\\"\",\n                      cimg::curl_path(),referer,filename_local,url);\n      else\n        cimg_snprintf(command,command._width,\"%s -f --silent --compressed -o \\\"%s\\\" \\\"%s\\\"\",\n                      cimg::curl_path(),filename_local,url);\n    }\n    cimg::system(command);\n\n    if (!(file = std::fopen(filename_local,\"rb\"))) {\n\n      // Try with 'wget' otherwise.\n      if (timeout) {\n        if (referer)\n          cimg_snprintf(command,command._width,\"%s --referer=%s -T %u -q -r -l 0 --no-cache -O \\\"%s\\\" \\\"%s\\\"\",\n                        cimg::wget_path(),referer,timeout,filename_local,url);\n        else\n          cimg_snprintf(command,command._width,\"%s -T %u -q -r -l 0 --no-cache -O \\\"%s\\\" \\\"%s\\\"\",\n                        cimg::wget_path(),timeout,filename_local,url);\n      } else {\n        if (referer)\n          cimg_snprintf(command,command._width,\"%s --referer=%s -q -r -l 0 --no-cache -O \\\"%s\\\" \\\"%s\\\"\",\n                        cimg::wget_path(),referer,filename_local,url);\n        else\n          cimg_snprintf(command,command._width,\"%s -q -r -l 0 --no-cache -O \\\"%s\\\" \\\"%s\\\"\",\n                        cimg::wget_path(),filename_local,url);\n      }\n      cimg::system(command);\n\n      if (!(file = std::fopen(filename_local,\"rb\")))\n        throw CImgIOException(\"cimg::load_network(): Failed to load file '%s' with external commands \"\n                              \"'wget' or 'curl'.\",url);\n      cimg::fclose(file);\n\n      // Try gunzip it.\n      cimg_snprintf(command,command._width,\"%s.gz\",filename_local);\n      std::rename(filename_local,command);\n      cimg_snprintf(command,command._width,\"%s --quiet \\\"%s.gz\\\"\",\n                    gunzip_path(),filename_local);\n      cimg::system(command);\n      file = std::fopen(filename_local,\"rb\");\n      if (!file) {\n        cimg_snprintf(command,command._width,\"%s.gz\",filename_local);\n        std::rename(command,filename_local);\n        file = std::fopen(filename_local,\"rb\");\n      }\n    }\n    cimg::fseek(file,0,SEEK_END); // Check if file size is 0.\n    if (std::ftell(file)<=0)\n      throw CImgIOException(\"cimg::load_network(): Failed to load URL '%s' with external commands \"\n                            \"'wget' or 'curl'.\",url);\n    cimg::fclose(file);\n    return filename_local;\n  }\n\n  // Implement a tic/toc mechanism to display elapsed time of algorithms.\n  inline cimg_ulong tictoc(const bool is_tic) {\n    cimg::mutex(2);\n    static CImg<cimg_ulong> times(64);\n    static unsigned int pos = 0;\n    const cimg_ulong t1 = cimg::time();\n    if (is_tic) { // Tic.\n      times[pos++] = t1;\n      if (pos>=times._width)\n        throw CImgArgumentException(\"cimg::tic(): Too much calls to 'cimg::tic()' without calls to 'cimg::toc()'.\");\n      cimg::mutex(2,0);\n      return t1;\n    }\n    // Toc.\n    if (!pos)\n      throw CImgArgumentException(\"cimg::toc(): No previous call to 'cimg::tic()' has been made.\");\n    const cimg_ulong\n      t0 = times[--pos],\n      dt = t1>=t0?(t1 - t0):cimg::type<cimg_ulong>::max();\n    const unsigned int\n      edays = (unsigned int)(dt/86400000.0),\n      ehours = (unsigned int)((dt - edays*86400000.0)/3600000.0),\n      emin = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0)/60000.0),\n      esec = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0)/1000.0),\n      ems = (unsigned int)(dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0 - esec*1000.0);\n    if (!edays && !ehours && !emin && !esec)\n      std::fprintf(cimg::output(),\"%s[CImg]%*sElapsed time: %u ms%s\\n\",\n                   cimg::t_red,1 + 2*pos,\"\",ems,cimg::t_normal);\n    else {\n      if (!edays && !ehours && !emin)\n        std::fprintf(cimg::output(),\"%s[CImg]%*sElapsed time: %u sec %u ms%s\\n\",\n                     cimg::t_red,1 + 2*pos,\"\",esec,ems,cimg::t_normal);\n      else {\n        if (!edays && !ehours)\n          std::fprintf(cimg::output(),\"%s[CImg]%*sElapsed time: %u min %u sec %u ms%s\\n\",\n                       cimg::t_red,1 + 2*pos,\"\",emin,esec,ems,cimg::t_normal);\n        else{\n          if (!edays)\n            std::fprintf(cimg::output(),\"%s[CImg]%*sElapsed time: %u hours %u min %u sec %u ms%s\\n\",\n                         cimg::t_red,1 + 2*pos,\"\",ehours,emin,esec,ems,cimg::t_normal);\n          else{\n            std::fprintf(cimg::output(),\"%s[CImg]%*sElapsed time: %u days %u hours %u min %u sec %u ms%s\\n\",\n                         cimg::t_red,1 + 2*pos,\"\",edays,ehours,emin,esec,ems,cimg::t_normal);\n          }\n        }\n      }\n    }\n    cimg::mutex(2,0);\n    return dt;\n  }\n\n  // Return a temporary string describing the size of a memory buffer.\n  inline const char *strbuffersize(const cimg_ulong size) {\n    static CImg<char> res(256);\n    cimg::mutex(5);\n    if (size<1024LU) cimg_snprintf(res,res._width,\"%lu byte%s\",size,size>1?\"s\":\"\");\n    else if (size<1024*1024LU) { const float nsize = size/1024.0f; cimg_snprintf(res,res._width,\"%.1f Kio\",nsize); }\n    else if (size<1024*1024*1024LU) {\n      const float nsize = size/(1024*1024.0f); cimg_snprintf(res,res._width,\"%.1f Mio\",nsize);\n    } else { const float nsize = size/(1024*1024*1024.0f); cimg_snprintf(res,res._width,\"%.1f Gio\",nsize); }\n    cimg::mutex(5,0);\n    return res;\n  }\n\n  //! Display a simple dialog box, and wait for the user's response.\n  /**\n     \\param title Title of the dialog window.\n     \\param msg Main message displayed inside the dialog window.\n     \\param button1_label Label of the 1st button.\n     \\param button2_label Label of the 2nd button (\\c 0 to hide button).\n     \\param button3_label Label of the 3rd button (\\c 0 to hide button).\n     \\param button4_label Label of the 4th button (\\c 0 to hide button).\n     \\param button5_label Label of the 5th button (\\c 0 to hide button).\n     \\param button6_label Label of the 6th button (\\c 0 to hide button).\n     \\param logo Image logo displayed at the left of the main message.\n     \\param is_centered Tells if the dialog window must be centered on the screen.\n     \\return Indice of clicked button (from \\c 0 to \\c 5), or \\c -1 if the dialog window has been closed by the user.\n     \\note\n     - Up to 6 buttons can be defined in the dialog window.\n     - The function returns when a user clicked one of the button or closed the dialog window.\n     - If a button text is set to 0, the corresponding button (and the followings) will not appear in the dialog box.\n     At least one button must be specified.\n  **/\n  template<typename t>\n  inline int dialog(const char *const title, const char *const msg,\n                    const char *const button1_label, const char *const button2_label,\n                    const char *const button3_label, const char *const button4_label,\n                    const char *const button5_label, const char *const button6_label,\n                    const CImg<t>& logo, const bool is_centered=false) {\n#if cimg_display==0\n    cimg::unused(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label,\n                 logo._data,is_centered);\n    throw CImgIOException(\"cimg::dialog(): No display available.\");\n#else\n    static const unsigned char\n      black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };\n\n    // Create buttons and canvas graphics\n    CImgList<unsigned char> buttons, cbuttons, sbuttons;\n    if (button1_label) { CImg<unsigned char>().draw_text(0,0,button1_label,black,gray,1,13).move_to(buttons);\n      if (button2_label) { CImg<unsigned char>().draw_text(0,0,button2_label,black,gray,1,13).move_to(buttons);\n        if (button3_label) { CImg<unsigned char>().draw_text(0,0,button3_label,black,gray,1,13).move_to(buttons);\n          if (button4_label) { CImg<unsigned char>().draw_text(0,0,button4_label,black,gray,1,13).move_to(buttons);\n            if (button5_label) { CImg<unsigned char>().draw_text(0,0,button5_label,black,gray,1,13).move_to(buttons);\n              if (button6_label) { CImg<unsigned char>().draw_text(0,0,button6_label,black,gray,1,13).move_to(buttons);\n              }}}}}}\n    if (!buttons._width)\n      throw CImgArgumentException(\"cimg::dialog(): No buttons have been defined.\");\n    cimglist_for(buttons,l) buttons[l].resize(-100,-100,1,3);\n\n    unsigned int bw = 0, bh = 0;\n    cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l]._width); bh = cimg::max(bh,buttons[l]._height); }\n    bw+=8; bh+=8;\n    if (bw<64) bw = 64;\n    if (bw>128) bw = 128;\n    if (bh<24) bh = 24;\n    if (bh>48) bh = 48;\n\n    CImg<unsigned char> button(bw,bh,1,3);\n    button.draw_rectangle(0,0,bw - 1,bh - 1,gray);\n    button.draw_line(0,0,bw - 1,0,white).draw_line(0,bh - 1,0,0,white);\n    button.draw_line(bw - 1,0,bw - 1,bh - 1,black).draw_line(bw - 1,bh - 1,0,bh - 1,black);\n    button.draw_line(1,bh - 2,bw - 2,bh - 2,gray2).draw_line(bw - 2,bh - 2,bw - 2,1,gray2);\n    CImg<unsigned char> sbutton(bw,bh,1,3);\n    sbutton.draw_rectangle(0,0,bw - 1,bh - 1,gray);\n    sbutton.draw_line(0,0,bw - 1,0,black).draw_line(bw - 1,0,bw - 1,bh - 1,black);\n    sbutton.draw_line(bw - 1,bh - 1,0,bh - 1,black).draw_line(0,bh - 1,0,0,black);\n    sbutton.draw_line(1,1,bw - 2,1,white).draw_line(1,bh - 2,1,1,white);\n    sbutton.draw_line(bw - 2,1,bw - 2,bh - 2,black).draw_line(bw - 2,bh - 2,1,bh - 2,black);\n    sbutton.draw_line(2,bh - 3,bw - 3,bh - 3,gray2).draw_line(bw - 3,bh - 3,bw - 3,2,gray2);\n    sbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true).draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false);\n    sbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false).draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false);\n    CImg<unsigned char> cbutton(bw,bh,1,3);\n    cbutton.draw_rectangle(0,0,bw - 1,bh - 1,black).draw_rectangle(1,1,bw - 2,bh - 2,gray2).\n      draw_rectangle(2,2,bw - 3,bh - 3,gray);\n    cbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true).draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false);\n    cbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false).draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false);\n\n    cimglist_for(buttons,ll) {\n      CImg<unsigned char>(cbutton).\n        draw_image(1 + (bw  -buttons[ll].width())/2,1 + (bh - buttons[ll].height())/2,buttons[ll]).\n        move_to(cbuttons);\n      CImg<unsigned char>(sbutton).\n        draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]).\n        move_to(sbuttons);\n      CImg<unsigned char>(button).\n        draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]).\n        move_to(buttons[ll]);\n    }\n\n    CImg<unsigned char> canvas;\n    if (msg)\n      ((CImg<unsigned char>().draw_text(0,0,\"%s\",gray,0,1,13,msg)*=-1)+=200).resize(-100,-100,1,3).move_to(canvas);\n\n    const unsigned int\n      bwall = (buttons._width - 1)*(12 + bw) + bw,\n      w = cimg::max(196U,36 + logo._width + canvas._width,24 + bwall),\n      h = cimg::max(96U,36 + canvas._height + bh,36 + logo._height + bh),\n      lx = 12 + (canvas._data?0:((w - 24 - logo._width)/2)),\n      ly = (h - 12 - bh - logo._height)/2,\n      tx = lx + logo._width + 12,\n      ty = (h - 12 - bh - canvas._height)/2,\n      bx = (w - bwall)/2,\n      by = h - 12 - bh;\n\n    if (canvas._data)\n      canvas = CImg<unsigned char>(w,h,1,3).\n        draw_rectangle(0,0,w - 1,h - 1,gray).\n        draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white).\n        draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black).\n        draw_image(tx,ty,canvas);\n    else\n      canvas = CImg<unsigned char>(w,h,1,3).\n        draw_rectangle(0,0,w - 1,h - 1,gray).\n        draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white).\n        draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black);\n    if (logo._data) canvas.draw_image(lx,ly,logo);\n\n    unsigned int xbuttons[6] = { 0 };\n    cimglist_for(buttons,lll) { xbuttons[lll] = bx + (bw + 12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); }\n\n    // Open window and enter events loop\n    CImgDisplay disp(canvas,title?title:\" \",0,false,is_centered?true:false);\n    if (is_centered) disp.move((CImgDisplay::screen_width() - disp.width())/2,\n                               (CImgDisplay::screen_height() - disp.height())/2);\n    bool stop_flag = false, refresh = false;\n    int oselected = -1, oclicked = -1, selected = -1, clicked = -1;\n    while (!disp.is_closed() && !stop_flag) {\n      if (refresh) {\n        if (clicked>=0)\n          CImg<unsigned char>(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp);\n        else {\n          if (selected>=0)\n            CImg<unsigned char>(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp);\n          else canvas.display(disp);\n        }\n        refresh = false;\n      }\n      disp.wait(15);\n      if (disp.is_resized()) disp.resize(disp,false);\n\n      if (disp.button()&1)  {\n        oclicked = clicked;\n        clicked = -1;\n        cimglist_for(buttons,l)\n          if (disp.mouse_y()>=(int)by && disp.mouse_y()<(int)(by + bh) &&\n              disp.mouse_x()>=(int)xbuttons[l] && disp.mouse_x()<(int)(xbuttons[l] + bw)) {\n            clicked = selected = l;\n            refresh = true;\n          }\n        if (clicked!=oclicked) refresh = true;\n      } else if (clicked>=0) stop_flag = true;\n\n      if (disp.key()) {\n        oselected = selected;\n        switch (disp.key()) {\n        case cimg::keyESC : selected = -1; stop_flag = true; break;\n        case cimg::keyENTER : if (selected<0) selected = 0; stop_flag = true; break;\n        case cimg::keyTAB :\n        case cimg::keyARROWRIGHT :\n        case cimg::keyARROWDOWN : selected = (selected + 1)%buttons.width(); break;\n        case cimg::keyARROWLEFT :\n        case cimg::keyARROWUP : selected = (selected + buttons.width() - 1)%buttons.width(); break;\n        }\n        disp.set_key();\n        if (selected!=oselected) refresh = true;\n      }\n    }\n    if (!disp) selected = -1;\n    return selected;\n#endif\n  }\n\n  //! Display a simple dialog box, and wait for the user's response \\specialization.\n  inline int dialog(const char *const title, const char *const msg,\n                    const char *const button1_label, const char *const button2_label, const char *const button3_label,\n                    const char *const button4_label, const char *const button5_label, const char *const button6_label,\n                    const bool is_centered) {\n    return dialog(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label,\n                  CImg<unsigned char>::_logo40x38(),is_centered);\n  }\n\n  //! Evaluate math expression.\n  /**\n     \\param expression C-string describing the formula to evaluate.\n     \\param x Value of the pre-defined variable \\c x.\n     \\param y Value of the pre-defined variable \\c y.\n     \\param z Value of the pre-defined variable \\c z.\n     \\param c Value of the pre-defined variable \\c c.\n     \\return Result of the formula evaluation.\n     \\note Set \\c expression to \\c 0 to keep evaluating the last specified \\c expression.\n     \\par Example\n     \\code\n     const double\n     res1 = cimg::eval(\"cos(x)^2 + sin(y)^2\",2,2),  // will return '1'.\n     res2 = cimg::eval(0,1,1);                    // will return '1' too.\n     \\endcode\n  **/\n  inline double eval(const char *const expression, const double x, const double y, const double z, const double c) {\n    static const CImg<float> empty;\n    return empty.eval(expression,x,y,z,c);\n  }\n\n  template<typename t>\n  inline CImg<typename cimg::superset<double,t>::type> eval(const char *const expression, const CImg<t>& xyzc) {\n    static const CImg<float> empty;\n    return empty.eval(expression,xyzc);\n  }\n\n  // End of cimg:: namespace\n}\n\n  // End of cimg_library:: namespace\n}\n\n//! Short alias name.\nnamespace cil = cimg_library_suffixed;\n\n#ifdef _cimg_redefine_False\n#define False 0\n#endif\n#ifdef _cimg_redefine_True\n#define True 1\n#endif\n#ifdef _cimg_redefine_None\n#define None 0\n#endif\n#ifdef _cimg_redefine_min\n#define min(a,b) (((a)<(b))?(a):(b))\n#endif\n#ifdef _cimg_redefine_max\n#define max(a,b) (((a)>(b))?(a):(b))\n#endif\n#ifdef _cimg_redefine_PI\n#define PI 3.141592653589793238462643383\n#endif\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n#endif\n// Local Variables:\n// mode: c++\n// End:\n"
  },
  {
    "path": "BOSS/source/CombatSearch.cpp",
    "content": "#include \"CombatSearch.h\"\n\nusing namespace BOSS;\n\n\n// function which is called to do the actual search\nvoid CombatSearch::search()\n{\n    _searchTimer.start();\n\n    // apply the opening build order to the initial state\n    GameState initialState(_params.getInitialState());\n    _buildOrder = _params.getOpeningBuildOrder();\n    _buildOrder.doActions(initialState);\n\n    try\n    {\n        recurse(initialState, 0);\n    \n        _results.solved = true;\n    }\n    catch (int e)\n    {\n        if (e == BOSS_COMBATSEARCH_TIMEOUT)\n        {\n            _results.timedOut = true;\n        }\n    }\n\n    _results.timeElapsed = _searchTimer.getElapsedTimeInMilliSec();\n}\n\n// This functio generates the legal actions from a GameState based on the input search parameters\nvoid CombatSearch::generateLegalActions(const GameState & state, ActionSet & legalActions, const CombatSearchParameters & params)\n{\n    // prune actions we have too many of already\n    const ActionSet & allActions = params.getRelevantActions();\n    for (ActionID a(0); a<(int)allActions.size(); ++a)\n    {\n        const ActionType & action = allActions[a];\n        bool isLegal = state.isLegal(action);\n\n        if (!isLegal)\n        {\n            continue;\n        }\n\n        // prune the action if we have too many of them already\n        if ((params.getMaxActions(action) != -1) && (state.getUnitData().getNumTotal(action) >= params.getMaxActions(action)))\n        {\n            continue;\n        }\n        \n        legalActions.add(action);\n    }\n\n    // if we enabled the always make workers flag, and workers are legal\n    const ActionType & worker = ActionTypes::GetWorker(state.getRace());\n    if (_params.getAlwaysMakeWorkers() && legalActions.contains(worker))\n    {\n        bool actionLegalBeforeWorker = false;\n\n        // when can we make a worker\n        FrameCountType workerReady = state.whenCanPerform(worker);\n        \n        // if we can make a worker in the next couple of frames, do it\n        if (workerReady <= state.getCurrentFrame() + 2)\n        {\n            legalActions.clear();\n            legalActions.add(worker);\n            return;\n        }\n\n        // figure out of anything can be made before a worker\n        for (size_t a(0); a < legalActions.size(); ++a)\n        {\n            const ActionType & actionType = legalActions[a];\n            const FrameCountType whenCanPerformAction = state.whenCanPerform(actionType);\n            if (whenCanPerformAction < workerReady)\n            {\n                actionLegalBeforeWorker = true;\n                break;\n            }\n        }\n\n        // if something can be made before a worker, then don't consider workers\n        if (actionLegalBeforeWorker)\n        {\n            legalActions.remove(worker);\n        }\n        // otherwise we can make a worker next so don't consider anything else\n        else\n        {\n            legalActions.clear();\n            legalActions.add(worker);\n        }\n    }\n}\n\nconst CombatSearchResults & CombatSearch::getResults() const\n{\n    return _results;\n}\n\nbool CombatSearch::timeLimitReached()\n{\n    return (_params.getSearchTimeLimit() && (_results.nodesExpanded % 100 == 0) && (_searchTimer.getElapsedTimeInMilliSec() > _params.getSearchTimeLimit()));\n}\n\nbool CombatSearch::isTerminalNode(const GameState & s, int depth)\n{\n    if (s.getCurrentFrame() >= _params.getFrameTimeLimit())\n    {\n        return true;\n    }\n\n    return false;\n}\n\nvoid CombatSearch::recurse(const GameState & state, size_t depth)\n{\n    // This base class function should never be called, leaving the code\n    // here as a basis to form child classes\n\n    BOSS_ASSERT(false, \"Base CombatSearch doSearch() should never be called\");\n\n    //if (timeLimitReached())\n    //{\n    //    throw BOSS_COMBATSEARCH_TIMEOUT;\n    //}\n\n    //updateResults(state);\n\n    //if (isTerminalNode(state, depth))\n    //{\n    //    return;\n    //}\n\n    //ActionSet legalActions;\n    //generateLegalActions(state, legalActions, _params);\n    //\n    //for (UnitCountType a(0); a < legalActions.size(); ++a)\n    //{\n    //    GameState child(state);\n    //    child.doAction(legalActions[a]);\n    //    _buildOrder.add(legalActions[a]);\n    //    \n    //    doSearch(child,depth+1);\n\n    //    _buildOrder.pop_back();\n    //}\n}\n\nvoid CombatSearch::updateResults(const GameState & state)\n{\n    _results.nodesExpanded++;\n}\n\nvoid CombatSearch::printResults()\n{\n    std::cout << \"Printing base class CombatSearch results!\\n\\n\";\n}\n\nvoid CombatSearch::writeResultsFile(const std::string & prefix)\n{\n    std::cout << \"Writing base class CombatSearch results!\\n\\n\";\n}"
  },
  {
    "path": "BOSS/source/CombatSearch.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Timer.hpp\"\n#include \"Eval.h\"\n#include \"BuildOrder.h\"\n#include \"CombatSearchParameters.h\"\n#include \"CombatSearchResults.h\"\n\nnamespace BOSS\n{\n\n#define BOSS_COMBATSEARCH_TIMEOUT -1\n#define MAX_COMBAT_SEARCH_DEPTH 100\n\n\nclass CombatSearch\n{\nprotected:\n\n    CombatSearchParameters      _params;            // parameters that will be used in this search\n    CombatSearchResults         _results;\t\t\t// the results of the search so far\n\n    FrameCountType              _upperBound; \t\t// the current upper bound for search\n    Timer                       _searchTimer;\n\n    BuildOrder                  _buildOrder;\n\n    virtual void                recurse(const GameState & s,size_t depth);\n    virtual void                generateLegalActions(const GameState & state,ActionSet & legalActions,const CombatSearchParameters & params);\n\n    //virtual double              eval(const GameState & state) const;\n    virtual bool                isTerminalNode(const GameState & s,int depth);\n\n    virtual void                updateResults(const GameState & state);\n    virtual bool                timeLimitReached();\n\npublic:\n\n    virtual void                search();\n    virtual void                printResults();\n    virtual void                writeResultsFile(const std::string & prefix);\n\n    virtual const CombatSearchResults & getResults() const;\n};\n\n}"
  },
  {
    "path": "BOSS/source/CombatSearchExperiment.cpp",
    "content": "#include \"CombatSearchExperiment.h\"\n#include \"BOSSParameters.h\"\n\nusing namespace BOSS;\n\nCombatSearchExperiment::CombatSearchExperiment()\n    : _race(Races::None)\n{\n\n}\n\nCombatSearchExperiment::CombatSearchExperiment(const std::string & name, const rapidjson::Value & val)\n    : _race(Races::None)\n    , _name(name)\n{\n    BOSS_ASSERT(val.HasMember(\"SearchTypes\") && val[\"SearchTypes\"].IsArray(), \"CombatSearchExperiment must have a 'SearchTypes' array\");\n    for (size_t i(0); i < val[\"SearchTypes\"].Size(); ++i)\n    {\n        BOSS_ASSERT(val[\"SearchTypes\"][i].IsString(), \"searchTypes element is not a string\");\n        \n        _searchTypes.push_back(val[\"SearchTypes\"][i].GetString());\n    }\n\n    BOSS_ASSERT(val.HasMember(\"Race\") && val[\"Race\"].IsString(), \"CombatSearchExperiment must have a 'Race' string\");\n    _race = Races::GetRaceID(val[\"Race\"].GetString());\n\n    BOSS_ASSERT(val.HasMember(\"State\") && val[\"State\"].IsString(), \"CombatSearchExperiment must have a 'State' string\");\n    _params.setInitialState(BOSSParameters::Instance().GetState(val[\"State\"].GetString()));\n\n    BOSS_ASSERT(val.HasMember(\"FrameTimeLimit\") && val[\"FrameTimeLimit\"].IsInt(), \"CombatSearchExperiment must have a 'FrameTimeLimit' int\");\n    _params.setFrameTimeLimit(val[\"FrameTimeLimit\"].GetInt());\n\n    BOSS_ASSERT(val.HasMember(\"SearchTimeLimitMS\") && val[\"SearchTimeLimitMS\"].IsInt(), \"CombatSearchExperiment must have a 'SearchTimeLimitMS' int\");\n    _params.setSearchTimeLimit(val[\"SearchTimeLimitMS\"].GetInt());\n\n    if (val.HasMember(\"MaxActions\"))\n    {\n        const rapidjson::Value & maxActions = val[\"MaxActions\"];\n        BOSS_ASSERT(maxActions.IsArray(), \"MaxActions is not an array\");\n\n        for (size_t i(0); i < maxActions.Size(); ++i)\n        {\n            BOSS_ASSERT(maxActions[i].IsArray(), \"MaxActions element must be array of size 2\");\n\n            BOSS_ASSERT(maxActions[i].Size() == 2 && maxActions[i][0u].IsString() && maxActions[i][1u].IsInt(), \"MaxActions element must be [\\\"Action\\\", Count]\");\n\n            BOSS_ASSERT(ActionTypes::TypeExists(maxActions[i][0u].GetString()), \"Action Type doesn't exist: %s\", maxActions[i][0u].GetString());\n\n            _params.setMaxActions(ActionTypes::GetActionType(maxActions[i][0u].GetString()), maxActions[i][1].GetInt());\n        }\n    }\n\n    if (val.HasMember(\"RelevantActions\"))\n    {\n        const rapidjson::Value & relevantActions = val[\"RelevantActions\"];\n        BOSS_ASSERT(relevantActions.IsArray(), \"RelevantActions is not an array\");\n\n        ActionSet relevantActionSet;\n\n        for (size_t i(0); i < relevantActions.Size(); ++i)\n        {\n            BOSS_ASSERT(relevantActions[i].IsString(), \"RelvantActions element must be action type string\");\n            BOSS_ASSERT(ActionTypes::TypeExists(relevantActions[i].GetString()), \"Action Type doesn't exist: %s\", relevantActions[i].GetString());\n            \n            relevantActionSet.add(ActionTypes::GetActionType(relevantActions[i].GetString()));\n        }\n\n        _params.setRelevantActions(relevantActionSet);\n    }\n\n    if (val.HasMember(\"AlwaysMakeWorkers\"))\n    {\n        BOSS_ASSERT(val[\"AlwaysMakeWorkers\"].IsBool(), \"AlwaysMakeWorkers should be a bool\");\n\n        _params.setAlwaysMakeWorkers(val[\"AlwaysMakeWorkers\"].GetBool());\n    }\n\n    if (val.HasMember(\"OpeningBuildOrder\"))\n    {\n        BOSS_ASSERT(val[\"OpeningBuildOrder\"].IsString(), \"OpeningBuildOrder should be a string\");\n        _params.setOpeningBuildOrder(BOSSParameters::Instance().GetBuildOrder(val[\"OpeningBuildOrder\"].GetString()));\n    }\n\n    if (val.HasMember(\"BestResponseParams\"))\n    {\n        const rapidjson::Value & brVal = val[\"BestResponseParams\"];\n\n        BOSS_ASSERT(brVal.IsObject(), \"BestResponseParams not an object\");\n        BOSS_ASSERT(brVal.HasMember(\"EnemyState\"), \"bestResponseParams must have 'enemyState' string\");\n        BOSS_ASSERT(brVal.HasMember(\"EnemyBuildOrder\"), \"bestResponseParams must have 'enemyBuildOrder' string\");\n\n        BOSS_ASSERT(brVal.HasMember(\"EnemyState\") && brVal[\"EnemyState\"].IsString(), \"bestResponseParams must have a 'EnemyState' string\");\n        _params.setEnemyInitialState(BOSSParameters::Instance().GetState(brVal[\"EnemyState\"].GetString()));\n\n        BOSS_ASSERT(brVal.HasMember(\"EnemyBuildOrder\") && brVal[\"EnemyBuildOrder\"].IsString(), \"BestResponseParams must have a 'EnemyBuildOrder' string\");\n        _params.setEnemyBuildOrder(BOSSParameters::Instance().GetBuildOrder(brVal[\"EnemyBuildOrder\"].GetString()));\n    }\n}\n\nvoid CombatSearchExperiment::run()\n{\n    static std::string stars = \"************************************************\";\n    for (size_t i(0); i < _searchTypes.size(); ++i)\n    {\n        std::shared_ptr<CombatSearch> combatSearch;\n        std::string resultsFile = \"gnuplot/\" + _name;\n\n        std::cout << \"\\n\" << stars << \"\\n* Running Experiment: \" << _name << \" [\" << _searchTypes[i] << \"]\\n\" << stars << \"\\n\";\n\n        if (_searchTypes[i].compare(\"Integral\") == 0)\n        {\n            combatSearch = std::shared_ptr<CombatSearch>(new CombatSearch_Integral(_params));\n            resultsFile += \"_Integral\"; \n        }\n        else if (_searchTypes[i].compare(\"Bucket\") == 0)\n        {\n            combatSearch = std::shared_ptr<CombatSearch>(new CombatSearch_Bucket(_params));\n            resultsFile += \"_Bucket\"; \n        }\n        else if (_searchTypes[i].compare(\"BestResponse\") == 0)\n        {\n            combatSearch = std::shared_ptr<CombatSearch>(new CombatSearch_BestResponse(_params));\n            resultsFile += \"_BestResponse\"; \n        }\n        else\n        {\n            BOSS_ASSERT(false, \"CombatSearch type not found: %s\", _searchTypes[i].c_str());\n        }\n\n        combatSearch->search();\n        combatSearch->printResults();\n        combatSearch->writeResultsFile(resultsFile);\n        const CombatSearchResults & results = combatSearch->getResults();\n        std::cout << \"\\nSearched \" << results.nodesExpanded << \" nodes in \" << results.timeElapsed << \"ms @ \" << (1000.0*results.nodesExpanded/results.timeElapsed) << \" nodes/sec\\n\\n\";\n    }\n}"
  },
  {
    "path": "BOSS/source/CombatSearchExperiment.h",
    "content": "#pragma once\n\n#include \"BOSS.h\"\n#include \"JSONTools.h\"\n#include <memory>\n#include \"rapidjson/rapidjson.h\"\n#include \"rapidjson/document.h\"\n\nnamespace BOSS\n{\n\nclass CombatSearchExperiment\n{\n    std::string                 _name;\n    CombatSearchParameters      _params;\n    RaceID                      _race;\n    std::vector<std::string>    _searchTypes;\n\n    RaceID                      _enemyRace;\n    BuildOrder                  _enemyBuildOrder;\n\npublic:\n\n    CombatSearchExperiment();\n    CombatSearchExperiment(const std::string & name, const rapidjson::Value & experimentVal);\n\n    void run();\n};\n}\n"
  },
  {
    "path": "BOSS/source/CombatSearchParameters.cpp",
    "content": "#include \"CombatSearchParameters.h\"\n\nusing namespace BOSS;\n\n// alternate constructor\nCombatSearchParameters::CombatSearchParameters()\n    : _useRepetitions                (true)\n    , _useIncreasingRepetitions      (false)\n    , _useWorkerCutoff               (false)\n    , _workerCutoff                  (1)\n    , _useAlwaysMakeWorkers          (false)\n    , _useSupplyBounding             (false)\n    , _supplyBoundingThreshold       (1)\n    , _useLandmarkLowerBoundHeuristic(false)\n    , _useResourceLowerBoundHeuristic(false)\n    , _searchTimeLimit               (0)\n    , _initialUpperBound             (0)\n    , _initialState                  (Races::None)\n    , _maxActions                    (Constants::MAX_ACTIONS, -1)\n    , _repetitionValues              (Constants::MAX_ACTIONS, 1)\n    , _repetitionThresholds          (Constants::MAX_ACTIONS, 0)\n    , _printNewBest                  (false)\n{\n    \n}\n\nvoid CombatSearchParameters::setSearchTimeLimit(const double timeLimitMS)\n{\n    _searchTimeLimit = timeLimitMS;\n}\n\ndouble CombatSearchParameters::getSearchTimeLimit() const\n{\n    return _searchTimeLimit;\n}\n\nvoid CombatSearchParameters::setRelevantActions(const ActionSet & set)\n{\n    _relevantActions = set;\n}\n\nconst ActionSet & CombatSearchParameters::getRelevantActions() const\n{\n    return _relevantActions;\n}\n\nvoid CombatSearchParameters::setInitialState(const GameState & s)\n{\n    _initialState = s;\n}\n\nconst GameState & CombatSearchParameters::getInitialState() const\n{\n    return _initialState;\n}\n\nvoid CombatSearchParameters::setEnemyInitialState(const GameState & s)\n{\n    _enemyInitialState = s;\n}\n\nconst GameState & CombatSearchParameters::getEnemyInitialState() const\n{\n    return _enemyInitialState;\n}\n\nvoid CombatSearchParameters::setMaxActions(const ActionType & a, int max)\n{\n    _maxActions[a.ID()] = max;\n}\n\nvoid CombatSearchParameters::setOpeningBuildOrder(const BuildOrder & buildOrder)\n{\n    _openingBuildOrder = buildOrder;\n}\n\nconst BuildOrder & CombatSearchParameters::getOpeningBuildOrder() const\n{\n    return _openingBuildOrder;\n}\n\nvoid CombatSearchParameters::setEnemyBuildOrder(const BuildOrder & buildOrder)\n{\n    _enemyBuildOrder = buildOrder;\n}\n\nconst BuildOrder & CombatSearchParameters::getEnemyBuildOrder() const\n{\n    return _enemyBuildOrder;\n}\n\nvoid CombatSearchParameters::setRepetitions(const ActionType & a,int repetitions)\n{ \n    _repetitionValues[a.ID()] = repetitions; \n}\n\nint CombatSearchParameters::getMaxActions(const ActionType & a) const\n{ \n    return _maxActions[a.ID()]; \n}\n\nint CombatSearchParameters::getRepetitions(const ActionType & a) const\n{ \n    return _repetitionValues[a.ID()]; \n}\n\nvoid CombatSearchParameters::setFrameTimeLimit(const FrameCountType limit)\n{\n    _frameTimeLimit = limit;\n}\n\nvoid CombatSearchParameters::setAlwaysMakeWorkers(const bool flag)\n{\n    _useAlwaysMakeWorkers = flag;\n}\n\nconst bool CombatSearchParameters::getAlwaysMakeWorkers() const\n{\n    return _useAlwaysMakeWorkers;\n}   \n\nFrameCountType CombatSearchParameters::getFrameTimeLimit() const\n{\n    return _frameTimeLimit;\n}\n\n\n\nvoid CombatSearchParameters::print()\n{\n    printf(\"\\n\\nSearch Parameter Information\\n\\n\");\n\n    printf(\"%s\", _useRepetitions ?                    \"\\tUSE      Repetitions\\n\" : \"\");\n    printf(\"%s\", _useIncreasingRepetitions ?          \"\\tUSE      Increasing Repetitions\\n\" : \"\");\n    printf(\"%s\", _useWorkerCutoff ?                   \"\\tUSE      Worker Cutoff\\n\" : \"\");\n    printf(\"%s\", _useLandmarkLowerBoundHeuristic ?    \"\\tUSE      Landmark Lower Bound\\n\" : \"\");\n    printf(\"%s\", _useResourceLowerBoundHeuristic ?    \"\\tUSE      Resource Lower Bound\\n\" : \"\");\n    printf(\"%s\", _useAlwaysMakeWorkers ?              \"\\tUSE      Always Make Workers\\n\" : \"\");\n    printf(\"%s\", _useSupplyBounding ?                 \"\\tUSE      Supply Bounding\\n\" : \"\");\n    printf(\"\\n\");\n\n    //for (int a = 0; a < ACTIONS.size(); ++a)\n    //{\n    //    if (repetitionValues[a] != 1)\n    //    {\n    //        printf(\"\\tREP %7d %s\\n\", repetitionValues[a], ACTIONS[a].getName().c_str());\n    //    }\n    //}\n\n    //for (int a = 0; a < ACTIONS.size(); ++a)\n    //{\n    //    if (repetitionThresholds[a] != 0)\n    //    {\n    //        printf(\"\\tTHR %7d %s\\n\", repetitionThresholds[a], ACTIONS[a].getName().c_str());\n    //    }\n    //}\n\n    printf(\"\\n\\n\");\n}"
  },
  {
    "path": "BOSS/source/CombatSearchParameters.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"BuildOrder.h\"\n\nnamespace BOSS\n{\n\nclass CombatSearchParameters\n{\n\tvoid init();\n\n    Vec<int, Constants::MAX_ACTIONS> _maxActions;\n\n\t//      Flag which determines whether or not doubling macro actions will be used in search.\n\t//      Macro actions (see paper) trade suboptimality for decreasing search depth. For large\n\t//          plans repetitions are necessary. For example, to make probes only build in twos\n\t//          set useRepetitions = true and repetitionValues[probeAction] = 2\n\t//\n\t//      true:  macro actions are used, stored in repetitionValues array\n    //      false: macro actions not used, all actions will be carried out once\n\tbool \t_useRepetitions;\n\tVec<UnitCountType, Constants::MAX_ACTIONS>\t_repetitionValues;\n\t\n\t//      Flag which determines whether increasing repetitions will be used in search\n\t//      Increasing repetitions means the reptition value will be 1 until we have at least\n    //      repetitionThresholds[a] count of action a. For example, setting:\n\t//          repetitionThresholds[pylonAction] = 1, repetitionValues[pylonAction] = 2\n\t//          means that the first pylon will build on its own but all further pylons will\n\t//          be built 2 at a time.\n\t//\n\t//      true:  increasing repetitions are used\n\t//      false: increasing repetitions not used\n\tbool\t_useIncreasingRepetitions;\n\tVec<UnitCountType, Constants::MAX_ACTIONS> _repetitionThresholds;\n\n\t//\t\tFlag which determines whether or not we use worker cutoff pruning in search.\n\t//\t\tWorker cutoff pruning stops workers from being constructed after a certain number\n\t//\t\t\tof frames have passed in the search. Intuitively we build the majority of workers\n\t//\t\t\tat the beginning of a build, so this can enforce it to make search faster. If\n\t//          true, workers are no longer legal if currentFrame > workerCutoff * uperBound\n\t//          in our search algorithm. If workerCutoff is 1, workers will not be pruned.\n\t//\n\t//      true:  worker cutoff is used\n\t//      false: worker cutoff not used\n\tbool\t_useWorkerCutoff;\t\t\t\t\t\n\tdouble \t_workerCutoff;\n\t\n\t//      Flag which determines whether or not we always make workers during search\n\t//      This abstraction changes the search so that it always makes a worker if it is able to. It\n\t//          accomplished this by modifying the current legal actions to exclude anything that\n\t//          can't be started before the next worker. This ends up producing longer makespans but\n\t//          the economy it produces is much better. Optimal makespan plans often produce very\n\t//          few workers and the long term economy suffers.\n\t//\n\t//      true:  always make workers is used\n\t//      false: always make workers is not used\n\tbool\t_useAlwaysMakeWorkers;\n\t\n\t//      Flag which determines whether or not we use supply bounding in our search\n\t//      Supply bounding makes supply producing buildings illegal if we are currently ahead\n\t//          on supply by a certain amount. If we currently have more than\n\t//          supplyBoundingThreshold extra supply buildings worth of supply, we no longer\n\t//          build them. This is an abstraction used to make search faster which may\n\t//          produce suboptimal plans.\n\t//\n\t//      true:  supply bounding is used\n\t//      false: supply bounding is not used\n\tbool\t_useSupplyBounding;\n\tint\t\t_supplyBoundingThreshold;\n\t\n\t\n\t//      Flag which determines whether or not we use various heuristics in our search.\n\t//\n\t//      true:  the heuristic is used\n\t//      false: the heuristic is not used\n\tbool\t_useLandmarkLowerBoundHeuristic;\n\tbool\t_useResourceLowerBoundHeuristic;\n\t\n\t//      Search time limit measured in milliseconds\n\t//      If searchTimeLimit is set to a value greater than zero, the search will effectively\n\t//          time out and the best solution so far will be used in the results. This is\n\t//          accomplished by throwing an exception if the time limit is hit. Time is checked\n\t//          once every 1000 nodes expanded, as checking the time is slow.\n\tdouble\t_searchTimeLimit;\n\t\n\t//      Initial upper bound for the DFBB search\n\t//      If this value is set to zero, DFBB search will automatically determine an\n\t//          appropriate upper bound using an upper bound heuristic. If it is non-zero,\n\t//          it will use the value as an initial bound.\n\tint\t\t_initialUpperBound;\n\t\t\t\n\t//      Initial GameState used for the search. See GameState.h for details\n\tGameState\t\t\t\t_initialState;\n    BuildOrder              _openingBuildOrder;\n\n    GameState               _enemyInitialState;\n    BuildOrder              _enemyBuildOrder;\n\n    ActionSet               _relevantActions;\n    FrameCountType          _frameTimeLimit;\n    bool                    _printNewBest;\n\n\n\npublic:\n\n\t// alternate constructor\n\tCombatSearchParameters();\n\t\n\tvoid \t            setRepetitions(const ActionType & a, int repetitions);\n\tint \t            getRepetitions(const ActionType & a) const;\n\n    void                setMaxActions(const ActionType & a, int max);\n    int \t            getMaxActions(const ActionType & a) const;\n\n    void                setRelevantActions(const ActionSet & set);\n    const ActionSet &   getRelevantActions() const;\n\n    void                setInitialState(const GameState & s);\n    const GameState &   getInitialState() const;\n\n    void                setEnemyInitialState(const GameState & s);\n    const GameState &   getEnemyInitialState() const;\n\n    void                setOpeningBuildOrder(const BuildOrder & buildOrder);\n    const BuildOrder &  getOpeningBuildOrder() const;\n\n    void                setEnemyBuildOrder(const BuildOrder & buildOrder);\n    const BuildOrder &  getEnemyBuildOrder() const;\n\n    void                setSearchTimeLimit(const double timeLimitMS);\n    double              getSearchTimeLimit() const;\n\n    void                setFrameTimeLimit(const FrameCountType limit);\n    FrameCountType      getFrameTimeLimit() const;\n\n    void                setAlwaysMakeWorkers(const bool flag);\n    const bool          getAlwaysMakeWorkers() const;\n\t\n\tvoid print();\n};\n\n}"
  },
  {
    "path": "BOSS/source/CombatSearchResults.cpp",
    "content": "#include \"CombatSearchResults.h\"\n\nusing namespace BOSS;\n\nCombatSearchResults::CombatSearchResults()\n    : solved(false)\n    , timedOut(false)\n    , solutionLength(-1)\n    , upperBound(-1)\n    , lowerBound(-1)\n    , nodesExpanded(0)\n    , timeElapsed(0)\n    , avgBranch(0)\n    , minerals(0)\n    , gas(0)\n    , frameCompleted(0)\n    , winner(Races::None)\n    , highestEval(0)\n{\n}\n\nvoid CombatSearchResults::printResults(bool pbo)\n{\n    printf(\"%12d%12d%12d%14llu%12.4lf%12.2lf%12.2lf       \",upperBound,lowerBound,solutionLength,nodesExpanded,avgBranch,timeElapsed,(nodesExpanded/(timeElapsed/1000.0)));\n\n    if (pbo)\n    {\n        printBuildOrder();\n    }\n\n    printf(\"\\n\");\n}\n\nvoid CombatSearchResults::printBuildOrder()\n{\n    for (size_t i(0); i<buildOrder.size(); ++i)\n    {\n        printf(\"%d \", buildOrder[buildOrder.size()-1-i].ID());\n    }\n}"
  },
  {
    "path": "BOSS/source/CombatSearchResults.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"PrerequisiteSet.h\"\n#include \"GameState.h\"\n#include \"ActionType.h\"\n#include \"Timer.hpp\"\n\nnamespace BOSS\n{\nclass CombatSearchResults\n{\n\npublic:\n\n    bool                solved;\t\t\t// whether ot not a solution was found\n    bool                timedOut;\t\t// did the search time-out?\n\n    int                 solutionLength;\t// the length of the solution\n    int                 upperBound;\t\t// upper bound of first node\n    int                 lowerBound;\t\t// lower bound of first node\n\n    unsigned long long  nodesExpanded;\t// number of nodes expanded in the search\n\n    double              timeElapsed;\t// time elapsed in milliseconds\n    double              avgBranch;\t\t// avg branching factor\n\n    Timer               searchTimer;         \n\n    GameState           winner;\n\n    std::vector<ActionType> buildOrder;\t\t// the build order\n\n    double              highestEval;\n\n    ResourceCountType   minerals;\n    ResourceCountType   gas;\n\n    FrameCountType      frameCompleted;\n\n    CombatSearchResults();\n    CombatSearchResults(bool s,int len,unsigned long long n,double t,std::vector<ActionType> solution);\n\n    void printResults(bool pbo = true);\n    void printBuildOrder();\n};\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_BestResponse.cpp",
    "content": "#include \"CombatSearch_BestResponse.h\"\n\nusing namespace BOSS;\n\nCombatSearch_BestResponse::CombatSearch_BestResponse(const CombatSearchParameters p)\n    : _bestResponseData(p.getEnemyInitialState(), p.getEnemyBuildOrder())\n{\n    _params = p;\n\n    BOSS_ASSERT(_params.getInitialState().getRace() != Races::None, \"Combat search initial state is invalid\");\n}\n\nvoid CombatSearch_BestResponse::recurse(const GameState & state, size_t depth)\n{\n    if (timeLimitReached())\n    {\n        throw BOSS_COMBATSEARCH_TIMEOUT;\n    }\n\n    _bestResponseData.update(_params.getInitialState(), state, _buildOrder);\n    updateResults(state);\n\n    if (isTerminalNode(state, depth))\n    {\n        return;\n    }\n\n    ActionSet legalActions;\n    generateLegalActions(state, legalActions, _params);\n    \n    for (UnitCountType a(0); a < (int)legalActions.size(); ++a)\n    {\n        size_t ri = legalActions.size() - 1 - a;\n\n        GameState child(state);\n        child.doAction(legalActions[ri]);\n        _buildOrder.add(legalActions[ri]);\n        \n        recurse(child,depth+1);\n\n        _buildOrder.pop_back();\n    }\n}\n\nvoid CombatSearch_BestResponse::printResults()\n{\n\n}\n\n#include \"BuildOrderPlot.h\"\nvoid CombatSearch_BestResponse::writeResultsFile(const std::string & filename)\n{\n    BuildOrderPlot plot(_params.getInitialState(), _bestResponseData.getBestBuildOrder());\n\n    plot.writeRectanglePlot(filename + \"_BestBuildOrder\");\n    plot.writeArmyValuePlot(filename + \"_BestArmyValue\");\n\n    BuildOrderPlot plot2(_params.getEnemyInitialState(), _params.getEnemyBuildOrder());\n\n    plot2.writeRectanglePlot(filename + \"_EnemyBuildOrder\");\n    plot2.writeArmyValuePlot(filename + \"_EnemyArmyValue\");\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_BestResponse.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Timer.hpp\"\n#include \"Eval.h\"\n#include \"BuildOrder.h\"\n#include \"CombatSearch.h\"\n#include \"CombatSearchParameters.h\"\n#include \"CombatSearchResults.h\"\n#include \"CombatSearch_BestResponseData.h\"\n\nnamespace BOSS\n{\n\nclass CombatSearch_BestResponse : public CombatSearch\n{\n\tvirtual void                    recurse(const GameState & s, size_t depth);\n\n    CombatSearch_BestResponseData   _bestResponseData;\n\n    BuildOrder                      _bestBuildOrder;\n\n    double                          compareBuildOrders(const GameState & selfState, const BuildOrder & selfBuildOrder, const GameState & enemyState, const BuildOrder & enemyBuildOrder);\n\npublic:\n\t\n\tCombatSearch_BestResponse(const CombatSearchParameters p = CombatSearchParameters());\n\t\n    virtual void printResults();\n\n    virtual void writeResultsFile(const std::string & filename);\n};\n\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_BestResponseData.cpp",
    "content": "#include \"CombatSearch_BestResponseData.h\"\n\nusing namespace BOSS;\n\nCombatSearch_BestResponseData::CombatSearch_BestResponseData(const GameState & enemyState, const BuildOrder & enemyBuildOrder)\n    : _enemyInitialState(enemyState)\n    , _enemyBuildOrder(enemyBuildOrder)\n    , _bestEval(std::numeric_limits<double>::max())\n{\n    // compute enemy army values\n\n    calculateArmyValues(_enemyInitialState, _enemyBuildOrder, _enemyArmyValues);\n}\n\nvoid CombatSearch_BestResponseData::calculateArmyValues(const GameState & initialState, const BuildOrder & buildOrder, std::vector< std::pair<double, double> > & values)\n{\n    values.clear();\n    GameState state(initialState);\n    for (size_t i(0); i < buildOrder.size(); ++i)\n    {\n        state.doAction(buildOrder[i]);\n        values.push_back(std::pair<double,double>(state.getCurrentFrame(), Eval::ArmyTotalResourceSum(state)));\n    }\n}\n\n#include \"BuildOrderPlot.h\"\nvoid CombatSearch_BestResponseData::update(const GameState & initialState, const GameState & currentState, const BuildOrder & buildOrder)\n{\n    double eval = compareBuildOrder(initialState, buildOrder);\n\n    if (eval < _bestEval)\n    {\n        _bestEval = eval;\n        _bestBuildOrder = buildOrder;\n        _bestState = currentState;\n\n        std::cout << eval/Constants::RESOURCE_SCALE << \"   \" << _bestBuildOrder.getNameString(2) << std::endl;\n    }\n}\n\ndouble CombatSearch_BestResponseData::compareBuildOrder(const GameState & initialState, const BuildOrder & buildOrder)\n{\n    calculateArmyValues(initialState, buildOrder, _selfArmyValues);\n\n    size_t selfIndex = 0;\n    size_t enemyIndex = 0;\n    double maxDiff = std::numeric_limits<double>::lowest();\n    double sumDiff = 0;\n    int n = 0;\n\n    for (size_t ei(0); ei < _enemyArmyValues.size(); ++ei)\n    {\n        double enemyTime = _enemyArmyValues[ei].first;\n        double enemyVal = _enemyArmyValues[ei].second;    \n    \n        size_t selfIndex = 0;\n\n        // find the corresponding self army value for this time\n        for (size_t si(0); si < _selfArmyValues.size(); ++si)\n        {\n            if (enemyTime < _selfArmyValues[si].first)\n            {\n                break;\n            }\n\n            selfIndex = si;\n        }\n    \n        double selfVal = _selfArmyValues[selfIndex].second;\n        double diff = enemyVal - selfVal;\n        maxDiff = std::max(maxDiff, diff);\n    }\n\n    return maxDiff;\n}\n\nsize_t CombatSearch_BestResponseData::getStateIndex(const GameState & state)\n{\n    FrameCountType frame = state.getCurrentFrame();\n\n    if (frame > _enemyStates.back().getCurrentFrame())\n    {\n        return _enemyStates.size() - 1;\n    }\n\n    for (size_t i(0); i < _enemyStates.size(); ++i)\n    {\n        if (frame < _enemyStates[i].getCurrentFrame())\n        {\n            return i;\n        }\n    }\n\n    BOSS_ASSERT(false, \"Should have found an index\");\n    return 0;\n}\n\nconst BuildOrder & CombatSearch_BestResponseData::getBestBuildOrder() const\n{\n    return _bestBuildOrder;\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_BestResponseData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"Eval.h\"\n#include \"BuildOrder.h\"\n\nnamespace BOSS\n{\n    \nclass CombatSearch_BestResponseData\n{\n    GameState               _enemyInitialState;\n    BuildOrder              _enemyBuildOrder;\n\n    std::vector<GameState>  _enemyStates;\n    std::vector< std::pair<double, double> >     _enemyArmyValues;\n    std::vector< std::pair<double, double> >     _selfArmyValues;\n\n    double                  _bestEval;\n    BuildOrder              _bestBuildOrder;\n    GameState               _bestState;\n\n    double compareBuildOrder(const GameState & state, const BuildOrder & buildOrder);\n    size_t getStateIndex(const GameState & state);\n\n    void calculateArmyValues(const GameState & state, const BuildOrder & buildOrder, std::vector< std::pair<double, double> > & values);\n\npublic:\n\n    CombatSearch_BestResponseData(const GameState & enemyState, const BuildOrder & enemyBuildOrder);\n\n    void update(const GameState & initialState, const GameState & currentState, const BuildOrder & buildOrder);\n\n    const BuildOrder & getBestBuildOrder() const;\n\n};\n\n}\n"
  },
  {
    "path": "BOSS/source/CombatSearch_Bucket.cpp",
    "content": "#include \"CombatSearch_Bucket.h\"\n\nusing namespace BOSS;\n\nCombatSearch_Bucket::CombatSearch_Bucket(const CombatSearchParameters p)\n    : _bucket(p.getFrameTimeLimit(), 200)\n{\n    _params = p;\n   \n    BOSS_ASSERT(_params.getInitialState().getRace() != Races::None, \"Combat search initial state is invalid\");\n}\nvoid CombatSearch_Bucket::doSearch(const GameState & state, size_t depth)\n{\n    if (timeLimitReached())\n    {\n        throw BOSS_COMBATSEARCH_TIMEOUT;\n    }\n\n    updateResults(state);\n    _bucket.update(state, _buildOrder);\n\n    if (isTerminalNode(state, depth))\n    {\n        return;\n    }\n\n    if (_bucket.isDominated(state))\n    {\n        //return;\n    }\n\n    ActionSet legalActions;\n    generateLegalActions(state, legalActions, _params);\n    \n    for (UnitCountType a(0); a < (int)legalActions.size(); ++a)\n    {\n        GameState child(state);\n        child.doAction(legalActions[a]);\n        _buildOrder.add(legalActions[a]);\n        \n        doSearch(child,depth+1);\n\n        _buildOrder.pop_back();\n    }\n}\n\nvoid CombatSearch_Bucket::printResults()\n{\n    _bucket.print();\n}\n\n#include \"BuildOrderPlot.h\"\nvoid CombatSearch_Bucket::writeResultsFile(const std::string & filename)\n{\n    BuildOrderPlot::WriteGnuPlot(filename + \"_BucketResults\", _bucket.getBucketResultsString(), \" with steps\");\n\n    // write the final build order data\n    BuildOrderPlot plot(_params.getInitialState(), _bucket.getBucket(_bucket.numBuckets()-1).buildOrder);\n    plot.writeArmyValuePlot(filename + \"_FinalBucketArmyPlot\");\n    plot.writeRectanglePlot(filename + \"_FinalBucketBuildOrder\");\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_Bucket.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Timer.hpp\"\n#include \"Eval.h\"\n#include \"BuildOrder.h\"\n#include \"CombatSearch.h\"\n#include \"CombatSearchParameters.h\"\n#include \"CombatSearchResults.h\"\n#include \"CombatSearch_BucketData.h\"\n\nnamespace BOSS\n{\n\nclass CombatSearch_Bucket : public CombatSearch\n{\n    CombatSearch_BucketData     _bucket;\n\n\tvirtual void                doSearch(const GameState & s, size_t depth);\n\npublic:\n\t\n\tCombatSearch_Bucket(const CombatSearchParameters p = CombatSearchParameters());\n\n    virtual void printResults();\n    virtual void writeResultsFile(const std::string & filename);\n};\n\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_BucketData.cpp",
    "content": "#include \"CombatSearch_BucketData.h\"\n\nusing namespace BOSS;\n\n\n// Combat Search Bucketing\n// \n// Computes and stores the build order which maximizes an evaluation function up to a given time interval [t0-t1]\n// The number of buckets and the frame limit determine the size of the buckets\n\n\nCombatSearch_BucketData::CombatSearch_BucketData(const FrameCountType frameLimit, const size_t numBuckets)\n        : _buckets(numBuckets, BucketData())\n        , _frameLimit(frameLimit)\n{\n    \n}\n\nconst size_t CombatSearch_BucketData::numBuckets() const\n{\n    return _buckets.size();\n}\n\nconst size_t CombatSearch_BucketData::getBucketIndex(const GameState & state) const\n{\n    return (size_t)(((double)state.getCurrentFrame() / (double)_frameLimit) * _buckets.size());\n}\n\nvoid CombatSearch_BucketData::update(const GameState & state, const BuildOrder & buildOrder)\n{\n    if (state.getCurrentFrame() >= _frameLimit)\n    {\n        return;\n    }\n\n    BOSS_ASSERT(state.getCurrentFrame() <= _frameLimit, \"State's frame exceeds bucket frame limit: (%d %d)\", (int)state.getCurrentFrame(), (int)_frameLimit);\n\n    // get the bucket index corresponding to the time of the current state finishing\n    size_t bucketIndex = getBucketIndex(state);\n\n    // evaluate the state with whatever value we want\n    double eval = Eval::ArmyTotalResourceSum(state);\n\n    // update the data if we have a new best value for this bucket\n    BucketData & bucket = _buckets[bucketIndex];\n    if ((eval > bucket.eval) || ((eval == bucket.eval) && Eval::BuildOrderBetter(buildOrder, bucket.buildOrder)))\n    {\n        // update every bucket for which this is a new record\n        for (size_t b=bucketIndex; b < _buckets.size(); ++b)\n        {\n            if (_buckets[b].eval >= eval)\n            {\n                break;\n            }\n\n            _buckets[b].eval = eval;\n            _buckets[b].buildOrder = buildOrder;\n            _buckets[b].state = state;\n        }\n    }\n}\n\nbool CombatSearch_BucketData::isDominated(const GameState & state)\n{\n    return Eval::StateDominates(getBucketData(state).state, state);\n}\n\nBucketData & CombatSearch_BucketData::getBucketData(const GameState & state)\n{\n    BOSS_ASSERT(getBucketIndex(state) < _buckets.size(), \"State goes over bucket limit\");\n\n    return _buckets[getBucketIndex(state)];\n}\n\nvoid CombatSearch_BucketData::print() const\n{\n    std::cout << \"\\n\\nFinal CombatBucket results\\n\";\n    std::cout << \"\\n  Frame     Sec     ArmyEval   BuildOrder\\n\";\n    double maxEval = 0;\n\n    for (size_t b(0); b<_buckets.size(); ++b)\n    {\n        if (_buckets[b].eval > maxEval)\n        {\n            maxEval = _buckets[b].eval;\n\n            double frame = ((double)b / _buckets.size()) * _frameLimit;\n            double sec   = frame / 24;\n\n            printf(\"%7d %7d %12.2lf   \", (int)frame, (int)sec, _buckets[b].eval/Constants::RESOURCE_SCALE);\n            std::cout << _buckets[b].buildOrder.getNameString(2) << std::endl;\n        }\n    }\n}\n\nconst BucketData & CombatSearch_BucketData::getBucket(const size_t index) const\n{\n    return _buckets[index];\n}\n\nstd::string CombatSearch_BucketData::getBucketResultsString()\n{\n    std::stringstream ss;\n\n    ss << \"0 0\" << std::endl;\n\n    double maxEval = 0;\n    for (size_t b(0); b<_buckets.size(); ++b)\n    {\n        if (_buckets[b].eval > maxEval)\n        {\n            maxEval = _buckets[b].eval;\n\n            double frame = ((double)b / _buckets.size()) * _frameLimit;\n            double sec   = frame / 24;\n\n            ss << frame << \" \" << _buckets[b].eval/Constants::RESOURCE_SCALE << std::endl;\n        }\n    }\n\n    return ss.str();\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_BucketData.h",
    "content": "#pragma once\n\n#include \"BuildOrder.h\"\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"Eval.h\"\n\nnamespace BOSS\n{\n\nclass BucketData\n{\npublic:\n    double                      eval;\n    BuildOrder                  buildOrder;\n    GameState                   state;\n\n    BucketData()\n        : eval(0)\n    {\n    }\n};\n\nclass CombatSearch_BucketData\n{\n    std::vector<BucketData>     _buckets;\n    FrameCountType              _frameLimit;\n\n    BucketData & getBucketData(const GameState & state);\n\npublic:\n\n    CombatSearch_BucketData(const FrameCountType frameLimit, const size_t numBuckets);\n\n    const BucketData & getBucket(const size_t index) const;\n    const size_t numBuckets() const;\n    const size_t getBucketIndex(const GameState & state) const;\n        \n    void update(const GameState & state, const BuildOrder & buildOrder);\n\n    bool isDominated(const GameState & state);\n\n    void print() const;\n    std::string getBucketResultsString();\n};\n\n}\n"
  },
  {
    "path": "BOSS/source/CombatSearch_Integral.cpp",
    "content": "#include \"CombatSearch_Integral.h\"\n\nusing namespace BOSS;\n\nCombatSearch_Integral::CombatSearch_Integral(const CombatSearchParameters p)\n{\n    _params = p;\n\n    BOSS_ASSERT(_params.getInitialState().getRace() != Races::None, \"Combat search initial state is invalid\");\n}\n\nvoid CombatSearch_Integral::doSearch(const GameState & state, size_t depth)\n{\n    if (timeLimitReached())\n    {\n        throw BOSS_COMBATSEARCH_TIMEOUT;\n    }\n\n    updateResults(state);\n\n    if (isTerminalNode(state, depth))\n    {\n        return;\n    }\n\n    ActionSet legalActions;\n    generateLegalActions(state, legalActions, _params);\n    \n    for (UnitCountType a(0); a < (int)legalActions.size(); ++a)\n    {\n        const UnitCountType index = legalActions.size()-1-a;\n\n        GameState child(state);\n        child.doAction(legalActions[index]);\n        _buildOrder.add(legalActions[index]);\n        _integral.update(state, _buildOrder);\n        \n        doSearch(child,depth+1);\n\n        _buildOrder.pop_back();\n        _integral.pop();\n    }\n}\n\nvoid CombatSearch_Integral::printResults()\n{\n    _integral.print();\n}\n\n#include \"BuildOrderPlot.h\"\nvoid CombatSearch_Integral::writeResultsFile(const std::string & filename)\n{\n    BuildOrderPlot plot(_params.getInitialState(), _integral.getBestBuildOrder());\n\n    plot.writeResourcePlot(filename + \"_Resources\");\n    plot.writeRectanglePlot(filename + \"_BuildOrder\");\n    plot.writeArmyValuePlot(filename + \"_ArmyValue\");\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_Integral.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Timer.hpp\"\n#include \"Eval.h\"\n#include \"BuildOrder.h\"\n#include \"CombatSearch.h\"\n#include \"CombatSearchParameters.h\"\n#include \"CombatSearchResults.h\"\n#include \"CombatSearch_IntegralData.h\"\n\nnamespace BOSS\n{\n\nclass CombatSearch_Integral : public CombatSearch\n{\n    CombatSearch_IntegralData   _integral;\n\n\tvirtual void                doSearch(const GameState & s, size_t depth);\n\npublic:\n\t\n\tCombatSearch_Integral(const CombatSearchParameters p = CombatSearchParameters());\n\t\n    virtual void printResults();\n    virtual void writeResultsFile(const std::string & filename);\n};\n\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_IntegralData.cpp",
    "content": "#include \"CombatSearch_IntegralData.h\"\n\nusing namespace BOSS;\n\nCombatSearch_IntegralData::CombatSearch_IntegralData()\n    : _bestIntegralValue(0)\n{\n    _integralStack.push_back(IntegralData(0,0,0));\n}\n\nvoid CombatSearch_IntegralData::update(const GameState & state, const BuildOrder & buildOrder)\n{\n    double value = Eval::ArmyTotalResourceSum(state);\n    double timeElapsed = state.getCurrentFrame() - _integralStack.back().timeAdded; \n    double valueToAdd = _integralStack.back().eval * timeElapsed;\n    IntegralData entry(value, _integralStack.back().integral + valueToAdd, state.getCurrentFrame());\n    _integralStack.push_back(entry);\n\n    // we have found a new best if:\n    // 1. the new army integral is higher than the previous best\n    // 2. the new army integral is the same as the old best but the build order is 'better'\n    if (    (_integralStack.back().integral >  _bestIntegralValue) \n        || ((_integralStack.back().integral == _bestIntegralValue) && Eval::BuildOrderBetter(buildOrder, _bestIntegralBuildOrder)))\n    {\n        _bestIntegralValue = _integralStack.back().integral;\n        _bestIntegralStack = _integralStack;\n        _bestIntegralBuildOrder = buildOrder;\n\n        // print the newly found best to console\n        printIntegralData(_integralStack.size()-1);\n    }\n}\n\nvoid CombatSearch_IntegralData::pop()\n{\n    _integralStack.pop_back();\n}\n\nvoid CombatSearch_IntegralData::printIntegralData(const size_t index) const\n{\n    printf(\"%7d %10.2lf %13.2lf   \", _bestIntegralStack[index].timeAdded, _bestIntegralStack[index].eval/Constants::RESOURCE_SCALE, _bestIntegralStack[index].integral/Constants::RESOURCE_SCALE);\n    std::cout << _bestIntegralBuildOrder.getNameString(2) << std::endl;   \n}\n\nvoid CombatSearch_IntegralData::print() const\n{\n    std::cout << \"\\nFinal CombatSearchIntegral Results\\n\\n\";\n    std::cout << \"  Frame   ArmyEval  ArmyIntegral   BuildOrder\\n\";\n    \n    for (size_t i(0); i<_bestIntegralStack.size(); ++i)\n    {\n        printIntegralData(i);\n    }\n}\n\nconst BuildOrder & CombatSearch_IntegralData::getBestBuildOrder() const\n{\n    return _bestIntegralBuildOrder;\n}"
  },
  {
    "path": "BOSS/source/CombatSearch_IntegralData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"Eval.h\"\n#include \"BuildOrder.h\"\n\nnamespace BOSS\n{\n    \nclass IntegralData\n{\npublic:\n    double              eval;\n    double              integral;\n    FrameCountType      timeAdded;\n\n    IntegralData(double e, double i, FrameCountType t)\n        : eval(e)\n        , integral(i)\n        , timeAdded(t)\n    {\n    \n    }\n    \n    IntegralData()\n        : eval(0)\n        , integral(0)\n        , timeAdded(0)\n    {\n    \n    }\n};\n\nclass CombatSearch_IntegralData\n{\n    std::vector<IntegralData>       _integralStack;\n\n    std::vector<IntegralData>       _bestIntegralStack;\n    double                          _bestIntegralValue;\n    BuildOrder                      _bestIntegralBuildOrder;\n\npublic:\n\n    CombatSearch_IntegralData();\n\n    void update(const GameState & state, const BuildOrder & buildOrder);\n    void pop();\n\n    void printIntegralData(const size_t index) const;\n    void print() const;\n\n    const BuildOrder & getBestBuildOrder() const;\n};\n\n}\n"
  },
  {
    "path": "BOSS/source/Common.h",
    "content": "#pragma once\n\n#include \"BWAPI.h\"\n#include <stdio.h>\n#include <math.h>\n#include <fstream>\n#include <fstream>\n#include <iostream>\n#include <sstream>\n#include <vector>\n#include <limits>\n\n#include \"BOSSAssert.h\"\n#include \"BaseTypes.h\"\n#include \"Constants.h\""
  },
  {
    "path": "BOSS/source/Constants.cpp",
    "content": "#include \"Constants.h\"\n#include \"Common.h\"\n\nnamespace BOSS\n{\n    namespace Races\n    {\n        RaceID GetRaceID(BWAPI::Race r)\n        {\n            if (r == BWAPI::Races::Protoss)\n            {\n                return Races::Protoss;\n            }\n            else if (r == BWAPI::Races::Terran)\n            {\n                return Races::Terran;\n            }\n            else if (r == BWAPI::Races::Zerg)\n            {\n                return Races::Zerg;\n            }\n            else\n            {\n                return Races::None;\n            }\n        }\n\n\t\tBWAPI::Race GetRace(RaceID id)\n\t\t{\n\t\t\tif (id == Races::Protoss)\n\t\t\t{\n\t\t\t\treturn BWAPI::Races::Protoss;\n\t\t\t}\n\t\t\telse if (id == Races::Terran)\n\t\t\t{\n\t\t\t\treturn BWAPI::Races::Terran;\n\t\t\t}\n\t\t\telse if (id == Races::Zerg)\n\t\t\t{\n\t\t\t\treturn BWAPI::Races::Zerg;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn BWAPI::Races::None;\n\t\t\t}\n\t\t}\n\n        RaceID GetRaceID(const std::string & race)\n        {\n            if (race.compare(\"Protoss\") == 0)\n            {\n                return Races::Protoss;\n            }\n            else if (race.compare(\"Terran\") == 0)\n            {\n                return Races::Terran;\n            }\n            else if (race.compare(\"Zerg\") == 0)\n            {\n                return Races::Zerg;\n            }\n            else\n            {\n                return Races::None;\n            }\n        }\n\n        std::string GetRaceName(RaceID race)\n        {\n            if (race == Races::Protoss)\n            {\n                return \"Protoss\";\n            }\n            else if (race == Races::Terran)\n            {\n                return \"Terran\";\n            }\n            else if (race == Races::Zerg)\n            {\n                return \"Zerg\";\n            }\n            else\n            {\n                return \"None\";\n            }\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "BOSS/source/Constants.h",
    "content": "#pragma once\n\n#include \"BWAPI.h\"\n#include \"BaseTypes.h\"\n\nnamespace BOSS\n{\n    namespace Constants\n    {\n        \n        const size_t MAX_ACTIONS            = 64;       // maximum number of actions allowed in StarcraftData\n\n        const size_t MAX_PROGRESS           = 50;       // maximum number of actions in progress allowed\n\n        const size_t MAX_BUILDINGS          = 70;         // maximum number of buildings allowed\n\n        const size_t BUILDING_ERROR         = -2;        // building error return code\n\n        const size_t MAX_HATCHERIES         = 10;      // maximum number of hatcheries allowed\n\n        const size_t ZERG_LARVA_TIMER       = 336;     // number of frames between zerg larva spawn\n\n        const size_t BUILDING_PLACEMENT     = 24 * 5;  // number of frames to use for building placement\n\n        const size_t MAX_OF_ACTION          = 200;\n\n        const size_t NUM_HASHES             = 2;\n\n        const size_t MPWPF                  = 45;\n\n        const size_t GPWPF                  = 70;\n\n        const size_t RESOURCE_SCALE         = 1000;\n    \n        const size_t MAX_ACTION_TYPES       = 100;\n\n        const size_t ZERG_LARVA_ID          = 255;\n\n    }\n    \n    namespace Races\n    {\n        enum {Protoss, Terran, Zerg, NUM_RACES, None};\n\n        RaceID GetRaceID(BWAPI::Race r);\n\t\tBWAPI::Race GetRace(RaceID id);\n        RaceID GetRaceID(const std::string & race);\n        std::string GetRaceName(RaceID race);\n    }\n\n}\n\n"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderSearchParameters.cpp",
    "content": "#include \"DFBB_BuildOrderSearchParameters.h\"\n\nusing namespace BOSS;\n\n// alternate constructor\nDFBB_BuildOrderSearchParameters::DFBB_BuildOrderSearchParameters(const RaceID & r)\n    : race(r)\n    , useRepetitions(true)\n    , useIncreasingRepetitions(false)\n    , useAlwaysMakeWorkers(false)\n    , useSupplyBounding(false)\n    , supplyBoundingThreshold(1)\n    , useLandmarkLowerBoundHeuristic(true)\n    , useResourceLowerBoundHeuristic(true)\n    , searchTimeLimit(0)\n    , initialUpperBound(0)\n    , repetitionValues(Constants::MAX_ACTIONS, 1)\n    , repetitionThresholds(Constants::MAX_ACTIONS, 0)\n    , goal(r)\n{\n    \n}\n\nvoid DFBB_BuildOrderSearchParameters::setRepetitions(const ActionType & a, const UnitCountType & repetitions)\n{ \n    BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)repetitionValues.size(), \"Action type not valid\");\n    BOSS_ASSERT(a.getRace() == race, \"Action type race doesn't match this parameter object\");\n\n    repetitionValues[a.ID()] = repetitions; \n}\n\nvoid DFBB_BuildOrderSearchParameters::setRepetitionThreshold(const ActionType & a, const UnitCountType & thresh)\t\n{ \n    BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)repetitionThresholds.size(), \"Action type not valid\");\n    BOSS_ASSERT(a.getRace() == race, \"Action type race doesn't match this parameter object\");\n\n    repetitionThresholds[a.ID()] = thresh; \n}\n\nconst UnitCountType & DFBB_BuildOrderSearchParameters::getRepetitions(const ActionType & a)\n{ \n    BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)repetitionValues.size(), \"Action type not valid\");\n    BOSS_ASSERT(a.getRace() == race, \"Action type race doesn't match this parameter object\");\n\n    return repetitionValues[a.ID()]; \n}\n\nconst UnitCountType & DFBB_BuildOrderSearchParameters::getRepetitionThreshold(const ActionType & a)\t\t\t\t\n{ \n    BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)repetitionThresholds.size(), \"Action type not valid\");\n    BOSS_ASSERT(a.getRace() == race, \"Action type race doesn't match this parameter object\");\n\n    return repetitionThresholds[a.ID()]; \n}\n\n\n\nstd::string DFBB_BuildOrderSearchParameters::toString() const\n{\n    std::stringstream ss;\n\n    ss << \"\\n\\nSearch Parameter Information\\n\\n\";\n\n    ss << (useRepetitions ?                    \"\\tUSE      Repetitions\\n\" : \"\");\n    ss << (useIncreasingRepetitions ?          \"\\tUSE      Increasing Repetitions\\n\" : \"\");\n    ss << (useLandmarkLowerBoundHeuristic ?    \"\\tUSE      Landmark Lower Bound\\n\" : \"\");\n    ss << (useResourceLowerBoundHeuristic ?    \"\\tUSE      Resource Lower Bound\\n\" : \"\");\n    ss << (useAlwaysMakeWorkers ?              \"\\tUSE      Always Make Workers\\n\" : \"\");\n    ss << (useSupplyBounding ?                 \"\\tUSE      Supply Bounding\\n\" : \"\");\n    ss << (\"\\n\");\n\n    for (ActionID a(0); a < (int)repetitionValues.size(); ++a)\n    {\n        if (repetitionValues[a] != 1)\n        {\n            ss << \"\\tREP \" << repetitionValues[a] << \" \" << ActionTypes::GetActionType(race, a).getName() << \"\\n\";\n        }\n    }\n\n    for (ActionID a(0); a < (int)repetitionThresholds.size(); ++a)\n    {\n        if (repetitionThresholds[a] != 0)\n        {\n            ss << \"\\tTHR \" << repetitionThresholds[a] << \" \" << ActionTypes::GetActionType(race, a).getName() << \"\\n\";\n        }\n    }\n\n    ss << \"\\n\\n\" << goal.toString();\n    ss << \"\\n\\n\" << initialState.toString();\n\n    for (size_t i(0); i < relevantActions.size(); ++i)\n    {\n        ss << \"Relevant:   \" << relevantActions[i].getName() << \"\\n\";\n    }\n\n    ss << \"\\n\\n\" << initialState.getUnitData().getBuildingData().toString();\n\n    return ss.str();\n}"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderSearchParameters.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BuildOrderSearchGoal.h\"\n#include \"GameState.h\"\n#include \"DFBB_BuildOrderSearchSaveState.h\"\n\nnamespace BOSS\n{\n\nclass DFBB_BuildOrderSearchParameters\n{\n\n\n    void init();\n\n\npublic:\n    RaceID race;\n\n    //      Flag which determines whether or not doubling macro actions will be used in search.\n    //      Macro actions (see paper) trade suboptimality for decreasing search depth. For large\n    //          plans repetitions are necessary. For example, to make probes only build in twos\n    //          set useRepetitions = true and repetitionValues[probeAction] = 2\n    //\n    //      true:  macro actions are used, stored in repetitionValues array\n    //      false: macro actions not used, all actions will be carried out once\n    bool useRepetitions;\n    Vec<UnitCountType,Constants::MAX_ACTIONS> repetitionValues;\n\n    //      Flag which determines whether increasing repetitions will be used in search\n    //      Increasing repetitions means the reptition value will be 1 until we have at least\n    //      repetitionThresholds[a] count of action a. For example, setting:\n    //          repetitionThresholds[pylonAction] = 1, repetitionValues[pylonAction] = 2\n    //          means that the first pylon will build on its own but all further pylons will\n    //          be built 2 at a time.\n    //\n    //      true:  increasing repetitions are used\n    //      false: increasing repetitions not used\n    bool useIncreasingRepetitions;\n    Vec<UnitCountType,Constants::MAX_ACTIONS> repetitionThresholds;\n\n    //      Flag which determines whether or not we always make workers during search\n    //      This abstraction changes the search so that it always makes a worker if it is able to. It\n    //          accomplished this by modifying the current legal actions to exclude anything that\n    //          can't be started before the next worker. This ends up producing longer makespans but\n    //          the economy it produces is much better. Optimal makespan plans often produce very\n    //          few workers and the long term economy suffers.\n    //\n    //      true:  always make workers is used\n    //      false: always make workers is not used\n    bool useAlwaysMakeWorkers;\n\n    //      Flag which determines whether or not we use supply bounding in our search\n    //      Supply bounding makes supply producing buildings illegal if we are currently ahead\n    //          on supply by a certain amount. If we currently have more than\n    //          supplyBoundingThreshold extra supply buildings worth of supply, we no longer\n    //          build them. This is an abstraction used to make search faster which may\n    //          produce suboptimal plans.\n    //\n    //      true:  supply bounding is used\n    //      false: supply bounding is not used\n    bool useSupplyBounding;\n    double supplyBoundingThreshold;\n\n\n    //      Flag which determines whether or not we use various heuristics in our search.\n    //\n    //      true:  the heuristic is used\n    //      false: the heuristic is not used\n    bool useLandmarkLowerBoundHeuristic;\n    bool useResourceLowerBoundHeuristic;\n\n    //      Search time limit measured in milliseconds\n    //      If searchTimeLimit is set to a value greater than zero, the search will effectively\n    //          time out and the best solution so far will be used in the results. This is\n    //          accomplished by throwing an exception if the time limit is hit. Time is checked\n    //          once every 1000 nodes expanded, as checking the time is slow.\n    double searchTimeLimit;\n\n    //      Initial upper bound for the DFBB search\n    //      If this value is set to zero, DFBB search will automatically determine an\n    //          appropriate upper bound using an upper bound heuristic. If it is non-zero,\n    //          it will use the value as an initial bound.\n    int initialUpperBound;\n\n    //      StarcraftSearchGoal used for the search. See StarcraftSearchGoal.hpp for details\n    BuildOrderSearchGoal goal;\n\n    //      Initial StarcraftState used for the search. See StarcraftState.hpp for details\n    GameState initialState;\n\n    ActionSet relevantActions;\n\n\n    // alternate constructor\n    DFBB_BuildOrderSearchParameters(const RaceID & r = Races::None);\n\n    void setMaxActions(const ActionType & a,const UnitCountType & max);\n    void setRepetitions(const ActionType & a,const UnitCountType & repetitions);\n    void setRepetitionThreshold(const ActionType & a,const UnitCountType & thresh);\n\n    const UnitCountType & getRepetitions(const ActionType & a);\n    const UnitCountType & getMaxActions(const ActionType & a);\n    const UnitCountType & getRepetitionThreshold(const ActionType & a);\n\n    std::string toString() const;\n};\n\n}"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderSearchResults.cpp",
    "content": "#include \"DFBB_BuildOrderSearchResults.h\"\n\nusing namespace BOSS;\n\nDFBB_BuildOrderSearchResults::DFBB_BuildOrderSearchResults()\n    : solved(false)\n    , timedOut(false)\n    , solutionFound(false)\n    , upperBound(0)\n    , nodesExpanded(0)\n    , timeElapsed(0)\n{\n}\n\nvoid DFBB_BuildOrderSearchResults::printResults(bool pbo) const\n{\n    printf(\"%12d%14llu%12.2lf       \",upperBound,nodesExpanded,timeElapsed);\n\n    if (pbo)\n    {\n        printBuildOrder();\n    }\n\n    printf(\"\\n\");\n}\n\nvoid DFBB_BuildOrderSearchResults::printBuildOrder() const\n{\n    for (size_t i(0); i<buildOrder.size(); ++i)\n    {\n        printf(\"%d \",buildOrder[i].ID());\n    }\n}"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderSearchResults.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"ActionType.h\"\n#include \"GameState.h\"\n#include \"BuildOrder.h\"\n\nnamespace BOSS\n{\nclass DFBB_BuildOrderSearchResults\n{\n\npublic:\n   \n\tBuildOrder                  buildOrder;\t\t// the build order\n\n\tbool \t\t\t\t        solved;\t\t\t// whether ot not a solution was found\n    bool    \t\t\t        timedOut;\t\t// did the search time-out?\n    bool                        solutionFound;  // did we find any solution\n\t\n\tint\t\t\t\t\t        upperBound;\t\t// upper bound of first node\n\t\n\tunsigned long long \t        nodesExpanded;\t// number of nodes expanded in the search\n\t\n\tdouble \t\t\t\t        timeElapsed;\t// time elapsed in milliseconds\n\n    GameState                   finalState;\n\t\n\tDFBB_BuildOrderSearchResults();\n\tDFBB_BuildOrderSearchResults(bool s, int len, unsigned long long n, double t, std::vector<ActionType> solution);\n\t\t\n\tvoid printResults(bool pbo = true) const;\n\tvoid printBuildOrder() const;\n};\n}"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderSearchSaveState.cpp",
    "content": "//#include \"DFBB_BuildOrderSearchSaveState.h\"\n//\n//using namespace BOSS;\n//\n//DFBBSearchSaveState::DFBBSearchSaveState()\n//    : depth(0) \n//{\n//}\n//\n//DFBBSearchSaveState::DFBBSearchSaveState(const std::vector<ActionType> & buildOrder, int ub)\n//    : upperBound(ub)\n//{\n//    // set the depth equal to the size of the build order vector\n//    depth = buildOrder.size();\n//\n//    // copy the values of the vector into the array (backwards due to buildorder vector being backwards)\n//    for (size_t i(0); i<buildOrder.size(); ++i)\n//    {\n//        currentActions[i] = buildOrder[buildOrder.size()-1-i];\n//    }\n//}\n//\n//int DFBBSearchSaveState::getUpperBound() const\n//{\n//    return upperBound;\n//}\n//\n//int DFBBSearchSaveState::operator [] (const int index) const\n//{\n//    return currentActions[index];\n//}\n//\n//int DFBBSearchSaveState::getDepth() const\n//{\n//    return depth;\n//}\n//\n//int DFBBSearchSaveState::getAction(const int d) const\n//{\n//    BOSS_ASSERT(d < depth, \"Depth overflow\");\n//\n//    return currentActions[d];\n//}\n//\n//void DFBBSearchSaveState::print() const\n//{\n//    printf(\"Depth(%d) UpperBound(%d) Actions \",depth,upperBound);\n//\n//    for (int i(0); i<depth; ++i)\n//    {\n//        printf(\"%d \",currentActions[i]);\n//    }\n//\n//    printf(\"\\n\");\n//}"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderSearchSaveState.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"ActionType.h\"\n\n#define MAX_SAVE_ACTIONS 100\n\nnamespace BOSS\n{\nclass DFBB_BuildOrderSearchSaveState\n{\n\n\tint\t\tdepth;\n\tint\t\tupperBound;\n\tint\t\tcurrentActions[MAX_SAVE_ACTIONS];\n\npublic:\n\n\tDFBB_BuildOrderSearchSaveState();\n\n\tDFBB_BuildOrderSearchSaveState(const std::vector<ActionType> & buildOrder, int ub);\n\t\n\tint getUpperBound() const;\n\tint operator [] (const int index) const;\n\tint getDepth() const;\n\tint getAction(const int d) const;\n\n\tvoid print() const;\n};\n}"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderSmartSearch.cpp",
    "content": "#include \"DFBB_BuildOrderSmartSearch.h\"\n\nusing namespace BOSS;\n\nDFBB_BuildOrderSmartSearch::DFBB_BuildOrderSmartSearch(const RaceID race) \n    : _race(race)\n    , _params(race)\n    , _goal(race)\n    , _stackSearch(race)\n    , _searchTimeLimit(30)\n{\n}\n\nvoid DFBB_BuildOrderSmartSearch::doSearch()\n{\n    BOSS_ASSERT(_initialState.getRace() != Races::None, \"Must set initial state before performing search\");\n\n    // if we are resuming a search\n    if (_stackSearch.getResults().timedOut)\n    {\n        _stackSearch.setTimeLimit(_searchTimeLimit);\n        _stackSearch.search();\n    }\n    else\n    {\n        calculateSearchSettings();\n        _params.goal = _goal;\n        _params.initialState = _initialState;\n        _params.useRepetitions \t\t\t\t= true;\n        _params.useIncreasingRepetitions \t= true;\n        _params.useAlwaysMakeWorkers \t\t= true;\n        _params.useSupplyBounding \t\t\t= true;\n        _params.supplyBoundingThreshold     = 1.5;\n        _params.relevantActions             = _relevantActions;\n        _params.searchTimeLimit             = _searchTimeLimit;\n\n        //BWAPI::Broodwar->printf(\"Constructing new search object time limit is %lf\", _params.searchTimeLimit);\n        _stackSearch = DFBB_BuildOrderStackSearch(_params);\n        _stackSearch.search();\n    }\n\n    _results = _stackSearch.getResults();\n\n    if (_results.solved && !_results.solutionFound)\n    {\n        //std::cout << \"No solution found better than naive, using naive build order\" << std::endl;\n        //_results.buildOrder = Tools::GetOptimizedNaiveBuildOrder(_params.initialState, _params.goal);\n    }\n}\n\nvoid DFBB_BuildOrderSmartSearch::calculateSearchSettings()\n{\n    // set the max number of resource depots to what we have since no expanding is allowed\n    const ActionType & resourceDepot    = ActionTypes::GetResourceDepot(getRace());\n    const ActionType & refinery         = ActionTypes::GetRefinery(getRace());\n    const ActionType & worker           = ActionTypes::GetWorker(getRace());\n    const ActionType & supplyProvider   = ActionTypes::GetSupplyProvider(getRace());\n\n    _goal.setGoalMax(resourceDepot, _initialState.getUnitData().getNumTotal(resourceDepot));\n\n    // set the number of refineries\n    _goal.setGoalMax(refinery, std::min((UnitCountType)3, calculateRefineriesRequired()));\n\n    // set the maximum number of workers to an initial ridiculously high upper bound\n    _goal.setGoalMax(worker, std::min((int)_initialState.getUnitData().getNumTotal(worker) + 20, 100));\n\n    // set the number of supply providers required\n    _goal.setGoalMax(supplyProvider, calculateSupplyProvidersRequired());\n        \n    // set the maximums for all goal prerequisites\n    setPrerequisiteGoalMax();\n\n    // set relevant actions\n    setRelevantActions();\n\n    // set the repetitions\n    setRepetitions();\n\n    int maxWorkers = 45;\n    if (_goal.getGoal(worker) > maxWorkers)\n    {\n        _goal.setGoal(worker, maxWorkers);\n    }\n\n    if (_goal.getGoalMax(worker) > maxWorkers)\n    {\n        _goal.setGoalMax(worker, maxWorkers);\n    }\n}\n\n// calculates maximum number of refineries we'll need\nUnitCountType DFBB_BuildOrderSmartSearch::calculateRefineriesRequired()\n{\n    const ActionType & refinery      = ActionTypes::GetRefinery(getRace());\n    const ActionType & resourceDepot = ActionTypes::GetResourceDepot(getRace());\n\n    if (_goal.getGoal(refinery))\n    {\n        return _goal.getGoal(refinery);\n    }\n\n    // loop to check if we need gas\n    bool gasRequired = false;\n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(getRace(), a);\n\n        if (_goal.getGoal(actionType) > 0 && actionType.gasPrice() > 0)\n        {\n            gasRequired = true;\n            break;\n        }\n    }\n\n    return gasRequired ? _initialState.getUnitData().getNumTotal(resourceDepot) : 0;\n}\n\n// handles all goalMax calculations for prerequisites of goal actions\nvoid DFBB_BuildOrderSmartSearch::setPrerequisiteGoalMax()\n{\n    if (getRace() == Races::Protoss || getRace() == Races::Terran)\n    {\n        // for each unit in the goal vector\n        for (const auto & actionType : ActionTypes::GetAllActionTypes(getRace()))\n        {\n            // if we want one of these\n            if (_goal.getGoal(actionType) > 0)\n            {\n                // set goalMax for each strict dependency equal to 1\n                recurseOverStrictDependencies(actionType);\n            }\n        }\n\n        // vector which stores the number of goal units which are built by [index]\n        std::vector<UnitCountType> numGoalUnitsBuiltBy(ActionTypes::GetAllActionTypes(getRace()).size(), 0);\n\n        for (size_t a(0); a < numGoalUnitsBuiltBy.size(); ++a)\n        {\n            const ActionType & actionType = ActionTypes::GetActionType(getRace(), a);\n\n            if (_goal.getGoal(actionType) > 0)\n            {\n                // add this to the sum\n                numGoalUnitsBuiltBy[actionType.whatBuildsAction()] += _goal.getGoal(actionType);\n\n                // if it's in the goal, make sure it's in the max\n                _goal.setGoalMax(actionType, std::max(_goal.getGoal(actionType), _goal.getGoalMax(actionType)));\n            }\n        }\n\n        UnitCountType additionalProductionBuildingLimit = 2;\n\n        for (size_t a(0); a < numGoalUnitsBuiltBy.size(); ++a)\n        {\n            const ActionType & actionType = ActionTypes::GetActionType(getRace(), a);\n\n            // if it's not a resource depot\n            if (!actionType.isResourceDepot() && actionType.isBuilding())\n            {\n                // if this building produces units\n                if (numGoalUnitsBuiltBy[actionType.ID()] > 0)\n                {\n                    // set the goal max to how many units\n                    _goal.setGoalMax(actionType, std::min(_initialState.getUnitData().getNumTotal(actionType) + additionalProductionBuildingLimit, (int)numGoalUnitsBuiltBy[actionType.ID()]));\n                }\n            }\n        }\n\n        // set the upper bound on addons to the upper bound on the building that makes them\n        for (const auto & actionType : ActionTypes::GetAllActionTypes(getRace()))\n        {\n            if (actionType.isAddon() && _goal.getGoalMax(actionType) > 0)\n            {\n                const ActionType & whatBuilds = actionType.whatBuildsActionType();\n\n                if (_goal.getGoalMax(whatBuilds) > 0)\n                {\n                    _goal.setGoalMax(actionType, _goal.getGoalMax(whatBuilds));\n                }\n            }\n        }\n    }\n    else if (getRace() == Races::Zerg)\n    {\n        _goal.setGoalMax(ActionTypes::GetActionType(\"Zerg_Spawning_Pool\"), 1);\n        _goal.setGoalMax(ActionTypes::GetActionType(\"Zerg_Extractor\"), 1);\n        _goal.setGoalMax(ActionTypes::GetActionType(\"Zerg_Lair\"), 1);\n        _goal.setGoalMax(ActionTypes::GetActionType(\"Zerg_Spire\"), 1);\n        _goal.setGoalMax(ActionTypes::GetActionType(\"Zerg_Hydralisk_Den\"), 1);\n    }\n}\n\n// recursively checks the tech tree of Action and sets each to have goalMax of 1\nvoid DFBB_BuildOrderSmartSearch::recurseOverStrictDependencies(const ActionType & actionType)\n{\n    if (actionType.isResourceDepot() || actionType.isWorker() || actionType.isSupplyProvider() || actionType.isRefinery())\n    {\n        return;\n    }\n\n    PrerequisiteSet recursivePrerequisites = actionType.getRecursivePrerequisites();\n\n    for (size_t a(0); a < recursivePrerequisites.size(); ++a)\n    {\n        const ActionType & actionType = recursivePrerequisites.getActionType(a);\n\n        if (actionType.isResourceDepot() ||actionType.isWorker() || actionType.isSupplyProvider() || actionType.isRefinery())\n        {\n            continue;\n        }\n\n        _goal.setGoalMax(actionType, std::max((UnitCountType)1, _goal.getGoalMax(actionType)));\n    }\n}\n\nvoid DFBB_BuildOrderSmartSearch::setRelevantActions()\n{\n    _relevantActions.clear();\n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(getRace(), a);\n\n        if (_goal.getGoalMax(actionType) > 0 || _goal.getGoal(actionType) > 0)\n        {\n            _relevantActions.add(actionType);\n        }\n    }\n}\n\nUnitCountType DFBB_BuildOrderSmartSearch::calculateSupplyProvidersRequired()\n{\n    const ActionType & resourceDepot    = ActionTypes::GetResourceDepot(getRace());\n    const ActionType & worker           = ActionTypes::GetWorker(getRace());\n    const ActionType & supplyProvider   = ActionTypes::GetSupplyProvider(getRace());\n\n    // calculate the upper bound on supply for this goal\n    int supplyNeeded = _goal.getGoalMax(worker) * worker.supplyRequired();\n\n    // for each prerequisite of things in the goal which aren't production facilities set one of\n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(getRace(), a);\n\n        // add the supply required for this number of goal units and all units currently made\n        supplyNeeded += std::max(_goal.getGoal(actionType), _initialState.getUnitData().getNumTotal(actionType)) * actionType.supplyRequired();\n    }\n\n    // set the upper bound on supply based on these values\n    UnitCountType supplyFromResourceDepots = _initialState.getUnitData().getNumTotal(resourceDepot) * resourceDepot.supplyProvided();\n\n    // take this away from the supply needed\n    supplyNeeded -= supplyFromResourceDepots;\n\n    // return the number of supply providers required\n    return supplyNeeded > 0 ? (UnitCountType)ceil((double)supplyNeeded / (double)supplyProvider.supplyProvided()) : 0;\n}\n\nvoid DFBB_BuildOrderSmartSearch::setRepetitions()\n{\n    //const ActionType & resourceDepot    = ActionTypes::GetResourceDepot(getRace());\n    //const ActionType & refinery         = ActionTypes::GetRefinery(getRace());\n    //const ActionType & worker           = ActionTypes::GetWorker(getRace());\n    //const ActionType & supplyProvider   = ActionTypes::GetSupplyProvider(getRace());\n\n    //_params.setRepetitions(supplyProvider, 1);\n    //_params.setRepetitionThreshold(supplyProvider, 3);\n\n    // for each action\n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(getRace(), a);\n\n        // if if want 4 or more of something that isn't supply providing\n        if (!actionType.isSupplyProvider() && _goal.getGoal(actionType) >= 5)\n        {\n            // set the repetitions to half of the value\n            _params.setRepetitions(actionType, std::min((UnitCountType)4, (UnitCountType)(_goal.getGoal(actionType) / 2)));\n            _params.setRepetitions(actionType.whatBuildsActionType(), 2);\n            _params.setRepetitionThreshold(actionType.whatBuildsActionType(), 1);\n        }\n    }\n}\n\nconst RaceID DFBB_BuildOrderSmartSearch::getRace() const\n{\n    return _race;\n}\n\nvoid DFBB_BuildOrderSmartSearch::addGoal(const ActionType & a, const UnitCountType count)\n{\n    _goal.setGoal(a,count);\n}\n\nvoid DFBB_BuildOrderSmartSearch::setGoal(const BuildOrderSearchGoal & g)\n{\n    _goal = g;    \n}\n\nvoid DFBB_BuildOrderSmartSearch::setState(const GameState & state)\n{\n    _initialState = state;\n}\n\n\nvoid DFBB_BuildOrderSmartSearch::setTimeLimit(int n)\n{\n    _searchTimeLimit = n;\n}\n\nvoid DFBB_BuildOrderSmartSearch::search()\n{\n    doSearch();\n}\n\nconst DFBB_BuildOrderSearchResults & DFBB_BuildOrderSmartSearch::getResults() const\n{\n    return _results;\n}\n\nconst DFBB_BuildOrderSearchParameters & DFBB_BuildOrderSmartSearch::getParameters()\n{\n    calculateSearchSettings();\n\n    _params.goal = _goal;\n    _params.initialState = _initialState;\n    _params.useRepetitions \t\t\t\t= true;\n    _params.useIncreasingRepetitions \t= true;\n    _params.useAlwaysMakeWorkers \t\t= true;\n    _params.useSupplyBounding \t\t\t= true;\n\n    return _params;\n}\n\nvoid DFBB_BuildOrderSmartSearch::print()\n{\n    //initialState.printData();\n    printf(\"\\n\\n\");\n}\n"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderSmartSearch.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"DFBB_BuildOrderStackSearch.h\"\n#include \"Timer.hpp\"\n\nnamespace BOSS\n{\nclass DFBB_BuildOrderSmartSearch\n{\n    RaceID                              _race;\n\n\tDFBB_BuildOrderSearchParameters\t\t_params;\n\tBuildOrderSearchGoal \t\t\t_goal;\n\n    ActionSet                           _relevantActions;\n\n\tGameState\t\t\t\t\t        _initialState;\n\t\n\tint \t\t\t\t\t\t\t    _searchTimeLimit;\n\n\tTimer\t\t\t\t\t\t\t    _searchTimer;\n\n    DFBB_BuildOrderStackSearch          _stackSearch;\n\n    DFBB_BuildOrderSearchResults        _results;\n\t\n\tvoid doSearch();\n\tvoid calculateSearchSettings();\n\tvoid setPrerequisiteGoalMax();\n\tvoid recurseOverStrictDependencies(const ActionType & action);\n    void setRelevantActions();\n\tvoid setRepetitions();\n\t\n\tUnitCountType calculateSupplyProvidersRequired();\n\tUnitCountType calculateRefineriesRequired();\n\n    const RaceID getRace() const;\n\t\npublic:\n\n\tDFBB_BuildOrderSmartSearch(const RaceID race);\n\t\n\tvoid addGoal(const ActionType & a, const UnitCountType count);\n\tvoid setGoal(const BuildOrderSearchGoal & goal);\n\tvoid setState(const GameState & state);\n\tvoid print();\n\tvoid setTimeLimit(int n);\n\t\n\tvoid search();\n\n    const DFBB_BuildOrderSearchResults & getResults() const;\n\tconst DFBB_BuildOrderSearchParameters & getParameters();\n};\n\n}"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderStackSearch.cpp",
    "content": "#include \"DFBB_BuildOrderStackSearch.h\"\n\nusing namespace BOSS;\n\nDFBB_BuildOrderStackSearch::DFBB_BuildOrderStackSearch(const DFBB_BuildOrderSearchParameters & p)\n    : _params(p)\n    , _depth(0)\n    , _firstSearch(true)\n    , _wasInterrupted(false)\n    , _stack(100, StackData())\n{\n    \n}\n\nvoid DFBB_BuildOrderStackSearch::setTimeLimit(double ms)\n{\n    _params.searchTimeLimit = ms;\n}\n\n// function which is called to do the actual search\nvoid DFBB_BuildOrderStackSearch::search()\n{\n    _searchTimer.start();\n\n    if (!_results.solved)\n    {\n        if (_firstSearch)\n        {\n            _results.upperBound = _params.initialUpperBound ? _params.initialUpperBound : Tools::GetUpperBound(_params.initialState, _params.goal);\n            \n            // add one frame to the upper bound so our strictly lesser than check still works if we have an exact upper bound\n            _results.upperBound += 1;\n\n            _stack[0].state = _params.initialState;\n            _firstSearch = false;\n            //BWAPI::Broodwar->printf(\"Upper bound is %d\", _results.upperBound);\n            //std::cout << \"Upper bound is: \" << _results.upperBound << std::endl;\n        }\n\n        try \n        {\n            // search on the initial state\n            DFBB();\n\n            _results.timedOut = false;\n        }\n        catch (int e) \n        {\n            if (e == DFBB_TIMEOUT_EXCEPTION)\n            {\n                //BWAPI::Broodwar->printf(\"I timed out!\");\n                _results.timedOut = true;\n            }\n        }\n        \n        double ms = _searchTimer.getElapsedTimeInMilliSec();\n        _results.solved = !_results.timedOut;\n        _results.timeElapsed = ms;\n    }\n}\n\nconst DFBB_BuildOrderSearchResults & DFBB_BuildOrderStackSearch::getResults() const\n{\n    return _results;\n}\n\nvoid DFBB_BuildOrderStackSearch::generateLegalActions(const GameState & state, ActionSet & legalActions)\n{\n    legalActions.clear();\n    BuildOrderSearchGoal & goal = _params.goal;\n    const ActionType & worker = ActionTypes::GetWorker(state.getRace());\n    \n    // add all legal relevant actions that are in the goal\n    for (size_t a(0); a < _params.relevantActions.size(); ++a)\n    {\n        const ActionType & actionType = _params.relevantActions[a];\n        const std::string & actionName = actionType.getName();\n        const size_t numTotal = state.getUnitData().getNumTotal(actionType);\n\n        if (state.isLegal(actionType))\n        {\n            // if there's none of this action in the goal it's not legal\n            if (!goal.getGoal(actionType) && !goal.getGoalMax(actionType))\n            {\n                continue;\n            }\n\n            // if we already have more than the goal it's not legal\n            if (goal.getGoal(actionType) && ((int)numTotal >= goal.getGoal(actionType)))\n            {\n                continue;\n            }\n\n            // if we already have more than the goal max it's not legal\n            if (goal.getGoalMax(actionType) && ((int)numTotal >= goal.getGoalMax(actionType)))\n            {\n                continue;\n            }\n            \n            legalActions.add(_params.relevantActions[a]);\n        }\n    }\n\n    // if we enabled the supply bounding flag\n    if (_params.useSupplyBounding)\n    {\n        UnitCountType supplySurplus = state.getUnitData().getMaxSupply() + state.getUnitData().getSupplyInProgress() - state.getUnitData().getCurrentSupply();\n        UnitCountType threshold = (UnitCountType)(ActionTypes::GetSupplyProvider(state.getRace()).supplyProvided() * _params.supplyBoundingThreshold);\n\n        if (supplySurplus >= threshold)\n        {\n            legalActions.remove(ActionTypes::GetSupplyProvider(state.getRace()));\n        }\n    }\n    \n    // if we enabled the always make workers flag, and workers are legal\n    if (_params.useAlwaysMakeWorkers && legalActions.contains(worker))\n    {\n        bool actionLegalBeforeWorker = false;\n        ActionSet legalEqualWorker;\n        FrameCountType workerReady = state.whenCanPerform(worker);\n\n        for (size_t a(0); a < legalActions.size(); ++a)\n        {\n            const ActionType & actionType = legalActions[a];\n            const FrameCountType whenCanPerformAction = state.whenCanPerform(actionType);\n            if (whenCanPerformAction < workerReady)\n            {\n                actionLegalBeforeWorker = true;\n                break;\n            }\n\n            if ((whenCanPerformAction == workerReady) && (actionType.mineralPrice() == worker.mineralPrice()))\n            {\n                legalEqualWorker.add(actionType);\n            }\n        }\n\n        if (actionLegalBeforeWorker)\n        {\n            legalActions.remove(worker);\n        }\n        else\n        {\n            legalActions = legalEqualWorker;\n        }\n    }\n}\n\nUnitCountType DFBB_BuildOrderStackSearch::getRepetitions(const GameState & state, const ActionType & a)\n{\n    // set the repetitions if we are using repetitions, otherwise set to 1\n    int repeat = _params.useRepetitions ? _params.getRepetitions(a) : 1;\n\n    // if we are using increasing repetitions\n    if (_params.useIncreasingRepetitions)\n    {\n        // if we don't have the threshold amount of units, use a repetition value of 1\n        repeat = state.getUnitData().getNumTotal(a) >= _params.getRepetitionThreshold(a) ? repeat : 1;\n    }\n\n    // make sure we don't repeat to more than we need for this unit type\n    if (_params.goal.getGoal(a))\n    {\n        repeat = std::min(repeat, (int)(_params.goal.getGoal(a) - state.getUnitData().getNumTotal(a)));\n    }\n    else if (_params.goal.getGoalMax(a))\n    {\n        repeat = std::min(repeat, (int)(_params.goal.getGoalMax(a) - state.getUnitData().getNumTotal(a)));\n    }\n    \n    return repeat;\n}\n\nbool DFBB_BuildOrderStackSearch::isTimeOut()\n{\n    return (_params.searchTimeLimit && (_results.nodesExpanded % 200 == 0) && (_searchTimer.getElapsedTimeInMilliSec() > _params.searchTimeLimit));\n}\n\nvoid DFBB_BuildOrderStackSearch::updateResults(const GameState & state)\n{\n    FrameCountType finishTime = state.getLastActionFinishTime();\n\n    // new best solution\n    if (finishTime < _results.upperBound)\n    {\n        _results.timeElapsed = _searchTimer.getElapsedTimeInMilliSec();\n        _results.upperBound = finishTime;\n        _results.solutionFound = true;\n        _results.finalState = state;\n        _results.buildOrder = _buildOrder;\n\n        //_results.printResults(true);\n    }\n}\n\n#define ACTION_TYPE     _stack[_depth].currentActionType\n#define STATE           _stack[_depth].state\n#define CHILD_STATE     _stack[_depth+1].state\n#define CHILD_NUM       _stack[_depth].currentChildIndex\n#define LEGAL_ACTINS    _stack[_depth].legalActions\n#define REPETITIONS     _stack[_depth].repetitionValue\n#define COMPLETED_REPS  _stack[_depth].completedRepetitions\n\n#define DFBB_CALL_RETURN  if (_depth == 0) { return; } else { --_depth; goto SEARCH_RETURN; }\n#define DFBB_CALL_RECURSE { ++_depth; goto SEARCH_BEGIN; }\n\n// recursive function which does all search logic\nvoid DFBB_BuildOrderStackSearch::DFBB()\n{\n    FrameCountType actionFinishTime = 0;\n    FrameCountType heuristicTime = 0;\n    FrameCountType maxHeuristic = 0;\n\nSEARCH_BEGIN:\n\n    _results.nodesExpanded++;\n\n    if (isTimeOut())\n    {\n        throw DFBB_TIMEOUT_EXCEPTION;\n    }\n\n    generateLegalActions(STATE, LEGAL_ACTINS);\n    for (CHILD_NUM = 0; CHILD_NUM < LEGAL_ACTINS.size(); ++CHILD_NUM)\n    {\n        ACTION_TYPE = LEGAL_ACTINS[CHILD_NUM];\n\n        actionFinishTime = STATE.whenCanPerform(ACTION_TYPE) + ACTION_TYPE.buildTime();\n        heuristicTime    = STATE.getCurrentFrame() + Tools::GetLowerBound(STATE, _params.goal);\n        maxHeuristic     = (actionFinishTime > heuristicTime) ? actionFinishTime : heuristicTime;\n\n        if (maxHeuristic > _results.upperBound)\n        {\n            continue;\n        }\n\n        REPETITIONS = getRepetitions(STATE, ACTION_TYPE);\n        BOSS_ASSERT(REPETITIONS > 0, \"Can't have zero repetitions!\");\n                \n        // do the action as many times as legal to to 'repeat'\n        CHILD_STATE = STATE;\n        COMPLETED_REPS = 0;\n        for (; COMPLETED_REPS < REPETITIONS; ++COMPLETED_REPS)\n        {\n            if (CHILD_STATE.isLegal(ACTION_TYPE))\n            {\n                _buildOrder.add(ACTION_TYPE);\n                CHILD_STATE.doAction(ACTION_TYPE);\n            }\n            else\n            {\n                break;\n            }\n        }\n\n        if (_params.goal.isAchievedBy(CHILD_STATE))\n        {\n            updateResults(CHILD_STATE);\n        }\n        else\n        {\n            DFBB_CALL_RECURSE;\n        }\n\nSEARCH_RETURN:\n\n        for (int r(0); r < COMPLETED_REPS; ++r)\n        {\n            _buildOrder.pop_back();\n        }\n    }\n\n    DFBB_CALL_RETURN;\n}"
  },
  {
    "path": "BOSS/source/DFBB_BuildOrderStackSearch.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"ActionType.h\"\n#include \"DFBB_BuildOrderSearchResults.h\"\n#include \"DFBB_BuildOrderSearchParameters.h\"\n#include \"Timer.hpp\"\n#include \"Tools.h\"\n#include \"BuildOrder.h\"\n\n#define DFBB_TIMEOUT_EXCEPTION 1\n\nnamespace BOSS\n{\n\nclass StackData\n{\npublic:\n\n    size_t              currentChildIndex;\n    GameState           state;\n    ActionSet           legalActions;\n    ActionType          currentActionType;\n    UnitCountType       repetitionValue;\n    UnitCountType       completedRepetitions;\n    \n    StackData()\n        : currentChildIndex(0)\n        , repetitionValue(1)\n        , completedRepetitions(0)\n    {\n    \n    }\n};\n\nclass DFBB_BuildOrderStackSearch\n{\n\tDFBB_BuildOrderSearchParameters     _params;                      //parameters that will be used in this search\n\tDFBB_BuildOrderSearchResults        _results;                     //the results of the search so far\n\t\t\t\t\t\n    Timer                               _searchTimer;\n    BuildOrder                          _buildOrder;\n\n    std::vector<StackData>              _stack;\n    size_t                              _depth;\n\n    bool                                _firstSearch;\n\n    bool                                _wasInterrupted;\n    \n    void                                updateResults(const GameState & state);\n    bool                                isTimeOut();\n    void                                calculateRecursivePrerequisites(const ActionType & action, ActionSet & all);\n    void                                generateLegalActions(const GameState & state, ActionSet & legalActions);\n\tstd::vector<ActionType>             getBuildOrder(GameState & state);\n    UnitCountType                       getRepetitions(const GameState & state, const ActionType & a);\n    ActionSet                           calculateRelevantActions();\n\npublic:\n\t\n\tDFBB_BuildOrderStackSearch(const DFBB_BuildOrderSearchParameters & p);\n\t\n    void setTimeLimit(double ms);\n\tvoid search();\n    const DFBB_BuildOrderSearchResults & getResults() const;\n\t\n\tvoid DFBB();\n\t\n\t\n};\n}"
  },
  {
    "path": "BOSS/source/Eval.cpp",
    "content": "#include \"Eval.h\"\n\nnamespace BOSS\n{\nnamespace Eval\n{\n    double ArmyCompletedResourceSum(const GameState & state)\n    {\n        ResourceCountType sum(0);\n\t    \n        const std::vector<ActionType> & allActions = ActionTypes::GetAllActionTypes(state.getRace());\n\t    for (ActionID i(0); i< (int)allActions.size(); ++i)\n\t    {\n            const ActionType & a = allActions[i];\n\t        if (!a.isBuilding() && !a.isWorker() && !a.isSupplyProvider())\n\t        {\n                sum += state.getUnitData().getNumCompleted(a)*a.mineralPrice();\n\t            sum += 2*state.getUnitData().getNumCompleted(a)*a.gasPrice();\n\t        }\n\t    }\n\t    \n\t    return sum;\n    }\n\n    double ArmyTotalResourceSum(const GameState & state)\n    {\n        ResourceCountType sum(0);\n\t    \n\t    const std::vector<ActionType> & allActions = ActionTypes::GetAllActionTypes(state.getRace());\n\t    for (ActionID i(0); i< (int)allActions.size(); ++i)\n\t    {\n            const ActionType & a = allActions[i];\n\t        if (!a.isBuilding() && !a.isWorker() && !a.isSupplyProvider())\n\t        {\n                sum += state.getUnitData().getNumTotal(a)*a.mineralPrice();\n\t            sum += 2*state.getUnitData().getNumTotal(a)*a.gasPrice();\n\t        }\n\t    }\n\t    \n\t    return sum;\n    }\n\n    bool BuildOrderBetter(const BuildOrder & buildOrder, const BuildOrder & compareTo)\n    {\n        size_t numWorkers = 0;\n        size_t numWorkersOther = 0;\n\n        for (size_t a(0); a<buildOrder.size(); ++a)\n        {\n            if (buildOrder[a].isWorker())\n            {\n                numWorkers++;\n            }\n        }\n\n        for (size_t a(0); a<compareTo.size(); ++a)\n        {\n            if (compareTo[a].isWorker())\n            {\n                numWorkersOther++;\n            }\n        }\n\n        if (numWorkers == numWorkersOther)\n        {\n            return buildOrder.size() < compareTo.size();\n        }\n        else\n        {\n            return numWorkers > numWorkersOther;\n        }\n    }\n\n    bool StateDominates(const GameState & state, const GameState & other)\n    {\n        // we can't define domination for different races\n        if (state.getRace() != other.getRace())\n        {\n            return false;\n        }\n\n        // if we have less resources than the other state we are not dominating it\n        if ((state.getMinerals() < other.getMinerals()) || (state.getGas() < other.getGas()))\n        {\n            return false;\n        }\n\n        // if we have less of any unit than the other state we are not dominating it\n        for (size_t a(0); a < ActionTypes::GetAllActionTypes(state.getRace()).size(); ++a)\n        {\n            const ActionType & action = ActionTypes::GetActionType(state.getRace(), a);\n\n            if (state.getUnitData().getNumTotal(action) < other.getUnitData().getNumTotal(action))\n            {\n                return false;\n            }\n\n            if (state.getUnitData().getNumCompleted(action) < other.getUnitData().getNumCompleted(action))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n}\n\n"
  },
  {
    "path": "BOSS/source/Eval.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"BuildOrder.h\"\n\nnamespace BOSS\n{\nnamespace Eval\n{\n    \n    double ArmyCompletedResourceSum(const GameState & state);\n    double ArmyTotalResourceSum(const GameState & state);\n\n    bool BuildOrderBetter(const BuildOrder & buildOrder, const BuildOrder & compareTo);\n\n    bool StateDominates(const GameState & state, const GameState & other);\n}\n}\n"
  },
  {
    "path": "BOSS/source/GameState.cpp",
    "content": "#include \"GameState.h\"\n\nusing namespace BOSS;\n\n\nGameState::GameState(const RaceID r)\n    : _race                 (r)\n    , _units                (r)\n    , _currentFrame         (0)\n    , _lastActionFrame      (0)\n    , _minerals             (0)\n    , _gas                  (0)\n{\n    \n}\n\n#ifdef _MSC_VER\nGameState::GameState(BWAPI::GameWrapper & game, BWAPI::PlayerInterface * self, const std::vector<BWAPI::UnitType> & buildingsQueued)\n    : _race                 (Races::GetRaceID(self->getRace()))\n    , _currentFrame         (game->getFrameCount())\n    , _lastActionFrame      (0)\n    , _units                (Races::GetRaceID(self->getRace()))\n    , _minerals             (self->minerals() * Constants::RESOURCE_SCALE)\n    , _gas                  (self->gas() * Constants::RESOURCE_SCALE)\n{ \n    // we will count the worker jobs as we add units\n    UnitCountType mineralWorkerCount    = 0;\n    UnitCountType gasWorkerCount        = 0;\n    UnitCountType buildingWorkerCount   = 0;\n    UnitCountType larvaCount            = 0;\n\n    _units.setMineralWorkers(mineralWorkerCount);\n    _units.setGasWorkers(gasWorkerCount);\n    _units.setBuildingWorkers(buildingWorkerCount);\n\n    // add buildings queued like they had just been started\n    for (const BWAPI::UnitType & type : buildingsQueued)\n    {\n        _units.addActionInProgress(ActionType(type), game->getFrameCount() + type.buildTime(), false);\n    }\n\n\t// add each unit we have to the current state\n\tfor (BWAPI::UnitInterface * unit : self->getUnits())\n\t{\n        // if the unit is an egg then we're building a zerg unit, add it with the finish time\n        if (unit->getType() == BWAPI::UnitTypes::Zerg_Egg)\n        {\n            _units.addActionInProgress(ActionType(unit->getBuildType()), game->getFrameCount() + unit->getRemainingBuildTime(), false);\n            continue;\n        }\n\n\t\tif (unit->getType() == BWAPI::UnitTypes::Zerg_Larva)\n\t\t{\n\t\t\t++larvaCount;\n\t\t\tcontinue;\n\t\t}\n\n        // don't add any units that we don't have any the action space, this should never happen though\n\t\tif (!ActionTypes::TypeExists(unit->getType()))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n        ActionType actionType(unit->getType());\n\n\t\t// if the unit is completed\n\t\tif (unit->isCompleted())\n\t\t{\n\t\t\t// if it is a building that is not an addon\n\t\t\tif (unit->getType().isBuilding())\n\t\t\t{\n                // add the building data accordingly\n\t\t\t\tFrameCountType  trainTime = unit->getRemainingTrainTime() + unit->getRemainingResearchTime() + unit->getRemainingUpgradeTime();\n                ActionType      constructing;\n                ActionType      addon;\n                bool            isHatchery = unit->getType().isResourceDepot() && unit->getType().getRace() == BWAPI::Races::Zerg;\n\n                // if this is a hatchery subtract the training time which is just larva production time\n                if (isHatchery)\n                {\n                    trainTime -= unit->getRemainingTrainTime();\n                }\n                // if this unit is currently building an addon, set it\n                if (unit->getAddon() && unit->getAddon()->isBeingConstructed())\n                {\n                    constructing = ActionType(unit->getAddon()->getType());\n                } \n                // if it's a non-hatchery currently training something, add it\n                else if (!isHatchery && unit->getRemainingTrainTime() > 0)\n                {\n                    // find the unit we have that has the same construction time remaining\n                    // this is an awful hack but there seems to be no alternative\n                    bool set = false;\n                    for (auto & u : self->getUnits())\n                    {\n                        if (u->getRemainingBuildTime() > 0 && u->getPosition().getDistance(unit->getPosition()) < 16)\n                        {\n                            constructing = ActionType(u->getType());\n                            set = true;\n                            break;\n                        }\n                    }\n\n                    // check to see if the last order issued was a trianing order and grab the unit type from that\n                    if (!set && unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Train)\n                    {\n                        BWAPI::UnitType trainType = unit->getLastCommand().getUnitType();\n\n                        if (BWAPI::Broodwar->getFrameCount() - unit->getLastCommandFrame() < 2*BWAPI::Broodwar->getLatencyFrames())\n                        {\n                            constructing = ActionType(trainType);\n                            set = true;\n\n                            // we now need to add this to units in progress, since it won't be detected below as an actual unit in progress\n                            _units.addActionInProgress(trainType, game->getFrameCount() + trainType.buildTime(), false);\n                        }\n                    }\n\n                    if (!set)\n                    {\n                        // if we couldn't find the unit type that this unit is training \n                        // then we have to treat it as if it doesn't exist otherwise BOSS will act strangely\n                        trainTime = 0;\n                        BWAPI::Broodwar->printf(\"Couldn't find training unit for %s %s %d %d\", unit->getType().getName().c_str(), unit->getBuildType().getName().c_str(), unit->getTrainingQueue().size(), unit->getRemainingTrainTime());\n                    }\n                }\n                // if it's researching something, add it\n\t\t\t\telse if (unit->getRemainingResearchTime() > 0)\n\t\t\t\t{\n\t\t\t\t\tconstructing = ActionType(unit->getTech());\n\t\t\t\t\t_units.addActionInProgress(constructing, game->getFrameCount() + unit->getRemainingResearchTime(), false);\n\t\t\t\t}\n                // if it's upgrading something, add it\n\t\t\t\telse if (unit->getRemainingUpgradeTime() > 0)\n\t\t\t\t{\n\t\t\t\t\tconstructing = ActionType(unit->getUpgrade());\n\t\t\t\t\t_units.addActionInProgress(constructing, game->getFrameCount() + unit->getRemainingUpgradeTime(), false);\n\t\t\t\t}\n\n                // add addons\n                if (unit->getAddon() != nullptr)\n                {\n                    if (unit->getAddon()->isConstructing())\n                    {\n                        constructing = ActionType(unit->getAddon()->getType());\n                    }\n                    else\n                    {\n                        addon = ActionType(unit->getAddon()->getType());    \n                    }\n                }\n\n                _units.addCompletedBuilding(actionType, trainTime, constructing, addon, unit->getLarva().size());\n\t\t\t}\n            // otherwise it is a non-building unit\n            else\n            {\n                if (unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode)\n                {\n                    actionType = ActionType(BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode);\n                }\n\n                // add the unit to the state\n\t\t\t    _units.addCompletedAction(actionType, false);\n\n                // set the supply accordingly\n                _units.setCurrentSupply(_units.getCurrentSupply() + actionType.supplyRequired());\n            }\n\t\t}\n        // the unit is currently under construction\n\t\telse if ((unit->getRemainingBuildTime() > 0) && !unit->getType().isAddon())\n\t\t{\n            // special case of a zerg building morphing into its upgrade\n            if (actionType.isBuilding() && actionType.isMorphed())\n            {\n                // add the completed building which is morphing into this building\n                _units.addCompletedBuilding(actionType.whatBuildsActionType(), unit->getRemainingBuildTime(), actionType, ActionType(), unit->getLarva().size());\n            }\n\n            // add the unit itself in progress\n\t\t\t_units.addActionInProgress(actionType, game->getFrameCount() + unit->getRemainingBuildTime(), false);\n\t\t}\n\t}\n\n    for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes())\n\t{\n        if (!ActionTypes::TypeExists(type))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (self->getUpgradeLevel(type) > 0)\n\t\t{\n\t\t\t_units.addCompletedAction(ActionType(type));\n\t\t}\n\t}\n    \n    for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes())\n\t{\n        if (!ActionTypes::TypeExists(type))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (self->hasResearched(type))\n\t\t{\n\t\t    _units.addCompletedAction(ActionType(type));\n\t\t}\n\t}\n}\n#endif\n\nvoid GameState::setStartingState()\n{\n    _minerals = 50 * Constants::RESOURCE_SCALE;\n    _gas = 0;\n\n    _units.addCompletedAction(ActionTypes::GetResourceDepot(getRace()), false);\n    _units.addCompletedAction(ActionTypes::GetWorker(getRace()), false);\n    _units.addCompletedAction(ActionTypes::GetWorker(getRace()), false);\n    _units.addCompletedAction(ActionTypes::GetWorker(getRace()), false);\n    _units.addCompletedAction(ActionTypes::GetWorker(getRace()), false);\n\n    if (getRace() == Races::Zerg)\n    {\n        _units.addCompletedAction(ActionTypes::GetSupplyProvider(Races::Zerg), false);\n    }\n\n    _units.setCurrentSupply(8);\n}\n\nconst RaceID GameState::getRace() const\n{\n    return _race;\n}\n\nvoid GameState::getAllLegalActions(ActionSet & actions) const\n{\n    const std::vector<ActionType> & allActions = ActionTypes::GetAllActionTypes(getRace());\n\tfor (ActionID i(0); i< (int)allActions.size(); ++i)\n\t{\n        const ActionType & action = allActions[i];\n\n        if (isLegal(action))\n        {\n            actions.add(action);\n        }\n    }   \n}\n\nbool GameState::isLegal(const ActionType & action) const\n{\n    const size_t mineralWorkers  = getNumMineralWorkers();\n    const size_t numRefineries  = _units.getNumTotal(ActionTypes::GetRefinery(getRace()));\n    const size_t numDepots      = _units.getNumTotal(ActionTypes::GetResourceDepot(getRace()));\n    const size_t refineriesInProgress = _units.getNumInProgress(ActionTypes::GetRefinery(getRace()));\n\n    // we can never build a larva\n    static const ActionType & Zerg_Larva = ActionTypes::GetActionType(\"Zerg_Larva\");\n    if (action == Zerg_Larva)\n    {\n        return false;\n    }\n\n    // check if the tech requirements are met\n    if (!_units.hasPrerequisites(action.getPrerequisites()))\n    {\n        return false;\n    }\n\t\n    // if it's a unit and we are out of supply and aren't making an overlord, it's not legal\n\tif (!action.isMorphed() && !action.isSupplyProvider() && ((_units.getCurrentSupply() + action.supplyRequired()) > (_units.getMaxSupply() + _units.getSupplyInProgress())))\n    {\n        return false;\n    }\n\n    // TODO: require an extra for refineries byt not buildings\n    // rules for buildings which are built by workers\n    if (action.isBuilding() && !action.isMorphed() && !action.isAddon())\n    {\n        // be very strict about when we can make refineries to ensure we have enough workers to go in gas\n        if (action.isRefinery() && (getNumMineralWorkers() <= (int)(4 + 3*refineriesInProgress)))\n        {\n            return false;\n        }\n\n        int workersPerRefinery = 3;\n        int workersRequiredToBuild = getRace() == Races::Protoss ? 0 : 1;\n        int buildingIsRefinery = action.isRefinery() ? 1 : 0;\n        int candidateWorkers = getNumMineralWorkers() + _units.getNumInProgress(ActionTypes::GetWorker(getRace())) + getNumBuildingWorkers();\n        int workersToBeUsed = workersRequiredToBuild + workersPerRefinery*(refineriesInProgress);\n\n        if (candidateWorkers < workersToBeUsed)\n        {\n            return false;\n        }\n    }\n\n    // if we have no gas income we can't make a gas unit\n    if (!canAffordGas(action) && !_units.hasGasIncome())\n    {\n        return false;\n    }\n\n    // if we have no mineral income we'll never have a minerla unit\n    if (!canAffordMinerals(action) && !_units.hasMineralIncome())\n    {\n        return false;\n    }\n\n    // don't build more refineries than resource depots\n    if (action.isRefinery() && (numRefineries >= numDepots))\n    {\n        return false;\n    }\n\n    // we don't need to go over the maximum supply limit with supply providers\n    if (action.isSupplyProvider() && (_units.getMaxSupply() + _units.getSupplyInProgress() > 400))\n    {\n        return false;\n    }\n\n    // can only build one of a tech type\n    if (action.isTech() && getUnitData().getNumTotal(action) > 0)\n    {\n        return false;\n    }\n\n    // check to see if an addon can ever be built\n    if (action.isAddon() && !_units.getBuildingData().canBuildEventually(action) && (_units.getNumInProgress(action.whatBuildsActionType()) == 0))\n    {\n        return false;\n    }\n\n    return true;\n}\n\n// do an action, action must be legal for this not to break\nstd::vector<ActionType> GameState::doAction(const ActionType & action)\n{\n    BOSS_ASSERT(action.getRace() == _race, \"Race of action does not match race of the state\");\n\n    _actionsPerformed.push_back(ActionPerformed());\n    _actionsPerformed[_actionsPerformed.size()-1].actionType = action;\n\n    BOSS_ASSERT(isLegal(action), \"Trying to perform an illegal action: %s %s\", action.getName().c_str(), getActionsPerformedString().c_str());\n    \n    // set the actionPerformed\n    _actionPerformed = action;\n    _actionPerformedK = 1;\n\n    FrameCountType workerReadyTime = whenWorkerReady(action);\n    FrameCountType ffTime = whenCanPerform(action);\n\n    const std::string & name = action.getName();\n\n    BOSS_ASSERT(ffTime >= 0 && ffTime < 1000000, \"FFTime is very strange: %d\", ffTime);\n\n    auto actionsFinished = fastForward(ffTime);\n\n    _actionsPerformed[_actionsPerformed.size()-1].actionQueuedFrame = _currentFrame;\n    _actionsPerformed[_actionsPerformed.size()-1].gasWhenQueued = _gas;\n    _actionsPerformed[_actionsPerformed.size()-1].mineralsWhenQueued = _minerals;\n\n    // how much time has elapsed since the last action was queued?\n    FrameCountType elapsed(_currentFrame - _lastActionFrame);\n    _lastActionFrame = _currentFrame;\n\n    BOSS_ASSERT(canAffordMinerals(action),   \"Minerals less than price: %ld < %d, ffTime=%d %s\", _minerals, action.mineralPrice(), (int)elapsed, action.getName().c_str());\n    BOSS_ASSERT(canAffordGas(action),       \"Gas less than price: %ld < %d, ffTime=%d %s\", _gas, action.gasPrice(), (int)elapsed, action.getName().c_str());\n\n    // modify our resources\n    _minerals   -= action.mineralPrice();\n    _gas        -= action.gasPrice();\n\n    // do race specific things here\n    if (getRace() == Races::Protoss)\n    {\n        _units.addActionInProgress(action, _currentFrame + action.buildTime());    \n    }\n    else if (getRace() == Races::Terran)\n    {\n        if (action.isBuilding() && !action.isAddon())\n        {\n            BOSS_ASSERT(getNumMineralWorkers() > 0, \"Don't have any mineral workers to assign\");\n            _units.setBuildingWorker();\n        }\n\n        _units.addActionInProgress(action, _currentFrame + action.buildTime());\n    }\n    else if (getRace() == Races::Zerg)\n    {\n     \t//  zerg must subtract a larva if the action was unit creation\n    \tif (action.isUnit() && !action.isBuilding()) \n        {\n            if (action.isMorphed())\n            {\n                _units.morphUnit(action.whatBuildsActionType(), action, _currentFrame + action.buildTime());   \n            }\n            else\n            {\n                BOSS_ASSERT(getHatcheryData().numLarva() > 0, \"We should have a larva to use\");\n                _units.getHatcheryData().useLarva();\n                _units.addActionInProgress(action, _currentFrame + action.buildTime());\n            }\n     \t}\n     \telse if (action.isBuilding())\n     \t{\n            _units.morphUnit(action.whatBuildsActionType(), action, _currentFrame + action.buildTime());\n     \t}\n        else\n        {\n            // if it's not a unit or a building it's a tech so we queue it normally\n            _units.addActionInProgress(action, _currentFrame + action.buildTime());\n        }\n     }\n\n\treturn actionsFinished;\n}\n\n// fast forwards the current state to time toFrame\nstd::vector<ActionType> GameState::fastForward(const FrameCountType toFrame)\n{\n    // fast forward the building timers to the current frame\n    FrameCountType previousFrame = _currentFrame;\n    _units.setBuildingFrame(toFrame - _currentFrame);\n\n    // update resources & finish each action\n    FrameCountType      lastActionFinished  = _currentFrame;\n    FrameCountType      totalTime           = 0;\n    ResourceCountType   moreGas             = 0;\n    ResourceCountType   moreMinerals        = 0;\n\n\n\tstd::vector<ActionType> actionsFinished;\n    // while we still have units in progress\n    while ((_units.getNumActionsInProgress() > 0) && (_units.getNextActionFinishTime() <= toFrame))\n    {\n        // figure out how long since the last action was finished\n        FrameCountType timeElapsed \t= _units.getNextActionFinishTime() - lastActionFinished;\n        totalTime \t\t\t+= timeElapsed;\n\n        // update our mineral and gas count for that period\n        moreMinerals \t\t+= timeElapsed * getMineralsPerFrame();\n        moreGas \t\t\t+= timeElapsed * getGasPerFrame();\n\n        // update when the last action was finished\n        lastActionFinished \t= _units.getNextActionFinishTime();\n\n        // finish the action, which updates mineral and gas rates if required\n\t\tactionsFinished.push_back(_units.finishNextActionInProgress());\n    }\n\n    // update resources from the last action finished to toFrame\n    FrameCountType elapsed  =  toFrame - lastActionFinished;\n    moreMinerals            += elapsed * getMineralsPerFrame();\n    moreGas                 += elapsed * getGasPerFrame();\n    totalTime               += elapsed;\n\n    _minerals               += moreMinerals;\n    _gas                    += moreGas;\n\n    // we are now in the FUTURE... \"the future, conan?\"\n    _currentFrame           = toFrame;\n\n    if (getRace() == Races::Zerg)\n    {\n        _units.getHatcheryData().fastForward(previousFrame, toFrame);\n    }\n\n\treturn actionsFinished;\n}\n\n// returns the time at which all resources to perform an action will be available\nconst FrameCountType GameState::whenCanPerform(const ActionType & action) const\n{\n    const std::string & name = action.getName();\n\n    // the resource times we care about\n    FrameCountType mineralTime  (_currentFrame); \t// minerals\n    FrameCountType gasTime      (_currentFrame); \t// gas\n    FrameCountType classTime    (_currentFrame); \t// class-specific\n    FrameCountType supplyTime   (_currentFrame); \t// supply\n    FrameCountType prereqTime   (_currentFrame); \t// prerequisites\n    FrameCountType workerTime   (_currentFrame);\n    FrameCountType maxVal       (_currentFrame);\n\n    // figure out when prerequisites will be ready\n    prereqTime      = whenPrerequisitesReady(action);\n\n    // check minerals\n    mineralTime     = whenMineralsReady(action);\n\n    // check gas\n    gasTime         = whenGasReady(action);\n\n    // race specific timings (Zerg Larva)\n    classTime       = raceSpecificWhenReady(action);\n\n    // set when we will have enough supply for this unit\n    supplyTime      = whenSupplyReady(action);\n\n    // when will we have a worker ready to build it?\n    workerTime      = whenWorkerReady(action);\n\n    // figure out the max of all these times\n    maxVal = (mineralTime > maxVal) ? mineralTime   : maxVal;\n    maxVal = (gasTime >     maxVal) ? gasTime       : maxVal;\n    maxVal = (classTime >   maxVal) ? classTime     : maxVal;\n    maxVal = (supplyTime >  maxVal) ? supplyTime    : maxVal;\n    maxVal = (prereqTime >  maxVal) ? prereqTime    : maxVal;\n    maxVal = (workerTime >  maxVal) ? workerTime    : maxVal;\n\n    // return the time\n    return maxVal;\n}\n\nconst FrameCountType GameState::raceSpecificWhenReady(const ActionType & a) const\n{\n    const static ActionType larva = ActionTypes::GetActionType(\"Zerg_Larva\");\n\n\n    if (getRace() == Races::Zerg)\n    {        \n        if (a.whatBuildsActionType() != larva)\n        {\n            return 0;\n        }\n\n        if (getHatcheryData().numLarva() == 0)\n        {\n            return getHatcheryData().nextLarvaFrameAfter(_currentFrame);\n        }\n    }\n\n    return 0;\n}\n\nconst FrameCountType GameState::whenWorkerReady(const ActionType & action) const\n{\n    if (!action.whatBuildsActionType().isWorker())\n    {\n        return _currentFrame;\n    }\n\n    int refineriesInProgress = _units.getNumInProgress(ActionTypes::GetRefinery(getRace()));\n\n    // protoss doesn't tie up a worker to build, so they can build whenever a mineral worker is free\n    if (getRace() == Races::Protoss && getNumMineralWorkers() > 0)\n    {\n        return _currentFrame;\n    }\n\n    // if we have a mineral worker, then it is ready right now\n    if (getNumMineralWorkers() > 3*refineriesInProgress)\n    {\n        return _currentFrame;\n    }\n    \n    // at this point we need to wait for the next worker to become free since existing workers\n    // are either all used, or they are reserved to be put into refineries\n    // so we must have either a worker in progress, or a building in progress\n    const ActionType & Worker = ActionTypes::GetWorker(getRace());\n    BOSS_ASSERT(_units.getNumInProgress(Worker) > 0 || getNumBuildingWorkers() > 0, \"No worker will ever be free\");\n\n    FrameCountType workerReadyTime = _currentFrame;\n\n    // if we have a worker in progress, when will it be ready?\n    FrameCountType whenWorkerInProgressFinished = std::numeric_limits<FrameCountType>::max();\n    if (_units.getNumInProgress(Worker))\n    {\n        whenWorkerInProgressFinished = _units.getFinishTime(Worker);\n    }\n\n    // if we have a worker currently building, when will it be free?\n    FrameCountType whenBuildingWorkerFree = std::numeric_limits<FrameCountType>::max();\n    if (getNumBuildingWorkers() > 0)\n    {\n        whenBuildingWorkerFree = _units.getNextBuildingFinishTime();\n    }\n\n    return std::min(whenWorkerInProgressFinished, whenBuildingWorkerFree);\n}\n\nconst FrameCountType GameState::whenSupplyReady(const ActionType & action) const\n{\n    int supplyNeeded = action.supplyRequired() + _units.getCurrentSupply() - _units.getMaxSupply();\n    if (supplyNeeded <= 0)\n    {\n        return getCurrentFrame();\n    }\n\n    FrameCountType whenSupplyReady = _currentFrame;\n\n    if (supplyNeeded > 0)\n    {\n        FrameCountType min = 99999;\n\n        // if we don't have the resources, this action would only be legal if there is an\n        // overlord in progress, so check to see when the first overlord will finish\n        for (int i(0); i<_units.getNumActionsInProgress(); ++i)\n        {\n            // so, if the unit provides the supply we need\n            if (_units.getActionInProgressByIndex(i).supplyProvided() > supplyNeeded)\n            {\n                // set 'min' to the min of these times\n                min = (_units.getFinishTimeByIndex(i) < min) ? _units.getFinishTimeByIndex(i) : min;\n            }\n\n            // then set supply time to min\n            whenSupplyReady = min;\n        }\n    }\n\n    return whenSupplyReady;\n}\n\nconst FrameCountType GameState::whenPrerequisitesReady(const ActionType & action) const\n{\n    if (action == ActionTypes::GetActionType(\"Protoss_Dark_Templar\"))\n    {\n        int a = 6;\n    }\n\n    FrameCountType preReqReadyTime = _currentFrame;\n\n    // if a building builds this action\n    if (action.whatBuildsIsBuilding())\n    {\n        // get when the building / prereqs will be ready\n        preReqReadyTime = whenBuildingPrereqReady(action);\n    }\n    // otherwise something else builds this action so we don't worry about buildings\n    else\n    {\n        // if requirement in progress (and not already made), set when it will be finished\n        PrerequisiteSet reqInProgress = _units.getPrerequistesInProgress(action);\n\n        // if it's not empty, check when they will be done\n        if (!reqInProgress.isEmpty())\n        {\n            preReqReadyTime = _units.getFinishTime(reqInProgress);\n        }\n    }\n\n    return preReqReadyTime;\n}\n\nconst FrameCountType GameState::whenBuildingPrereqReady(const ActionType & action) const\n{\n    FrameCountType buildingAvailableTime(0);\n    const ActionType & builder = action.whatBuildsActionType();\n\n    BOSS_ASSERT(builder.isBuilding(), \"The thing that builds this is not a building\");\n\n    bool buildingIsConstructed                  = _units.getBuildingData().canBuildEventually(action);//getNumCompleted(builder) > 0;\n    bool buildingInProgress                     = _units.getNumInProgress(builder) > 0;\n    FrameCountType constructedBuildingFreeTime  = std::numeric_limits<int>::max()-10;\n    FrameCountType buildingInProgressFinishTime = std::numeric_limits<int>::max()-10;\n\n    BOSS_ASSERT(buildingIsConstructed || (!action.requiresAddon() && buildingInProgress), \"We will never be able to build action: %s\", action.getName().c_str());\n    \n    if (buildingIsConstructed)\n    {\n        constructedBuildingFreeTime  = _currentFrame + _units.getBuildingData().getTimeUntilCanBuild(action);\n    }\n        \n    if (!action.requiresAddon() && buildingInProgress)\n    {\n        buildingInProgressFinishTime = _units.getFinishTime(builder);\n    }\n\n    // this will give us when the building will be free to build this action\n    buildingAvailableTime = std::min(constructedBuildingFreeTime, buildingInProgressFinishTime);\n\n    // get all prerequisites currently in progress but do not have any completed\n    PrerequisiteSet prereqInProgress = _units.getPrerequistesInProgress(action);\n\n    // remove the specific builder from this list since we calculated that earlier\n    prereqInProgress.remove(builder);\n\n    //// if we actually have some prerequisites in progress other than the building\n    if (!prereqInProgress.isEmpty())\n    {\n        // get the max time the earliest of each type will be finished in\n        FrameCountType C = _units.getFinishTime(prereqInProgress);\n\n        // take the maximum of this value and when the building was available\n        buildingAvailableTime = (C > buildingAvailableTime) ? C : buildingAvailableTime;\n    }\n    \n    return buildingAvailableTime;\n}\n\n//const FrameCountType GameState::whenConstructedBuildingReady(const ActionType & builder) const\n//{\n//    // if what builds a is a building and we have at least one of them completed so far\n//    if (builder.isBuilding() && _units.getNumTotal(builder) > 0)\n//    {\n//        FrameCountType returnTime = _currentFrame + _units.getTimeUntilBuildingFree(builder);\n//\n//        // get when the next building is available\n//        return returnTime;\n//    }\n//\n//    return getCurrentFrame();\n//}\n\n// when will minerals be ready\nconst FrameCountType GameState::whenMineralsReady(const ActionType & action) const\n{\n    if (_minerals >= action.mineralPrice())\n    {\n        return getCurrentFrame();\n    }\n    \n    UnitCountType currentMineralWorkers     = _units.getNumMineralWorkers();\n    UnitCountType currentGasWorkers         = _units.getNumGasWorkers();\n    FrameCountType lastActionFinishFrame    = _currentFrame;\n    FrameCountType addedTime                = 0;\n    ResourceCountType addedMinerals         = 0;\n    ResourceCountType difference            = action.mineralPrice() - _minerals;\n\n    // loop through each action in progress, adding the minerals we would gather from each interval\n    for (int i(0); i< (int)_units.getNumActionsInProgress(); ++i)\n    {\n        // the vector is sorted in descending order\n        int progressIndex = _units.getNumActionsInProgress() - i - 1;\n\n        // the time elapsed and the current minerals per frame\n        FrameCountType elapsed = _units.getFinishTimeByIndex(progressIndex) - lastActionFinishFrame;\n        ResourceCountType mineralsPerFrame = (currentMineralWorkers * Constants::MPWPF);\n\n        // the amount of minerals that would be added this time step\n        ResourceCountType tempAdd = elapsed * mineralsPerFrame;\n\n        // if this amount isn't enough, update the amount added for this interval\n        if (addedMinerals + tempAdd < difference)\n        {\n            addedMinerals += tempAdd;\n            addedTime += elapsed;\n        }\n        else\n        {\n            // otherwise we can just break out and update at the end\n            break;\n        }\n\n        // if it was a drone or extractor update the temp variables\n        const ActionType & actionPerformed = _units.getActionInProgressByIndex(progressIndex);\n\n        // finishing a building as terran gives you a mineral worker back\n        if (actionPerformed.isBuilding() && !actionPerformed.isAddon() && (getRace() == Races::Terran))\n        {\n            currentMineralWorkers++;\n        }\n\n        if (actionPerformed.isWorker())\n        {\n            currentMineralWorkers++;\n        }\n        else if (actionPerformed.isRefinery())\n        {\n            BOSS_ASSERT(currentMineralWorkers > 3, \"Not enough mineral workers \\n\");\n            currentMineralWorkers -= 3; \n            currentGasWorkers += 3;\n        }\n\n\n        // update the last action\n        lastActionFinishFrame = _units.getFinishTimeByIndex(progressIndex);\n    }\n\n    // if we still haven't added enough minerals, add more time\n    if (addedMinerals < difference)\n    {\n        BOSS_ASSERT(currentMineralWorkers > 0, \"Shouldn't have 0 mineral workers\");\n\n       FrameCountType finalTimeToAdd;\n\t   if (currentMineralWorkers != 0)\n\t\t{\n\t\t\tfinalTimeToAdd = (difference - addedMinerals) / (currentMineralWorkers * Constants::MPWPF);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfinalTimeToAdd = 1000000;\n\t\t}\n        addedMinerals += finalTimeToAdd * currentMineralWorkers * Constants::MPWPF;\n        addedTime     += finalTimeToAdd;\n\n        // the last operation could have added one frame too little due to integer division so we need to check\n        if (addedMinerals < difference)\n        {\n            addedTime += 1;\n            addedMinerals += currentMineralWorkers * Constants::MPWPF;\n        }\n    }\n    \n    BOSS_ASSERT(addedMinerals >= difference, \"Mineral prediction error\");\n\n    // for some reason if i don't return +1, i mine 1 less mineral in the interval\n    return _currentFrame + addedTime;\n}\n\nconst FrameCountType GameState::whenGasReady(const ActionType & action) const\n{\n    if (_gas >= action.gasPrice())\n    {\n        return getCurrentFrame();\n    }\n    \n    UnitCountType currentMineralWorkers     = _units.getNumMineralWorkers();\n    UnitCountType currentGasWorkers         = _units.getNumGasWorkers();\n    FrameCountType lastActionFinishFrame    = _currentFrame;\n    FrameCountType addedTime                = 0;\n    ResourceCountType addedGas              = 0;\n    ResourceCountType difference            = action.gasPrice() - _gas;\n\n    // loop through each action in progress, adding the minerals we would gather from each interval\n    for (int i(0); i<_units.getNumActionsInProgress(); ++i)\n    {\n        // the vector is sorted in descending order\n        int progressIndex = _units.getNumActionsInProgress() - i - 1;\n\n        // the time elapsed and the current minerals per frame\n        FrameCountType elapsed = _units.getFinishTimeByIndex(progressIndex) - lastActionFinishFrame;\n        ResourceCountType gasPerFrame = (currentGasWorkers * Constants::GPWPF);\n\n        // the amount of minerals that would be added this time step\n        ResourceCountType tempAdd = elapsed * gasPerFrame;\n\n        // if this amount isn't enough, update the amount added for this interval\n        if (addedGas + tempAdd < difference)\n        {\n            addedGas += tempAdd;\n            addedTime += elapsed;\n        }\n        else\n        {\n            // otherwise we can just break out and update at the end\n            break;\n        }\n\n        // if it was a drone or extractor update the temp variables\n        const ActionType & actionPerformed = _units.getActionInProgressByIndex(progressIndex);\n\n        // finishing a building as terran gives you a mineral worker back\n        if (actionPerformed.isBuilding() && !actionPerformed.isAddon() && (getRace() == Races::Terran))\n        {\n            currentMineralWorkers++;\n        }\n\n        if (actionPerformed.isWorker())\n        {\n            currentMineralWorkers++;\n        }\n        else if (actionPerformed.isRefinery())\n        {\n            BOSS_ASSERT(currentMineralWorkers > 3, \"Not enough mineral workers\");\n            currentMineralWorkers -= 3; currentGasWorkers += 3;\n        }\n\n        // update the last action\n        lastActionFinishFrame = _units.getFinishTimeByIndex(progressIndex);\n    }\n\n    // if we still haven't added enough minerals, add more time\n    if (addedGas < difference)\n    {\n\t\tBOSS_ASSERT(currentGasWorkers > 0, \"Shouldn't have 0 gas workers\");\n\t\tFrameCountType finalTimeToAdd;\n\t\tif (currentGasWorkers != 0)\n\t\t{\n\t\t\tfinalTimeToAdd = (difference - addedGas) / (currentGasWorkers * Constants::GPWPF);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfinalTimeToAdd = 1000000;\n\t\t}\n        addedGas    += finalTimeToAdd * currentGasWorkers * Constants::GPWPF;\n        addedTime   += finalTimeToAdd;\n\n        // the last operation could have added one frame too little due to integer division so we need to check\n        if (addedGas < difference)\n        {\n            addedTime += 1;\n            addedGas += currentGasWorkers * Constants::GPWPF;\n        }\n    }\n    \n    BOSS_ASSERT(addedGas >= difference, \"Gas prediction error\");\n\n    // for some reason if i don't return +1, i mine 1 less mineral in the interval\n    return _currentFrame + addedTime;\n}\n\nconst FrameCountType GameState::getCurrentFrame() const\n{\n    return _currentFrame;\n}\n\nconst FrameCountType GameState::getLastActionFinishTime() const\n{\n    return _units.getLastActionFinishTime();\n}\n\nbool GameState::canAfford(const ActionType & action) const\n{\n    return canAffordMinerals(action) && canAffordGas(action);\n}\n\nbool GameState::canAffordGas(const ActionType & action) const\n{\n    return _gas >= action.gasPrice();\n}\n\nbool GameState::canAffordMinerals(const ActionType & action) const\n{\n    return _minerals >= action.mineralPrice();\n}\n\n// getter methods for the internal variables\nsize_t GameState::getMineralsPerFrame() const\n{\n    return Constants::MPWPF * _units.getNumMineralWorkers();\n}\n\nsize_t GameState::getGasPerFrame() const\n{\n    return Constants::GPWPF * _units.getNumGasWorkers();\n}\n\nconst UnitCountType GameState::getNumMineralWorkers() const\n{\n    return _units.getNumMineralWorkers();\n}\n\nconst UnitCountType GameState::getNumBuildingWorkers() const\n{\n    return _units.getNumBuildingWorkers();\n}\n\nconst UnitCountType GameState::getNumGasWorkers() const\n{\n    return _units.getNumGasWorkers();\n}\n\nconst ResourceCountType GameState::getMinerals() const\n{\n    return _minerals;\n\n}\n\nconst ResourceCountType GameState::getGas() const\n{\n    return _gas;\n}\n\nconst ResourceCountType GameState::getMinerals(const int frame) const\n{\n    BOSS_ASSERT(frame >= _currentFrame, \"Frame is not in the future\");\n\n    return _minerals + (int)(getMineralsPerFrame() * (frame-_currentFrame));\n}\n\nconst ResourceCountType GameState::getGas(const int frame) const\n{\n    BOSS_ASSERT(frame >= _currentFrame, \"Frame is not in the future\");\n\n    return _gas + (int)(getGasPerFrame() * (frame-_currentFrame));\n}\n\nconst ResourceCountType GameState::getFinishTimeMinerals() const\n{\n    return getMinerals(_units.getLastActionFinishTime());\n}\n\nconst ResourceCountType GameState::getFinishTimeGas() const\n{\n    return getGas(_units.getLastActionFinishTime());\n}\n\nconst UnitData & GameState::getUnitData() const\n{\n    return _units;\n}\n\nconst BuildingData & GameState::getBuildingData() const\n{\n    return _units.getBuildingData();\n}\n\nconst HatcheryData & GameState::getHatcheryData() const\n{\n    return _units.getHatcheryData();\n}\n\nvoid GameState::setMinerals(const ResourceCountType & minerals)\n{\n    _minerals = minerals * Constants::RESOURCE_SCALE;\n}\n\nvoid GameState::setGas(const ResourceCountType & gas)\n{\n    _gas = gas * Constants::RESOURCE_SCALE;\n}\n\nvoid GameState::addCompletedAction(const ActionType & action, const size_t num)\n{\n    for (size_t i(0); i < num; ++i)\n    {\n        _units.addCompletedAction(action, false);\n        _units.setCurrentSupply(_units.getCurrentSupply() + action.supplyRequired());\n    }\n}\n\nvoid GameState::removeCompletedAction(const ActionType & action, const size_t num)\n{\n\tfor (size_t i(0); i < num; ++i)\n\t{\n\t\t_units.setCurrentSupply(_units.getCurrentSupply() - action.supplyRequired());\n\t\t_units.removeCompletedAction(action);\n\t}\n}\n\nconst std::string GameState::toString() const\n{\n\tstd::stringstream ss;\n\tss << \"\\n-----------------------------------------------------------\\n\";\n    \n\tss << \"Current Frame: \" << _currentFrame << \" (\" << (_currentFrame / (60 * 24)) << \"m \" << ((_currentFrame / 24) % 60) << \"s)\\n\\n\";\n\n\tss << \"Units Completed:\\n\";\n    const std::vector<ActionType> & allActions = ActionTypes::GetAllActionTypes(getRace());\n\tfor (ActionID i(0); i< (int)allActions.size(); ++i)\n\t{\n        const ActionType & action = allActions[i];\n        if (_units.getNumCompleted(action) > 0) \n        {\n\t\t\tss << \"\\t\" << (int)_units.getNumCompleted(action) << \"\\t\" << action.getName() << \"\\n\";\n        }\n    }\n\n\tss << \"\\nUnits In Progress:\\n\";\n    for (int i(0); i<_units.getNumActionsInProgress(); i++) \n    {\n\t\tss << \"\\t\" << (int)_units.getFinishTimeByIndex(i) << \"\\t\" << _units.getActionInProgressByIndex(i).getName() << \"\\n\";\n    }\n\n    if (_race == Races::Zerg)\n    {\n        const HatcheryData & hd = _units.getHatcheryData();\n        ss << \"\\nHatcheries:\\n\";\n        ss << \"\\t\" << hd.size() << \" Hatcheries\\n\";\n        ss << \"\\t\" << hd.numLarva() << \" Larva\\n\";\n    }\n\n    \n    ss << \"\\nLegal Actions:\\n\";\n    ActionSet legalActions;\n    getAllLegalActions(legalActions);\n    for (UnitCountType a(0); a< (int)legalActions.size(); ++a)\n    {\n        ss << \"\\t\" << legalActions[a].getName() << \"\\n\";\n    }\n\n\tss << \"\\nResources:\\n\";\n\tss << \"\\t\" << _minerals / Constants::RESOURCE_SCALE << \"\\tMinerals\\n\";\n\tss << \"\\t\" << _gas / Constants::RESOURCE_SCALE << \"\\tGas\\n\";\n\tss << \"\\t\" << _units.getNumMineralWorkers() << \"\\tMineral Workers\\n\";\n    ss << \"\\t\" << _units.getNumGasWorkers() << \"\\tGas Workers\\n\";\n    ss << \"\\t\" << _units.getNumBuildingWorkers() << \"\\tBuilding Workers\\n\";\n    ss << \"\\n\\t\" << _units.getCurrentSupply()/2 << \" / \" << _units.getMaxSupply()/2 << \"\\tSupply\\n\";\n\n\n    ss << \"-----------------------------------------------------------\\n\";\n    //printPath();\n\n    return ss.str();\n}\n\nconst std::string GameState::getActionsPerformedString() const\n{\n    std::stringstream ss;\n    ss << std::endl;\n    for (size_t a(0); a<_actionsPerformed.size(); ++a)\n    {\n        ss << (int)_actionsPerformed[a].actionQueuedFrame << \" \" << (int)_actionsPerformed[a].mineralsWhenQueued << \" \" << (int)_actionsPerformed[a].gasWhenQueued << \" \" << _actionsPerformed[a].actionType.getName() << std::endl;\n    }\n\n    return ss.str();\n}\n\nstd::string GameState::whyIsNotLegal(const ActionType & action) const\n{\n    std::stringstream ss;\n\n    const size_t mineralWorkers  = getNumMineralWorkers();\n    const size_t numRefineries  = _units.getNumTotal(ActionTypes::GetRefinery(getRace()));\n    const size_t numDepots      = _units.getNumTotal(ActionTypes::GetResourceDepot(getRace()));\n    const size_t refineriesInProgress = _units.getNumInProgress(ActionTypes::GetRefinery(getRace()));\n\n    // we can never build a larva\n    static const ActionType & Zerg_Larva = ActionTypes::GetActionType(\"Zerg_Larva\");\n    if (action == Zerg_Larva)\n    {\n        ss << action.getName() << \" - Reason: Cannot build a Larva\" << std::endl;\n        return ss.str();\n    }\n\n    if (action.getRace() == Races::Protoss && action.isBuilding() && !action.isResourceDepot() && _units.getNumTotal(ActionTypes::GetSupplyProvider(Races::Protoss)) == 0)\n    {\n        ss << action.getName() << \" - Reason: Protoss buildings require a Pylon\" << std::endl;\n        return ss.str();\n    }\n\n    // check if the tech requirements are met\n    if (!_units.hasPrerequisites(action.getPrerequisites()))\n    {\n        ss << action.getName() << \" - Reason: Tech prerequisites not met\" << std::endl;\n        return ss.str();\n    }\n\t\n    // if it's a unit and we are out of supply and aren't making an overlord, it's not legal\n\tif (!action.isMorphed() && !action.isSupplyProvider() && ((_units.getCurrentSupply() + action.supplyRequired()) > (_units.getMaxSupply() + _units.getSupplyInProgress())))\n    {\n        ss << action.getName() << \" - Reason: Not enough supply\" << std::endl;\n        return ss.str();\n    }\n\n    // TODO: require an extra for refineries byt not buildings\n    // rules for buildings which are built by workers\n    if (action.isBuilding() && !action.isMorphed() && !action.isAddon())\n    {\n        // be very strict about when we can make refineries to ensure we have enough workers to go in gas\n        if (action.isRefinery() && (getNumMineralWorkers() <= (int)(4 + 3*refineriesInProgress)))\n        {\n            ss << action.getName() << \" - Reason: Not enough workers for refinery\" << std::endl;\n            return ss.str();\n        }\n\n        int workersPerRefinery = 3;\n        int workersRequiredToBuild = getRace() == Races::Protoss ? 0 : 1;\n        int buildingIsRefinery = action.isRefinery() ? 1 : 0;\n        int candidateWorkers = getNumMineralWorkers() + _units.getNumInProgress(ActionTypes::GetWorker(getRace())) + getNumBuildingWorkers();\n        int workersToBeUsed = workersRequiredToBuild + workersPerRefinery*(refineriesInProgress);\n\n        if (candidateWorkers < workersToBeUsed)\n        {\n            ss << action.getName() << \" - Reason: Not enough workers to build building\" << std::endl;\n            return ss.str();\n        }\n    }\n\n    // if we have no gas income we can't make a gas unit\n    if (!canAffordGas(action) && !_units.hasGasIncome())\n    {\n        ss << action.getName() << \" - Reason: No gas income\" << std::endl;\n        return ss.str();\n    }\n\n    // if we have no mineral income we'll never have a minerla unit\n    if (!canAffordMinerals(action) && !_units.hasMineralIncome())\n    {\n        ss << action.getName() << \" - Reason: No mineral income\" << std::endl;\n        return ss.str();\n    }\n\n    // don't build more refineries than resource depots\n    if (action.isRefinery() && (numRefineries >= numDepots))\n    {\n        ss << action.getName() << \" - Reason: Can't have more refineries than depots\" << std::endl;\n        return ss.str();\n    }\n\n    // we don't need to go over the maximum supply limit with supply providers\n    if (action.isSupplyProvider() && (_units.getMaxSupply() + _units.getSupplyInProgress() > 420))\n    {\n        ss << action.getName() << \" - Reason: Unnecessary supply providers\" << std::endl;\n        return ss.str();\n    }\n\n    // can only build one of a tech type\n    if (action.isTech() && getUnitData().getNumTotal(action) > 0)\n    {\n        ss << action.getName() << \" - Reason: Can't build more than one of a tech\" << std::endl;\n        return ss.str();\n    }\n\n    // check to see if an addon can ever be built\n    if (action.isAddon() && !_units.getBuildingData().canBuildEventually(action) && (_units.getNumInProgress(action.whatBuildsActionType()) == 0))\n    {\n        ss << action.getName() << \" - Reason: No building for addon\" << std::endl;\n        return ss.str();\n    }\n\n    return \"Legal\";\n}"
  },
  {
    "path": "BOSS/source/GameState.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\n#include \"ActionInProgress.h\"\n#include \"BuildingData.h\"\n#include \"UnitData.h\"\n#include \"ActionType.h\"\n#include \"PrerequisiteSet.h\"\n#include \"ActionSet.h\"\n\n//#define ENABLE_BWAPI_GAMESTATE_CONSTRUCTOR\n\nnamespace BOSS\n{\n    \ntypedef std::pair<ResourceCountType, ResourceCountType>     ResourcePair;\ntypedef std::pair<FrameCountType, FrameCountType>           FramePair;\n\nclass ActionPerformed\n{\npublic:\n    ActionType          actionType;\n    FrameCountType      actionQueuedFrame;\n    ResourceCountType   mineralsWhenQueued;\n    ResourceCountType   gasWhenQueued;\n\n    ActionPerformed()\n        : actionQueuedFrame(0)\n        , mineralsWhenQueued(0)\n        , gasWhenQueued(0)\n    {\n    \n    }\n};\n\nclass GameState \n{\n    UnitData                    _units;  \n    RaceID                      _race;\n\n    ActionType                  _actionPerformed; \t\t    // the action which generated this state\n    size_t                      _actionPerformedK;\n\n    FrameCountType              _currentFrame;\n    FrameCountType              _lastActionFrame;\t\t    // the current frame of the game\n\n    ResourceCountType           _minerals; \t\t\t        // current mineral count\n    ResourceCountType           _gas;\t\t\t\t\t\t// current gas count\n\n    std::vector<ActionPerformed>   _actionsPerformed;\n\n    const FrameCountType        raceSpecificWhenReady(const ActionType & a) const;\n    void                        fixZergUnitMasks();\n    \n    const FrameCountType        whenSupplyReady(const ActionType & action)                              const;\n    const FrameCountType        whenPrerequisitesReady(const ActionType & action)                       const;\n    const FrameCountType        whenBuildingPrereqReady(const ActionType & action)                      const;\n    //const FrameCountType        whenConstructedBuildingReady(const ActionType & builder)                const;\n    const FrameCountType        whenMineralsReady(const ActionType & action)                            const;\n    const FrameCountType        whenGasReady(const ActionType & action)                                 const;\n    const FrameCountType        whenWorkerReady(const ActionType & action)                              const;\n\npublic: \n\n    GameState(const RaceID r = Races::None);\n\n// constructor based on BWAPI::Game only makes sense if using VS\n// we won't be using this if we're compiling to emscripten or linux\n#ifdef _MSC_VER\n    GameState(BWAPI::GameWrapper & game, BWAPI::PlayerInterface * player, const std::vector<BWAPI::UnitType> & buildingsQueued);\n#endif\n\n\tstd::vector<ActionType>     doAction(const ActionType & action);\n    std::vector<ActionType>     fastForward(const FrameCountType toFrame) ;\n    void                        finishNextActionInProgress();\n\n    const FrameCountType        getCurrentFrame()                                                       const;\n    const FrameCountType        whenCanPerform(const ActionType & action)                               const;\n    const FrameCountType        getLastActionFinishTime()                                               const;\n\n    void                        getAllLegalActions(ActionSet & actions)                                 const;\n    std::string                 whyIsNotLegal(const ActionType & action)                                const;\n    bool                        isLegal(const ActionType & action)                                      const;\n    bool                        canAfford(const ActionType & action)                                    const;\n    bool                        canAffordGas(const ActionType & action)                                 const;\n    bool                        canAffordMinerals(const ActionType & action)                            const;\n\n    size_t \t\t\t\t        getMineralsPerFrame()\t\t    const;\n    size_t \t\t\t\t        getGasPerFrame()\t            const;\n    const UnitCountType \t\tgetNumMineralWorkers()\t        const;\t\t\t\t\n    const UnitCountType \t\tgetNumGasWorkers()\t\t        const;\t\t\t\t\t\n    const UnitCountType \t\tgetNumBuildingWorkers()\t        const;\t\t\n    const ResourceCountType \tgetMinerals() \t\t\t\t    const;\n    const ResourceCountType\t    getGas()\t\t\t\t\t    const;\n    const RaceID                getRace()                       const;\n\n    const UnitData &            getUnitData()                   const;\n\n    const ResourceCountType     getMinerals(const int frame)    const;\n    const ResourceCountType     getGas(const int frame)         const;\n    const ResourceCountType     getFinishTimeMinerals()         const;\n    const ResourceCountType     getFinishTimeGas()              const;\n\n    const std::string           toString()                      const;\n    const std::string           getActionsPerformedString()     const;\n    const BuildingData &        getBuildingData()               const;\n    const HatcheryData &        getHatcheryData()               const;\n\n    void                        setStartingState();\n    void                        setMinerals(const ResourceCountType & minerals);\n    void                        setGas(const ResourceCountType & gas);\n    void                        addCompletedAction(const ActionType & action, const size_t num = 1);\n\tvoid                        removeCompletedAction(const ActionType & action, const size_t num = 1);\n};\n}\n"
  },
  {
    "path": "BOSS/source/GraphViz.hpp",
    "content": "#pragma once\n\n#include <iostream>\n#include <vector>\n#include <fstream>\n#include <sstream>\n\nnamespace BOSS\n{\nnamespace GraphViz\n{\n\tclass Property\n\t{\n\tpublic:\n\t\tstd::string prop;\n\t\tstd::string value;\n\t\tProperty(std::string p, std::string val) : prop(p), value(val) { }\t\n\t\tvoid print(std::ofstream & out) { out << prop << \"=\\\"\" << value << \"\\\", \"; }\n\t};\n\n\tclass Node\n\t{\t\n\tpublic:\n\t\tstd::vector<Property> props;\n\t\tstd::string name;\n\t\tNode(std::string n) : name(n) {}\n\t\tNode() {}\n\t\n\t\tvoid set(std::string p, std::string v) { props.push_back(Property(p,v)); }\n\t\tvoid print(std::ofstream & out)\n\t\t{\n\t\t\tout << name << \" [\";\n\t\t\tfor (size_t p(0); p<props.size(); ++p) { props[p].print(out); }\n\t\t\tout << \"]\\n\";\n\t\t}\n\t};\n\n\tclass Edge\n\t{\n\tpublic:\n\t\tstd::pair<std::string, std::string> nodes;\n\t\tstd::vector<Property> props;\n\n\t\tEdge(std::string n1, std::string n2) : nodes(n1, n2) {}\n\t\tEdge(Node & n1, Node & n2) : nodes(n1.name, n2.name) {}\n\t\tvoid set(std::string p, std::string v) { props.push_back(Property(p,v)); }\n\t\tvoid print(std::ofstream & out)\n\t\t{\n\t\t\tout << nodes.first << \" -> \" << nodes.second << \" [\";\n\t\t\tfor (size_t p(0); p<props.size(); ++p) { props[p].print(out); }\n\t\t\tout << \"]\\n\";\n\t\t}\n\t};\n\n\tclass Graph\n\t{\n\t\tstd::vector<Node> nodes;\n\t\tstd::vector<Edge> edges;\n\t\tstd::vector<Property> props;\n\t\tstd::string name;\n\n\tpublic:\n\n\t\tGraph(std::string n) : name(n) {}\n\t\tvoid set(std::string p, std::string v) { props.push_back(Property(p,v)); }\n\t\tvoid addNode(Node & n) { nodes.push_back(n); }\n\t\tvoid addEdge(Edge & e) { edges.push_back(e); }\n\n        void print(std::ofstream & out)\n\t\t{\n\t\t\tout << \"digraph \" << name << \" {\\n\";\n\t\t\tfor (size_t p(0); p<props.size(); ++p) { out << props[p].prop << \"=\\\"\" << props[p].value << \"\\\"\\n\"; }\n\t\t\tfor (size_t n(0); n<nodes.size(); ++n) { nodes[n].print(out); }\n\t\t\tfor (size_t e(0); e<edges.size(); ++e) { edges[e].print(out); }\n\t\t    out << \"}\\n\";\n\t\t}\n\n        void printToFile(const std::string & filename)\n        {\n            std::ofstream out(filename);\n            print(out);\n            out.close();\n        }\n\t};\n\n\t/*\n\tvoid example()\n\t{\n\t\t// construct a graph, give it a name and some properties\n\t\tGraphViz::Graph G(\"g\");\n\t\t                G.set(\"bgcolor\", \"#000000\");\n\n\t\t// construct some nodes with unique identifiers then give them some properties\n\t\tGraphViz::Node  n1(\"n1\");\n\t\t                n1.set(\"fontcolor\", \"#ffffff\");\n\t\t\t\t\t\tn1.set(\"style\", \"filled\");\n\t\t\t\t\t\tn1.set(\"fillcolor\", \"#ff0000\");\n\t\t\t\t\t\tn1.set(\"label\", \"Node 1\");\n\t\t\t\t\t\tn1.set(\"shape\", \"box\");\n\t\t\t\t\t\tn1.set(\"color\", \"white\");\n\n\t\tGraphViz::Node  n2(\"n2\");\n\t\t                n2.set(\"fontcolor\", \"#ff00ff\");\n\t\t\t\t\t\tn2.set(\"style\", \"filled\");\n\t\t\t\t\t\tn2.set(\"fillcolor\", \"#ffffff\");\n\t\t\t\t\t\tn2.set(\"label\", \"Node 2\");\n\n\t\t// construct an edge, either on unique identifier or node object\n\t\tGraphViz::Edge  e1(n1, n2);\n                        e1.set(\"label\", \"Edge 1\");\n\t\t\t\t\t\te1.set(\"color\", \"white\");\n\n\t\t// add the elements to the graph, this can happen at any time in any order\n\t\tG.addNode(n1);\n\t\tG.addNode(n2);\n\t\tG.addEdge(e1);\n\n\t\t// print out the graph\n\t\tG.print();\n\n\t\t// to use this output you need to have GraphViz installed\n\t\t// to run the above example, pipe the output to test.txt then run\n\t\t//     dot < test.txt -Tpng > test.png\n\t}*/\n}\n}"
  },
  {
    "path": "BOSS/source/HatcheryData.cpp",
    "content": "#include \"HatcheryData.h\"\n\nusing namespace BOSS;\n\nHatchery::Hatchery(const UnitCountType & numLarva) \n\t: _numLarva(numLarva)\n{\n}\n\nHatchery::Hatchery() \n\t: _numLarva(3)\n{\n}\n\nvoid Hatchery::fastForward(const FrameCountType & currentFrame, const FrameCountType & toFrame)\n{\n    if (_numLarva == 3)\n    {\n        return;\n    }\n\n    UnitCountType  larvaToAdd   = (toFrame / Constants::ZERG_LARVA_TIMER) - (currentFrame / Constants::ZERG_LARVA_TIMER);\n\n    larvaToAdd                  = std::min(larvaToAdd, (UnitCountType)(3 - _numLarva));\n\n    _numLarva += larvaToAdd;\n}\n\nvoid Hatchery::useLarva()\n{\n    BOSS_ASSERT(_numLarva > 0, \"We should have larva to use\");\n\n    _numLarva--;\n}\n\nconst UnitCountType & Hatchery::numLarva() const\n{\n    return _numLarva;\n}\n\nHatcheryData::HatcheryData()\n{\n\n}\n\nvoid HatcheryData::addHatchery(const UnitCountType & numLarva)\n{\n    _hatcheries.push_back(Hatchery(numLarva));\n}\n\nvoid HatcheryData::removeHatchery()\n{\n\t_hatcheries.pop_back();\n}\n\nvoid HatcheryData::fastForward(const FrameCountType & currentFrame, const FrameCountType & toFrame)\n{\n    for (size_t i(0); i < _hatcheries.size(); ++i)\n    {\n        _hatcheries[i].fastForward(currentFrame, toFrame);\n    }\n}\n\nvoid HatcheryData::useLarva()\n{\n    int maxLarvaIndex = -1;\n    for (size_t i(0); i < _hatcheries.size(); ++i)\n    {\n        if (_hatcheries[i].numLarva() > 0)\n        {\n            if (maxLarvaIndex == -1 || (_hatcheries[i].numLarva() > _hatcheries[maxLarvaIndex].numLarva()))\n            {\n                maxLarvaIndex = i;\n            }\n        }\n    }\n\n    if (maxLarvaIndex != -1)\n    {\n        _hatcheries[maxLarvaIndex].useLarva();\n    }\n    else\n    {\n        BOSS_ASSERT(false, \"Should have found a larva to use\");\n    }\n}\n\nconst FrameCountType HatcheryData::nextLarvaFrameAfter(const FrameCountType & currentFrame) const\n{\n    if (currentFrame % Constants::ZERG_LARVA_TIMER == 0)\n    {\n        return currentFrame + Constants::ZERG_LARVA_TIMER;\n    }\n    else\n    {\n        return Constants::ZERG_LARVA_TIMER * ((currentFrame / Constants::ZERG_LARVA_TIMER) + 1);\n    }\n}\n\nconst UnitCountType HatcheryData::numLarva() const\n{\n    UnitCountType sumLarva = 0;\n\n    for (size_t i(0); i < _hatcheries.size(); ++i)\n    {\n        sumLarva += _hatcheries[i].numLarva();\n    }\n\n    return sumLarva;\n}\n\nconst UnitCountType HatcheryData::size() const\n{\n    return _hatcheries.size();\n}\n\nconst Hatchery & HatcheryData::getHatchery(const UnitCountType & index) const\n{\n    return _hatcheries[index];\n}"
  },
  {
    "path": "BOSS/source/HatcheryData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\n#include <string.h>\n#include <queue>\n#include <algorithm>\n\n#include \"PrerequisiteSet.h\"\n#include \"Array.hpp\"\n#include \"ActionType.h\"\n\nnamespace BOSS\n{\n\nclass Hatchery\n{ \n    UnitCountType           _numLarva;\n\t\npublic:\n\t\n\tHatchery(const UnitCountType & numLarva);\n\tHatchery();\n\n       \n    void                    useLarva();\n    void                    fastForward(const FrameCountType & currentFrame, const FrameCountType & toFrame);\n\n    const UnitCountType &   numLarva() const;\n};\n\nclass HatcheryData\n{\n    Vec<Hatchery, Constants::MAX_HATCHERIES> _hatcheries;\n\npublic:\n\n    HatcheryData();\n\n    void                    addHatchery(const UnitCountType & numLarva);\n\tvoid                    removeHatchery();\n    void                    useLarva();\n    void                    fastForward(const FrameCountType & currentFrame, const FrameCountType & toFrame);\n\n    const FrameCountType    nextLarvaFrameAfter(const FrameCountType & currentFrame) const;\n    const UnitCountType     numLarva() const;\n    const UnitCountType     size() const;\n    const Hatchery &        getHatchery(const UnitCountType & index) const;\n};\n\n}"
  },
  {
    "path": "BOSS/source/JSONTools.cpp",
    "content": "#include \"JSONTools.h\"\n\nusing namespace BOSS;\n\nstd::string JSONTools::ReadJsonFile(const std::string & filename)\n{\n\n    // set up the file\n    std::ifstream fin(filename.c_str());\n    if (!fin.is_open())\n    {\n        BOSS_ASSERT(false, \"Could not open file: %s\", filename.c_str());\n    }\n\n\tstd::string line;\n    std::stringstream ss;\n\n    // each line of the file will be a new player to add\n    while (fin.good())\n    {\n        // get the line and set up the string stream\n        getline(fin, line);\n       \n        ss << line;\n    }\n\n\tfin.close();\n    return ss.str();\n}\n\nvoid JSONTools::ParseJSONString(rapidjson::Document & document, const std::string & json)\n{\n    bool parsingFailed = document.Parse<0>(json.c_str()).HasParseError();\n\n    if (parsingFailed)\n    {\n        int errorPos = document.GetErrorOffset();\n\n        std::stringstream ss;\n        ss << std::endl << \"JSON Parse Error: \" << document.GetParseError() << std::endl;\n        ss << \"Error Position:   \" << errorPos << std::endl;\n        ss << \"Error Substring:  \" << json.substr(errorPos-5, 10) << std::endl;\n\n        BOSS_ASSERT(!parsingFailed, \"Error parsing JSON config file: %s\", ss.str().c_str());\n    }\n\n    BOSS_ASSERT(!parsingFailed, \"Parsing of the JSON string failed\");\n\n}\n\nvoid JSONTools::ParseJSONFile(rapidjson::Document & document, const std::string & filename)\n{\n    JSONTools::ParseJSONString(document, JSONTools::ReadJsonFile(filename));\n}\n\nGameState JSONTools::GetGameState(const std::string & jsonString)\n{\n    rapidjson::Document document;\n    JSONTools::ParseJSONString(document, jsonString);\n    return GetGameState(document);\n}\n\nGameState JSONTools::GetGameState(const rapidjson::Value & stateVal)\n{\n    BOSS_ASSERT(stateVal.HasMember(\"race\") && stateVal[\"race\"].IsString(), \"State doesn't have a race\");\n    \n    const RaceID race = Races::GetRaceID(stateVal[\"race\"].GetString());\n\n    BOSS_ASSERT(race != Races::None, \"Unknown race (make sure to use a single upper case): %s\", stateVal[\"race\"].GetString());\n\n    GameState state(race);\n\n    if (stateVal.HasMember(\"minerals\") && stateVal[\"minerals\"].IsInt())\n    {   \n        state.setMinerals(stateVal[\"minerals\"].GetInt());\n    }\n\n    if (stateVal.HasMember(\"gas\") && stateVal[\"gas\"].IsInt())\n    {   \n        state.setGas(stateVal[\"gas\"].GetInt());\n    }\n\n    if (stateVal.HasMember(\"units\") && stateVal[\"units\"].IsArray())\n    {\n        const rapidjson::Value & units = stateVal[\"units\"];\n        for (size_t i(0); i < units.Size(); ++i)\n        {\n            const rapidjson::Value & unit = units[i];\n            BOSS_ASSERT(unit.IsArray() && unit.Size() == 2 && unit[0u].IsString() && unit[1u].IsInt(), \"Unit has to be array of size 2\");\n\n            state.addCompletedAction(ActionTypes::GetActionType(unit[0u].GetString()), unit[1u].GetInt());\n        }\n    }\n\n    return state;\n}\n\nBuildOrder JSONTools::GetBuildOrder(const std::string & jsonString)\n{\n    rapidjson::Document document;\n    JSONTools::ParseJSONString(document, jsonString);\n    return GetBuildOrder(document);\n}\n\nBuildOrder JSONTools::GetBuildOrder(const rapidjson::Value & stateVal)\n{\n    BOSS_ASSERT(stateVal.IsArray(), \"Build order isn't an array\");\n    \n    BuildOrder buildOrder;\n\n    for (size_t i(0); i < stateVal.Size(); ++i)\n    {\n        BOSS_ASSERT(stateVal[i].IsString(), \"Build order item is not a string\");\n\n        buildOrder.add(ActionTypes::GetActionType(stateVal[i].GetString()));\n    }\n    \n    return buildOrder;\n}\n\nBuildOrderSearchGoal JSONTools::GetBuildOrderSearchGoal(const std::string & jsonString)\n{\n    rapidjson::Document document;\n    JSONTools::ParseJSONString(document, jsonString);\n    return GetBuildOrderSearchGoal(document);\n}\n\nBuildOrderSearchGoal JSONTools::GetBuildOrderSearchGoal(const rapidjson::Value & val)\n{\n    BOSS_ASSERT(val.HasMember(\"race\") && val[\"race\"].IsString(), \"State doesn't have a race\");\n    \n    const RaceID race = Races::GetRaceID(val[\"race\"].GetString());\n\n    BOSS_ASSERT(race != Races::None, \"Unknown race (make sure to use a single upper case): %s\", val[\"race\"].GetString());\n\n    BuildOrderSearchGoal goal(race);\n\n    if (val.HasMember(\"goal\") && val[\"goal\"].IsArray())\n    {\n        const rapidjson::Value & goalUnits = val[\"goal\"];\n        for (size_t i(0); i < goalUnits.Size(); ++i)\n        {\n            const rapidjson::Value & unit = goalUnits[i];\n            BOSS_ASSERT(unit.IsArray() && unit.Size() == 2 && unit[0u].IsString() && unit[1u].IsInt(), \"Goal entry has to be array of size 2\");\n\n            goal.setGoal(ActionTypes::GetActionType(unit[0u].GetString()), unit[1u].GetInt());\n        }\n    }\n\n    if (val.HasMember(\"goalMax\") && val[\"goalMax\"].IsArray())\n    {\n        const rapidjson::Value & goalMax = val[\"goalMax\"];\n        for (size_t i(0); i < goalMax.Size(); ++i)\n        {\n            const rapidjson::Value & unit = goalMax[i];\n            BOSS_ASSERT(unit.IsArray() && unit.Size() == 2 && unit[0u].IsString() && unit[1u].IsInt(), \"Goal max entry has to be array of size 2\");\n\n            goal.setGoalMax(ActionTypes::GetActionType(unit[0u].GetString()), unit[1u].GetInt());\n        }\n    }\n\n    return goal;\n}\n\nstd::string JSONTools::GetBuildOrderString(const std::vector<ActionType> & buildOrder)\n{\n    std::stringstream ss;\n\n    ss << \"\\\"Test Build\\\" : [\";\n\n    for (size_t i(0); i < buildOrder.size(); ++i)\n    {\n        ss << \"\\\"\" << buildOrder[i].getName() << \"\\\"\" << (i < buildOrder.size() - 1 ? \", \" : \"\");\n    }\n\n    ss << \"]\";\n\n    return ss.str();\n}"
  },
  {
    "path": "BOSS/source/JSONTools.h",
    "content": "#pragma once\n\n#include \"BOSS.h\"\n#include \"Common.h\"\n#include \"BuildOrder.h\"\n#include \"rapidjson/rapidjson.h\"\n#include \"rapidjson/document.h\"\n\nnamespace BOSS\n{\nnamespace JSONTools\n{\n    std::string ReadJsonFile(const std::string & filename);\n    void ParseJSONString(rapidjson::Document & document, const std::string & json);\n    void ParseJSONFile(rapidjson::Document & document, const std::string & filename);\n\n    GameState GetGameState(const std::string & jsonString);\n    GameState GetGameState(const rapidjson::Value & stateVal);\n\n    BuildOrder GetBuildOrder(const std::string & jsonString);\n    BuildOrder GetBuildOrder(const rapidjson::Value & stateVal);\n\n    BuildOrderSearchGoal GetBuildOrderSearchGoal(const std::string & jsonString);\n    BuildOrderSearchGoal GetBuildOrderSearchGoal(const rapidjson::Value & stateVal);\n\n    std::string GetBuildOrderString(const std::vector<ActionType> & buildOrder);\n}\n}\n"
  },
  {
    "path": "BOSS/source/NaiveBuildOrderSearch.cpp",
    "content": "#include \"NaiveBuildOrderSearch.h\"\n\nusing namespace BOSS;\n\nNaiveBuildOrderSearch::NaiveBuildOrderSearch(const GameState & state, const BuildOrderSearchGoal & goal)\n    : _state(state)\n    , _goal(goal)\n    , _naiveSolved(false)\n{\n\n}\n\nbool NaiveBuildOrderSearch::checkUnsolvable()\n{\n    const ActionType & worker = ActionTypes::GetWorker(_state.getRace());\n    const ActionType & supply = ActionTypes::GetSupplyProvider(_state.getRace());\n    const ActionType & depot = ActionTypes::GetResourceDepot(_state.getRace());\n\n    UnitCountType mineralWorkers = _state.getUnitData().getNumMineralWorkers();\n    UnitCountType numDepot = _state.getUnitData().getNumTotal(depot);\n\n    if (mineralWorkers == 0 || numDepot == 0)\n    {\n        return true;\n    }\n\n    if (!_state.isLegal(worker) && !_state.isLegal(supply))\n    {\n        return true;\n    }\n\n    return false;\n}\n\nconst BuildOrder & NaiveBuildOrderSearch::solve()\n{\n    if (_naiveSolved)\n    {\n        return _buildOrder;\n    }\n\n    if (checkUnsolvable())\n    {\n        bool temp = checkUnsolvable();\n        _buildOrder = BuildOrder();\n        return _buildOrder;\n    }\n\n    PrerequisiteSet wanted;\n    int minWorkers = 0;\n\n    const ActionType & worker = ActionTypes::GetWorker(_state.getRace());\n\n    // add everything from the goal to the needed set\n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(_state.getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(_state.getRace(), a);\n        UnitCountType numCompleted = _state.getUnitData().getNumTotal(actionType);\n            \n        if (_goal.getGoal(actionType) > numCompleted)\n        {\n            wanted.addUnique(actionType);\n        }\n    }\n\n    if (wanted.size() == 0)\n    {\n        return _buildOrder;\n    }\n\n    // Calculate which prerequisite units we need to build to achieve the units we want from the goal\n    PrerequisiteSet requiredToBuild;\n    Tools::CalculatePrerequisitesRequiredToBuild(_state, wanted, requiredToBuild);\n\n    // Add the required units to a preliminary build order\n    BuildOrder buildOrder;\n    for (size_t a(0); a < requiredToBuild.size(); ++a)\n    {\n        const ActionType & type = requiredToBuild.getActionType(a);\n        buildOrder.add(type);\n    }\n\n    // Add some workers to the build order if we don't have many, this usually gives a lower upper bound\n    int requiredWorkers = minWorkers - _state.getUnitData().getNumCompleted(ActionTypes::GetWorker(_state.getRace()));\n    buildOrder.add(worker, requiredWorkers);\n\n    // Add the goal units to the end of the build order \n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(_state.getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(_state.getRace(), a);\n        int need = (int)_goal.getGoal(actionType);\n        int have = (int)_state.getUnitData().getNumTotal(actionType);\n        int numNeeded = need - have - buildOrder.getTypeCount(actionType);\n         \n        buildOrder.add(actionType, numNeeded);\n    }\n\n    // if we are zerg, make sure we have enough morphers for morphed units\n    if (_state.getRace() == Races::Zerg)\n    {\n        // do this whole thing twice so that Hive->Lair->Hatchery is satisfied\n        for (size_t t=0; t<2; ++t)\n        {\n            std::vector<size_t> neededMorphers(ActionTypes::GetAllActionTypes(_state.getRace()).size(), 0);\n            for (size_t i(0); i < ActionTypes::GetAllActionTypes(_state.getRace()).size(); ++i)\n            {\n                const ActionType & type = ActionTypes::GetActionType(Races::Zerg, i);\n\n                if (type.isMorphed())\n                {\n                    const ActionType & morpher = type.whatBuildsActionType();\n\n                    int willMorph = buildOrder.getTypeCount(type);\n                    int haveMorpher = _state.getUnitData().getNumTotal(morpher);\n                    int boMoprher = buildOrder.getTypeCount(morpher);\n\n                    int need = willMorph - haveMorpher - boMoprher;\n\n                    if (need > 0)\n                    {\n                        neededMorphers[morpher.ID()] += need;\n                    }\n                }\n            }\n            \n            // add the morphers to the build order\n            for (size_t i(0); i<neededMorphers.size(); ++i)\n            {\n                buildOrder.add(ActionTypes::GetActionType(Races::Zerg, i), neededMorphers[i]);\n            }\n        }\n\n        // special case: hydra/lurker both in goal, need to add hydras, same with creep/sunken and muta/guardian\n        // ignore other spire / hatchery since they recursively serve all purposes\n        static const ActionType & Hydralisk     = ActionTypes::GetActionType(\"Zerg_Hydralisk\");\n        static const ActionType & Lurker        = ActionTypes::GetActionType(\"Zerg_Lurker\");\n        static const ActionType & Creep         = ActionTypes::GetActionType(\"Zerg_Creep_Colony\");\n        static const ActionType & Sunken        = ActionTypes::GetActionType(\"Zerg_Sunken_Colony\");\n        static const ActionType & Spore         = ActionTypes::GetActionType(\"Zerg_Spore_Colony\");\n        static const ActionType & Mutalisk      = ActionTypes::GetActionType(\"Zerg_Mutalisk\");\n        static const ActionType & Guardian      = ActionTypes::GetActionType(\"Zerg_Guardian\");\n        static const ActionType & Devourer      = ActionTypes::GetActionType(\"Zerg_Devourer\");\n\n        if (_goal.getGoal(Hydralisk) > 0)\n        {\n            int currentHydras = _state.getUnitData().getNumTotal(Hydralisk) + buildOrder.getTypeCount(Hydralisk) - buildOrder.getTypeCount(Lurker);\n            int additionalHydras = _goal.getGoal(Hydralisk) - currentHydras;\n            buildOrder.add(Hydralisk, additionalHydras);\n        }\n\n        if (_goal.getGoal(Guardian) > 0 && _goal.getGoal(Devourer) > 0)\n        {\n            int currentMutas = _state.getUnitData().getNumTotal(Mutalisk) + buildOrder.getTypeCount(Mutalisk);\n            int additionalMutas = buildOrder.getTypeCount(Guardian) + buildOrder.getTypeCount(Devourer) - currentMutas;\n            buildOrder.add(Mutalisk, additionalMutas);\n        }\n\n        if (_goal.getGoal(Mutalisk) > 0)\n        {\n            int currentMutas = _state.getUnitData().getNumTotal(Mutalisk) + buildOrder.getTypeCount(Mutalisk) - buildOrder.getTypeCount(Guardian) - buildOrder.getTypeCount(Devourer);\n            int additionalMutas = _goal.getGoal(Mutalisk) - currentMutas;\n            buildOrder.add(Mutalisk, additionalMutas);\n        }\n\n        if (_goal.getGoal(Sunken) > 0 && _goal.getGoal(Spore) > 0)\n        {\n            int currentCreep = _state.getUnitData().getNumTotal(Creep) + buildOrder.getTypeCount(Creep);\n            int additionalCreep = buildOrder.getTypeCount(Spore) + buildOrder.getTypeCount(Sunken) - currentCreep;\n            buildOrder.add(Creep, additionalCreep);\n        }\n\n        if (_goal.getGoal(Creep) > 0)\n        {\n            int currentCreep = _state.getUnitData().getNumTotal(Creep) + buildOrder.getTypeCount(Creep) - buildOrder.getTypeCount(Spore) - buildOrder.getTypeCount(Sunken);\n            int additionalCreep = _goal.getGoal(Creep) - currentCreep;\n            buildOrder.add(Creep, additionalCreep);\n        }\n    }\n\n    // figure out how many workers are needed for the build order to be legal      \n    size_t workersNeeded = _goal.getGoal(worker);\n\n    // we need enough workers to fill all the refineries that will be built\n    size_t gasWorkersNeeded = 3*_state.getUnitData().getNumTotal(ActionTypes::GetRefinery(_state.getRace())) + 3*buildOrder.getTypeCount(ActionTypes::GetRefinery(_state.getRace()));\n\n    workersNeeded = std::max(workersNeeded, gasWorkersNeeded);\n\n    // special case for zerg: buildings consume drones\n    if (_state.getRace() == Races::Zerg)\n    {\n        for (size_t i(0); i < ActionTypes::GetAllActionTypes(_state.getRace()).size(); ++i)\n        {\n            const ActionType & type = ActionTypes::GetActionType(Races::Zerg, i);\n\n            if (type.whatBuildsActionType().isWorker() && !type.isMorphed())\n            {\n                workersNeeded += buildOrder.getTypeCount(type);\n            }\n        }\n    }\n\n    int workersToAdd = workersNeeded - _state.getUnitData().getNumTotal(worker) - buildOrder.getTypeCount(worker);\n    workersToAdd = std::max(0, workersToAdd);\n    \n    buildOrder.add(worker, workersToAdd);\n\n\n    // Check to see if we have enough buildings for the required addons\n    if (_state.getRace() == Races::Terran)\n    {\n        // Terran buildings that can make addons\n        static const ActionType CommandCenter   = ActionTypes::GetActionType(\"Terran_Command_Center\");\n        static const ActionType Factory         = ActionTypes::GetActionType(\"Terran_Factory\");\n        static const ActionType Starport        = ActionTypes::GetActionType(\"Terran_Starport\");\n        static const ActionType ScienceFacility = ActionTypes::GetActionType(\"Terran_Science_Facility\");\n\n        // Terran building addons\n        static const ActionType ComsatStation   = ActionTypes::GetActionType(\"Terran_Comsat_Station\");\n        static const ActionType NuclearSilo     = ActionTypes::GetActionType(\"Terran_Nuclear_Silo\");\n        static const ActionType MachineShop     = ActionTypes::GetActionType(\"Terran_Machine_Shop\");\n        static const ActionType ControlTower    = ActionTypes::GetActionType(\"Terran_Control_Tower\");\n        static const ActionType PhysicsLab      = ActionTypes::GetActionType(\"Terran_Physics_Lab\");\n        static const ActionType CovertOps       = ActionTypes::GetActionType(\"Terran_Covert_Ops\");\n\n        int numCommandCenters   = _state.getUnitData().getNumTotal(CommandCenter)   + buildOrder.getTypeCount(CommandCenter);\n        int numFactories        = _state.getUnitData().getNumTotal(Factory)         + buildOrder.getTypeCount(Factory);\n        int numStarports        = _state.getUnitData().getNumTotal(Starport)        + buildOrder.getTypeCount(Starport);\n        int numSci              = _state.getUnitData().getNumTotal(ScienceFacility) + buildOrder.getTypeCount(ScienceFacility);\n\n        int commandCenterAddons = buildOrder.getTypeCount(ComsatStation) + buildOrder.getTypeCount(NuclearSilo);\n        int factoryAddons       = buildOrder.getTypeCount(MachineShop);\n        int starportAddons      = buildOrder.getTypeCount(ControlTower);\n        int sciAddons           = buildOrder.getTypeCount(PhysicsLab) + buildOrder.getTypeCount(CovertOps);\n        \n        // add the necessary buildings to make the addons\n        buildOrder.add(CommandCenter, commandCenterAddons - numCommandCenters);\n        buildOrder.add(Factory, factoryAddons - numFactories);\n        buildOrder.add(Starport, starportAddons - numStarports);\n        buildOrder.add(ScienceFacility, sciAddons - numSci);\n    }\n\n    // Bubble sort the build order so that prerequites always come before what requires them\n    buildOrder.sortByPrerequisites();\n\n    // Insert supply buildings so that build order is legal w.r.t. supply counts\n    int maxSupply = _state.getUnitData().getMaxSupply() + _state.getUnitData().getSupplyInProgress();\n    int currentSupply = _state.getUnitData().getCurrentSupply();\n\n    const ActionType & supplyProvider = ActionTypes::GetSupplyProvider(_state.getRace());\n\n    BuildOrder finalBuildOrder;\n    for (size_t a(0); a < buildOrder.size(); ++a)\n    {\n        const ActionType & nextAction = buildOrder[a];\n        UnitCountType maxSupply = _state.getUnitData().getMaxSupply();\n        UnitCountType currentSupply = _state.getUnitData().getCurrentSupply();\n        UnitCountType supplyInProgress = _state.getUnitData().getSupplyInProgress();\n\n\t\t// insert 1 or more supply providers if needed\n        // TODO: don't go over 200 supply\n\t\twhile (!nextAction.isMorphed() && !nextAction.isSupplyProvider() && (nextAction.supplyRequired() > (maxSupply + supplyInProgress - currentSupply)))\n\t\t{\n\t\t\tBOSS_ASSERT(_state.isLegal(supplyProvider), \"Should be able to build more supply here. Max: %d\", maxSupply);\n\t\t\tfinalBuildOrder.add(supplyProvider);\n\t\t\t_state.doAction(supplyProvider);\n\n\t\t\tmaxSupply = _state.getUnitData().getMaxSupply();\n\t\t\tcurrentSupply = _state.getUnitData().getCurrentSupply();\n\t\t\tsupplyInProgress = _state.getUnitData().getSupplyInProgress();\n\t\t}\n\n\t\tBOSS_ASSERT(_state.isLegal(nextAction), \"Should be able to build the next action now\");\n\t\tfinalBuildOrder.add(nextAction);\n\t\t_state.doAction(nextAction);\n\t}\n\n    _buildOrder = finalBuildOrder;\n    _naiveSolved = true;\n\n    return _buildOrder;\n}\n\n"
  },
  {
    "path": "BOSS/source/NaiveBuildOrderSearch.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BuildOrderSearchGoal.h\"\n#include \"GameState.h\"\n#include \"BuildOrder.h\"\n#include \"Tools.h\"\n\nnamespace BOSS\n{\n\nclass NaiveBuildOrderSearch\n{\n    GameState                   _state;\n    BuildOrderSearchGoal        _goal;\n    BuildOrder                  _buildOrder;\n\n    bool                        _naiveSolved;\n\n    bool                        checkUnsolvable();\n\npublic:\n\n    NaiveBuildOrderSearch(const GameState & state, const BuildOrderSearchGoal & goal);\n\n    const BuildOrder & solve();\n};\n\n}"
  },
  {
    "path": "BOSS/source/Position.hpp",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include <sstream>\n\ntypedef int PositionType;\n\nnamespace BOSS\n{\nclass Position\n{\n\n    PositionType    _x; \n    PositionType    _y;\n\npublic:\n \n    Position()\n        : _x(0)\n        , _y(0)\n    {\n    }\n\n    Position(const PositionType & x, const PositionType & y)\n        : _x(x)\n        , _y(y)\n    {\n    }\n\n\n    const bool operator < (const Position & rhs) const\n    {\n        return (x() < rhs.x()) || ((x() == rhs.x()) && y() < rhs.y());\n    }\n\n    const bool operator == (const Position & rhs) const\n    {\n        return x() == rhs.x() && y() == rhs.y();\n    }\n\n    const Position operator + (const Position & rhs) const\n    {\n        return Position(x() + rhs.x(), y() + rhs.y());\n    }\n\n    const Position operator - (const Position & rhs) const\n    {\n        return Position(x() - rhs.x(), y() - rhs.y());\n    }\n\n    const Position operator / (const PositionType & d) const\n    {\n        return Position(_x / d, _y / d);\n    }\n\n    const Position operator * (const PositionType & d) const\n    {\n        return Position(_x * d, _y * d);\n    }\n\n    const Position scale(const float & f) const\n    {\n        return Position((PositionType)(f * x()), (PositionType)(f * y()));\n    }\n\n    void scalePosition(const float & f)\n    {\n        _x = (PositionType)(f * _x);\n        _y = (PositionType)(f * _y);\n    }\n\n    void add(const Position & rhs)\n    {\n        _x += rhs.x();\n        _y += rhs.y();\n    }\n\n    void subtract(const Position & rhs)\n    {\n        _x -= rhs.x();\n        _y -= rhs.y();\n    }\n \n    void moveTo(const Position & pos)\n    {\n        _x = pos.x();\n        _y = pos.y();\n    }\n\n    void add(const PositionType & x, const PositionType & y)\n    {\n        _x += x;\n        _y += y;\n    }\n\n    void moveTo(const PositionType & x, const PositionType & y)\n    {\n        _x = x;\n        _y = y;\n    }\n\n    const PositionType x() const\n    {\n        return _x;\n    }\n\n    const PositionType y() const\n    {\n        return _y;\n    }\n\n    const Position flipX() const\n    {\n        return Position(-_x,_y);\n    }\n\n    const Position flipY() const\n    {\n        return Position(_y,_x);\n    }\n\n    const float Q_rsqrt( float number ) const\n    {\n        long i;\n        float x2, y;\n        const float threehalfs = 1.5F;\n \n        x2 = number * 0.5F;\n        y  = number;\n        i  = * ( long * ) &y;                       // evil floating point bit level hacking\n        i  = 0x5f3759df - ( i >> 1 );               \n        y  = * ( float * ) &i;\n        y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration\n//      y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed\n \n        return y;\n    }\n\n    const Position flip() const\n    {\n        return Position(-_x, -_y);\n    }\n\n    inline const PositionType getDistance(const Position & p) const \n    {\n        PositionType dX = x() - p.x();\n        PositionType dY = y() - p.y();\n\n        if (dX == 0)\n        {\n            return abs(dY);\n        }\n        else if (dY == 0)\n        {\n            return abs(dX);\n        }\n        else\n        {\n            return (PositionType)sqrt((float)(dX*dX - dY*dY));\n        }\n     }\n\n    inline const PositionType getDistanceSq(const Position & p) const \n    {\n        return (x()-p.x())*(x()-p.x()) + (y()-p.y())*(y()-p.y());\n    }\n\n    void print() const\n    {\n        printf(\"Position = (%d, %d)\\n\", _x, _y);\n    }\n\n    const std::string getString() const\n    {\n        std::stringstream ss;\n        ss << \"(\" << x() << \", \" << y() << \")\";\n        return ss.str();\n    }\n\n};\n}"
  },
  {
    "path": "BOSS/source/PrerequisiteSet.cpp",
    "content": "#include \"PrerequisiteSet.h\"\n\nusing namespace BOSS;\n\nActionCountPair::ActionCountPair()\n    : _count(0)\n{\n\n}\n\nActionCountPair::ActionCountPair(const ActionType & action, const UnitCountType count)\n    : _action(action)\n    , _count(count)\n{\n}\n\nconst ActionType & ActionCountPair::getAction() const\n{\n    return _action;\n}\n\nconst UnitCountType & ActionCountPair::getCount() const\n{\n    return _count;       \n}\n\nPrerequisiteSet::PrerequisiteSet()\n{\n\n}\n\nconst size_t PrerequisiteSet::size() const\n{\n    return _actionCounts.size();\n}\n\nconst bool PrerequisiteSet::isEmpty() const\n{\n    return size() == 0;\n}\n\nconst bool PrerequisiteSet::contains(const ActionType & action) const\n{\n    for (size_t i(0); i<_actionCounts.size(); ++i)\n    {\n        if (getActionType(i) == action)\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nconst ActionType & PrerequisiteSet::getActionType(const UnitCountType index) const\n{\n    return _actionCounts[index].getAction();\n}\n\nconst UnitCountType & PrerequisiteSet::getActionTypeCount(const UnitCountType index) const\n{\n    return _actionCounts[index].getCount();\n}\n    \nvoid PrerequisiteSet::add(const ActionType & action, const UnitCountType count)\n{\n    _actionCounts.push_back(ActionCountPair(action, count));\n}\n\nvoid PrerequisiteSet::addUnique(const ActionType & action, const UnitCountType count)\n{\n    if (!contains(action))\n    {\n        add(action, count);\n    }\n}\n\nvoid PrerequisiteSet::addUnique(const PrerequisiteSet & set)\n{\n    for (size_t i(0); i<set.size(); ++i)\n    {\n        addUnique(set.getActionType(i), set.getActionTypeCount(i));\n    }\n}\n\nvoid PrerequisiteSet::remove(const ActionType & action)\n{\n    for (size_t i(0); i<_actionCounts.size(); ++i)\n    {\n        if (_actionCounts[i].getAction() == action)\n        {\n            _actionCounts.remove(i);\n            return;\n        }\n    }\n}\n\nvoid PrerequisiteSet::remove(const PrerequisiteSet & set)\n{\n    if (isEmpty())\n    {\n        return;\n    }\n\n    for (size_t i(0); i < set.size(); ++i)\n    {\n        remove(set.getActionType(i));\n    }\n}\n\nconst std::string PrerequisiteSet::toString() const\n{\n    std::stringstream ss;\n    \n    for (size_t i(0); i<size(); ++i)\n    {\n        ss << \"    Prereq:   \" << (int)getActionTypeCount(i) << \" \" << getActionType(i).getName() << \"\\n\";\n    }\n\n    return ss.str();\n}"
  },
  {
    "path": "BOSS/source/PrerequisiteSet.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Constants.h\"\n#include \"Array.hpp\"\n#include \"ActionType.h\"\n\nnamespace BOSS\n{\n\nclass ActionCountPair\n{\n    ActionType      _action;\n    UnitCountType   _count;\n\npublic:\n\n    ActionCountPair();\n\n    ActionCountPair(const ActionType & action, const UnitCountType count);\n\n    const ActionType & getAction() const;\n\n    const UnitCountType & getCount() const;\n};\n\nclass PrerequisiteSet\n{\n\tVec<ActionCountPair, Constants::MAX_ACTION_TYPES> _actionCounts;\n\npublic:\n\n\tPrerequisiteSet();\n\n    const size_t size() const;\n    const bool isEmpty() const;\n    const bool contains(const ActionType & action) const;\n    const ActionType & getActionType(const UnitCountType index) const;\n    const UnitCountType & getActionTypeCount(const UnitCountType index) const;\n    \n    void add(const ActionType & action, const UnitCountType count = 1);\n    void addUnique(const ActionType & action, const UnitCountType count = 1);\n    void addUnique(const PrerequisiteSet & set);\n    void remove(const ActionType & action);\n    void remove(const PrerequisiteSet & set);\n\n    const std::string toString() const;\n};\n\n}"
  },
  {
    "path": "BOSS/source/StarCraftGUI.cpp",
    "content": "#include \"StarCraftGUI.h\"\n#include \"BWAPI.h\"\n#include <cassert>\n#include <iostream>\n\nusing namespace BOSS;\n\nconst size_t MaxStarCraftTextures                   = 512;\nconst int StarCraftGUI::TextureFont                 = 256;\n\nGLfloat ColorWhite[4] = {1.0f, 1.0f, 1.0f, 1.0f};\n\nStarCraftGUI::StarCraftGUI(int width, int height) \n    : _initialWidth(width)\n    , _initialHeight(height)\n    , _cameraX(0)\n    , _cameraY(0)\n    , _previousMouseX(0)\n    , _previousMouseY(0)\n    , _isStarted(false)\n    , _mousePressed(false)\n    , _shiftPressed(false)\n    , _currentFrame(0)\n{\n    if (SDL_Init(SDL_INIT_VIDEO) != 0)\n    {\n        std::cout << \"Could not initialize SDL\\n\";\n        exit(-1);\n    }\n\n    onStart();\n}\n\nStarCraftGUI::~StarCraftGUI()\n{\n    SDL_Quit();\n}\n\nbool StarCraftGUI::isStarted() const\n{\n    return _isStarted;\n}\n\n// This function must be called before OnFrame\nvoid StarCraftGUI::onStart()\n{\n    // if we've already called OnStart, don't re-initialize everything\n    if (_isStarted)\n    {\n        return;\n    }\n\n    // the top-left corner of the scene will be 0, 0\n    _cameraX = 0;\n    _cameraY = 0;\n\n    // double buffer and swap attributes, makes switching scenes fast\n    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);\n    SDL_GL_SetSwapInterval(1);\n\n    // set up the window that the OpenGL context will be bound to\n    _window = SDL_CreateWindow(\"StarCraft OpenGL Visualization\", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _initialWidth, _initialHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);\n\n    // set the glcontext to the window we just created\n    _glcontext = SDL_GL_CreateContext(_window);\n\n    // load all the Starcraft textures that we'll need\n    loadTextures();\n\n    // enable alpha blending for transparency\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glEnable(GL_BLEND);\n\n    // set up the viewport\n    glViewport(0, 0, width(), height());\n\n    _isStarted = true;\n}\n\n\nvoid StarCraftGUI::onFrame()\n{\n    BOSS_ASSERT(isStarted(), \"Must initialize GUI before calling OnFrame()\");\n\n    // Handle input events\n    handleEvents();\n\n    // Render the frame\n    glClear(GL_COLOR_BUFFER_BIT);\n    render();\n\n    SDL_GL_SwapWindow(_window);\n}\n\nvoid StarCraftGUI::handleEvents()\n{\n    // Handle SDL events\n    SDL_Event event;\n    while (SDL_PollEvent(&event))\n    {\n        const bool pressed(event.key.state == SDL_PRESSED);\n        switch (event.type)\n        {\n            case SDL_MOUSEMOTION:\n            {\n                if ((_previousMouseX != 0 || _previousMouseY != 0) && (event.motion.state & SDL_BUTTON_LEFT))\n                {\n                    _cameraX -= event.motion.xrel;\n                    _cameraY -= event.motion.yrel;\n                }\n\n                _previousMouseX = event.motion.x;\n                _previousMouseY = event.motion.y;\n                break;\n            }\n            case SDL_KEYDOWN:\n            {\n                switch (event.key.keysym.sym)\n                {\n                case SDLK_LSHIFT:\n                    _shiftPressed = pressed;\n                    break;\n                case SDLK_p:\n                {\n                    \n                }\n                }\n                break;\n            }\n            case SDL_KEYUP:\n            {\n                switch (event.key.keysym.sym)\n                {\n                case SDLK_LSHIFT:\n                    _shiftPressed = pressed;\n                    break;\n                }\n                break;\n            }\n            case SDL_MOUSEWHEEL:\n            {\n\n                break;\n            }\n            case SDL_MOUSEBUTTONDOWN:\n            {\n\n\t\t\t\n                break;\n            }\n            case SDL_MOUSEBUTTONUP:\n            {\n                if (event.button.button == SDL_BUTTON_LEFT)\n                {\n\n                }\n                break;\n            }\n            case SDL_WINDOWEVENT_RESIZED:\n            {\n            \n                break;\n            }\n            case SDL_QUIT:\n            {\n                std::cerr << \"SDL_QUIT caught\\n\\n\";\n                exit(0);\n            }\n        }\n    }\n}\n\nvoid StarCraftGUI::render()\n{\n    glViewport(0, 0, width(), height());\n\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    {\n        glOrtho(0, width(), height(), 0, -1, 1);\n\n        glMatrixMode(GL_MODELVIEW);\n        glPushMatrix();\n        {\n            glTranslatef(static_cast<float>(-_cameraX),static_cast<float>(-_cameraY),0);\n              \n            drawAllBWAPIUnits();\n            \n            //GUITools::DrawTexturedRect(Position(0,0), Position(200,200), TextureFont, ColorWhite);\n            //GUITools::DrawString(Position(300, 300), \"Test String\", ColorWhite);\n        }\n\n        glPopMatrix();\n    }\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n\n    _currentFrame++;\n}\n\nint StarCraftGUI::width()\n{\n    int x, y;\n    SDL_GetWindowSize(_window, &x, &y);\n\n    return x;\n}\n\nint StarCraftGUI::height()\n{\n    int x, y;\n    SDL_GetWindowSize(_window, &x, &y);\n\n    return y;\n}\n\nvoid StarCraftGUI::setCenter(int x, int y)\n{\n    _cameraX = -(width() - x) / 2;\n    _cameraY = -(height() - y) / 2;\n}\n\nvoid StarCraftGUI::drawAllBWAPIUnits()\n{\n    Position p(0, 0);\n    size_t maxHeight = 0;\n\n    std::vector<int> allIDs;\n\n    for (const auto & kv : _techTypeTextureID)\n    {\n        allIDs.push_back(kv.second);\n    }\n\n    for (const auto & kv : _upgradeTypeTextureID)\n    {\n        allIDs.push_back(kv.second);\n    }\n\n    for (const auto & kv : _unitTypeTextureID)\n    {\n        allIDs.push_back(kv.second);\n    }\n\n    for (const auto & id : allIDs)\n    {\n        if (p.x() + _textureSizes[id].x() > width())\n        {\n            p = Position(0, p.y() + maxHeight);\n            maxHeight = 0;\n        }\n\n        GUITools::DrawTexturedRect(p, p + _textureSizes[id], id, ColorWhite);\n            \n        maxHeight = std::max((size_t)_textureSizes[id].y(), maxHeight);\n            \n        p.add(Position(_textureSizes[id].x(), 0));\n    }\n}\n\nvoid StarCraftGUI::drawUnitType(const BWAPI::UnitType & type, Position & p)\n{\n    const int id = _unitTypeTextureID[type];\n    GUITools::DrawString(p, type.getName(), ColorWhite);\n    GUITools::DrawTexturedRect(p, p + _textureSizes[id], id, ColorWhite);\n}\n\nvoid StarCraftGUI::loadTextures()\n{\n    std::string imageDir = \"../asset/images/\";\n\n    // set up the vectors that will hold the textures\n    _textures = std::vector<GLuint>(MaxStarCraftTextures, 0);\n    _textureSizes = std::vector<Position>(MaxStarCraftTextures);\n    glGenTextures(MaxStarCraftTextures, &_textures[0]);\n\n    // load all the starcraft unit textures\n    size_t textureNumber = 1;\n    for (const BWAPI::UnitType & type : BWAPI::UnitTypes::allUnitTypes())\n    {\n        if (loadTexture(textureNumber, imageDir + GetTextureFileName(type)))\n        {\n            _unitTypeTextureID[type] = textureNumber;\n            textureNumber++;\n        }\n    }\n\n    for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes())\n    {\n        if (loadTexture(textureNumber, imageDir + GetTextureFileName(type)))\n        {\n            _techTypeTextureID[type] = textureNumber;\n            textureNumber++;\n        }\n    }\n\n    for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes())\n    {\n        if (loadTexture(textureNumber, imageDir + GetTextureFileName(type)))\n        {\n            _upgradeTypeTextureID[type] = textureNumber;\n            textureNumber++;\n        }\n    }\n    \n    loadTexture(TextureFont, imageDir + \"fonts/alpha_trans.png\");\n\n    std::cout << \"Successfully loaded \" << textureNumber << \" textures\" << std::endl;\n}\n\nbool StarCraftGUI::loadTexture(int textureNumber, const std::string & fileName)\n{\n    struct stat buf;\n    if (stat(fileName.c_str(), &buf) == -1)\n    {\n        //std::cout << \"Couldn't find texture: \" << fileName << std::endl;\n        return false;\n    }\n\n    SDL_Surface *surface2 = IMG_Load(fileName.c_str());\n    GLenum texture_format = GL_RGBA;\n    GLint nOfColors = 4;\n\n    if (surface2 != NULL)\n    {\n        glBindTexture( GL_TEXTURE_2D, textureNumber );\n\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n        glTexImage2D(GL_TEXTURE_2D, 0, texture_format, surface2->w, surface2->h, 0, texture_format, GL_UNSIGNED_BYTE, surface2->pixels);\n    } \n    else \n    {\n        printf(\"SDL could not load image: %s\\n\", SDL_GetError());\n    }    \n\n    if (surface2) \n    { \n        _textureSizes[textureNumber] = Position(surface2->w, surface2->h);\n        SDL_FreeSurface( surface2 );\n    }\n\n    std::cout << textureNumber << \"Loaded: \" << fileName << std::endl;\n\n    return true;\n}\n\nbool StarCraftGUI::saveScreenshotBMP(const std::string & filename) \n{\n    SDL_Surface * image = SDL_CreateRGBSurface(SDL_SWSURFACE, width(), height(), 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);\n\n    glReadBuffer(GL_FRONT);\n    glReadPixels(0, 0, width(), height(), GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);\n\n    SDL_SaveBMP(image, filename.c_str());\n    SDL_FreeSurface(image);\n\n    return true;\n}\n\nstd::string StarCraftGUI::GetTextureFileName(const BWAPI::TechType & type)\n{\n\tstd::string filename = \"command_icons/\" + type.getName() + \".png\";\n\n\tfor (size_t i(0); i < filename.size(); ++i)\n\t{\n\t\tif (filename[i] == ' ')\n\t\t{\n\t\t\tfilename[i] = '_';\n\t\t}\n\t}\n\n\treturn filename;\n}\n\nstd::string StarCraftGUI::GetTextureFileName(const BWAPI::UnitType & type)\n{\n\tstd::string filename = \"units/\" + type.getName() + \".png\";\n\n\tfor (size_t i(0); i < filename.size(); ++i)\n\t{\n\t\tif (filename[i] == ' ')\n\t\t{\n\t\t\tfilename[i] = '_';\n\t\t}\n\t}\n\n\treturn filename;\n}\n\nstd::string StarCraftGUI::GetTextureFileName(const BWAPI::UpgradeType & type)\n{\n\tstd::string filename = \"command_icons/\" + type.getName() + \".png\";\n\n\tfor (size_t i(0); i < filename.size(); ++i)\n\t{\n\t\tif (filename[i] == ' ')\n\t\t{\n\t\t\tfilename[i] = '_';\n\t\t}\n\t}\n\n\treturn filename;\n}"
  },
  {
    "path": "BOSS/source/StarCraftGUI.h",
    "content": "#pragma once\n\n#include \"BWAPI.h\"\n#include \"GUITools.h\"\n#include \"Timer.hpp\"\n#include \"Position.hpp\"\n#include <vector>\n\n#include <SDL.h>\n#undef main\n\n#include <SDL_opengl.h>\n#include <SDL_image.h>\n#include \"GUITools.h\"\n#include <sys/stat.h>\n\nusing BOSS::Position;\n\nstruct TextureInfo\n{\n    int _id;\n    Position _size;\n\n    TextureInfo(int i, Position & s) : _id(i), _size(s)\n    {\n        \n    }\n};\n\nclass StarCraftGUI\n{\n    int                 _initialWidth;\n    int                 _initialHeight;\n    int                 _windowSizeY;\n    int                 _cameraX;\n    int                 _cameraY;\n    bool                _isStarted;\n    int                 _previousMouseX;\n    int                 _previousMouseY;\n    bool                _mousePressed;\n    bool                _shiftPressed;\n\n    size_t              _currentFrame;\n\n    SDL_Window *        _window;\n    SDL_Surface *       _surface;\n    SDL_GLContext       _glcontext;\n\n    std::vector<GLuint>     _textures;\n    std::vector<Position>   _textureSizes;\n\n    std::map<std::string, TextureInfo> _textureInfo;\n\n    std::map<BWAPI::UnitType, int> _unitTypeTextureID;\n    std::map<BWAPI::TechType, int> _techTypeTextureID;\n    std::map<BWAPI::UpgradeType, int> _upgradeTypeTextureID;\n    \n    void handleEvents();\n    void render();\n    void renderTextGlut(int x, int y, std::string & s);\n    void loadTextures();\n    bool loadTexture(int textureNumber, const std::string & fileName);\n    void onResize(SDL_Event & event);\n    void drawAllBWAPIUnits();\n    void onStart();\n    void testRender();\n    void drawUnitType(const BWAPI::UnitType & type, Position & p);\n    bool isStarted() const;\n\n    static std::string GetTextureFileName(const BWAPI::UnitType & type);\n    static std::string GetTextureFileName(const BWAPI::UpgradeType & type);\n    static std::string GetTextureFileName(const BWAPI::TechType & type);\n\npublic:\n    \n    static const int TextureASCIIOffset;\n    static const int TextureFont;\n    \n    StarCraftGUI(int width, int height);\n    ~StarCraftGUI();\n\n    int width();\n    int height();\n\n    void onFrame();\n    void setCenter(int x, int y);\n\n    bool saveScreenshotBMP(const std::string & filename);\n};\n\n"
  },
  {
    "path": "BOSS/source/Timer.hpp",
    "content": "//////////////////////////////////////////////////////////////////////////////\n// Timer.hpp\n// =======\n// High Resolution Timer.\n// This timer is able to measure the elapsed time with 1 micro-second accuracy\n// in both Windows, Linux and Unix system \n//\n//  AUTHOR: Song Ho Ahn (song.ahn@gmail.com)\n// CREATED: 2003-01-13\n// UPDATED: 2006-01-13\n//\n// Copyright (c) 2003 Song Ho Ahn\n//////////////////////////////////////////////////////////////////////////////\n\n#ifndef TIMER_H_DEF\n#define TIMER_H_DEF\n\n#ifdef WIN32   // Windows system specific\n\t#include <windows.h>\n#else          // Unix based system specific\n\t#include <sys/time.h>\n#endif\n\nnamespace BOSS\n{\nclass Timer\n{\n \tdouble startTimeInMicroSec;                 // starting time in micro-second\n    double endTimeInMicroSec;                   // ending time in micro-second\n    int    stopped;                             // stop flag \n\t#ifdef WIN32\n\t\tLARGE_INTEGER frequency;                    // ticks per second\n\t\tLARGE_INTEGER startCount;                   //\n\t\tLARGE_INTEGER endCount;                     //\n\t#else\n\t\ttimeval startCount;                         //\n\t\ttimeval endCount;                           //\n\t#endif\n\npublic:\n\n\tTimer()\n\t{\n\t\t#ifdef WIN32\n\t\t\tQueryPerformanceFrequency(&frequency);\n\t\t\tstartCount.QuadPart = 0;\n\t\t\tendCount.QuadPart = 0;\n\t\t#else\n\t\t\tstartCount.tv_sec = startCount.tv_usec = 0;\n\t\t\tendCount.tv_sec = endCount.tv_usec = 0;\n\t\t#endif\n\n\t\tstopped = 0;\n\t\tstartTimeInMicroSec = 0;\n\t\tendTimeInMicroSec = 0;\n\t\t\n\t\tstart();\n\t}\n\t\n    ~Timer() {}                                 // default destructor\n\n    void start()\n\t{\n\t\tstopped = 0; // reset stop flag\n\t\t\n\t\t#ifdef WIN32\n\t\t\tQueryPerformanceCounter(&startCount);\n\t\t#else\n\t\t\tgettimeofday(&startCount, NULL);\n\t\t#endif\n\t}\n\t\n    void stop()\n\t{\n\t\tstopped = 1; // set timer stopped flag\n\n\t\t#ifdef WIN32\n\t\t\tQueryPerformanceCounter(&endCount);\n\t\t#else\n\t\t\tgettimeofday(&endCount, NULL);\n\t\t#endif\n\t}\n\t\n    double getElapsedTimeInMicroSec()\n\t{\n\t\t#ifdef WIN32\n\t\t\tif(!stopped)\n\t\t\t\tQueryPerformanceCounter(&endCount);\n\n\t\t\tstartTimeInMicroSec = startCount.QuadPart * (1000000.0 / frequency.QuadPart);\n\t\t\tendTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart);\n\t\t#else\n\t\t\tif(!stopped)\n\t\t\t\tgettimeofday(&endCount, NULL);\n\n\t\t\tstartTimeInMicroSec = (startCount.tv_sec * 1000000.0) + startCount.tv_usec;\n\t\t\tendTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec;\n\t\t#endif\n\n\t\treturn endTimeInMicroSec - startTimeInMicroSec;\n\t}\n\t \n\tdouble getElapsedTimeInMilliSec()\n\t{\n\t\treturn this->getElapsedTimeInMicroSec() * 0.001;\n\t}\n\n\n\tdouble getElapsedTimeInSec()\n\t{\n\t\treturn this->getElapsedTimeInMicroSec() * 0.000001;\n\t}\n\n\n\n\tdouble getElapsedTime()\n\t{\n\t\treturn this->getElapsedTimeInSec();\n\t}\n};\n}\n\n#endif // TIMER_H_DEF\n"
  },
  {
    "path": "BOSS/source/Tools.cpp",
    "content": "#include \"Tools.h\"\n#include \"BuildOrderSearchGoal.h\"\n#include \"NaiveBuildOrderSearch.h\"\n\nusing namespace BOSS;\n\n#include \"JSONTools.h\"\n\nBuildOrder Tools::GetOptimizedNaiveBuildOrderOld(const GameState & state, const BuildOrderSearchGoal & goal)\n{\n    BuildOrder bestBuildOrder = GetNaiveBuildOrderAddWorkersOld(state, goal, 4);\n    FrameCountType minCompletionTime = bestBuildOrder.getCompletionTime(state);\n    UnitCountType bestNumWorkers = bestBuildOrder.getTypeCount(ActionTypes::GetWorker(state.getRace()));\n\n    for (UnitCountType numWorkers(8); numWorkers < 27; ++numWorkers)\n    {\n        BuildOrder buildOrder = Tools::GetNaiveBuildOrderAddWorkersOld(state, goal, numWorkers);\n        FrameCountType completionTime = buildOrder.getCompletionTime(state);\n        UnitCountType workers = buildOrder.getTypeCount(ActionTypes::GetWorker(state.getRace()));\n        \n        if (completionTime <= minCompletionTime + ((workers-bestNumWorkers)*24))\n        {\n            minCompletionTime = completionTime;\n            bestBuildOrder = buildOrder;\n        }\n    }\n\n    \n    FrameCountType bestCompletionTime = bestBuildOrder.getCompletionTime(state);\n    BuildOrder testBuildOrder;\n\n    //std::cout << \"Found a better build order that takes \" << bestCompletionTime << \" frames\\n\";\n    while (true)\n    {\n        const static ActionType gateway = ActionTypes::GetActionType(\"Protoss_Gateway\");\n        InsertActionIntoBuildOrder(testBuildOrder, bestBuildOrder, state, gateway);\n\n        FrameCountType completionTime = testBuildOrder.getCompletionTime(state);\n\n        if (completionTime < bestCompletionTime)\n        {\n            //std::cout << \"Found a better build order that takes \" << completionTime << \" frames\\n\";\n            bestCompletionTime = completionTime;\n            bestBuildOrder = testBuildOrder;\n        }\n        else\n        {\n            break;\n        }\n    }\n\n\n    return bestBuildOrder;\n}\n\nBuildOrder Tools::GetNaiveBuildOrderAddWorkersOld(const GameState & state, const BuildOrderSearchGoal & goal, UnitCountType maxWorkers)\n{\n    PrerequisiteSet wanted;\n    int minWorkers = 8;\n\n    const ActionType & worker = ActionTypes::GetWorker(state.getRace());\n    std::vector<size_t> buildOrderActionTypeCount(ActionTypes::GetAllActionTypes(state.getRace()).size(), 0);\n\n    // add everything from the goal to the needed set\n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(state.getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(state.getRace(), a);\n        UnitCountType numCompleted = state.getUnitData().getNumTotal(actionType);\n            \n        if (goal.getGoal(actionType) > numCompleted)\n        {\n            wanted.addUnique(actionType);\n        }\n    }\n\n    if (wanted.size() == 0)\n    {\n        return BuildOrder();\n    }\n\n    // Calculate which prerequisite units we need to build to achieve the units we want from the goal\n    PrerequisiteSet requiredToBuild;\n    CalculatePrerequisitesRequiredToBuild(state, wanted, requiredToBuild);\n\n    // Add the required units to a preliminary build order\n    BuildOrder buildOrder;\n    for (size_t a(0); a < requiredToBuild.size(); ++a)\n    {\n        const ActionType & type = requiredToBuild.getActionType(a);\n        buildOrder.add(type);\n        buildOrderActionTypeCount[type.ID()]++;\n    }\n\n    // Add some workers to the build order if we don't have many, this usually gives a lower upper bound\n    int requiredWorkers = minWorkers - state.getUnitData().getNumCompleted(ActionTypes::GetWorker(state.getRace()));\n    while (requiredWorkers-- > 0)\n    {\n        buildOrder.add(worker);\n        buildOrderActionTypeCount[worker.ID()]++;\n    }\n\n    // Add the goal units to the end of the build order \n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(state.getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(state.getRace(), a);\n        int need = (int)goal.getGoal(actionType);\n        int have = (int)state.getUnitData().getNumTotal(actionType);\n        int numNeeded = need - have - buildOrderActionTypeCount[actionType.ID()]; \n            \n        for (int i(0); i < numNeeded; ++i)\n        {\n            buildOrder.add(actionType);\n        }\n    }\n\n    \n    static const ActionType commandCenter = ActionTypes::GetActionType(\"Terran_Command_Center\");\n    static const ActionType factory = ActionTypes::GetActionType(\"Terran_Factory\");\n    static const ActionType starport = ActionTypes::GetActionType(\"Terran_Starport\");\n    static const ActionType scienceFacility = ActionTypes::GetActionType(\"Terran_Science_Facility\");\n\n\n    // Check to see if we have enough buildings for the required addons\n    if (state.getRace() == Races::Terran)\n    {\n        int commandCenterAddons = 0;\n        int factoryAddons = 0;\n        int starportAddons = 0;\n        int sciAddons = 0;\n\n        int numCommandCenters = state.getUnitData().getNumTotal(commandCenter);\n        int numFactories = state.getUnitData().getNumTotal(factory);\n        int numStarports = state.getUnitData().getNumTotal(starport);\n        int numSci = state.getUnitData().getNumTotal(scienceFacility);\n        \n        for (size_t a(0); a < buildOrder.size(); ++a)\n        {\n            const ActionType & actionType = buildOrder[a];\n\n            if (actionType.isAddon())\n            {\n                if (actionType.whatBuildsActionType() == commandCenter)\n                {\n                    ++commandCenterAddons;\n                }\n                else if (actionType.whatBuildsActionType() == factory)\n                {\n                    ++factoryAddons;\n                }\n                else if (actionType.whatBuildsActionType() == starport)\n                {\n                    ++starportAddons;\n                }\n                else if (actionType.whatBuildsActionType() == scienceFacility)\n                {\n                    ++sciAddons;\n                }\n                else\n                {\n                    BOSS_ASSERT(false, \"Addon has no builder: %s %s\", actionType.getName().c_str(), actionType.whatBuildsActionType().getName().c_str());\n                }\n            }\n\n            if (actionType == commandCenter)\n            {\n                ++numCommandCenters;\n            }\n            else if (actionType == factory)\n            {\n                ++numFactories;\n            }\n            else if (actionType == starport)\n            {\n                ++numStarports;\n            }\n            else if (actionType == scienceFacility)\n            {\n                ++numSci;\n            }\n        }\n\n        // add the necessary buildings to make the addons\n        for (int n(0); n < commandCenterAddons - numCommandCenters; ++n)\n        {\n            buildOrder.add(commandCenter);\n        }\n\n        for (int n(0); n < factoryAddons - numFactories; ++n)\n        {\n            buildOrder.add(factory);\n        }\n\n        for (int n(0); n < starportAddons - numStarports; ++n)\n        {\n            buildOrder.add(starport);\n        }\n        for (int n(0); n < sciAddons - numSci; ++n)\n        {\n            buildOrder.add(scienceFacility);\n        }\n\n    }\n\n    // Bubble sort the build order so that prerequites always come before what requires them\n    for (size_t i(0); i < buildOrder.size()-1; ++i)\n    {\n        for (size_t j(i+1); j < buildOrder.size(); ++j)\n        {\n            const PrerequisiteSet & recursivePre = buildOrder[i].getRecursivePrerequisites();\n\n            if (recursivePre.contains(buildOrder[j]))\n            {\n                std::swap(buildOrder[i], buildOrder[j]);\n            }\n        }\n    }\n\n    // finish the build order with workers and supply\n    BuildOrder finalBuildOrder;\n    GameState currentState(state);\n    size_t i = 0;\n    while (i < buildOrder.size())\n    {\n        const ActionType & worker           = ActionTypes::GetWorker(currentState.getRace());\n        const ActionType & supplyProvider   = ActionTypes::GetSupplyProvider(currentState.getRace());\n        const ActionType & nextAction       = buildOrder[i];\n        UnitCountType maxSupply             = currentState.getUnitData().getMaxSupply() + currentState.getUnitData().getSupplyInProgress();\n        UnitCountType numWorkers            = currentState.getUnitData().getNumTotal(worker);\n        UnitCountType currentSupply         = currentState.getUnitData().getCurrentSupply();\n\n        if (numWorkers < 8)\n        {\n            finalBuildOrder.add(worker);\n            currentState.doAction(worker);\n            continue;\n        }\n\n        // insert a supply provider if we are behind\n        int surplusSupply = maxSupply - currentSupply;\n\t\tif (surplusSupply < nextAction.supplyRequired() + 2)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tBOSS_ASSERT(currentState.isLegal(supplyProvider), \"supplyProvider should be legal\");\n\t\t\t\tfinalBuildOrder.add(supplyProvider);\n\t\t\t\tcurrentState.doAction(supplyProvider);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcatch (BOSSException e)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t}\n\n       \n        FrameCountType whenWorkerReady      = currentState.whenCanPerform(worker);\n        FrameCountType whennextActionReady  = currentState.whenCanPerform(nextAction);\n\n        if ((numWorkers < maxWorkers) && (whenWorkerReady < whennextActionReady))\n        {\n\t\t\t// check to see if we should insert a worker\n\t\t\ttry\n\t\t\t{\n\t\t\t\tBOSS_ASSERT(currentState.isLegal(worker), \"Worker should be legal\");\n\t\t\t\tfinalBuildOrder.add(worker);\n\t\t\t\tcurrentState.doAction(worker);\n\t\t\t}\n\t\t\tcatch (BOSSException)\n\t\t\t{\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tActionType testNextAction = buildOrder[i];\n\t\t\tBOSS_ASSERT(currentState.isLegal(nextAction), \"nextAction should be legal\");\n\t\t\tfinalBuildOrder.add(nextAction);\n\t\t\tcurrentState.doAction(nextAction);\n\t\t\t++i;\n\t\t}\n    }\n\n    return finalBuildOrder;\n}\n\nvoid Tools::InsertActionIntoBuildOrder(BuildOrder & result, const BuildOrder & buildOrder, const GameState & initialState, const ActionType & action)\n{\n    int bestInsertIndex = -1;\n    BuildOrder runningBuildOrder;\n    GameState runningState(initialState);\n    FrameCountType minCompletionTime = buildOrder.getCompletionTime(initialState);\n\n    BuildOrder testBuildOrder = buildOrder;\n\n    for (size_t insertIndex(0); insertIndex < buildOrder.size(); ++insertIndex)\n    {\n        // if we can test the action here, do it\n        if (runningState.isLegal(action))\n        {\n            // figure out the build time of build order with action inserted here\n            GameState tempState(runningState);\n            tempState.doAction(action);\n            for (size_t a(insertIndex); a < buildOrder.size(); ++a)\n            {\n                tempState.doAction(buildOrder[a]);\n            }\n\n            FrameCountType completionTime = tempState.getLastActionFinishTime();\n\n            if (completionTime < minCompletionTime)\n            {\n                minCompletionTime = completionTime;\n                bestInsertIndex = insertIndex;\n            }\n        }\n\n        BOSS_ASSERT(runningState.isLegal(buildOrder[insertIndex]), \"We have made the next action illegal somehow\");\n        runningBuildOrder.add(buildOrder[insertIndex]);\n        runningState.doAction(buildOrder[insertIndex]);\n    }\n\n    result.clear();\n    for (size_t a(0); a<buildOrder.size(); ++a)\n    {\n        if (bestInsertIndex == a)\n        {\n            result.add(action);\n        }\n\n        result.add(buildOrder[a]);\n    }\n}\n\nFrameCountType Tools::GetUpperBound(const GameState & state, const BuildOrderSearchGoal & goal)\n{\n    NaiveBuildOrderSearch naiveSearch(state, goal);\n    const BuildOrder & naiveBuildOrder = naiveSearch.solve();\n    FrameCountType upperBound = naiveBuildOrder.getCompletionTime(state);\n\n    return upperBound;\n}\n\nFrameCountType Tools::GetLowerBound(const GameState & state, const BuildOrderSearchGoal & goal)\n{\n    PrerequisiteSet wanted;\n\n    // add everything from the goal to the needed set\n    for (size_t a(0); a < ActionTypes::GetAllActionTypes(state.getRace()).size(); ++a)\n    {\n        const ActionType & actionType = ActionTypes::GetActionType(state.getRace(), a);\n        UnitCountType numCompleted = state.getUnitData().getNumTotal(actionType);\n            \n        if (goal.getGoal(actionType) > numCompleted)\n        {\n            wanted.addUnique(actionType);\n        }\n    }\n\n    FrameCountType lowerBound = Tools::CalculatePrerequisitesLowerBound(state, wanted, 0);\n\n    return lowerBound;\n}\n\nvoid Tools::CalculatePrerequisitesRequiredToBuild(const GameState & state, const PrerequisiteSet & needed, PrerequisiteSet & added)\n{\n    // if anything needed gas and we don't have a refinery, we need to add one\n    PrerequisiteSet allNeeded(needed);\n    const ActionType & refinery = ActionTypes::GetRefinery(state.getRace());\n    if (!needed.contains(refinery) && (state.getUnitData().getNumCompleted(refinery) == 0) && !added.contains(refinery))\n    {\n        for (size_t n(0); n<needed.size(); ++n)\n        {\n            if (needed.getActionType(n).gasPrice() > 0)\n            {\n                allNeeded.add(refinery);\n                break;\n            }\n        }\n    }\n\n    for (size_t n(0); n<allNeeded.size(); ++n)\n    {\n        const ActionType & neededType = allNeeded.getActionType(n);\n\n        // if we already have the needed type completed we can skip it\n        if (added.contains(neededType) || state.getUnitData().getNumCompleted(neededType) > 0)\n        {\n            \n        }\n        // if we have the needed type in progress we can add that time\n        else if (state.getUnitData().getNumInProgress(neededType) > 0)\n        {\n            //added.add(neededType);\n        }\n        // otherwise we need to recurse on the needed type to build its prerequisites\n        else\n        {\n            added.add(neededType);\n            CalculatePrerequisitesRequiredToBuild(state, neededType.getPrerequisites(), added);\n        }\n    }\n}\n\n// returns the amount of time necessary to complete the longest chain of sequential prerequisites\nFrameCountType Tools::CalculatePrerequisitesLowerBound(const GameState & state, const PrerequisiteSet & needed, FrameCountType timeSoFar, int depth)\n{\n    FrameCountType max = 0;\n    for (size_t n(0); n<needed.size(); ++n)\n    {\n        const ActionType & neededType = needed.getActionType(n);\n        FrameCountType thisActionTime = 0;\n\n        // if we already have the needed type completed we can skip it\n        if (state.getUnitData().getNumCompleted(neededType) > 0)\n        {\n            thisActionTime = timeSoFar;\n        }\n        // if we have the needed type in progress we can add that time\n        else if (state.getUnitData().getNumInProgress(neededType) > 0)\n        {\n            thisActionTime = timeSoFar + state.getUnitData().getFinishTime(neededType) - state.getCurrentFrame();\n        }\n        // otherwise we need to recurse on the needed type to build its prerequisites\n        else\n        {\n            /*for (int i=0; i<depth; ++i)\n            {\n                std::cout << \"    \";\n            }\n            std::cout << neededType.getName() << \" \" << neededType.buildTime() << \" \" << timeSoFar << std::endl;*/\n            thisActionTime = CalculatePrerequisitesLowerBound(state, neededType.getPrerequisites(), timeSoFar + neededType.buildTime(), depth + 1);\n        }\n\n        if (thisActionTime > max)\n        {\n            max = thisActionTime;\n        }\n    }\n\n    return max;\n}\n\n"
  },
  {
    "path": "BOSS/source/Tools.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"BuildOrderSearchGoal.h\"\n#include \"BuildOrder.h\"\n\nnamespace BOSS\n{\nnamespace Tools\n{\n    FrameCountType              GetUpperBound(const GameState & state, const BuildOrderSearchGoal & goal);\n    FrameCountType              GetLowerBound(const GameState & state, const BuildOrderSearchGoal & goal);\n    FrameCountType              CalculatePrerequisitesLowerBound(const GameState & state, const PrerequisiteSet & needed, FrameCountType timeSoFar, int depth = 0);\n    void                        InsertActionIntoBuildOrder(BuildOrder & result, const BuildOrder & buildOrder, const GameState & initialState, const ActionType & action);\n    void                        CalculatePrerequisitesRequiredToBuild(const GameState & state, const PrerequisiteSet & wanted, PrerequisiteSet & requiredToBuild);\n    BuildOrder                  GetOptimizedNaiveBuildOrderOld(const GameState & state, const BuildOrderSearchGoal & goal);\n    BuildOrder                  GetNaiveBuildOrderAddWorkersOld(const GameState & state, const BuildOrderSearchGoal & goal, UnitCountType maxWorkers);\n}\n}\n"
  },
  {
    "path": "BOSS/source/UnitData.cpp",
    "content": "#include \"UnitData.h\"\n\nusing namespace BOSS;\n\nUnitData::UnitData(const RaceID race)\n    : _race(race)\n    , _numUnits(Constants::MAX_ACTIONS, 0)\n    , _currentSupply(0)\n    , _maxSupply(0)\n    , _mineralWorkers(0)\n    , _gasWorkers(0)\n    , _buildingWorkers(0)\n{\n\n}\n\nconst RaceID UnitData::getRace() const\n{\n    return _race;\n}\n\nconst UnitCountType UnitData::getNumCompleted(const ActionType & action) const\n{\n    return _numUnits[action.ID()];\n}\n\nvoid UnitData::setCurrentSupply(const UnitCountType & supply)\n{\n    _currentSupply = supply;\n}\n\nconst FrameCountType UnitData::getWhenBuildingCanBuild(const ActionType & action) const\n{\n    return _buildings.getTimeUntilCanBuild(action);\n}\n\n// only used for adding existing buildings from a BWAPI Game * object\nvoid UnitData::addCompletedBuilding(const ActionType & action, const FrameCountType timeUntilFree, const ActionType & constructing, const ActionType & addon, int numLarva)\n{\n    _numUnits[action.ID()] += action.numProduced();\n\n    _maxSupply += action.supplyProvided();\n\n    // if it's an extractor\n\tif (action.isRefinery()) \n\t{\n\t\t// take those workers from minerals and put them into it\n\t\t_mineralWorkers -= 3; _gasWorkers += 3;\n\t}\t\n\n    // if it's a building that can produce units, add it to the building data\n\tif (action.isBuilding() && !action.isSupplyProvider())\n\t{\n\t\t_buildings.addBuilding(action, timeUntilFree, constructing, addon);\n\t}\n\n    // special case for hatcheries\n    if (action.getRace() == Races::Zerg && action.isResourceDepot())\n    {\n        _hatcheryData.addHatchery(numLarva);\n    }\n}\n\nvoid UnitData::addCompletedAction(const ActionType & action, bool wasBuilt)\n{\n    const static ActionType Lair = ActionTypes::GetActionType(\"Zerg_Lair\");\n    const static ActionType Hive = ActionTypes::GetActionType(\"Zerg_Hive\");\n\n    _numUnits[action.ID()] += wasBuilt ? action.numProduced() : 1;\n\n    if (wasBuilt)\n    {\n        // a lair or hive from a hatchery don't produce additional supply\n        if (action != Lair && action != Hive)\n        {\n            _maxSupply += action.supplyProvided();\n        }\n    }\n    else\n    {\n        _maxSupply += action.supplyProvided();\n    }\n    \n    if (action.isWorker()) \n\t{ \n\t\t_mineralWorkers++;\n\t}\n\n    // if it's an extractor\n\tif (action.isRefinery()) \n\t{\n\t\t// take those workers from minerals and put them into it\n\t\t_mineralWorkers -= 3; _gasWorkers += 3;\n\t}\t\n\n    // if it's a building that can produce units, add it to the building data\n\tif (action.isBuilding() && !action.isSupplyProvider())\n\t{\n        if (!action.isMorphed())\n        {\n            _buildings.addBuilding(action, ActionTypes::None);\n        }\n\t}\n\n    // special case for hatcheries\n    if (action.isBuilding() && (action.getUnitType() == BWAPI::UnitTypes::Zerg_Hatchery))\n    {\n        _hatcheryData.addHatchery(wasBuilt ? 1 : 3);\n    }\n}\n\nvoid UnitData::removeCompletedAction(const ActionType & action)\n{\n\t//Logger::LogAppendToFile(BOSS_LOGFILE, \"Unit removed \" + action.getName());\n\tconst static ActionType Lair = ActionTypes::GetActionType(\"Zerg_Lair\");\n\tconst static ActionType Hive = ActionTypes::GetActionType(\"Zerg_Hive\");\n\n\t_numUnits[action.ID()] -= action.numProduced();\n\n\n\t\t// a lair or hive from a hatchery don't produce additional supply\n\tif (action != Lair && action != Hive)\n\t{\n\t\t_maxSupply -= action.supplyProvided();\n\t}\n\n\n\tif (action.isWorker())\n\t{\n\t\tif (_mineralWorkers > 0)\n\t\t{\n\t\t\t_mineralWorkers--;\n\t\t}\n\t\telse if (_gasWorkers > 0)\n\t\t{\n\t\t\t_gasWorkers--;\n\t\t}\n\t}\n\n\t// if it's an extractor\n\tif (action.isRefinery())\n\t{\n\t\t// take those workers from minerals and put them into it\n\t\t_mineralWorkers += 3; _gasWorkers -= 3;\n\t}\n\tBOSS_ASSERT(_mineralWorkers >= 0, \"Can't have negative mineral workers\");\n\tBOSS_ASSERT(_gasWorkers >= 0, \"Can't have negative gas workers\");\n\t// if it's a building that can produce units, add it to the building data\n\tif (action.isBuilding() && !action.isSupplyProvider())\n\t{\n\t\tif (!action.isMorphed())\n\t\t{\n\t\t\t_buildings.removeBuilding(action, ActionTypes::None);\n\t\t}\n\t}\n\n\t// special case for hatcheries\n\tif (action.isBuilding() && (action.getUnitType() == BWAPI::UnitTypes::Zerg_Hatchery))\n\t{\n\t\t_hatcheryData.removeHatchery();\n\t}\n}\n\nvoid UnitData::addActionInProgress(const ActionType & action, const FrameCountType & completionFrame, bool queueAction)\n{\n    FrameCountType finishTime = (action.isBuilding() && !action.isMorphed()) ? completionFrame + Constants::BUILDING_PLACEMENT : completionFrame;\n\n\t// add it to the actions in progress\n\t_progress.addAction(action, finishTime);\n    \n    if (!action.isMorphed())\n    {\n        _currentSupply += action.supplyRequired() * action.numProduced();\n    }\n\n    if (queueAction && action.whatBuildsIsBuilding())\n\t{\n\t\t// add it to a free building, which MUST be free since it's called from doAction\n\t\t// which must be already fastForwarded to the correct time\n\t\t_buildings.queueAction(action);\n\t}\n}\n\nconst bool UnitData::hasActionsInProgress() const\n{\n    return _progress.isEmpty();\n}\n\nconst SupplyCountType UnitData::getCurrentSupply() const\n{\n    return _currentSupply;\n}\n\nconst SupplyCountType UnitData::getMaxSupply() const\n{\n    return _maxSupply;\n}\n\nvoid UnitData::setBuildingWorker()\n{\n    BOSS_ASSERT(_mineralWorkers > 0, \"Tried to build without a worker\");\n\n    _mineralWorkers--;\n    _buildingWorkers++;\n}\n\nconst bool UnitData::hasGasIncome() const\n{\n    return _gasWorkers > 0 || getNumTotal(ActionTypes::GetRefinery(getRace())) > 0;\n}\n\nconst bool UnitData::hasMineralIncome() const\n{\n    return getNumMineralWorkers() > 0 || getNumBuildingWorkers() > 0 || getNumInProgress(ActionTypes::GetWorker(getRace())) > 0;\n}\n\nvoid UnitData::releaseBuildingWorker()\n{\n    _mineralWorkers++;\n    _buildingWorkers--;\n}\n\nvoid UnitData::setMineralWorkers(const UnitCountType & mineralWorkers)\n{\n    _mineralWorkers = mineralWorkers;\n}\n\nvoid UnitData::setGasWorkers(const UnitCountType & gasWorkers)\n{\n    _gasWorkers = gasWorkers;\n}\n\nvoid UnitData::setBuildingWorkers(const UnitCountType & buildingWorkers)\n{\n    _buildingWorkers = buildingWorkers;\n}\n\nvoid UnitData::morphUnit(const ActionType & from, const ActionType & to, const FrameCountType & completionFrame)\n{\n    BOSS_ASSERT(getNumCompleted(from) > 0, \"Must have the unit type to morph it\");\n    _numUnits[from.ID()]--;\n    _currentSupply -= from.supplyRequired();\n\n    if (from.isWorker())\n    {\n        BOSS_ASSERT(_mineralWorkers > 0, \"Need mineral worker\");\n        _mineralWorkers--;\n    }\n\n    addActionInProgress(to, completionFrame);\n}\n\nconst UnitCountType UnitData::getNumMineralWorkers() const\n{\n    return _mineralWorkers;\n}\n\nconst UnitCountType UnitData::getNumGasWorkers() const\n{\n    return _gasWorkers;\n}\n\nconst UnitCountType UnitData::getNumBuildingWorkers() const\n{\n    return _buildingWorkers;\n}\n\nActionType UnitData::finishNextActionInProgress() \n{\t\n\t// get the actionUnit from the progress data\n\tActionType action = _progress.nextAction();\n\n\t// add the unit to the unit counter\n\taddCompletedAction(action);\n\t\t\t\n\t// pop it from the progress vector\n\t_progress.popNextAction();\n\t\t\t\n\tif (getRace() == Races::Terran)\n\t{\n\t\t// if it's a building, release the worker back\n\t\tif (action.isBuilding() && !action.isAddon())\n\t\t{\n\t\t\treleaseBuildingWorker();\n\t\t}\n\t}\n\telse if (getRace() == Races::Zerg)\n\t{\n        const static ActionType hatchery = ActionTypes::GetActionType(\"Zerg_Hatchery\");\n\n\t}\n\n\treturn action;\n}\n\nconst FrameCountType UnitData::getNextActionFinishTime() const\n{\n    return _progress.nextActionFinishTime();\n}\n\nconst FrameCountType UnitData::getNextBuildingFinishTime() const\n{\n    return _progress.nextBuildingFinishTime();\n}\n\nvoid UnitData::setBuildingFrame(const FrameCountType & frame)\n{\n    _buildings.fastForwardBuildings(frame);\n}\n\nconst UnitCountType UnitData::getNumTotal(const ActionType & action) const\n{\n    return _numUnits[action.ID()] + (_progress.numInProgress(action) * action.numProduced());\n}\n\nconst bool UnitData::hasPrerequisites(const PrerequisiteSet & required) const\n{\n    static const ActionType & Hatchery      = ActionTypes::GetActionType(\"Zerg_Hatchery\");\n    static const ActionType & Lair          = ActionTypes::GetActionType(\"Zerg_Lair\");\n    static const ActionType & Hive          = ActionTypes::GetActionType(\"Zerg_Hive\");\n    static const ActionType & Spire         = ActionTypes::GetActionType(\"Zerg_Spire\");\n    static const ActionType & GreaterSpire  = ActionTypes::GetActionType(\"Zerg_Greater_Spire\");\n\n    for (size_t a(0); a<required.size(); ++a)\n    {\n        const ActionType & type = required.getActionType(a);\n        const size_t & req = required.getActionTypeCount(a);\n        size_t have = getNumTotal(type);\n\n        // special check for zerg moprhed buildings\n        if (_race == Races::Zerg)\n        {\n            if (type == Hatchery)\n            {\n                have += getNumTotal(Lair);\n                have += getNumTotal(Hive);\n            }\n            else if (type == Lair)\n            {\n                have += getNumTotal(Hive);\n            }\n            else if (type == Spire)\n            {\n                have += getNumTotal(GreaterSpire);\n            }\n        }\n\n        if (have < req)\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nconst UnitCountType UnitData::getSupplyInProgress() const\n{\n    const ActionType & provider(ActionTypes::GetSupplyProvider(getRace()));\n    const ActionType & depot(ActionTypes::GetResourceDepot(getRace()));\n    \n    return _progress.numInProgress(provider) * provider.supplyProvided() + _progress.numInProgress(depot) * depot.supplyProvided();\n}\n\nconst UnitCountType UnitData::getNumActionsInProgress() const\n{\n    return _progress.size();\n}\n\nconst UnitCountType UnitData::getNumInProgress(const ActionType & action) const\n{\n    return _progress.numInProgress(action);\n}\n\nconst ActionType & UnitData::getActionInProgressByIndex(const UnitCountType & index) const\n{\n    return _progress.getAction(index);\n}\n\nconst FrameCountType UnitData::getActionInProgressFinishTimeByIndex(const UnitCountType & index) const\n{\n    return _progress.getTime(index);\n}\n\nconst FrameCountType UnitData::getLastActionFinishTime() const\n{\n    return _progress.getLastFinishTime();\n}\n\nconst FrameCountType UnitData::getFinishTimeByIndex(const UnitCountType & index) const\n{\n    return _progress.getTime(index);\n}\n\nconst FrameCountType UnitData::getFinishTime(const PrerequisiteSet & set) const\n{\n    return _progress.whenActionsFinished(set);\n}\n\n//const FrameCountType UnitData::getTimeUntilBuildingFree(const ActionType & action) const\n//{\n//    return _buildings.timeUntilFree(action);\n//}\n\nconst FrameCountType UnitData::getFinishTime(const ActionType & action) const\n{\n    return _progress.nextActionFinishTime(action);\n}\n\nconst PrerequisiteSet UnitData::getPrerequistesInProgress(const ActionType & action) const\n{\n    PrerequisiteSet inProgress;\n\n    for (size_t a(0); a<action.getPrerequisites().size(); ++a)\n    {\n        const ActionType & actionType = action.getPrerequisites().getActionType(a);\n        if (getNumInProgress(actionType) > 0 && getNumCompleted(actionType) == 0)\n        {\n            inProgress.add(actionType);\n        }\n    } \n\n    return inProgress;\n}\n\nconst BuildingData & UnitData::getBuildingData() const\n{\n    return _buildings;\n}\n\nHatcheryData & UnitData::getHatcheryData()\n{\n    return _hatcheryData;\n}\n\nconst HatcheryData & UnitData::getHatcheryData() const\n{\n    return _hatcheryData;\n}"
  },
  {
    "path": "BOSS/source/UnitData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Array.hpp\"\n#include \"BuildingData.h\"\n#include \"ActionType.h\"\n#include \"ActionInProgress.h\"\n#include \"HatcheryData.h\"\n\nnamespace BOSS\n{\n\nclass UnitData\n{\n    RaceID                              _race;\n\n    UnitCountType                       _mineralWorkers; \t\t    // number of workers currently mining\n    UnitCountType                       _gasWorkers; \t\t\t    // number of workers currently getting gas\n    UnitCountType                       _buildingWorkers;\n    \n    SupplyCountType\t\t                _maxSupply; \t\t\t    // our maximum allowed supply\n    SupplyCountType                     _currentSupply; \t\t\t// our current allocated supply\n    \n    Vec<UnitCountType, Constants::MAX_ACTIONS>     _numUnits;                  // how many of each unit are completed\n    HatcheryData                        _hatcheryData;\n\n    ActionsInProgress\t                _progress;\t\t\t\t\t\n    BuildingData\t\t                _buildings;\n\npublic:\n\n    UnitData(const RaceID race);\n\n    const RaceID            getRace() const;\n    const bool              hasActionsInProgress() const;\n    const bool              hasPrerequisites(const PrerequisiteSet & required) const;\n    const bool              hasGasIncome() const;\n    const bool              hasMineralIncome() const;\n\n    const PrerequisiteSet   getPrerequistesInProgress(const ActionType & action) const;\n    \n    const UnitCountType     getNumTotal(const ActionType & action) const;\n    const UnitCountType     getNumInProgress(const ActionType & action) const;\n    const UnitCountType     getNumCompleted(const ActionType & action) const;\n    const UnitCountType     getNumActionsInProgress() const;\n    const UnitCountType     getNumLarva() const;\n    const UnitCountType     getNumMineralWorkers() const;\n    const UnitCountType     getNumGasWorkers() const;\n    const UnitCountType     getNumBuildingWorkers() const;\n    const UnitCountType     getSupplyInProgress() const;\n\n    const ActionType &      getActionInProgressByIndex(const UnitCountType & index) const;\n    const FrameCountType    getActionInProgressFinishTimeByIndex(const UnitCountType & index) const;\n\n    const FrameCountType    getNextBuildingFinishTime() const;\n    const FrameCountType    getFinishTime(const ActionType & action) const;\n    const FrameCountType    getFinishTime(const PrerequisiteSet & set) const;\n    const FrameCountType    getFinishTimeByIndex(const UnitCountType & index) const;\n    const FrameCountType    getNextActionFinishTime() const;\n    const FrameCountType    getLastActionFinishTime() const;\n    //const FrameCountType    getTimeUntilBuildingFree(const ActionType & action) const;\n\n    const FrameCountType    getWhenBuildingCanBuild(const ActionType & action) const;\n\n    const SupplyCountType   getCurrentSupply() const;\n    const SupplyCountType   getMaxSupply() const;\n    \n    void                    setCurrentSupply(const UnitCountType & supply);\n    void                    setBuildingWorker();\n    void                    releaseBuildingWorker();\n    void                    addCompletedBuilding(const ActionType & action, const FrameCountType timeUntilFree, const ActionType & constructing, const ActionType & addon, int numLarva);\n    void                    addCompletedAction(const ActionType & action, bool wasBuilt = true);\n\tvoid                    removeCompletedAction(const ActionType & action);\n    void                    addActionInProgress(const ActionType & action, const FrameCountType & completionFrame, bool queueAction = true);\n    void                    setBuildingFrame(const FrameCountType & frame);\n    void                    setMineralWorkers(const UnitCountType & mineralWorkers);\n    void                    setGasWorkers(const UnitCountType & gasWorkers);\n    void                    setBuildingWorkers(const UnitCountType & buildingWorkers);\n    void                    morphUnit(const ActionType & from, const ActionType & to, const FrameCountType & completionFrame);\n\n    ActionType              finishNextActionInProgress();\n\n    const BuildingData &    getBuildingData() const;\n    const HatcheryData &    getHatcheryData() const;\n          HatcheryData &    getHatcheryData();\n};\n\n}"
  },
  {
    "path": "BOSS/source/deprecated/BOSSAssert.cpp",
    "content": "#include \"BOSSAssert.h\"\n\nusing namespace BOSS;\nchar BOSS_LOGFILE[100] { \"BOSS_error_log.txt\" };\n\nnamespace BOSS\n{\nnamespace Assert\n{\n    std::string lastErrorMessage;\n\n    const std::string currentDateTime() \n    {\n        time_t     now = time(0);\n        struct tm  tstruct;\n        char       buf[80];\n\t\t//tstruct = *localtime(&now); \n\t\tlocaltime_s(&tstruct, &now);\n        strftime(buf, sizeof(buf), \"%Y-%m-%d_%X\", &tstruct);\n\n        return buf;\n    }\n\n    void ReportFailure(const char * condition, const char * file, int line, const char * msg, ...)\n    {\n        char messageBuffer[1024] = \"\";\n        if (msg != NULL)\n        {\n            va_list args;\n            va_start(args, msg);\n            //vsprintf(messageBuffer, msg, args);\n\t\t\tvsnprintf_s(messageBuffer, 1024, msg, args);\n            va_end(args);\n        }\n\n        std::stringstream ss;\n        ss                                              << std::endl;\n        ss << \"!Assert:   \" << condition                << std::endl;\n        ss << \"File:      \" << file                     << std::endl;\n        ss << \"Message:   \" << messageBuffer            << std::endl;\n        ss << \"Line:      \" << line                     << std::endl;\n        ss << \"Time:      \" << currentDateTime()        << std::endl;\n        \n        lastErrorMessage = messageBuffer;\n\n        std::cerr << ss.str();  \n\n        throw BOSSException(ss.str());\n    }\n}\n}\n\n"
  },
  {
    "path": "BOSS/source/deprecated/BOSSAssert.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include <cstdio>\n#include <cstdarg>\n#include \"BOSSLogger.h\"\n#include <sstream>\n#include <stdarg.h>\n\n#include <ctime>\n#include <iomanip>\n\nextern char BOSS_LOGFILE[100];\n\n#ifdef _MSC_VER\n    #define BOSS_BREAK\n#else\n    #define BOSS_BREAK exit(-1);\n#endif\n\n#define BOSS_ASSERT_ALL\n\n#ifdef BOSS_ASSERT_ALL\n    #define BOSS_ASSERT(cond, msg, ...) \\\n        do \\\n        { \\\n            if (!(cond)) \\\n            { \\\n                BOSS::Assert::ReportFailure(#cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \\\n                BOSS_BREAK \\\n            } \\\n        } while(0)\n#else\n    #define BOSS_ASSERT(cond, msg, ...) \n#endif\n\nnamespace BOSS\n{\n    namespace Assert\n    {\n        class BOSSException : public std::exception\n        {\n            std::string s;\n\n        public :\n\n            BOSSException(std::string ss) : s(ss) {}\n            ~BOSSException() throw () {} \n            const char* what() const throw() { return s.c_str(); }\n        }; \n\n        void ShutDown();\n\n        extern std::string lastErrorMessage;\n\n        const std::string currentDateTime();\n\n        void ReportFailure(const char * condition, const char * file, int line, const char * msg, ...);\n    }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/BOSSVisExperiment.cpp",
    "content": "#include \"BOSSVisExperiment.h\"\n\n#include \"GUI.h\"\n\nusing namespace BOSS;\n\nBOSSVisExperiment::BOSSVisExperiment()\n    : _fps(0)\n    , _scenarios(0)\n    , _finished(true)\n{\n\n}\n\nBOSSVisExperiment::BOSSVisExperiment(const rapidjson::Value & val, std::map< std::string, GameState > & stateMap, std::map< std::string, BuildOrder > & buildOrderMap)\n    : _startTimes(val[\"scenarios\"].Size(), std::vector<FrameCountType>())\n    , _finishTimes(val[\"scenarios\"].Size(), std::vector<FrameCountType>())\n    , _nextActionIndexes(val[\"scenarios\"].Size(), 0)\n    , _fps(0)\n    , _scenarios(0)\n    , _finished(false)\n{\n    if (val.HasMember(\"fps\") && val[\"fps\"].IsInt())\n    {\n        _fps = val[\"fps\"].GetInt();\n    }\n\n    const rapidjson::Value & scenarios = val[\"scenarios\"];\n    _scenarios = scenarios.Size();\n    for (size_t i(0); i < scenarios.Size(); ++i)\n    {\n        const rapidjson::Value & scenario = scenarios[i];\n\n        BOSS_ASSERT(scenario.HasMember(\"state\") && scenario[\"state\"].IsString(), \"Scenario has no 'state' string\");\n        BOSS_ASSERT(scenario.HasMember(\"buildOrder\") && scenario[\"buildOrder\"].IsString(), \"Scenario has no 'buildOrder' string\");\n\n        const std::string & stateName = scenario[\"state\"].GetString();\n        const std::string & boName = scenario[\"buildOrder\"].GetString();\n\n        BOSS_ASSERT(stateMap.find(stateName) != stateMap.end(), \"State not found: %s\", stateName.c_str());\n        BOSS_ASSERT(buildOrderMap.find(boName) != buildOrderMap.end(), \"Build Order not found: %s\", boName.c_str());\n\n        _states.push_back(stateMap[scenario[\"state\"].GetString()]);\n        _buildOrders.push_back(buildOrderMap[scenario[\"buildOrder\"].GetString()]);\n    }\n}\n\nconst Position & BOSSVisExperiment::getLastDrawPosition() const\n{\n    return _lastDrawPosition;\n}\n\nvoid BOSSVisExperiment::draw()\n{\n    Position drawAt(0,0);\n    for (size_t i(0); i < _scenarios; ++i)\n    {\n        PositionType endY = DrawScenario(drawAt, i);\n        drawAt = Position(0, endY);\n    }\n\n    _lastDrawPosition = drawAt;\n}\n\nvoid BOSSVisExperiment::onFrame()\n{\n    if (_finished)\n    {\n        return;\n    }\n    \n    for (size_t s(0); s < _states.size(); ++s)\n    {\n        bool didAction = false;\n\n        if (_nextActionIndexes[s] < _buildOrders[s].size())\n        {\n            FrameCountType nextActionFrame = _states[s].whenCanPerform(_buildOrders[s][_nextActionIndexes[s]]);\n\n            if (nextActionFrame == _states[s].getCurrentFrame())\n            {\n                ActionType type = _buildOrders[s][_nextActionIndexes[s]];\n                FrameCountType finish = _states[s].getCurrentFrame() + _buildOrders[s][_nextActionIndexes[s]].buildTime();\n                if (type.isBuilding() && !type.isAddon() && !type.isMorphed())\n                {\n                    finish += Constants::BUILDING_PLACEMENT;\n                }\n\n                _startTimes[s].push_back(_states[s].getCurrentFrame());\n                _finishTimes[s].push_back(finish);\n\n                _states[s].doAction(_buildOrders[s][_nextActionIndexes[s]]);\n\n                didAction = true;\n                //std::cout << states[s].getCurrentFrame() << \" Action Performed: \" << buildOrder[nextActionIndex].getName() << std::endl;\n                _nextActionIndexes[s]++;\n            }\n        }\n        \n        if (!didAction)\n        {\n            _states[s].fastForward(_states[s].getCurrentFrame() + 3);\n        }\n    }\n\n    draw();\n\n    bool notFinished = false;\n    for (size_t i(0); i < _states.size(); ++i)\n    {\n        if (_nextActionIndexes[i] < _buildOrders[i].size() || _states[i].getCurrentFrame() < _states[i].getLastActionFinishTime())\n        {\n            notFinished = true;\n            return;\n        }\n    }\n\n    _finished = !notFinished;\n}\n\nstd::string BOSSVisExperiment::getTimeString(const FrameCountType & frameCount)\n{\n    std::stringstream min;\n    min << (frameCount/24)/60;\n    std::string minString = min.str();\n\n    std::stringstream sec;\n    sec << (frameCount/24)%60;\n    std::string secString = sec.str();\n    while (secString.length() < 2) secString = \"0\" + secString;\n\n    std::string timeString = minString + \":\" + secString;\n    return timeString;\n}\n\n//const GameState & currentState, const std::vector<ActionType> & buildOrder, const size_t & boIndex, const std::vector<FrameCountType> & startTimes, const std::vector<FrameCountType> & finishTimes);\nPositionType BOSSVisExperiment::DrawScenario(const Position & pos, const size_t scenario)\n{\n    const GameState & currentState                      = _states[scenario];\n    const BuildOrder & buildOrder                       = _buildOrders[scenario];\n    const std::vector<FrameCountType> & startTimes      = _startTimes[scenario];\n    const std::vector<FrameCountType> & finishTimes     = _finishTimes[scenario];\n    //const size_t & boIndex = _buildO\n\n    const std::vector<ActionType> & allActions = ActionTypes::GetAllActionTypes(currentState.getRace());\n    static const ActionType & Larva = ActionTypes::GetActionType(\"Zerg_Larva\");\n    static const ActionType & Hatchery = ActionTypes::GetActionType(\"Zerg_Hatchery\");\n    GLfloat black[4] = {0.0f, 0.0f, 0.0f, 1.0f};\n    GLfloat white2[4] = {1.0f, 1.0f, 1.0f, 1.0f};\n    GLfloat white[4] = {1.0f, 1.0f, 1.0f, 0.8f};\n    GLfloat grey[4] = {0.1f, 0.1f, 0.1f, 1.0f};\n    GLfloat grey2[4] = {0.4f, 0.4f, 0.4f, 1.0f};\n    GLfloat red[4] = {0.6f, 0.0f, 0.0f, 1.0f};\n    GLfloat blue[4] = {0.0f, 0.0f, 0.5f, 1.0f};\n    GLfloat bblue[4] = {0.5f, 0.5f, 1.0f, 1.0f};\n    GLfloat bred[4] = {1.0f, 0.0f, 0.0f, 1.0f};\n    GLfloat green[4] = {0.0f, 0.4f, 0.0f, 1.0f};\n    GLfloat bgreen[4] = {0.0f, 1.0f, 0.0f, 1.0f};\n\n    std::string stateTime = getTimeString(currentState.getCurrentFrame());\n\n    std::stringstream ssres;\n    ssres << \"Frame:    \" << currentState.getCurrentFrame() <<\"\\n\";\n    ssres << \"Minerals: \" << currentState.getMinerals()/Constants::RESOURCE_SCALE << \"\\n\";\n    ssres << \"Gas:      \" << currentState.getGas()/Constants::RESOURCE_SCALE << \"\\n\";\n    ssres << \"MWorkers: \" << currentState.getNumMineralWorkers() << \"\\n\";\n    ssres << \"GWorkers: \" << currentState.getNumGasWorkers() << \"\\n\";\n    ssres << \"C Supply: \" << currentState.getUnitData().getCurrentSupply() << \"\\n\";\n    ssres << \"M Supply: \" << currentState.getUnitData().getMaxSupply() << \"\\n\";\n    GUITools::DrawString(pos + Position(20, 20), ssres.str(), white);\n\n    Position completed = pos + Position(225,0);\n    size_t cwidth = 64;\n    if (currentState.getRace() == Races::Zerg)\n    {\n        const UnitCountType & numLarva = currentState.getHatcheryData().numLarva();\n\n        GUI::Instance().DrawActionType(Larva, completed, cwidth);\n        std::stringstream num; num << numLarva << \"\\n\" << (Constants::ZERG_LARVA_TIMER-(currentState.getCurrentFrame() % Constants::ZERG_LARVA_TIMER));\n        GUITools::DrawString(completed + Position(10, 20), num.str(), white);\n        completed.add(cwidth, 0);\n    }\n\n    for (size_t a(0); a < allActions.size(); ++a)\n    {\n        const size_t numCompleted = currentState.getUnitData().getNumCompleted(allActions[a]);\n\n        if (numCompleted > 0)\n        {\n            GUI::Instance().DrawActionType(allActions[a], completed, cwidth);\n            std::stringstream num; num << numCompleted;\n            GUITools::DrawString(completed + Position(10, 20), num.str(), white);\n            completed.add(cwidth, 0);\n        }\n    }\n\n    Position legal = pos + Position(225,80);\n    ActionSet legalActions;\n    currentState.getAllLegalActions(legalActions);\n    GUITools::DrawString(legal + Position(0,-5), \"Legal Actions\", white);\n    for (size_t a(0); a < legalActions.size(); ++a)\n    {\n        const ActionType & action = legalActions[a];\n        GUI::Instance().DrawActionType(legalActions[a], legal, 32);\n        legal.add(32, 0);\n    }\n\n    std::vector<int> layers(startTimes.size(), -1);\n    int maxLayer = 0;\n\n    for (size_t i(0); i < startTimes.size(); ++i)\n    {\n        FrameCountType start    = startTimes[i];\n        FrameCountType finish   = finishTimes[i];\n\n        std::vector<int> layerOverlap;\n        // loop through everything up to this action and see which layers it can't be in\n        for (size_t j(0); j < i; ++j)\n        {\n            if (start < finishTimes[j])\n            {\n                layerOverlap.push_back(layers[j]);\n            }\n        }\n\n        // find a layer we can assign to this value\n        int layerTest = 0;\n        while (true)\n        {\n            if (std::find(layerOverlap.begin(), layerOverlap.end(), layerTest) == layerOverlap.end())\n            {\n                layers[i] = layerTest;\n                if (layerTest > maxLayer)\n                {\n                    maxLayer = layerTest;\n                }\n                break;\n            }\n\n            layerTest++;\n        }\n    }\n\n    float maxWidth = (float)GUI::Instance().Width() - 430;\n    float maxFinishTime = 1;\n\n    for (size_t i(0); i < _finishTimes.size(); ++i)\n    {\n        for (size_t j(0); j < _finishTimes[i].size(); ++j)\n        {\n            if (_finishTimes[i][j] > maxFinishTime)\n            {\n                maxFinishTime = (float)_finishTimes[i][j];\n            }\n        }\n    }\n\n    if (currentState.getCurrentFrame() < maxWidth && currentState.getCurrentFrame() > maxFinishTime)\n    {\n        maxFinishTime = (float)currentState.getCurrentFrame();\n    }\n\n    maxFinishTime = std::max(maxFinishTime, maxWidth);\n    //maxFinishTime = std::max(currentState.getCurrentFrame()*1.10f, maxWidth);\n\n    float scale = maxWidth / maxFinishTime;\n\n    // draw it\n\n    PositionType height         = 20;\n    PositionType heightBuffer   = 3;\n    Position concurrent         = pos + Position(25, 200);\n\n    float framePos              =  (concurrent.x() + scale*currentState.getCurrentFrame());\n    Position boxTopLeft         = Position(concurrent.x() - 10, concurrent.y() - 10);\n    Position boxBottomRight     = Position(PositionType(concurrent.x() + maxWidth + 10), (PositionType)(concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height));\n    \n    GUITools::DrawRect(boxTopLeft, boxBottomRight, grey2);\n    GUITools::DrawRect(boxTopLeft + Position(1,1), boxBottomRight - Position(1,1), grey);\n\n    for (size_t i(0); i < layers.size(); ++i)\n    {\n        float boxWidth = (finishTimes[i] - startTimes[i])*scale;\n\n        Position topLeft(PositionType(concurrent.x() + startTimes[i]*scale), PositionType(concurrent.y() + (height + heightBuffer) * layers[i]));\n        Position bottomRight(PositionType(topLeft.x() + boxWidth), topLeft.y() + height);\n\n        std::string name = buildOrder[i].getName();\n#ifndef EMSCRIPTEN\n        size_t loc = name.find(\"_\") + 1;\n#else\n        size_t loc = name.find(\" \") + 1;\n#endif\n        if (loc != std::string::npos)\n        {\n            name = name.substr(loc);\n        }\n\n        GUITools::DrawRect(topLeft, bottomRight, white);\n        GUITools::DrawRect(topLeft+Position(1,1), bottomRight-Position(1,1), finishTimes[i] < currentState.getCurrentFrame() ? red : blue);\n        GUITools::DrawString(topLeft + Position(3, 13), name, white);\n    }\n\n    PositionType boWidth = std::min(32, (PositionType)(maxWidth / buildOrder.size()));\n    for (size_t i(0); i < buildOrder.size(); ++i)\n    {\n        Position topLeft(concurrent.x() + i*boWidth, concurrent.y() - boWidth - 20);\n\n        if (i < _nextActionIndexes[scenario])\n        {\n            GUITools::DrawRect(topLeft, topLeft + Position(boWidth, boWidth), grey2);\n            GUITools::DrawRect(topLeft + Position(1,1), topLeft + Position(boWidth-1, boWidth-1), finishTimes[i] < currentState.getCurrentFrame() ? grey : blue);\n        }\n\n        if (i < startTimes.size())\n        {\n            //GUITools::DrawString(topLeft - Position(-2,20), getTimeString(startTimes[i]).c_str(), bblue);\n            //GUITools::DrawString(topLeft - Position(-2,9), getTimeString(finishTimes[i]).c_str(), bred);\n        }\n\n        GUI::Instance().DrawActionType(buildOrder[i], topLeft, boWidth);\n\n        std::string name = buildOrder[i].getName();\n#ifndef EMSCRIPTEN\n        size_t loc = name.find(\"_\") + 1;\n#else\n        size_t loc = name.find(\" \") + 1;\n#endif\n        if (loc != std::string::npos)\n        {\n            name = name.substr(loc, 2);\n        }\n\n        GUITools::DrawString(topLeft - Position(-1, 3), name, white);\n    }\n\n    if (currentState.getCurrentFrame() < maxFinishTime)\n    {\n        GUITools::DrawLine(Position((PositionType)framePos, concurrent.y() - 10), Position((PositionType)framePos, concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height), 1, white);\n        GUITools::DrawString(Position((PositionType)framePos, concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height + 20), stateTime.c_str(), white);\n    }\n\n    for (FrameCountType timeFrame = 0; timeFrame < maxFinishTime; timeFrame += 24*30)\n    {\n        float xPos = concurrent.x() + timeFrame*scale;\n        GUITools::DrawString(Position((PositionType)xPos, concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height + 20), getTimeString(timeFrame).c_str(), white);\n    }\n\n    Position progress = concurrent + Position(PositionType(maxWidth + 20), 0);\n    Position progressBar(175,20);\n    Position progressBuffer(0, 3);\n\n    GUITools::DrawString(progress - Position(0,5), \"Actions in Progress:\", white);\n    for (size_t a(0); a < currentState.getUnitData().getNumActionsInProgress(); ++a)\n    {\n        size_t index = currentState.getUnitData().getNumActionsInProgress() - a - 1;\n\n        const ActionType actionInProgress = currentState.getUnitData().getActionInProgressByIndex(index);\n        const FrameCountType finishTime = currentState.getUnitData().getActionInProgressFinishTimeByIndex(index);\n        \n        //DrawActionType(actionInProgress, progress, width);\n        double remainingTime = (finishTime - currentState.getCurrentFrame());\n        double timeRatio = remainingTime / actionInProgress.buildTime();\n        Position ratioBar((PositionType)(timeRatio * progressBar.x()), progressBar.y());\n\n        GUITools::DrawRect(progress + progressBuffer, progress + progressBuffer + progressBar, white);\n        GUITools::DrawRect(progress + progressBuffer + Position(1,1), progress + progressBuffer - Position(1,1) + progressBar, grey);\n        GUITools::DrawRect(progress + progressBuffer + Position(1,1), progress + progressBuffer - Position(1,1) + ratioBar, blue);\n\n        std::stringstream time; time << actionInProgress.getName() << \" \" << (int)remainingTime;\n        GUITools::DrawString(progress + progressBuffer + Position(10, 13), time.str(), white);\n        progress.add(0, progressBar.y() + progressBuffer.y());\n    }\n\n    Position buildings(progress.x() + 195, concurrent.y());\n    const BuildingData & buildingData = currentState.getBuildingData();\n    GUITools::DrawString(buildings - Position(0,5), \"Completed Buildings\", white);\n    for (size_t i(0); i < buildingData.size(); ++i)\n    {\n        const BuildingStatus & buildingStatus = buildingData.getBuilding(i);\n\n        const ActionType & type = buildingStatus._type;\n        const FrameCountType & finishTime = buildingStatus._timeRemaining;\n        const ActionType & makingType = buildingStatus._isConstructing;\n\n        GUITools::DrawRect(buildings + progressBuffer, buildings + progressBuffer + progressBar, white);\n        GUITools::DrawRect(buildings + progressBuffer + Position(1,1), buildings + progressBuffer - Position(1,1) + progressBar, grey);\n\n        if (finishTime > 0)\n        {\n            double remainingTime = finishTime;\n            double timeRatio = remainingTime / makingType.buildTime();\n            Position ratioBar((PositionType)(timeRatio * progressBar.x()), progressBar.y());\n        \n            GUITools::DrawRect(buildings + progressBuffer + Position(1,1), buildings + progressBuffer - Position(1,1) + ratioBar, blue);\n            std::stringstream time; time << type.getName() << \" \" << (int)remainingTime;\n            \n            GUITools::DrawString(buildings + progressBuffer + Position(10, 13), time.str(), white);\n        }\n        else\n        {\n            GUITools::DrawString(buildings + progressBuffer + Position(10, 13), type.getName(), white);\n        }\n        \n        buildings.add(0, progressBar.y() + progressBuffer.y());\n    }\n\n    return concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height + 20 + 30;\n}"
  },
  {
    "path": "BOSS/source/deprecated/BOSSVisExperiment.h",
    "content": "#pragma once\n\n#include \"BOSS.h\"\n#include \"GUITools.h\"\n#include \"JSONTools.h\"\n#include \"rapidjson/rapidjson.h\"\n#include \"rapidjson/document.h\"\n\nnamespace BOSS\n{\n\nclass BOSSVisExperiment\n{\n    std::vector< GameState >                        _states;\n    std::vector< BuildOrder >                       _buildOrders;\n    std::vector< std::vector<FrameCountType> >      _startTimes;\n    std::vector< std::vector<FrameCountType> >      _finishTimes;\n    std::vector< size_t >                           _nextActionIndexes;\n\n    double                                          _fps;\n    size_t                                          _scenarios;\n\n    bool                                            _finished;\n    Position                                        _lastDrawPosition;\n\n    PositionType    DrawScenario(const Position & pos, const size_t scenario);\n\n    std::string getTimeString(const FrameCountType & frameCount);\n\n    void draw();\n\npublic:\n\n    BOSSVisExperiment();\n    BOSSVisExperiment(const rapidjson::Value & experimentVal, std::map< std::string, GameState > & stateMap, std::map< std::string, BuildOrder > & buildOrderMap);\n\n    void onFrame();\n\n    const Position & getLastDrawPosition() const;\n\n};\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/GUI.cpp",
    "content": "#include \"GUI.h\"\n\nusing namespace BOSS;\n\n#define GUI_INITIAL_WIDTH  1920 \n#define GUI_INITIAL_HEIGHT 1080\n\n#define BOSS_MAX_TEXTURES 512\n#define BOSS_TEXTURE_INTERVAL 64\n\nconst int GUI::TextureASCIIOffset           = 200;\nconst int GUI::TextureFont                  = 198;\n\nGLfloat white[4] = {1.0f, 1.0f, 1.0f, 1.0f};\n\nGUI::GUI() \n    : windowSizeX(GUI_INITIAL_WIDTH)\n    , windowSizeY(GUI_INITIAL_HEIGHT)\n    , bl(false)\n    , br(false)\n    , bu(false)\n    , bd(false)\n    , cameraX(0)\n    , cameraY(0)\n    , previousMouseX(0)\n    , previousMouseY(0)\n    , started(false)\n    , mousePressed(false)\n    , shiftPressed(false)\n    , currentFrame(0)\n    , lastFrameTime(0)\n    , zoomX(1.0)\n    , zoomY(1.0)\n{\n    timer.start();\n    if(SDL_Init(SDL_INIT_VIDEO) != 0)\n    {\n        BOSS_ASSERT(false, \"Unable to initialise SDL\");\n    }\n}\n\nGUI & GUI::Instance()\n{\n    static GUI g;\n    return g;\n}\n\nGUI::~GUI()\n{\n    SDL_Quit();\n}\n\nbool GUI::isStarted() const\n{\n    return started;\n}\n\nvoid GUI::OnStart()\n{\n    if (started)\n    {\n        return;\n    }\n\n    cameraX   = 0;\n    cameraY   = 0;\n\n    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);\n    SDL_GL_SetSwapInterval(1);\n\n#ifndef EMSCRIPTEN\n    window = SDL_CreateWindow(\"Prismata OpenGL Visualization\",\n                          SDL_WINDOWPOS_UNDEFINED,\n                          SDL_WINDOWPOS_UNDEFINED,\n                          windowSizeX, windowSizeY,\n                          SDL_WINDOW_OPENGL);\n\n    glcontext = SDL_GL_CreateContext(window);\n#else\n    screen = SDL_SetVideoMode(windowSizeX,windowSizeY,32,SDL_OPENGL | SDL_RESIZABLE);\n#endif\n\n    LoadTextures();\n\n    // enable alpha blending for transparency\n    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);\n    glEnable(GL_BLEND);\n\n    glViewport(0,0,(GLsizei)(windowSizeX*zoomX),(GLsizei)(windowSizeY*zoomY));\n\n    started = true;\n}\n\n\nvoid GUI::OnFrame()\n{\n    BOSS_ASSERT(isStarted(), \"Must initialize GUI before calling OnFrame()\");\n\n    // Handle input events\n    HandleEvents();\n\n    // Render the frame\n    glClear(GL_COLOR_BUFFER_BIT);\n    Render();\n\n    SDL_GL_SwapWindow(window);\n}\n\nvoid GUI::OnResize(SDL_Event & event)\n{\n    //windowSizeX = event.resize.w;\n    //windowSizeY = event.resize.h;\n\n    glViewport(0,0,(GLsizei)(windowSizeX*zoomX),(GLsizei)(windowSizeY*zoomY));\n    OnFrame();\n}\n\nvoid GUI::HandleEvents()\n{\n    // Handle SDL events\n    SDL_Event event;\n    while (SDL_PollEvent(&event))\n    {\n        const bool pressed(event.key.state == SDL_PRESSED);\n        switch (event.type)\n        {\n            /*case SDL_VIDEORESIZE:\n            {\n                OnResize(event);\n                break;\n            }*/\n            case SDL_MOUSEMOTION:\n            {\n                if ((previousMouseX != 0 || previousMouseY != 0) && (event.motion.state & SDL_BUTTON_LEFT))\n                {\n                    cameraX -= (int)(event.motion.xrel * zoomX);\n                    cameraY -= (int)(event.motion.yrel * zoomY);\n                }\n                previousMouseX = event.motion.x;\n                previousMouseY = event.motion.y;\n                break;\n            }\n            case SDL_KEYDOWN:\n            {\n                switch (event.key.keysym.sym)\n                {\n                case SDLK_LSHIFT:\n                    shiftPressed = pressed;\n                    break;\n                case SDLK_p:\n                {\n                    \n                }\n                }\n                break;\n            }\n            case SDL_KEYUP:\n            {\n                switch (event.key.keysym.sym)\n                {\n                case SDLK_LSHIFT:\n                    shiftPressed = pressed;\n                    break;\n                }\n                break;\n            }\n            case SDL_MOUSEWHEEL:\n            {\n                //cameraY -= event.wheel.y;\n                zoomX *= event.wheel.y < 0 ? 1.05 : 0.95;\n                zoomY *= event.wheel.y < 0 ? 1.05 : 0.95;\n                //glViewport(0,0,windowSizeX*zoomX,windowSizeY*zoomY);\n                break;\n            }\n            case SDL_MOUSEBUTTONDOWN:\n            {\n\t\t\t\t\n\t\t\t\n                break;\n            }\n            case SDL_MOUSEBUTTONUP:\n            {\n                if (event.button.button == SDL_BUTTON_LEFT)\n                {\n\n                }\n                break;\n            }\n            case SDL_QUIT:\n            {\n                std::cerr << \"SDL_QUIT caught\\n\\n\";\n                exit(0);\n            }\n        }\n    }\n}\n\nvoid GUI::Render()\n{\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    {\n        glOrtho(0,windowSizeX*zoomX,windowSizeY*zoomY,0,-1,1);\n\n        glMatrixMode(GL_MODELVIEW);\n        glPushMatrix();\n        {\n            glTranslatef(static_cast<float>(-cameraX),static_cast<float>(-cameraY),0);\n                \n            _currentExperiment.onFrame();\n\n            //GUITools::DrawTexturedRect(Position(0,0), Position(200,200), TextureFont, white);\n        }\n\n        glPopMatrix();\n    }\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n\n    currentFrame++;\n}\n\nvoid GUI::DrawActionType(const ActionType & type, const Position & topLeft, const size_t & width)\n{\n    int textureNumber = getTextureNumber(type);\n    float ratio = (float)width / textureSizes[textureNumber].x();\n    Position size = Position((PositionType)(textureSizes[textureNumber].x() * ratio), (PositionType)(textureSizes[textureNumber].y() * ratio));\n    Position bottomRight(topLeft + size);\n\n    GUITools::DrawTexturedRect(topLeft, bottomRight, textureNumber, white);\n}\n\nint GUI::Width()\n{\n    return windowSizeX;\n}\n\nint GUI::Height()\n{\n    return windowSizeY;\n}\n\nvoid GUI::DrawAllUnits()\n{\n    GLfloat color[4] = {1.0f, 1.0f, 1.0f, 1.0f};\n    \n    float width = 64;\n    Position p;\n    Position techp(p.x(), p.y() + 100);\n\n    for (size_t r(0); r < 3; ++r)\n    {\n        for (size_t i(0); i < ActionTypes::GetAllActionTypes(r).size(); ++i)\n        {   \n            const ActionType & type = ActionTypes::GetAllActionTypes(r)[i];\n            DrawActionType(type, (type.isUnit() ? p : techp), (PositionType)width);\n            \n            if (type.isUnit())\n            {\n                p = p + Position((PositionType)width, 0);\n            }\n            else\n            {\n                techp = techp + Position((PositionType)width, 0);\n            }\n        }\n        \n        p = Position(0, (r+1) * 200);\n        techp = Position(p.x(), p.y() + 100);\n    }\n\n}\n\nvoid GUI::LoadTextures()\n{\n    std::string imageDir = \"../asset/images/\";\n#ifdef EMSCRIPTEN\n    imageDir = \"asset/images/\";\n#endif\n\n    textures = std::vector<GLuint>(BOSS_MAX_TEXTURES);\n    textureSizes = std::vector<Position>(BOSS_MAX_TEXTURES);\n    glGenTextures(BOSS_MAX_TEXTURES,&textures[0]);\n\n    for (size_t r(0); r < Races::NUM_RACES; ++r)\n    {\n        for (size_t i(0); i < ActionTypes::GetAllActionTypes(r).size(); ++i)\n        {\n            const ActionType & type = ActionTypes::GetAllActionTypes(r)[i];\n\n            LoadTexture(getTextureNumber(type), imageDir + getTextureFileName(type).c_str());\n        }\n    }\n\n    LoadTexture(TextureFont, imageDir + \"fonts/alpha_trans.png\");\n\n}\n\nconst int GUI::getTextureNumber(const ActionType & type) const\n{\n    return BOSS_TEXTURE_INTERVAL * type.getRace() + type.ID();\n}\n\nvoid GUI::LoadTexture(int textureNumber, const std::string & fileName)\n{\n    struct stat buf;\n    if (stat(fileName.c_str(), &buf) == -1)\n    {\n        std::cout << \"Couldn't find texture: \" << fileName << std::endl;\n        return;\n    }\n\n    SDL_Surface *surface2 = IMG_Load(fileName.c_str());\n    GLenum texture_format = GL_RGBA;\n    GLint nOfColors = 4;\n\n    if (surface2 != NULL)\n    {\n        glBindTexture( GL_TEXTURE_2D, textureNumber );\n\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n        glTexImage2D(GL_TEXTURE_2D, 0, texture_format, surface2->w, surface2->h, 0, texture_format, GL_UNSIGNED_BYTE, surface2->pixels);\n    } \n    else \n    {\n        printf(\"SDL could not load image: %s\\n\", SDL_GetError());\n    }    \n\n    if ( surface2 ) \n    { \n        textureSizes[textureNumber] = Position(surface2->w, surface2->h);\n        SDL_FreeSurface( surface2 );\n    }\n}\n\nvoid GUI::SetVisExperiment(BOSSVisExperiment & exp)\n{\n    _currentExperiment = exp;\n}\n\nbool GUI::saveScreenshotBMP(const std::string & filename) \n{\n    SDL_Surface * image = SDL_CreateRGBSurface(SDL_SWSURFACE, windowSizeX, windowSizeY, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);\n\n    glReadBuffer(GL_FRONT);\n    glReadPixels(0, 0, windowSizeX, windowSizeY, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);\n\n    SDL_SaveBMP(image, filename.c_str());\n    SDL_FreeSurface(image);\n\n    return true;\n}\n\nconst std::string GUI::getTextureFileName(const ActionType & type) const\n{\n\tstd::string filename = \"units/\" + type.getName() + \".png\";\n\n    if (type.isTech())\n    {\n        filename = \"command_icons/\" + type.getName() + \".png\";\n    }\n    else if (type.isUpgrade())\n    {\n        filename = \"command_icons/\" + type.getName() + \".png\";\n    }\n\n\tfor (size_t i(0); i<filename.size(); ++i)\n\t{\n\t\tif (filename[i] == ' ')\n\t\t{\n\t\t\tfilename[i] = '_';\n\t\t}\n\t}\n\n\treturn filename;\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/GUI.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BOSS.h\"\n#include \"GUITools.h\"\n\n#include <SDL.h>\n#undef main\n\n#include <SDL_opengl.h>\n#include <SDL_image.h>\n#include \"GameState.h\"\n#include \"GUITools.h\"\n#include <sys/stat.h>\n#include \"BOSSVisExperiment.h\"\n\nnamespace BOSS\n{\n\nclass BOSSVisExperiment;\n\nclass GUI\n{\n    unsigned int                texFont;\n    int                         windowSizeX;\n    int                         windowSizeY;\n    int                         cameraX;\n    int                         cameraY;\n    int                         mapPixelWidth;\n    int                         mapPixelHeight;\n    bool                        bl,br,bd,bu;\n    bool                        started;\n    int                         previousMouseX;\n    int                         previousMouseY;\n    bool                        mousePressed;\n\n    bool                        shiftPressed;\n\n    double                      zoomX, zoomY;\n\n    size_t                      currentFrame;\n    Timer                       timer;\n    double                      lastFrameTime;\n\n    SDL_Window *                window;\n    SDL_Surface *               screen;\n    SDL_GLContext               glcontext;\n\n    std::vector<GLuint>         textures;\n    std::vector<Position>       textureSizes;\n\n    BOSSVisExperiment           _currentExperiment;\n    \n    void HandleEvents();\n    void Render();\n    void RenderTextGlut(int x, int y, std::string & s);\n    void LoadTextures();\n    void LoadTexture(int textureNumber, const std::string & fileName);\n    void OnResize(SDL_Event & event);\n    void DrawAllUnits();\n    void DrawGameState();\n    PositionType DrawVisExperiment(const Position & pos, const GameState & currentState, const std::vector<ActionType> & buildOrder, const size_t & boIndex, const std::vector<FrameCountType> & startTimes, const std::vector<FrameCountType> & finishTimes);\n    \n\n    std::string getTimeString(const FrameCountType & frameCount);\n\n    const std::string getTextureFileName(const ActionType & type) const;\n    const int getTextureNumber(const ActionType & type) const;\n\n    PositionType DrawScenario(const Position & pos, const size_t scenario);\n\n    GUI();\n\npublic:\n    \n    static const int            TextureASCIIOffset;\n    static const int            TextureFont;\n\n    static GUI & Instance();\n    ~GUI();\n\n    int Width();\n    int Height();\n    void OnStart();\n    void OnFrame();\n    bool isStarted() const;\n    bool saveScreenshotBMP(const std::string & filename);\n\n    void SetVisExperiment(BOSSVisExperiment & exp);\n\n    void DrawActionType(const ActionType & type, const Position & tl, const size_t & width);\n};\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/GUITools.cpp",
    "content": "#include \"GUITools.h\"\n#include \"StarCraftGUI.h\"\n\nnamespace BOSS\n{\nnamespace GUITools\n{\n    void DrawString(const Position & p, const std::string & text, const GLfloat * rgba) \n    {\n        Position origin(p);\n        Position fontSize(8,8);\n\n        int linePos = 0;\n        for (size_t i(0); i < text.length(); ++i)\n        {\n            if (text[i] == '\\n') \n            { \n                origin = Position(p.x(), origin.y() + fontSize.y()); \n                linePos = 0;\n            }\n            else\n            {\n                Position charStart = Position(origin.x() + linePos*fontSize.x(), origin.y() - fontSize.y());\n                Position charEnd = charStart + fontSize;\n\n                DrawChar(charStart, charEnd, text[i], rgba);\n                    \n                linePos++;    \n            }\n        }\n    }\n\n    const size_t FontTextureSize = 128;\n    const size_t CharSize = 8;\n    const float CharDelta = 1.0f / 16.0f;\n    void DrawChar(const Position & tl, const Position & br, char ch, const GLfloat * rgba) \n    {\n        float xPos = ((ch % 16) / 16.0f);\n        float yPos = (ch >> 4) / 16.0f;\n        \n        glPushMatrix();\n            glEnable( GL_TEXTURE_2D );\n                glColor4fv(rgba);\n                glBindTexture( GL_TEXTURE_2D, StarCraftGUI::TextureFont );\n                glBegin( GL_QUADS );\n                    glTexCoord2f(xPos,yPos);                        glVertex2i(tl.x(), tl.y());\n                    glTexCoord2f(xPos+CharDelta,yPos);              glVertex2i(br.x(), tl.y());\n                    glTexCoord2f(xPos+CharDelta,yPos+CharDelta);    glVertex2i(br.x(), br.y());\n                    glTexCoord2f(xPos,yPos+CharDelta);              glVertex2i(tl.x(), br.y());\n                glEnd();\n            glDisable( GL_TEXTURE_2D );\n        glPopMatrix();\n    }\n\n    void DrawLine(const Position & p1, const Position & p2, const float thickness, const GLfloat * rgba)\n    {\n        glPushMatrix();\n            glLineWidth(thickness); \n            glColor4fv(rgba);\n            glBegin(GL_LINES);\n                glVertex2i(p1.x(),p1.y());\n                glVertex2i(p2.x(),p2.y());\n            glEnd();\n        glPopMatrix();\n    }\n\n    void DrawCircle(const Position & pos, float r, int num_segments) \n    { \n        float theta = 2 * (float)3.1415926 / float(num_segments); \n        float c = cosf(theta);//precalculate the sine and cosine\n        float s = sinf(theta);\n        float t;\n\n        float x = r;//we start at angle = 0 \n        float y = 0; \n\n        glBegin(GL_LINE_LOOP); \n            for(int ii = 0; ii < num_segments; ii++) \n            { \n                glVertex2f(x + pos.x(), y + pos.y());//output vertex \n\n                //apply the rotation matrix\n                t = x;\n                x = c * x - s * y;\n                y = s * t + c * y;\n            } \n        glEnd(); \n    }\n\n    void DrawRect(const Position & tl, const Position & br, const GLfloat * rgba)\n    {\n        glPushMatrix();\n            glColor4fv(rgba);\n            glBegin(GL_QUADS);\n                glVertex2i(tl.x(),tl.y());\n                glVertex2i(br.x(),tl.y());\n                glVertex2i(br.x(),br.y());\n                glVertex2i(tl.x(),br.y());\n            glEnd();\n        glPopMatrix();\n    }\n\n    void DrawRectGradient(const Position & tl, const Position & br, const GLfloat * rgbaLeft, const GLfloat * rgbaRight)\n    {\n        glPushMatrix();\n            glBegin(GL_QUADS);\n                glColor4fv(rgbaLeft);  glVertex2i(tl.x(),tl.y());\n                glColor4fv(rgbaRight); glVertex2i(br.x(),tl.y());\n                glColor4fv(rgbaRight); glVertex2i(br.x(),br.y());\n                glColor4fv(rgbaLeft);  glVertex2i(tl.x(),br.y());\n            glEnd();\n        glPopMatrix();\n    }\n  \n    void DrawTexturedRect(const Position & tl, const Position & br, const int & textureID, const GLfloat * rgba)\n    {\n        glPushMatrix();\n            glEnable( GL_TEXTURE_2D );\n                glColor4fv(rgba);\n                glBindTexture( GL_TEXTURE_2D, textureID );\n                glBegin( GL_QUADS );\n                    glTexCoord2f(0.0,0.0); glVertex2i(tl.x(),tl.y());\n                    glTexCoord2f(1.0,0.0); glVertex2i(br.x(),tl.y());\n                    glTexCoord2f(1.0,1.0); glVertex2i(br.x(),br.y());\n                    glTexCoord2f(0.0,1.0); glVertex2i(tl.x(),br.y());\n                glEnd();\n            glDisable( GL_TEXTURE_2D );\n        glPopMatrix();\n    }\n\n    void DrawIconAndText(const Position & tl, const Position & br, const int & textureID, const int & textureID2, const GLfloat * rgba)\n    {\n        GLfloat white[4] = {1.0f, 1.0f, 1.0f, 1.0f};\n        Position iconSize = br - tl;\n        Position statusNumPos = tl + Position(-iconSize.scale(0.15f).x(), iconSize.scale(0.4f).y());\n        GUITools::DrawTexturedRect(tl, br, textureID, rgba);\n        GUITools::DrawTexturedRect(statusNumPos, statusNumPos + iconSize.scale(0.65f), textureID2, rgba); \n    }\n\n    \n}\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/GUITools.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\n#include \"Position.hpp\"\n#include <SDL.h>\n#include <SDL_opengl.h>\n\nnamespace BOSS\n{\n    namespace GUITools\n    {\n        const int FLIP_VERTICAL = 1;\n        const int FLIP_HORIZONTAL = 2;\n\n        void DrawLine(const Position & p1, const Position & p2, const float thickness, const GLfloat * rgba);\n        void DrawString(const Position & p, const std::string & text, const GLfloat * rgba);\n        void DrawChar(const Position & tl, const Position & br, char ch, const GLfloat * rgba);\n        void DrawCircle(const Position & p, float r, int num_segments);\n        void DrawTexturedRect(const Position & tl, const Position & br, const int & textureID, const GLfloat * rgba); \n        void DrawRect(const Position & tl, const Position & br, const GLfloat * rgba); \n        void DrawRectGradient(const Position & tl, const Position & br, const GLfloat * rgbaLeft, const GLfloat * rgbaRight); \n        void SetColor(const GLfloat * src, GLfloat * dest);\n        void SetColor(const GLfloat * src, GLfloat * dest);\n    }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/README.txt",
    "content": "bwapidata\n----------------\n\nThis is used to compile SparCraft in a linux environment without having to worry about reconfiguring BWAPI\n\nThis is a stripped-down version of BWAPI which contains only headers and .cpp files, without BWTA\n\nUsed with permission from Adam Heinermann of the BWAPI project:\n\nhttps://code.google.com/p/bwapi/"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/AIModule.cpp",
    "content": "#include <BWAPI/AIModule.h>\nnamespace BWAPI\n{\n  AIModule::AIModule()\n  { }\n  AIModule::~AIModule()\n  { }\n  void AIModule::onStart()\n  { }\n  void AIModule::onEnd(bool isWinner)\n  { }\n  void AIModule::onFrame()\n  { }\n  void AIModule::onSendText(std::string text)\n  { }\n  void AIModule::onReceiveText(Player* player, std::string text)\n  { }\n  void AIModule::onPlayerLeft(Player *player)\n  { }\n  void AIModule::onNukeDetect(Position target)\n  { }\n  void AIModule::onUnitDiscover(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitEvade(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitShow(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitHide(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitCreate(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitDestroy(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitMorph(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitRenegade(BWAPI::Unit* unit)\n  { }\n  void AIModule::onSaveGame(std::string gameName)\n  { }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/AIModule.h",
    "content": "#pragma once\n#include <iostream>\n#include <string>\n#include <BWAPI/Position.h>\nnamespace BWAPI\n{\n  class Unit;\n  class Player;\n\n  /** AIModule is a virtual class that is intended to be implemented or inherited by a custom AI class.\n   *\n   * \\note\n   * Using BWAPI in a different thread than the default one will produce unexpected results and possibly crash\n   * the program. Multi-threaded AIs are possible so long as all BWAPI interaction is limited to the default\n   * thread (during one of the call-backs). */\n  class AIModule\n  {\n    public:\n      AIModule();\n      virtual ~AIModule();\n\n      /** BWAPI calls this at the start of a match. Typically an AI will execute set up code in this method\n       * (initialize data structures, load build orders, etc). */\n      virtual void onStart();\n\n      /** BWAPI calls this at the end of the match. isWinner will be true if the AIModule won the game. If the\n       * game is a replay, isWinner will always be false. */\n      virtual void onEnd(bool isWinner);\n\n      /** BWAPI calls this on every logical frame in the game. */\n      virtual void onFrame();\n\n      /** If Flag::UserInput is enabled, BWAPI will call this each time a user enters a message into the chat.\n       * */\n      virtual void onSendText(std::string text);\n\n      /** BWAPI calls this when another player sends a message. */\n      virtual void onReceiveText(Player* player, std::string text);\n\n      /** BWAPI calls this when a player leaves the game. */\n      virtual void onPlayerLeft(Player* player);\n\n      /** BWAPI calls this when a nuclear launch has been detected. If the target position is visible, or if\n       * Complete Map Information is enabled, the target position will also be provided. If Complete Map\n       * Information is disabled and the target position is not visible, target will be set to\n       * Positions::Unknown. */\n      virtual void onNukeDetect(Position target);\n\n      /** BWAPI calls this when a unit becomes accessible. */\n      virtual void onUnitDiscover(Unit* unit);\n\n      /** BWAPI calls this when a unit becomes inaccessible. */\n      virtual void onUnitEvade(Unit* unit);\n\n      /** BWAPI calls this the instant a previously invisible unit becomes visible. The complete map\n       * information flag has no effect on this callback. */\n      virtual void onUnitShow(Unit* unit);\n\n      /** BWAPI calls this right before a unit becomes invisible, so if you want your non-cheating AI to\n       * remember where it last saw a unit, this callback would be a good place to implement it. The complete\n       * map information flag has no effect on this callback. */\n      virtual void onUnitHide(Unit* unit);\n\n      /** BWAPI calls this when a unit is created. Note that this is NOT called when a unit changes type\n       * (such as larva into egg or egg into drone). Building a refinery/assimilator/extractor will not\n       * produce an onUnitCreate call since the vespene geyser changes to the unit type of the\n       * refinery/assimilator/extractor. If Complete Map Information is enabled, this will also be called for\n       * new units that are hidden by the fog of war. If the unit is visible upon creation, onUnitShow will be\n       * called shortly after onUnitCreate is called. */\n      virtual void onUnitCreate(Unit* unit);\n\n      /** BWAPI calls this when a unit dies or otherwise removed from the game (i.e. a mined out mineral\n       * patch). When a zerg drone becomes an extractor, the Vespene geyser changes to the Zerg Extractor type\n       * and the drone is removed. If Complete Map Information is enabled, this will also be called for units\n       * that are hidden by the fog of war. If a unit that was visible gets destroyed, onUnitHide will be\n       * called right before onUnitDestroy is called. */\n      virtual void onUnitDestroy(Unit* unit);\n\n      /** BWAPI calls this when a unit changes type, such as from a Zerg Drone to a Zerg Hatchery, or from a\n       * Terran Siege Tank Tank Mode to Terran Siege Tank Siege Mode. This is not called when the type changes\n       * to or from UnitTypes::Unknown (which happens when a unit becomes visible or invisible). */\n      virtual void onUnitMorph(Unit* unit);\n\n      /** BWAPI calls this when an accessible unit changes ownership. */\n      virtual void onUnitRenegade(Unit* unit);\n\n      // TODO: Add Doxygen documentation\n      virtual void onSaveGame(std::string gameName);\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Bitmap.h",
    "content": "#include <BWAPI/Color.h>\n#pragma once\n\nnamespace BWAPI\n{\n  class BitmapProxy\n  {\n  public:\n    BitmapProxy(unsigned char *data, unsigned short width, unsigned short height, int x);\n    Color operator[](int y);\n  private:\n    unsigned char *data;\n    unsigned short width;\n    unsigned short height;\n    int x;\n  };\n\n  class Bitmap\n  {\n    public:\n      BitmapProxy operator[](int x);\n      unsigned short getWidth();\n      unsigned short getHeight();\n\n    private:\n      unsigned short wid;\n      unsigned short ht;\n      unsigned char  *data;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Bullet.h",
    "content": "#pragma once\n\n#include <BWAPI/BulletType.h>\n#include <BWAPI/Position.h>\n\nnamespace BWAPI\n{\n  class Player;\n  class Unit;\n  class Bullet\n  {\n    public:\n      virtual int getID() const = 0;\n      virtual Player* getPlayer() const = 0;\n      virtual BulletType getType() const = 0;\n      virtual Unit* getSource() const = 0;\n      virtual Position getPosition() const = 0;\n      virtual double getAngle() const = 0;\n      virtual double getVelocityX() const = 0;\n      virtual double getVelocityY() const = 0;\n      virtual Unit* getTarget() const = 0;\n      virtual Position getTargetPosition() const = 0;\n      virtual int getRemoveTimer() const = 0;\n      virtual bool exists() const = 0;\n      virtual bool isVisible() const = 0;\n      virtual bool isVisible(Player* player) const = 0;\n  };\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/BulletType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\n\nnamespace BWAPI\n{\n  class BulletType\n  {\n    public:\n      BulletType();\n      BulletType(int id);\n      BulletType(const BulletType& other);\n      BulletType& operator=(const BulletType& other);\n      bool operator==(const BulletType& other) const;\n      bool operator!=(const BulletType& other) const;\n      bool operator<(const BulletType& other) const;\n\n      /** Returns the unique ID for this bullet type. */\n      int getID() const;\n\n      /** Returns the name of this bullet type. */\n      std::string getName() const;\n    private:\n      int id;\n  };\n\n  namespace BulletTypes\n  {\n    /** Given the name of an bullet type, getBulletType() will return the corresponding BulletType object. */\n    BulletType getBulletType(std::string name);\n\n    /** Returns the set of all the BulletTypes. */\n    std::set<BulletType>& allBulletTypes();\n    void init();\n    extern const BulletType Melee;\n    extern const BulletType Fusion_Cutter_Hit;\n    extern const BulletType Gauss_Rifle_Hit;\n    extern const BulletType C_10_Canister_Rifle_Hit;\n    extern const BulletType Gemini_Missiles;\n    extern const BulletType Fragmentation_Grenade;\n    extern const BulletType Longbolt_Missile;\n    extern const BulletType ATS_ATA_Laser_Battery;\n    extern const BulletType Burst_Lasers;\n    extern const BulletType Arclite_Shock_Cannon_Hit;\n    extern const BulletType EMP_Missile;\n    extern const BulletType Dual_Photon_Blasters_Hit;\n    extern const BulletType Particle_Beam_Hit;\n    extern const BulletType Anti_Matter_Missile;\n    extern const BulletType Pulse_Cannon;\n    extern const BulletType Psionic_Shockwave_Hit;\n    extern const BulletType Psionic_Storm;\n    extern const BulletType Yamato_Gun;\n    extern const BulletType Phase_Disruptor;\n    extern const BulletType STA_STS_Cannon_Overlay;\n    extern const BulletType Sunken_Colony_Tentacle;\n    extern const BulletType Acid_Spore;\n    extern const BulletType Glave_Wurm;\n    extern const BulletType Seeker_Spores;\n    extern const BulletType Queen_Spell_Carrier;\n    extern const BulletType Plague_Cloud;\n    extern const BulletType Consume;\n    extern const BulletType Needle_Spine_Hit;\n    extern const BulletType Invisible;\n    extern const BulletType Optical_Flare_Grenade;\n    extern const BulletType Halo_Rockets;\n    extern const BulletType Subterranean_Spines;\n    extern const BulletType Corrosive_Acid_Shot;\n    extern const BulletType Neutron_Flare;\n    extern const BulletType None;\n    extern const BulletType Unknown;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/BulletData.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  struct BulletData\n  {\n    int id;\n    int player;\n    int type;\n    int source;\n    int positionX;\n    int positionY;\n    double angle;\n    double velocityX;\n    double velocityY;\n    int target;\n    int targetPositionX;\n    int targetPositionY;\n    int removeTimer;\n    bool exists;\n    bool isVisible[9];\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/BulletImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"BulletData.h\"\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Player;\n  class Unit;\n  class BulletImpl : public Bullet\n  {\n    private:\n      const BulletData* self;\n      int index;\n    public:\n\n      BulletImpl(int index);\n      virtual int getID() const;\n      virtual Player* getPlayer() const;\n      virtual BulletType getType() const;\n      virtual Unit* getSource() const;\n      virtual Position getPosition() const;\n      virtual double getAngle() const;\n      virtual double getVelocityX() const;\n      virtual double getVelocityY() const;\n      virtual Unit* getTarget() const;\n      virtual Position getTargetPosition() const;\n      virtual int getRemoveTimer() const;\n      virtual bool exists() const;\n      virtual bool isVisible() const;\n      virtual bool isVisible(Player* player) const;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/Client.h",
    "content": "#pragma once\n#include <windows.h>\n#include \"GameData.h\"\n#include \"GameImpl.h\"\n#include \"ForceImpl.h\"\n#include \"PlayerImpl.h\"\n#include \"UnitImpl.h\"\n\n\nnamespace BWAPI\n{\n  class Client\n  {\n    public:\n    Client();\n    ~Client();\n    GameData* data;\n    bool isConnected();\n    bool connect();\n    void disconnect();\n    void update();\n\n  private:\n    HANDLE pipeObjectHandle;\n    HANDLE mapFileHandle;\n    bool connected;\n  };\n  extern Client BWAPIClient;\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/Command.h",
    "content": "#pragma once\n#include \"CommandType.h\"\n\nnamespace BWAPIC\n{\n  struct Command\n  {\n    Command(CommandType::Enum _commandType, int _value1=0, int _value2=0)\n    {\n      type=_commandType;\n      value1=_value1;\n      value2=_value2;\n    }\n    CommandType::Enum type;\n    int value1;\n    int value2;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/CommandType.h",
    "content": "#pragma once\n/**\n *  Used in UnitCommand\n */\n\nnamespace BWAPIC\n{\n  namespace CommandType\n  {\n    enum Enum\n    {\n      None,\n      SetScreenPosition,\n      PingMinimap,\n      EnableFlag,\n      Printf,\n      SendText,\n      ChangeRace,\n      StartGame,\n      PauseGame,\n      ResumeGame,\n      LeaveGame,\n      RestartGame,\n      SetLocalSpeed,\n      SetTextSize,\n      SetLatCom,\n      SetGui\n    };\n  }\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/Event.h",
    "content": "#pragma once\n\n#include <BWAPI\\Event.h>\n#include <BWAPI\\EventType.h>\n\nnamespace BWAPIC\n{ \n  struct Event\n  {\n    BWAPI::EventType::Enum type;\n    int v1;\n    int v2;\n  };\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/ForceData.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  struct ForceData\n  {\n    char name[32];\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/ForceImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"ForceData.h\"\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Game;\n  class Player;\n  class Unit;\n  class ForceImpl : public Force\n  {\n    private:\n      const ForceData* self;\n      int id;\n    public:\n      ForceImpl(int id);\n      virtual int getID() const;\n      virtual std::string getName() const;\n      virtual std::set<Player*> getPlayers() const;\n  };\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/GameData.h",
    "content": "#pragma once\n\n#include \"UnitCommand.h\"\n#include \"ForceData.h\"\n#include \"PlayerData.h\"\n#include \"UnitData.h\"\n#include \"BulletData.h\"\n#include \"Event.h\"\n#include \"Command.h\"\n#include \"Shape.h\"\n\nnamespace BWAPI\n{\n  struct GameData\n  {\n    GameData();\n    int instanceID;\n\n    //forces\n    int forceCount;\n    ForceData forces[5];\n\n    //players\n    int playerCount;\n    PlayerData players[12];\n\n    //units\n    int initialUnitCount;\n    UnitData units[10000];\n\n    //unit table\n    int unitArray[1700];\n\n    //bullets\n    BulletData bullets[100];\n\n    int gameType;\n    int latency;\n    int latencyFrames;\n    int latencyTime;\n    int remainingLatencyFrames;\n    int remainingLatencyTime;\n    int revision;\n    bool isDebug;\n    bool hasLatCom;\n    int replayFrameCount;\n    int frameCount;\n    int fps;\n    double averageFPS;\n\n    // user input\n    int mouseX;\n    int mouseY;\n    bool mouseState[3];\n    bool keyState[256];\n    int screenX;\n    int screenY;\n\n    bool flags[2];\n\n    // map\n    int mapWidth;\n    int mapHeight;\n    char mapFileName[261];  //size based on broodwar memory\n    char mapPathName[261];  //size based on broodwar memory\n    char mapName[33];      //size based on broodwar memory\n    char mapHash[41];\n\n    //tile data\n    int getGroundHeight[256][256];\n    bool isWalkable[1024][1024]; \n    bool isBuildable[256][256];\n    bool isVisible[256][256];\n    bool isExplored[256][256];\n    bool hasCreep[256][256];\n\n    unsigned short mapTileRegionId[256][256];\n    unsigned short mapSplitTilesMiniTileMask[5000];\n    unsigned short mapSplitTilesRegion1[5000];\n    unsigned short mapSplitTilesRegion2[5000];\n    unsigned short regionGroupIndex[5000];\n\n\n    // start locations\n    int startLocationCount;\n    int startLocationsX[8];\n    int startLocationsY[8];\n\n    // match mode\n    bool isInGame;\n    bool isMultiplayer;\n    bool isBattleNet;\n    bool isPaused;\n    bool isReplay;\n\n    //selected units\n    int selectedUnitCount;\n    int selectedUnits[12];\n\n    // players\n    int self;\n\n    //events from server to client\n    int eventCount;\n    BWAPIC::Event events[10000];\n\n    //strings (used in events, shapes, and commands)\n    int stringCount;\n    char strings[20000][256];\n\n    //shapes, commands, unitCommands, from client to server\n    int shapeCount;\n    BWAPIC::Shape shapes[20000];\n\n    int commandCount;\n    BWAPIC::Command commands[20000];\n\n    int unitCommandCount;\n    BWAPIC::UnitCommand unitCommands[20000];\n\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/GameImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"GameData.h\"\n#include \"Client.h\"\n#include \"Shape.h\"\n#include \"Command.h\"\n#include \"UnitCommand.h\"\n#include \"ForceImpl.h\"\n#include \"PlayerImpl.h\"\n#include \"UnitImpl.h\"\n#include \"BulletImpl.h\"\n#include <list>\n#include <map>\n#include <set>\n#include <vector>\n\nnamespace BWAPI\n{\n  class Force;\n  class Player;\n  class Unit;\n  class GameImpl : public Game\n  {\n    private :\n      int addShape(BWAPIC::Shape &s);\n      int addString(const char* text);\n      int addText(BWAPIC::Shape &s, const char* text);\n      int addCommand(BWAPIC::Command &c);\n      void clearAll();\n\n      GameData* data;\n      std::vector<ForceImpl> forceVector;\n      std::vector<PlayerImpl> playerVector;\n      std::vector<UnitImpl> unitVector;\n      std::vector<BulletImpl> bulletVector;\n\n      std::set<Force*> forces;\n      std::set<Player*> players;\n      std::set<Unit*> accessibleUnits;//all units that are accessible (and definitely alive)\n      //notDestroyedUnits - accessibleUnits = all units that may or may not be alive (status unknown)\n      std::set<Unit*> minerals;\n      std::set<Unit*> geysers;\n      std::set<Unit*> neutralUnits;\n      std::set<Unit*> staticMinerals;\n      std::set<Unit*> staticGeysers;\n      std::set<Unit*> staticNeutralUnits;\n      std::set<Bullet*> bullets;\n      std::set<Unit*> selectedUnits;\n      std::set<Unit*> pylons;\n      std::set<Unit*> unitsOnTileData[256][256];\n\n      std::set< TilePosition > startLocations;\n      std::list< Event > events;\n      bool flagEnabled[2];\n      Player* thePlayer;\n      Player* theEnemy;\n      Error lastError;\n\n    public :\n      Event makeEvent(BWAPIC::Event e);\n      int addUnitCommand(BWAPIC::UnitCommand& c);\n      bool inGame;\n      GameImpl(GameData* data);\n      void onMatchStart();\n      void onMatchEnd();\n      void onMatchFrame();\n      const GameData* getGameData() const;\n      std::set<Unit*>& getPlayerUnits(const Player* player);\n\n      virtual std::set< Force* >& getForces();\n      virtual std::set< Player* >& getPlayers();\n      virtual std::set< Unit* >& getAllUnits();\n      virtual std::set< Unit* >& getMinerals();\n      virtual std::set< Unit* >& getGeysers();\n      virtual std::set< Unit* >& getNeutralUnits();\n\n      virtual std::set< Unit* >& getStaticMinerals();\n      virtual std::set< Unit* >& getStaticGeysers();\n      virtual std::set< Unit* >& getStaticNeutralUnits();\n\n      virtual std::set< Bullet* >& getBullets();\n      virtual std::list< Event>& getEvents();\n\n      virtual Force* getForce(int forceID);\n      virtual Player* getPlayer(int playerID);\n      virtual Unit* getUnit(int unitID);\n      virtual Unit* indexToUnit(int unitIndex);\n\n      virtual GameType getGameType();\n      virtual int getLatency();\n      virtual int getFrameCount();\n      virtual int getFPS();\n      virtual double getAverageFPS();\n      virtual BWAPI::Position getMousePosition();\n      virtual bool getMouseState(MouseButton button);\n      virtual bool getMouseState(int button);\n      virtual bool getKeyState(Key key);\n      virtual bool getKeyState(int key);\n      virtual BWAPI::Position getScreenPosition();\n      virtual void setScreenPosition(int x, int y);\n      virtual void setScreenPosition(BWAPI::Position p);\n      virtual void pingMinimap(int x, int y);\n      virtual void pingMinimap(BWAPI::Position p);\n\n      virtual bool  isFlagEnabled(int flag);\n      virtual void  enableFlag(int flag);\n      virtual std::set<Unit*>& unitsOnTile(int x, int y);\n      virtual Error getLastError() const;\n      virtual bool  setLastError(BWAPI::Error e);\n\n      virtual int         mapWidth();\n      virtual int         mapHeight();\n      virtual std::string mapFileName();\n      virtual std::string mapPathName();\n      virtual std::string mapName();\n      virtual std::string mapHash();\n\n      virtual bool isWalkable(int x, int y);\n      virtual int  getGroundHeight(int x, int y);\n      virtual int  getGroundHeight(TilePosition position);\n      virtual bool isBuildable(int x, int y);\n      virtual bool isBuildable(TilePosition position);\n      virtual bool isVisible(int x, int y);\n      virtual bool isVisible(TilePosition position);\n      virtual bool isExplored(int x, int y);\n      virtual bool isExplored(TilePosition position);\n      virtual bool hasCreep(int x, int y);\n      virtual bool hasCreep(TilePosition position);\n      virtual bool hasPower(int x, int y, int tileWidth, int tileHeight);\n      virtual bool hasPower(TilePosition position, int tileWidth, int tileHeight);\n\n      virtual bool canBuildHere(Unit* builder, TilePosition position, UnitType type, bool checkExplored = false);\n      virtual bool canMake(Unit* builder, UnitType type);\n      virtual bool canResearch(Unit* unit, TechType type);\n      virtual bool canUpgrade(Unit* unit, UpgradeType type);\n      virtual std::set< TilePosition >& getStartLocations();\n\n      virtual void printf(const char* text, ...);\n      virtual void sendText(const char* text, ...);\n      virtual void sendTextEx(bool toAllies, const char *format, ...);\n\n      virtual void changeRace(BWAPI::Race race);\n      virtual bool isInGame();\n      virtual bool isMultiplayer();\n      virtual bool isBattleNet();\n      virtual bool isPaused();\n      virtual bool isReplay();\n\n      virtual void  startGame();\n      virtual void  pauseGame();\n      virtual void  resumeGame();\n      virtual void  leaveGame();\n      virtual void  restartGame();\n      virtual void  setLocalSpeed(int speed = -1);\n      virtual std::set<BWAPI::Unit*>& getSelectedUnits();\n      virtual Player*  self();\n      virtual Player*  enemy();\n\n      virtual void setTextSize(int size = 1);\n      virtual void drawText(int ctype, int x, int y, const char* text, ...);\n      virtual void drawTextMap(int x, int y, const char* text, ...);\n      virtual void drawTextMouse(int x, int y, const char* text, ...);\n      virtual void drawTextScreen(int x, int y, const char* text, ...);\n\n      virtual void drawBox(int ctype, int left, int top, int right, int bottom, Color color, bool isSolid = false);\n      virtual void drawBoxMap(int left, int top, int right, int bottom, Color color, bool isSolid = false);\n      virtual void drawBoxMouse(int left, int top, int right, int bottom, Color color, bool isSolid = false);\n      virtual void drawBoxScreen(int left, int top, int right, int bottom, Color color, bool isSolid = false);\n\n      virtual void drawTriangle(int ctype, int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false);\n      virtual void drawTriangleMap(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false);\n      virtual void drawTriangleMouse(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false);\n      virtual void drawTriangleScreen(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false);\n\n      virtual void drawCircle(int ctype, int x, int y, int radius, Color color, bool isSolid = false);\n      virtual void drawCircleMap(int x, int y, int radius, Color color, bool isSolid = false);\n      virtual void drawCircleMouse(int x, int y, int radius, Color color, bool isSolid = false);\n      virtual void drawCircleScreen(int x, int y, int radius, Color color, bool isSolid = false);\n\n      virtual void drawEllipse(int ctype, int x, int y, int xrad, int yrad, Color color, bool isSolid = false);\n      virtual void drawEllipseMap(int x, int y, int xrad, int yrad, Color color, bool isSolid = false);\n      virtual void drawEllipseMouse(int x, int y, int xrad, int yrad, Color color, bool isSolid = false);\n      virtual void drawEllipseScreen(int x, int y, int xrad, int yrad, Color color, bool isSolid = false);\n\n      virtual void drawDot(int ctype, int x, int y, Color color);\n      virtual void drawDotMap(int x, int y, Color color);\n      virtual void drawDotMouse(int x, int y, Color color);\n      virtual void drawDotScreen(int x, int y, Color color);\n\n      virtual void drawLine(int ctype, int x1, int y1, int x2, int y2, Color color);\n      virtual void drawLineMap(int x1, int y1, int x2, int y2, Color color);\n      virtual void drawLineMouse(int x1, int y1, int x2, int y2, Color color);\n      virtual void drawLineScreen(int x1, int y1, int x2, int y2, Color color);\n\n      virtual void *getScreenBuffer();\n      virtual int  getLatencyFrames();\n      virtual int  getLatencyTime();\n      virtual int  getRemainingLatencyFrames();\n      virtual int  getRemainingLatencyTime();\n      virtual int  getRevision();\n      virtual bool isDebug();\n      virtual bool isLatComEnabled();\n      virtual void setLatCom(bool isEnabled);\n      virtual int  getReplayFrameCount();\n      virtual void setGUI(bool enabled = true);\n      virtual int  getInstanceNumber();\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/PlayerData.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  struct PlayerData\n  {\n    char name[25];\n    int  race;\n    int  type;\n    int  force;\n    bool isAlly[12];\n    bool isEnemy[12];\n    bool isNeutral;\n    int  startLocationX;\n    int  startLocationY;\n    bool isVictorious;\n    bool isDefeated;\n    bool leftGame;\n\n    int minerals;\n    int gas;\n    int cumulativeMinerals;\n    int cumulativeGas;\n    int supplyTotal[3];\n    int supplyUsed[3];\n\n    int allUnitCount[230];\n    int completedUnitCount[230];\n    int deadUnitCount[230];\n    int killedUnitCount[230];\n\n    int  upgradeLevel[63];\n    bool hasResearched[47];\n    bool isResearching[47];\n    bool isUpgrading[63];\n\n    int colorByte;\n    int color;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/PlayerImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"PlayerData.h\"\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Unit;\n  class Force;\n  class PlayerImpl : public Player\n  {\n    private:\n      int id;\n    public:\n      PlayerData* self;\n      std::set<Unit*> units;\n      void clear();\n      PlayerImpl(int id);\n      virtual int getID() const;\n      virtual std::string getName() const;\n      virtual const std::set<Unit*>& getUnits() const;\n      virtual Race getRace() const;\n      virtual PlayerType getType() const;\n      virtual Force* getForce() const;\n      virtual bool isAlly(Player* player) const;\n      virtual bool isEnemy(Player* player) const;\n      virtual bool isNeutral() const;\n      virtual TilePosition getStartLocation() const;\n      virtual bool isVictorious() const;\n      virtual bool isDefeated() const;\n      virtual bool leftGame() const;\n\n      virtual int minerals() const;\n      virtual int gas() const;\n      virtual int cumulativeMinerals() const;\n      virtual int cumulativeGas() const;\n\n      virtual int supplyTotal() const;\n      virtual int supplyUsed() const;\n      virtual int supplyTotal(Race race) const;\n      virtual int supplyUsed(Race race) const;\n\n      virtual int allUnitCount(UnitType unit) const;\n      virtual int completedUnitCount(UnitType unit) const;\n      virtual int incompleteUnitCount(UnitType unit) const;\n      virtual int deadUnitCount(UnitType unit) const;\n      virtual int killedUnitCount(UnitType unit) const;\n\n      virtual int  getUpgradeLevel(UpgradeType upgrade) const;\n      virtual bool hasResearched(TechType tech) const;\n      virtual bool isResearching(TechType tech) const;\n      virtual bool isUpgrading(UpgradeType upgrade) const;\n\n      virtual int maxEnergy(UnitType unit) const;\n\n      virtual BWAPI::Color getColor() const;\n      virtual int getTextColor() const;\n  };\n};\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/Shape.h",
    "content": "#pragma once\n#include \"ShapeType.h\"\n\nnamespace BWAPIC\n{\n  struct Shape\n  {\n    Shape(ShapeType::Enum _shapeType, int _ctype, int _x1, int _y1, int _x2, int _y2, int _extra1, int _extra2, int _color, bool _isSolid)\n    {\n      type=_shapeType;\n      ctype=_ctype;\n      x1=_x1;\n      y1=_y1;\n      x2=_x2;\n      y2=_y2;\n      extra1=_extra1;\n      extra2=_extra2;\n      color=_color;\n      isSolid=_isSolid;\n    }\n    ShapeType::Enum type;\n    int ctype;\n    int x1;\n    int y1;\n    int x2;\n    int y2;\n    int extra1;\n    int extra2;\n    int color;\n    bool isSolid;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/ShapeType.h",
    "content": "#pragma once\n/**\n *  Used in UnitCommand\n */\n\nnamespace BWAPIC\n{\n  namespace ShapeType\n  {\n    enum Enum\n    {\n      None,\n      Text,\n      Box,\n      Triangle,\n      Circle,\n      Ellipse,\n      Dot,\n      Line\n    };\n  }\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/UnitCommand.h",
    "content": "#pragma once\n\n#include <BWAPI.h>\n\n/**\n * UnitOrder contains a single whole order\n */\n\nnamespace BWAPIC\n{\n  struct UnitCommand\n  {\n    BWAPI::UnitCommandType type;\n    int unitIndex;\n    int targetIndex;\n    int x;\n    int y;\n    int extra;\n  };\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/UnitData.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  struct UnitData\n  {\n    int clearanceLevel;\n    int id;\n    int player;\n    int type;\n    int positionX;\n    int positionY;\n    double angle;\n    double velocityX;\n    double velocityY;\n    int hitPoints;\n    int lastHitPoints;\n    int shields;\n    int energy;\n    int resources;\n    int resourceGroup;\n\n    int killCount;\n    int scarabCount;\n    int spiderMineCount;\n    int groundWeaponCooldown;\n    int airWeaponCooldown;\n    int spellCooldown;\n    int defenseMatrixPoints;\n\n    int defenseMatrixTimer;\n    int ensnareTimer;\n    int irradiateTimer;\n    int lockdownTimer;\n    int maelstromTimer;\n    int orderTimer;\n    int plagueTimer;\n    int removeTimer;\n    int stasisTimer;\n    int stimTimer;\n\n    int buildType;\n    int trainingQueueCount;\n    int trainingQueue[5];\n    int tech;\n    int upgrade;\n    int remainingBuildTime;\n    int remainingTrainTime;\n    int remainingResearchTime;\n    int remainingUpgradeTime;\n    int buildUnit;\n\n    int target;\n    int targetPositionX;\n    int targetPositionY;\n    int order;\n    int orderTarget;\n    int secondaryOrder;\n    int rallyPositionX;\n    int rallyPositionY;\n    int rallyUnit;\n    int addon;\n    int nydusExit;\n    int powerUp;\n\n    int transport;\n    int carrier;\n    int hatchery;\n    \n    bool exists;\n    bool hasNuke;\n    bool isAccelerating;\n    bool isAttacking;\n    bool isBeingGathered;\n    bool isBlind;\n    bool isBraking;\n    bool isBurrowed;\n    int carryResourceType;\n    bool isCloaked;\n    bool isCompleted;\n    bool isConstructing;\n    bool isDetected;\n    bool isGathering;\n    bool isHallucination;\n    bool isIdle;\n    bool isInterruptible;\n    bool isLifted;\n    bool isMorphing;\n    bool isMoving;\n    bool isParasited;\n    bool isSelected;\n    bool isStartingAttack;\n    bool isStuck;\n    bool isTraining;\n    bool isUnderStorm;\n    bool isUnpowered;\n    bool isVisible[9];\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client/UnitImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"UnitData.h\"\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Player;\n  class UnitImpl : public Unit\n  {\n    private:\n      int id;\n      UnitType initialType;\n      int initialResources;\n      int initialHitPoints;\n      Position initialPosition;\n      int lastOrderFrame;\n      void* clientInfo;\n    public:\n      UnitData* self;\n      std::set<Unit*> connectedUnits;\n      std::set<Unit*> loadedUnits;\n      void clear();\n      void saveInitialState();\n\n      UnitImpl(int id);\n      virtual int          getID() const;\n      virtual Player*      getPlayer() const;\n      virtual UnitType     getType() const;\n      virtual Position     getPosition() const;\n      virtual TilePosition getTilePosition() const;\n      virtual double       getAngle() const;\n      virtual double       getVelocityX() const;\n      virtual double       getVelocityY() const;\n      virtual int          getHitPoints() const;\n      virtual int          getShields() const;\n      virtual int          getEnergy() const;\n      virtual int          getResources() const;\n      virtual int          getResourceGroup() const;\n\n      virtual double getDistance(Unit* target) const;\n      virtual double getDistance(Position target) const;\n      virtual bool   hasPath(Unit* target) const;\n      virtual bool   hasPath(Position target) const;\n      virtual int    getLastOrderFrame() const;\n      virtual int    getUpgradeLevel(UpgradeType upgrade) const;\n\n      virtual UnitType     getInitialType() const;\n      virtual Position     getInitialPosition() const;\n      virtual TilePosition getInitialTilePosition() const;\n      virtual int          getInitialHitPoints() const;\n      virtual int          getInitialResources() const;\n\n      virtual int getKillCount() const;\n      virtual int getInterceptorCount() const;\n      virtual int getScarabCount() const;\n      virtual int getSpiderMineCount() const;\n      virtual int getGroundWeaponCooldown() const;\n      virtual int getAirWeaponCooldown() const;\n      virtual int getSpellCooldown() const;\n      virtual int getDefenseMatrixPoints() const;\n\n      virtual int getDefenseMatrixTimer() const;\n      virtual int getEnsnareTimer() const;\n      virtual int getIrradiateTimer() const;\n      virtual int getLockdownTimer() const;\n      virtual int getMaelstromTimer() const;\n      virtual int getOrderTimer() const;\n      virtual int getPlagueTimer() const;\n      virtual int getRemoveTimer() const;\n      virtual int getStasisTimer() const;\n      virtual int getStimTimer() const;\n\n      virtual UnitType            getBuildType() const;\n      virtual std::list<UnitType> getTrainingQueue() const;\n      virtual TechType            getTech() const;\n      virtual UpgradeType         getUpgrade() const;\n      virtual int                 getRemainingBuildTime() const;\n      virtual int                 getRemainingTrainTime() const;\n      virtual int                 getRemainingResearchTime() const;\n      virtual int                 getRemainingUpgradeTime() const;\n      virtual Unit*               getBuildUnit() const;\n\n      virtual Unit*    getTarget() const;\n      virtual Position getTargetPosition() const;\n      virtual Order    getOrder() const;\n      virtual Unit*    getOrderTarget() const;\n      virtual Order    getSecondaryOrder() const;\n      virtual Position getRallyPosition() const;\n      virtual Unit*    getRallyUnit() const;\n      virtual Unit*    getAddon() const;\n      virtual Unit*    getNydusExit() const;\n      virtual Unit*    getPowerUp() const;\n\n      virtual Unit*           getTransport() const;\n      virtual std::set<Unit*> getLoadedUnits() const;\n      virtual Unit*           getCarrier() const;\n      virtual std::set<Unit*> getInterceptors() const;\n      virtual Unit*           getHatchery() const;\n      virtual std::set<Unit*> getLarva() const;\n\n      virtual bool exists() const;\n      virtual bool hasNuke() const;\n      virtual bool isAccelerating() const;\n      virtual bool isAttacking() const;\n      virtual bool isBeingConstructed() const;\n      virtual bool isBeingGathered() const;\n      virtual bool isBeingHealed() const;\n      virtual bool isBlind() const;\n      virtual bool isBraking() const;\n      virtual bool isBurrowed() const;\n      virtual bool isCarryingGas() const;\n      virtual bool isCarryingMinerals() const;\n      virtual bool isCloaked() const;\n      virtual bool isCompleted() const;\n      virtual bool isConstructing() const;\n      virtual bool isDefenseMatrixed() const;\n      virtual bool isDetected() const;\n      virtual bool isEnsnared() const;\n      virtual bool isFollowing() const;\n      virtual bool isGatheringGas() const;\n      virtual bool isGatheringMinerals() const;\n      virtual bool isHallucination() const;\n      virtual bool isHoldingPosition() const;\n      virtual bool isIdle() const;\n      virtual bool isInterruptible() const;\n      virtual bool isIrradiated() const;\n      virtual bool isLifted() const;\n      virtual bool isLoaded() const;\n      virtual bool isLockedDown() const;\n      virtual bool isMaelstrommed() const;\n      virtual bool isMorphing() const;\n      virtual bool isMoving() const;\n      virtual bool isParasited() const;\n      virtual bool isPatrolling() const;\n      virtual bool isPlagued() const;\n      virtual bool isRepairing() const;\n      virtual bool isResearching() const;\n      virtual bool isSelected() const;\n      virtual bool isSieged() const;\n      virtual bool isStartingAttack() const;\n      virtual bool isStasised() const;\n      virtual bool isStimmed() const;\n      virtual bool isStuck() const;\n      virtual bool isTraining() const;\n      virtual bool isUnderStorm() const;\n      virtual bool isUnpowered() const;\n      virtual bool isUpgrading() const;\n      virtual bool isVisible() const;\n      virtual bool isVisible(Player* player) const;\n\n      virtual bool issueCommand(UnitCommand command);\n\n      virtual bool attackMove(Position target);\n      virtual bool attackUnit(Unit* target);\n      virtual bool build(TilePosition target, UnitType type);\n      virtual bool buildAddon(UnitType type);\n      virtual bool train(UnitType type);\n      virtual bool morph(UnitType type);\n      virtual bool research(TechType tech);\n      virtual bool upgrade(UpgradeType upgrade);\n      virtual bool setRallyPoint(Position target);\n      virtual bool setRallyPoint(Unit* target);\n      virtual bool move(Position target);\n      virtual bool patrol(Position target);\n      virtual bool holdPosition();\n      virtual bool stop();\n      virtual bool follow(Unit* target);\n      virtual bool gather(Unit* target);\n      virtual bool returnCargo();\n      virtual bool repair(Unit* target);\n      virtual bool burrow();\n      virtual bool unburrow();\n      virtual bool cloak();\n      virtual bool decloak();\n      virtual bool siege();\n      virtual bool unsiege();\n      virtual bool lift();\n      virtual bool land(TilePosition target);\n      virtual bool load(Unit* target);\n      virtual bool unload(Unit* target);\n      virtual bool unloadAll();\n      virtual bool unloadAll(Position target);\n      virtual bool rightClick(Position target);\n      virtual bool rightClick(Unit* target);\n      virtual bool haltConstruction();\n      virtual bool cancelConstruction();\n      virtual bool cancelAddon();\n      virtual bool cancelTrain(int slot = -2);\n      virtual bool cancelMorph();\n      virtual bool cancelResearch();\n      virtual bool cancelUpgrade();\n      virtual bool useTech(TechType tech);\n      virtual bool useTech(TechType tech, Position target);\n      virtual bool useTech(TechType tech, Unit* target);\n\n      virtual void setClientInfo(void* clientinfo);\n      virtual void* getClientInfo() const;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Client.h",
    "content": "#pragma once\n#include <BWAPI/Client/Client.h>\n#include <BWAPI/Client/Command.h>\n#include <BWAPI/Client/CommandType.h>\n#include <BWAPI/Client/Event.h>\n#include <BWAPI/Client/ForceData.h>\n#include <BWAPI/Client/ForceImpl.h>\n#include <BWAPI/Client/GameData.h>\n#include <BWAPI/Client/GameImpl.h>\n#include <BWAPI/Client/PlayerData.h>\n#include <BWAPI/Client/PlayerImpl.h>\n#include <BWAPI/Client/Shape.h>\n#include <BWAPI/Client/ShapeType.h>\n#include <BWAPI/Client/UnitCommand.h>\n#include <BWAPI/Client/UnitData.h>\n#include <BWAPI/Client/UnitImpl.h>"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Color.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  // TODO: Add color palette image and info about text color\n  /** StarCraft uses a 256 color palette to render everything, so the colors we can use to draw shapes using\n   * BWAPI is limited to the colors available in the Palette. */\n  class Color\n  {\n    public:\n      Color();\n\n      /** Create a color using the specified index from the Broodwar color palette. */\n      Color(int id);\n      Color(const Color& other);\n\n      /** Create a color using the color in the palette that is closest to the RGB color specified. */\n      Color(int red, int green, int blue);\n\n      /** Return the index of the color in the color palette. */\n      int getID() const;\n\n      /** Return the red component of the color. */\n      int red() const;\n\n      /** Return the green component of the color. */\n      int green() const;\n\n      /** Return the blue component of the color. */\n      int blue() const;\n\n      Color& operator=(const Color& other);\n      bool operator==(const Color& other) const;\n      bool operator!=(const Color& other) const;\n      bool operator<(const Color& other) const;\n    private:\n      int id;\n  };\n\n  /** While any color from the palette can be used, the following colors are available as short cuts. */\n  namespace Colors\n  {\n    void init();\n    extern const Color Red;\n    extern const Color Blue;\n    extern const Color Teal;\n    extern const Color Purple;\n    extern const Color Orange;\n    extern const Color Brown;\n    extern const Color White;\n    extern const Color Yellow;\n    extern const Color Green;\n    extern const Color Cyan;\n    extern const Color Black;\n    extern const Color Grey;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Constants.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  /** Used for converting between TilePosition coordinates and Position coordinates. */\n  #define TILE_SIZE      32\n  #define PYLON_X_RADIUS  8\n  #define PYLON_Y_RADIUS  5\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/CoordinateType.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  namespace CoordinateType\n  {\n    enum Enum\n    {\n      Screen    = 1, /**< (0,0) corresponds to the top left corner of the screen. */\n      Map       = 2, /**< (0,0) corresponds to the top left corner of the map. */\n      Mouse     = 3, /**< (0,0) corresponds to the tip of the mouse . */\n    };\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/DamageType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class DamageType\n  {\n    public:\n      DamageType();\n      DamageType(int id);\n      DamageType(const DamageType& other);\n      DamageType& operator=(const DamageType& other);\n      bool operator==(const DamageType& other) const;\n      bool operator!=(const DamageType& other) const;\n      bool operator<(const DamageType& other) const;\n\n      /** Returns a unique ID for this damage type. */\n      int getID() const;\n\n      /** Returns the name of this damage type. For example DamageTypes::Explosive.getName() will return\n       * std::string(\"Explosive\"). */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace DamageTypes\n  {\n    /** Given the name of a damage type, this will return a corresponding DamageType object. For example,\n     * DamageTypes::getDamageType(\"Concussive\") will return DamageTypes::Concussive. */\n    DamageType getDamageType(std::string name);\n\n    /** Returns the set of all the DamageTypes. */\n    std::set<DamageType>& allDamageTypes();\n\n    void init();\n    extern const DamageType Independent;\n    extern const DamageType Explosive;\n    extern const DamageType Concussive;\n    extern const DamageType Normal;\n    extern const DamageType Ignore_Armor;\n    extern const DamageType None;\n    extern const DamageType Unknown;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Error.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class UnitType;\n\n  /** Functions in BWAPI may set an error code. To retrieve the error code, call Game::getLastError. */\n  class Error\n  {\n    public:\n      Error();\n      Error(int id);\n      Error(const Error& other);\n      Error& operator=(const Error& other);\n      bool operator==(const Error& other) const;\n      bool operator!=(const Error& other) const;\n      bool operator<(const Error& other) const;\n\n      /** Returns a unique ID for this error. */\n      int getID() const;\n\n      /** Returns the name of the error. For example Errors::Insufficient_Minerals?.toString() will return a\n       * std::string object containing \"Insufficient Minerals\". */\n      std::string toString() const;\n    private:\n      int id;\n  };\n  namespace Errors\n  {\n    /** Given the name of an error, this function will return the error code. For example:\n     * Errors::getError(\"Unbuildable Location\") will return Errors::Unbuildable_Location?. */\n    Error getError(std::string name);\n\n    /** The set of all the error codes. */\n    std::set<Error>& allErrors();\n\n    void init();\n\n    /** Returned if you try to order a unit or get information from a unit that no longer exists. */\n    extern const Error Unit_Does_Not_Exist;\n\n    /** Returned if you try to retrieve information about a unit that is not currently visible or is dead. */\n    extern const Error Unit_Not_Visible;\n\n    /** Returned when attempting to order a unit that BWAPI does not own (i.e. can't order enemy army to go\n     *  away) */\n    extern const Error Unit_Not_Owned;\n\n    /** Returned when trying to order a unit to do something when it is performing another order or is in a\n     * state which prevents it from performing the desired order. For example, ordering a Terran Engineering\n     * Bay to upgrade something while it is already upgrading something else will return this error.\n     * Similarly, trying to train units from a factory that is lifted will return this error. */\n    extern const Error Unit_Busy;\n\n    /** Returned if you do something weird like try to build a Pylon with an SCV, or train Vultures in a\n     * Barracks, or order a Hydralisk to lay a spider mine. */\n    extern const Error Incompatible_UnitType;\n\n    /** Returned when trying to use a tech type with the wrong Unit::useTech method. */\n    extern const Error Incompatible_TechType;\n\n    /** Returned if you to do something like try to cancel an upgrade when the unit isn't upgrading. */\n    extern const Error Incompatible_State;\n\n    /** Returned if you try to research something that is already researched. */\n    extern const Error Already_Researched;\n\n    /** Returned if you try to upgrade something that is already fully upgraded. */\n    extern const Error Fully_Upgraded;\n\n    /** Returned if you try to research something that is already being researched. */\n    extern const Error Currently_Researching;\n\n    /** Returned if you try to upgrade something that is already being upgraded. */\n    extern const Error Currently_Upgrading;\n\n    /** Returned if you try to train or build something without enough minerals. */\n    extern const Error Insufficient_Minerals;\n\n    /** Returned if you try to train or build something without enough vespene gas. */\n    extern const Error Insufficient_Gas;\n\n    /** Returned if you try to train something without enough supply. */\n    extern const Error Insufficient_Supply;\n\n    /** Returned if you to do something like try to order a Defiler to cast a Dark Swarm without enough\n     * energy. */\n    extern const Error Insufficient_Energy;\n\n    /** Returned if you do something like try to train Medics when you don't have an Academy, or try to lay\n     * Spider Mines before spider mines have been researched. */\n    extern const Error Insufficient_Tech;\n\n    /** Returned if you do something like try to lay Spider Mines when your Vulture is out of Spider Mines.\n     * Same thing with Reavers and Scarabs. */\n    extern const Error Insufficient_Ammo;\n\n    /** Returned if you try to build something on unbuildable terrain (either from the buildability map data\n     * or if a unit is in the way). For build tiles that are not visible, we could just use the buildability\n     * map data and assume that no units are blocking it (to prevent cheating). */\n    extern const Error Insufficient_Space;\n\n    /** Returned if you order an immovable unit, like a Protoss Photon Cannon, to attack a unit that is out\n     * of range. */\n    extern const Error Unbuildable_Location;\n\n    /** Returned if you try to construct a building where the worker cannot reach based on static map data. */\n    extern const Error Unreachable_Location;\n\n    /** Returned if you order an immovable unit, like a Protoss Photon Cannon, to attack a unit that is out of\n     * range.*/\n    extern const Error Out_Of_Range;\n\n    /** Returned if you do something like order a Vulture to attack a flying unit. */\n    extern const Error Unable_To_Hit;\n\n    /** Returned if you try to get information that is not allowed with the given flag settings. For example,\n     * trying to read the enemy's resource counts while the CompleteMapInformation?  flag is not enabled will\n     * return this error. Similarly, trying to read the coordinates of the screen or mouse while the UserInput\n     *  flag is not enabled will also return this error. */\n    extern const Error Access_Denied;\n\n    /** Used when no error has been encountered. */\n    extern const Error None;\n\n    /** Used when the error code is not recognized or can not be determined. */\n    extern const Error Unknown;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Event.h",
    "content": "#pragma once\n#include <BWAPI/EventType.h>\n#include <BWAPI/Player.h>\n#include <BWAPI/Unit.h>\n#include <BWAPI/Position.h>\n#include <string>\n\nnamespace BWAPI\n{\n  class Event\n  {\n    public:\n      Event();\n      bool operator==(const Event& other);\n      static Event MatchStart();\n      static Event MatchEnd(bool isWinner);\n      static Event MatchFrame();\n      static Event MenuFrame();\n      static Event SendText(std::string text);\n      static Event ReceiveText(Player* player, std::string text);\n      static Event PlayerLeft(Player* player);\n      static Event NukeDetect(Position target);\n      static Event UnitDiscover(Unit* unit);\n      static Event UnitEvade(Unit* unit);\n      static Event UnitShow(Unit* unit);\n      static Event UnitHide(Unit* unit);\n      static Event UnitCreate(Unit* unit);\n      static Event UnitDestroy(Unit* unit);\n      static Event UnitMorph(Unit* unit);\n      static Event UnitRenegade(Unit* unit);\n      static Event SaveGame(std::string gameName);\n      EventType::Enum type;\n      Position position;\n      std::string text;\n      Unit* unit;\n      Player* player;\n      bool isWinner;\n  };\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/EventType.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  namespace EventType\n  {\n    enum Enum\n    {\n      MatchStart,\n      MatchEnd,\n      MatchFrame,\n      MenuFrame,\n      SendText,\n      ReceiveText,\n      PlayerLeft,\n      NukeDetect,\n      UnitDiscover,\n      UnitEvade,\n      UnitShow,\n      UnitHide,\n      UnitCreate,\n      UnitDestroy,\n      UnitMorph,\n      UnitRenegade,\n      SaveGame,\n      None\n    };\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/ExplosionType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class ExplosionType\n  {\n    public:\n      ExplosionType();\n      ExplosionType(int id);\n      ExplosionType(const ExplosionType& other);\n      ExplosionType& operator=(const ExplosionType& other);\n      bool operator==(const ExplosionType& other) const;\n      bool operator!=(const ExplosionType& other) const;\n      bool operator<(const ExplosionType& other) const;\n\n      /** Returns a unique ID for this explosion type. */\n      int getID() const;\n\n      /** Returns the name of this explosion type. */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace ExplosionTypes\n  {\n    /** Given a name of an explosion type, this will return the corresponding ExplosionType  object. */\n    ExplosionType getExplosionType(std::string name);\n\n    /** Returns the set of all ExplosionTypes. */\n    std::set<ExplosionType>& allExplosionTypes();\n\n    void init();\n    extern const ExplosionType None;\n    extern const ExplosionType Normal;\n    extern const ExplosionType Radial_Splash;\n    extern const ExplosionType Enemy_Splash;\n    extern const ExplosionType Lockdown;\n    extern const ExplosionType Nuclear_Missile;\n    extern const ExplosionType Parasite;\n    extern const ExplosionType Broodlings;\n    extern const ExplosionType EMP_Shockwave;\n    extern const ExplosionType Irradiate;\n    extern const ExplosionType Ensnare;\n    extern const ExplosionType Plague;\n    extern const ExplosionType Stasis_Field;\n    extern const ExplosionType Dark_Swarm;\n    extern const ExplosionType Consume;\n    extern const ExplosionType Yamato_Gun;\n    extern const ExplosionType Restoration;\n    extern const ExplosionType Disruption_Web;\n    extern const ExplosionType Corrosive_Acid;\n    extern const ExplosionType Mind_Control;\n    extern const ExplosionType Feedback;\n    extern const ExplosionType Optical_Flare;\n    extern const ExplosionType Maelstrom;\n    extern const ExplosionType Air_Splash;\n    extern const ExplosionType Unknown;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Flag.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  namespace Flag\n  {\n    enum Enum\n    {\n      /** Enable to get information about all units on the map, not just the visible units. */\n      CompleteMapInformation = 0,\n\n      /** Enable to get information from the user (what units are selected, chat messages the user enters,\n       * etc) */\n      UserInput              = 1,\n\n      Max\n    };\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Force.h",
    "content": "#pragma once\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Player;\n\n  /** The Force class is used to get information about each force in the match, such as the name of the force\n   * and the set of players in the force. */\n  class Force\n  {\n    public :\n      /** Returns a unique ID for the force. */\n      virtual int getID() const = 0;\n\n      /** Returns the name of the force. */\n      virtual std::string getName() const = 0;\n\n      /** Returns the set of players in the force. */\n      virtual std::set<Player*> getPlayers() const = 0;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Game.h",
    "content": "#pragma once\n\n#include <list>\n#include <map>\n#include <set>\n#include <vector>\n\n#include <BWAPI/Color.h>\n#include <BWAPI/CoordinateType.h>\n#include <BWAPI/Error.h>\n#include <BWAPI/Event.h>\n#include <BWAPI/Flag.h>\n#include <BWAPI/GameType.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/Order.h>\n#include <BWAPI/Latency.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/Input.h>\nnamespace BWAPI\n{\n  class Force;\n  class Player;\n  class Unit;\n  class Bullet;\n\n  /** The abstract Game class is implemented by BWAPI and offers many methods for retrieving information\n   * about the current Broodwar game, including the set of players, units, map information, as well as\n   * information about the user, such as mouse position, screen position, and the current selection of\n   * units. */\n  class Game\n  {\n    public :\n      /** Returns the set of all forces in the match. */\n      virtual std::set< Force* >& getForces() = 0;\n\n      /** Returns the set of all players in the match. Note that this includes the Neutral player, which owns\n       * all the neutral units such as minerals, critters, etc. */\n      virtual std::set< Player* >& getPlayers() = 0;\n\n      /** Returns all the visible units. If Flag::CompleteMapInformation is enabled, the set of all units\n       * is returned, not just visible ones. Note that units inside refineries are not included in this set\n       * yet. */\n      virtual std::set< Unit* >& getAllUnits() = 0;\n\n      /** Returns the set of all accessible mineral patches. */\n      virtual std::set< Unit* >& getMinerals() = 0;\n\n      /** Returns the set of all accessible vespene geysers. */\n      virtual std::set< Unit* >& getGeysers() = 0;\n\n      /** Returns the set of all accessible neutral units. */\n      virtual std::set< Unit* >& getNeutralUnits() = 0;\n\n      /** Returns the set of all mineral patches (including mined out and other inaccessible ones). */\n      virtual std::set< Unit* >& getStaticMinerals() = 0;\n\n      /** Returns the set of all vespene geysers (including mined out and other inaccessible ones). */\n      virtual std::set< Unit* >& getStaticGeysers() = 0;\n\n      /** Returns the set of all neutral units (including mined out and other inaccessible ones). */\n      virtual std::set< Unit* >& getStaticNeutralUnits() = 0;\n\n      /** Returns all visible bullets. If Flag::CompleteMapInformation is enabled, the set of all bullets is\n       * returned, not just visible ones. */\n\n      virtual std::set< Bullet* >& getBullets() = 0;\n\n      /** Returns the list of events */\n      virtual std::list< Event >& getEvents() = 0;\n\n      /** Returns the force with the given ID, or NULL if no force has the given ID */\n      virtual Force* getForce(int forceID) = 0;\n\n      /** Returns the player with the given ID, or NULL if no player has the given ID */\n      virtual Player* getPlayer(int playerID) = 0;\n\n      /** Returns the unit with the given ID, or NULL if no unit has the given ID */\n      virtual Unit* getUnit(int unitID) = 0;\n\n      /** Returns a pointer to a Unit given an index. */\n      virtual Unit* indexToUnit(int unitIndex) = 0;\n\n      /** Returns the game type */\n      virtual GameType getGameType() = 0;\n\n      /** Returns the amount of latency the current game has. Currently only returns Latency::SinglePlayer,\n       * Latency::LanLow, Latency::LanMedium, or Latency::LanHigh. */\n      virtual int getLatency() = 0;\n\n      /** Returns the number of logical frames since the match started. If the game is paused,\n       * Game::getFrameCount will not increase however AIModule::onFrame will still be called while paused.\n       * On Fastest, there are about 23.8 - 24 frames per second. */\n      virtual int getFrameCount() = 0;\n\n      /** Returns the Frames Per Second (FPS) that the game is currently running at */\n      virtual int getFPS() = 0;\n      virtual double getAverageFPS() = 0;\n\n      /** Returns the position of the mouse on the screen. Returns Positions::Unknown if Flag::UserInput is\n       * disabled. */\n      virtual BWAPI::Position getMousePosition() = 0;\n\n      /** Returns true if the specified mouse button is pressed. Returns false if Flag::UserInput is\n       * disabled. */\n      virtual bool getMouseState(MouseButton button) = 0;\n\n      /** \\copydoc getMouseState(MouseButton) */\n      virtual bool getMouseState(int button) = 0;\n\n      /** Returns true if the specified key is pressed. Returns false if Flag::UserInput is disabled.\n       * Unfortunately this does not read the raw keyboard input yet - when you hold down a key, the\n       * getKeyState function is true for a frame, then false for a few frames, and then alternates between\n       * true and false (as if you were holding down the key in a text box). Hopefully this will be fixed in\n       * a later version. */\n      virtual bool getKeyState(Key key) = 0;\n\n      /** \\copydoc getKeyState(Key) */\n      virtual bool getKeyState(int key) = 0;\n\n      /** Returns the position of the top left corner of the screen on the map. Returns Positions::Unknown if\n       * Flag::UserInput is disabled. */\n      virtual BWAPI::Position getScreenPosition() = 0;\n\n      /** Moves the screen to the given position on the map. The position specified where the top left corner\n       * of the screen will be. */\n      virtual void setScreenPosition(int x, int y) = 0;\n\n      /** \\copydoc setScreenPosition(int, int) */\n      virtual void setScreenPosition(BWAPI::Position p) = 0;\n\n      /** Pings the given position on the minimap. */\n      virtual void pingMinimap(int x, int y) = 0;\n\n      /** \\copydoc pingMinimap(int, int) */\n      virtual void pingMinimap(BWAPI::Position p) = 0;\n\n      /** Returns true if the given flag has been enabled. Note that flags can only be enabled at the\n       * beginning of a match, during the AIModule::onStart callback. */\n      virtual bool isFlagEnabled(int flag) = 0;\n\n      /** Enables the specified flag. Note that flags can only be enabled at the beginning of a match, during\n       * the AIModule::onStart callback. */\n      virtual void enableFlag(int flag) = 0;\n\n      /** Returns the set of units that are on the given build tile. Only returns accessible units on\n       * accessible tiles. */\n      virtual std::set<Unit*>& unitsOnTile(int tileX, int tileY) = 0;\n\n      /** Returns the last error that was set. If you try to order enemy units around, or morph bunkers into\n       * lurkers, BWAPI will set error codes, which can be retrieved using this function. */\n      virtual Error getLastError() const = 0;\n\n      /** Sets the last error code. */\n      virtual bool setLastError(BWAPI::Error e) = 0;\n\n      /** Returns the width of the current map, in build tile units. To get the width of the current map in\n       * walk tile units, multiply by 4. To get the width of the current map in Position units, multiply by\n       * TILE_SIZE (which is 32). */\n      virtual int mapWidth() = 0;\n\n      /** Returns the height of the current map, in build tile units. To get the height of the current map in\n       * walk tile units, multiply by 4. To get the height of the current map in Position units, multiply by\n       * TILE_SIZE (which is 32). */\n      virtual int mapHeight() = 0;\n\n      /** Returns the file name of the current map. */\n      virtual std::string mapFileName() = 0;\n\n      /** Returns the full path name of the current map. */\n      virtual std::string mapPathName() = 0;\n\n      /** Returns the name/title of the current map. */\n      virtual std::string mapName() = 0;\n\n      /** Returns the SHA-1 hash of the map file. */\n      virtual std::string mapHash() = 0;\n\n      /** Returns true if the specified walk tile is walkable. The values of x and y are in walk tile\n       * coordinates (different from build tile coordinates). Note that this just uses the static map data.\n       * You will also need to make sure no ground units are on the coresponding build tile to see if its\n       * currently walkable. To do this, see unitsOnTile. */\n      virtual bool isWalkable(int walkX, int walkY) = 0;\n\n      /** Returns the ground height of the given build tile. 0 = normal, 1 = high ground.  2 = very high ground. */\n      virtual int  getGroundHeight(int tileX, int tileY) = 0;\n      /** Returns the ground height of the given build tile. 0 = normal, 1 = high ground. 2 = very high ground. */\n      virtual int  getGroundHeight(TilePosition position) = 0;\n\n      /** Returns true if the specified build tile is buildable. Note that this just uses the static map data.\n       * You will also need to make sure no ground units on the tile to see if its currently buildable. To do\n       * this, see unitsOnTile. */\n      virtual bool isBuildable(int tileX, int tileY) = 0;\n      /** \\copydoc isBuildable(int, int) */\n      virtual bool isBuildable(TilePosition position) = 0;\n\n      /** Returns true if the specified build tile is visible. If the tile is concealed by fog of war, the\n       * function will return false. */\n      virtual bool isVisible(int tileX, int tileY) = 0;\n      /** \\copydoc isVisible(int, int) */\n      virtual bool isVisible(TilePosition position) = 0;\n\n      /** Returns true if the specified build tile has been explored (i.e. was visible at some point in the\n       * match). */\n      virtual bool isExplored(int tileX, int tileY) = 0;\n      /** \\copydoc isExplored(int, int) */\n      virtual bool isExplored(TilePosition position) = 0;\n\n      /** Returns true if the specified build tile has zerg creep on it. If the tile is concealed by fog of\n       * war, the function will return false. */\n      virtual bool hasCreep(int tileX, int tileY) = 0;\n      /** \\copydoc hasCreep(int, int) */\n      virtual bool hasCreep(TilePosition position) = 0;\n\n      /** Returns true if the given build location is powered by a nearby friendly pylon. */\n      virtual bool hasPower(int tileX, int tileY, int tileWidth, int tileHeight) = 0;\n      /** \\copydoc hasPower(int, int, int, int) */\n      virtual bool hasPower(TilePosition position, int tileWidth, int tileHeight) = 0;\n\n      /** Returns true if the given unit type can be built at the given build tile position. Note the tile\n       * position specifies the top left tile of the building. If builder is not null, the unit will be\n       * discarded when determining whether or not any ground units are blocking the build location. */\n      virtual bool canBuildHere(Unit *builder, TilePosition position, UnitType type, bool checkExplored = false) = 0;\n\n      /** Returns true if the AI player has enough resources, supply, tech, and required units in order to\n       * make the given unit type. If builder is not null, canMake will return true only if the builder unit\n       * can build the given unit type. */\n      virtual bool canMake(Unit *builder, UnitType type) = 0;\n\n      /** Returns true if the AI player has enough resources required to research the given tech type. If unit\n       * is not null, canResearch will return true only if the given unit can research the given tech type. */\n      virtual bool canResearch(Unit *unit, TechType type) = 0;\n\n      /** Returns true if the AI player has enough resources required to upgrade the given upgrade type. If\n       * unit is not null, canUpgrade will return true only if the given unit can upgrade the given upgrade\n       * type. */\n      virtual bool canUpgrade(Unit *unit, UpgradeType type) = 0;\n\n      /** Returns the set of starting locations for the given map. To determine the starting location for the\n       * players in the current match, see Player::getStartLocation. */\n      virtual std::set< TilePosition >& getStartLocations() = 0;\n\n      /** Prints text on the screen. Text is not sent to other players in multiplayer games. */\n      virtual void printf(const char *format, ...) = 0;\n\n      /** Sends text to other players - as if it were entered in chat. In single player games and replays,\n       * this will just print the text on the screen. If the game is a single player match and not a replay,\n       * then this function can be used to execute cheat codes, i.e. Broodwar->sendText(\"show me the money\"). */\n      virtual void sendText(const char *format, ...) = 0;\n      virtual void sendTextEx(bool toAllies, const char *format, ...) = 0;\n\n      /** Used to change the race while in a lobby. Note that there is no onLobbyEnter callback yet, so this\n       * function cannot be used at this time. */\n      virtual void changeRace(Race race) = 0;\n\n      /** Returns true if Broodwar is in a game. Returns false for lobby and menu screens */\n      virtual bool isInGame() = 0;\n\n      /** Returns true if Broodwar is in a multiplayer game. Returns false for single player games and\n       * replays. */\n      virtual bool isMultiplayer() = 0;\n\n      /** Returns true if Broodwar is in a BNet multiplayer game.\n      */\n      virtual bool isBattleNet() = 0;\n\n      /** Returns true if Broodwar is paused. If the game is paused, Game::getFrameCount will continue to\n       * increase and AIModule::onFrame will still be called while paused. */\n      virtual bool isPaused() = 0;\n\n      /** Returns true if Broodwar is in a replay. */\n      virtual bool isReplay() = 0;\n\n      /** Used to start the game while in a lobby. Note that there is no onLobbyEnter callback yet, so this\n       * function cannot be used at this time. */\n      virtual void startGame() = 0;\n\n      /** Pauses the game. If the game is paused, Game::getFrameCount will not increase however\n       * AIModule::onFrame will still be called while paused. */\n      virtual void pauseGame() = 0;\n\n      /** Resumes the game. */\n      virtual void resumeGame() = 0;\n\n      /** Leaves the current match and goes to the after-game stats screen. */\n      virtual void leaveGame() = 0;\n\n      /** Restarts the match. Works the same way as if you restarted the match from the menu screen. Only\n       * available in single player mode. */\n      virtual void restartGame() = 0;\n\n      /** Sets the speed of the game to the given number. Lower numbers are faster. 0 is the fastest speed\n       * StarCraft can handle (which is about as fast as the fastest speed you can view a replay at). Any\n       * negative value will reset the speed to the StarCraft default. */\n      virtual void setLocalSpeed(int speed = -1) = 0;\n\n      /** Returns the set of units currently selected by the user in the GUI. If Flag?::UserInput? was not\n       * enabled during the AIModule::onStart callback, this function will always return an empty set. */\n      virtual std::set<Unit*>& getSelectedUnits() = 0;\n\n      /** Returns a pointer to the player that BWAPI controls. In replays this will return null. */\n      virtual Player* self() = 0;\n\n      /** Returns a pointer to the enemy player. If there is more than one enemy, this returns a pointer to\n       * just one enemy (see getPlayers  and Player::isEnemy to get the other enemies). In replays this will\n       * return NULL. */\n      virtual Player* enemy() = 0;\n\n      virtual void setTextSize(int size = 1) = 0;\n      /** Draws text on the screen at the given position. Text can be drawn in different colors by using the\n       * following control characters: TODO: add image from wiki.*/\n      virtual void drawText(int ctype, int x, int y, const char* text, ...) = 0;\n      virtual void drawTextMap(int x, int y, const char* text, ...) = 0;\n      virtual void drawTextMouse(int x, int y, const char* text, ...) = 0;\n      virtual void drawTextScreen(int x, int y, const char* text, ...) = 0;\n\n      /** Draws a box on the screen, with the given color. If isSolid is true, the entire box will be\n       * rendered, otherwise just the outline will be drawn. */\n      virtual void drawBox(int ctype, int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0;\n      virtual void drawBoxMap(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0;\n      virtual void drawBoxMouse(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0;\n      virtual void drawBoxScreen(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0;\n\n      /** Draws a triangle on the screen. If isSolid is true, a solid triangle is drawn, otherwise just the\n       * outline of the triangle will be drawn. */\n      virtual void drawTriangle(int ctype, int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0;\n      virtual void drawTriangleMap(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0;\n      virtual void drawTriangleMouse(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0;\n      virtual void drawTriangleScreen(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0;\n\n      /** Draws a circle on the screen, with the given color. If isSolid is true, a solid circle is drawn,\n       * otherwise just the outline of a circle will be drawn. */\n      virtual void drawCircle(int ctype, int x, int y, int radius, Color color, bool isSolid = false) = 0;\n      virtual void drawCircleMap(int x, int y, int radius, Color color, bool isSolid = false) = 0;\n      virtual void drawCircleMouse(int x, int y, int radius, Color color, bool isSolid = false) = 0;\n      virtual void drawCircleScreen(int x, int y, int radius, Color color, bool isSolid = false) = 0;\n\n      /** Draws an ellipse on the screen, with the given color. If isSolid is true, a solid ellipse is drawn,\n       * otherwise just the outline of an ellipse will be drawn. */\n      virtual void drawEllipse(int ctype, int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0;\n      virtual void drawEllipseMap(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0;\n      virtual void drawEllipseMouse(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0;\n      virtual void drawEllipseScreen(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0;\n\n      /** Draws a dot on the screen at the given position with the given color. */\n      virtual void drawDot(int ctype, int x, int y, Color color) = 0;\n      virtual void drawDotMap(int x, int y, Color color) = 0;\n      virtual void drawDotMouse(int x, int y, Color color) = 0;\n      virtual void drawDotScreen(int x, int y, Color color) = 0;\n\n      /** Draws a line on the screen from (x1,y1) to (x2,y2) with the given color. */\n      virtual void drawLine(int ctype, int x1, int y1, int x2, int y2, Color color) = 0;\n      virtual void drawLineMap(int x1, int y1, int x2, int y2, Color color) = 0;\n      virtual void drawLineMouse(int x1, int y1, int x2, int y2, Color color) = 0;\n      virtual void drawLineScreen(int x1, int y1, int x2, int y2, Color color) = 0;\n\n      /** Retrieves the screen buffer for the game (excluding the HUD) */\n      virtual void *getScreenBuffer() = 0;\n\n      /** Retrieves latency values for the game. Includes latency, speed, and mode */\n      virtual int getLatencyFrames() = 0;\n      virtual int getLatencyTime() = 0;\n      virtual int getRemainingLatencyFrames() = 0;\n      virtual int getRemainingLatencyTime() = 0;\n\n      /** Retrieves the current revision of BWAPI. */\n      virtual int getRevision() = 0;\n\n      /** Retrieves the debug state of the BWAPI build. */\n      virtual bool isDebug() = 0;\n\n      /** Returns true if latency compensation is enabled */\n      virtual bool isLatComEnabled() = 0;\n\n      /** Use to enable or disable latency compensation. Default: Enabled */\n      virtual void setLatCom(bool isEnabled) = 0;\n\n      /** Retrieves the number of frames in the replay */\n      virtual int getReplayFrameCount() = 0;\n\n      /** Sets the rendering state of the Starcraft GUI */\n      virtual void setGUI(bool enabled = true) = 0;\n\n      /** Retrieves the instance number recorded by BWAPI to identify which instance an AI module belongs to */\n      virtual int  getInstanceNumber() = 0;\n  };\n  extern Game* Broodwar;\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/GameType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class GameType\n  {\n    public:\n      GameType();\n      GameType(int id);\n      GameType(const GameType& other);\n      GameType& operator=(const GameType& other);\n      bool operator==(const GameType& other) const;\n      bool operator!=(const GameType& other) const;\n      bool operator<(const GameType& other) const;\n\n      /** Returns the unique ID for this game type. */\n      int getID() const;\n\n      /** Returns the name of the game type. For example GameTypes::Melee.getName() will return an\n       * std::string object containing \"Melee\". */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace GameTypes\n  {\n    /** Given the name of a game type, this function will return the GameType. For example:\n     *  GameTypes::getGameType(\"Free For All\") will return GameTypes::Free_For_All. */\n    GameType getGameType(std::string name);\n\n    /** Returns the set of all the GameTypes. */\n    std::set<GameType>& allGameTypes();\n    void init();\n    extern const GameType Melee;\n    extern const GameType Free_For_All;\n    extern const GameType One_on_One;\n    extern const GameType Capture_The_Flag;\n    extern const GameType Greed;\n    extern const GameType Slaughter;\n    extern const GameType Sudden_Death;\n    extern const GameType Ladder;\n    extern const GameType Use_Map_Settings;\n    extern const GameType Team_Melee;\n    extern const GameType Team_Free_For_All;\n    extern const GameType Team_Capture_The_Flag;\n    extern const GameType Top_vs_Bottom;\n    extern const GameType Pro_Gamer_League;\n    extern const GameType None;\n    extern const GameType Unknown;\n  }\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Input.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  enum MouseButton\n  {\n    M_LEFT   = 0,\n    M_RIGHT  = 1,\n    M_MIDDLE = 2,\n  };\n\n  enum Key\n  {\n    K_LBUTTON             = 0x01,\n    K_RBUTTON             = 0x02,\n    K_CANCEL              = 0x03,\n    K_MBUTTON             = 0x04,\n    K_XBUTTON1            = 0x05,\n    K_XBUTTON2            = 0x06,\n    K_BACK                = 0x08,\n    K_TAB                 = 0x09,\n    K_CLEAR               = 0x0C,\n    K_RETURN              = 0x0D,\n    K_SHIFT               = 0x10,\n    K_CONTROL             = 0x11,\n    K_MENU                = 0x12,\n    K_PAUSE               = 0x13,\n    K_CAPITAL             = 0x14,\n    K_KANA                = 0x15,\n    K_HANGEUL             = 0x15,\n    K_HANGUL              = 0x15,\n    K_JUNJA               = 0x17,\n    K_FINAL               = 0x18,\n    K_HANJA               = 0x19,\n    K_KANJI               = 0x19,\n    K_ESCAPE              = 0x1B,\n    K_CONVERT             = 0x1C,\n    K_NONCONVERT          = 0x1D,\n    K_ACCEPT              = 0x1E,\n    K_MODECHANGE          = 0x1F,\n    K_SPACE               = 0x20,\n    K_PRIOR               = 0x21,\n    K_NEXT                = 0x22,\n    K_END                 = 0x23,\n    K_HOME                = 0x24,\n    K_LEFT                = 0x25,\n    K_UP                  = 0x26,\n    K_RIGHT               = 0x27,\n    K_DOWN                = 0x28,\n    K_SELECT              = 0x29,\n    K_PRINT               = 0x2A,\n    K_EXECUTE             = 0x2B,\n    K_SNAPSHOT            = 0x2C,\n    K_INSERT              = 0x2D,\n    K_DELETE              = 0x2E,\n    K_HELP                = 0x2F,\n    K_0                   = 0x30,\n    K_1                   = 0x31,\n    K_2                   = 0x32,\n    K_3                   = 0x33,\n    K_4                   = 0x34,\n    K_5                   = 0x35,\n    K_6                   = 0x36,\n    K_7                   = 0x37,\n    K_8                   = 0x38,\n    K_9                   = 0x39,\n    K_A                   = 0x41,\n    K_B                   = 0x42,\n    K_C                   = 0x43,\n    K_D                   = 0x44,\n    K_E                   = 0x45,\n    K_F                   = 0x46,\n    K_G                   = 0x47,\n    K_H                   = 0x48,\n    K_I                   = 0x49,\n    K_J                   = 0x4A,\n    K_K                   = 0x4B,\n    K_L                   = 0x4C,\n    K_M                   = 0x4D,\n    K_N                   = 0x4E,\n    K_O                   = 0x4F,\n    K_P                   = 0x50,\n    K_Q                   = 0x51,\n    K_R                   = 0x52,\n    K_S                   = 0x53,\n    K_T                   = 0x54,\n    K_U                   = 0x55,\n    K_V                   = 0x56,\n    K_W                   = 0x57,\n    K_X                   = 0x58,\n    K_Y                   = 0x59,\n    K_Z                   = 0x5A,\n    K_LWIN                = 0x5B,\n    K_RWIN                = 0x5C,\n    K_APPS                = 0x5D,\n    K_SLEEP               = 0x5F,\n    K_NUMPAD0             = 0x60,\n    K_NUMPAD1             = 0x61,\n    K_NUMPAD2             = 0x62,\n    K_NUMPAD3             = 0x63,\n    K_NUMPAD4             = 0x64,\n    K_NUMPAD5             = 0x65,\n    K_NUMPAD6             = 0x66,\n    K_NUMPAD7             = 0x67,\n    K_NUMPAD8             = 0x68,\n    K_NUMPAD9             = 0x69,\n    K_MULTIPLY            = 0x6A,\n    K_ADD                 = 0x6B,\n    K_SEPARATOR           = 0x6C,\n    K_SUBTRACT            = 0x6D,\n    K_DECIMAL             = 0x6E,\n    K_DIVIDE              = 0x6F,\n    K_F1                  = 0x70,\n    K_F2                  = 0x71,\n    K_F3                  = 0x72,\n    K_F4                  = 0x73,\n    K_F5                  = 0x74,\n    K_F6                  = 0x75,\n    K_F7                  = 0x76,\n    K_F8                  = 0x77,\n    K_F9                  = 0x78,\n    K_F10                 = 0x79,\n    K_F11                 = 0x7A,\n    K_F12                 = 0x7B,\n    K_F13                 = 0x7C,\n    K_F14                 = 0x7D,\n    K_F15                 = 0x7E,\n    K_F16                 = 0x7F,\n    K_F17                 = 0x80,\n    K_F18                 = 0x81,\n    K_F19                 = 0x82,\n    K_F20                 = 0x83,\n    K_F21                 = 0x84,\n    K_F22                 = 0x85,\n    K_F23                 = 0x86,\n    K_F24                 = 0x87,\n    K_NUMLOCK             = 0x90,\n    K_SCROLL              = 0x91,\n    K_OEM_NEC_EQUAL       = 0x92,\n    K_OEM_FJ_JISHO        = 0x92,\n    K_OEM_FJ_MASSHOU      = 0x93,\n    K_OEM_FJ_TOUROKU      = 0x94,\n    K_OEM_FJ_LOYA         = 0x95,\n    K_OEM_FJ_ROYA         = 0x96,\n    K_LSHIFT              = 0xA0,\n    K_RSHIFT              = 0xA1,\n    K_LCONTROL            = 0xA2,\n    K_RCONTROL            = 0xA3,\n    K_LMENU               = 0xA4,\n    K_RMENU               = 0xA5,\n    K_BROWSER_BACK        = 0xA6,\n    K_BROWSER_FORWARD     = 0xA7,\n    K_BROWSER_REFRESH     = 0xA8,\n    K_BROWSER_STOP        = 0xA9,\n    K_BROWSER_SEARCH      = 0xAA,\n    K_BROWSER_FAVORITES   = 0xAB,\n    K_BROWSER_HOME        = 0xAC,\n    K_VOLUME_MUTE         = 0xAD,\n    K_VOLUME_DOWN         = 0xAE,\n    K_VOLUME_UP           = 0xAF,\n    K_MEDIA_NEXT_TRACK    = 0xB0,\n    K_MEDIA_PREV_TRACK    = 0xB1,\n    K_MEDIA_STOP          = 0xB2,\n    K_MEDIA_PLAY_PAUSE    = 0xB3,\n    K_LAUNCH_MAIL         = 0xB4,\n    K_LAUNCH_MEDIA_SELECT = 0xB5,\n    K_LAUNCH_APP1         = 0xB6,\n    K_LAUNCH_APP2         = 0xB7,\n    K_OEM_1               = 0xBA,\n    K_OEM_PLUS            = 0xBB,\n    K_OEM_COMMA           = 0xBC,\n    K_OEM_MINUS           = 0xBD,\n    K_OEM_PERIOD          = 0xBE,\n    K_OEM_2               = 0xBF,\n    K_OEM_3               = 0xC0,\n    K_OEM_4               = 0xDB,\n    K_OEM_5               = 0xDC,\n    K_OEM_6               = 0xDD,\n    K_OEM_7               = 0xDE,\n    K_OEM_8               = 0xDF,\n    K_OEM_AX              = 0xE1,\n    K_OEM_102             = 0xE2,\n    K_ICO_HELP            = 0xE3,\n    K_ICO_00              = 0xE4,\n    K_PROCESSKEY          = 0xE5,\n    K_ICO_CLEAR           = 0xE6,\n    K_PACKET              = 0xE7,\n    K_OEM_RESET           = 0xE9,\n    K_OEM_JUMP            = 0xEA,\n    K_OEM_PA1             = 0xEB,\n    K_OEM_PA2             = 0xEC,\n    K_OEM_PA3             = 0xED,\n    K_OEM_WSCTRL          = 0xEE,\n    K_OEM_CUSEL           = 0xEF,\n    K_OEM_ATTN            = 0xF0,\n    K_OEM_FINISH          = 0xF1,\n    K_OEM_COPY            = 0xF2,\n    K_OEM_AUTO            = 0xF3,\n    K_OEM_ENLW            = 0xF4,\n    K_OEM_BACKTAB         = 0xF5,\n    K_ATTN                = 0xF6,\n    K_CRSEL               = 0xF7,\n    K_EXSEL               = 0xF8,\n    K_EREOF               = 0xF9,\n    K_PLAY                = 0xFA,\n    K_ZOOM                = 0xFB,\n    K_NONAME              = 0xFC,\n    K_PA1                 = 0xFD,\n    K_OEM_CLEAR           = 0xFE\n  };\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Latency.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  namespace Latency\n  {\n    enum Enum\n    {\n      SinglePlayer    = 2,\n      LanLow          = 5,\n      LanMedium       = 7,\n      LanHigh         = 9,\n      BattlenetLow    = 14,\n      BattlenetMedium = 19,\n      BattlenetHigh   = 24\n    };\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Order.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  /** To get detailed information about what a unit is doing, you can use the Unit::getOrder method, which\n   * will return an Order object. Note that a single command, like gather minerals, can consist of several\n   * orders ( MoveToMinerals, HarvestMinerals2, MiningMinerals, ReturnMinerals, etc) which will indicate what\n   * state the unit is in while executing the command. For information about how to issue commands to units,\n   * go to Unit. */\n  class Order\n  {\n    public:\n      Order();\n      Order(int id);\n      Order(const Order& other);\n      Order& operator=(const Order& other);\n      bool operator==(const Order& other) const;\n      bool operator!=(const Order& other) const;\n      bool operator<(const Order& other) const;\n\n      /** Returns the unique ID for this order. */\n      int getID() const;\n\n      /** Returns the name of this order. */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace Orders\n  {\n    /** Given the name of an order, getOrder() will return the corresponding order object. */\n    Order getOrder(std::string name);\n\n    /** Returns the set of all the Orders. */\n    std::set<Order>& allOrders();\n\n    void init();\n    extern const Order Die;\n    extern const Order Stop;\n    extern const Order Guard;\n    extern const Order PlayerGuard;\n    extern const Order TurretGuard;\n    extern const Order BunkerGuard;\n    extern const Order Move;\n    extern const Order AttackUnit;\n    extern const Order AttackTile;\n    extern const Order Hover;\n    extern const Order AttackMove;\n    extern const Order InfestedCommandCenter;\n    extern const Order UnusedNothing;\n    extern const Order UnusedPowerup;\n    extern const Order TowerGuard;\n    extern const Order VultureMine;\n    extern const Order Nothing;\n    extern const Order Nothing3;\n    extern const Order CastInfestation;\n    extern const Order InfestingCommandCenter;\n    extern const Order PlaceBuilding;\n    extern const Order BuildProtoss2;\n    extern const Order ConstructingBuilding;\n    extern const Order Repair;\n    extern const Order PlaceAddon;\n    extern const Order BuildAddon;\n    extern const Order Train;\n    extern const Order RallyPointUnit;\n    extern const Order RallyPointTile;\n    extern const Order ZergBirth;\n    extern const Order ZergUnitMorph;\n    extern const Order ZergBuildingMorph;\n    extern const Order IncompleteBuilding;\n    extern const Order BuildNydusExit;\n    extern const Order EnterNydusCanal;\n    extern const Order Follow;\n    extern const Order Carrier;\n    extern const Order ReaverCarrierMove;\n    extern const Order CarrierIgnore2;\n    extern const Order Reaver;\n    extern const Order TrainFighter;\n    extern const Order InterceptorAttack;\n    extern const Order ScarabAttack;\n    extern const Order RechargeShieldsUnit;\n    extern const Order RechargeShieldsBattery;\n    extern const Order ShieldBattery;\n    extern const Order InterceptorReturn;\n    extern const Order BuildingLand;\n    extern const Order BuildingLiftOff;\n    extern const Order DroneLiftOff;\n    extern const Order LiftingOff;\n    extern const Order ResearchTech;\n    extern const Order Upgrade;\n    extern const Order Larva;\n    extern const Order SpawningLarva;\n    extern const Order Harvest1;\n    extern const Order Harvest2;\n    extern const Order MoveToGas;\n    extern const Order WaitForGas;\n    extern const Order HarvestGas;\n    extern const Order ReturnGas;\n    extern const Order MoveToMinerals;\n    extern const Order WaitForMinerals;\n    extern const Order MiningMinerals;\n    extern const Order Harvest3;\n    extern const Order Harvest4;\n    extern const Order ReturnMinerals;\n    extern const Order Interrupted;\n    extern const Order EnterTransport;\n    extern const Order PickupIdle;\n    extern const Order PickupTransport;\n    extern const Order PickupBunker;\n    extern const Order Pickup4;\n    extern const Order PowerupIdle;\n    extern const Order Sieging;\n    extern const Order Unsieging;\n    extern const Order InitCreepGrowth;\n    extern const Order SpreadCreep;\n    extern const Order StoppingCreepGrowth;\n    extern const Order GuardianAspect;\n    extern const Order ArchonWarp;\n    extern const Order CompletingArchonsummon;\n    extern const Order HoldPosition;\n    extern const Order Cloak;\n    extern const Order Decloak;\n    extern const Order Unload;\n    extern const Order MoveUnload;\n    extern const Order FireYamatoGun;\n    extern const Order CastLockdown;\n    extern const Order Burrowing;\n    extern const Order Burrowed;\n    extern const Order Unburrowing;\n    extern const Order CastDarkSwarm;\n    extern const Order CastParasite;\n    extern const Order CastSpawnBroodlings;\n    extern const Order CastEMPShockwave;\n    extern const Order NukeWait;\n    extern const Order NukeTrain;\n    extern const Order NukeLaunch;\n    extern const Order NukeUnit;\n    extern const Order CastNuclearStrike;\n    extern const Order NukeTrack;\n    extern const Order CloakNearbyUnits;\n    extern const Order PlaceMine;\n    extern const Order RightClickAction;\n    extern const Order CastRecall;\n    extern const Order TeleporttoLocation;\n    extern const Order CastScannerSweep;\n    extern const Order Scanner;\n    extern const Order CastDefensiveMatrix;\n    extern const Order CastPsionicStorm;\n    extern const Order CastIrradiate;\n    extern const Order CastPlague;\n    extern const Order CastConsume;\n    extern const Order CastEnsnare;\n    extern const Order CastStasisField;\n    extern const Order CastHallucination;\n    extern const Order Hallucination2;\n    extern const Order ResetCollision;\n    extern const Order Patrol;\n    extern const Order CTFCOPInit;\n    extern const Order CTFCOP1;\n    extern const Order CTFCOP2;\n    extern const Order ComputerAI;\n    extern const Order AtkMoveEP;\n    extern const Order HarassMove;\n    extern const Order AIPatrol;\n    extern const Order GuardPost;\n    extern const Order RescuePassive;\n    extern const Order Neutral;\n    extern const Order ComputerReturn;\n    extern const Order SelfDestrucing;\n    extern const Order Critter;\n    extern const Order HiddenGun;\n    extern const Order OpenDoor;\n    extern const Order CloseDoor;\n    extern const Order HideTrap;\n    extern const Order RevealTrap;\n    extern const Order Enabledoodad;\n    extern const Order Disabledoodad;\n    extern const Order Warpin;\n    extern const Order Medic;\n    extern const Order MedicHeal1;\n    extern const Order HealMove;\n    extern const Order MedicHeal2;\n    extern const Order CastRestoration;\n    extern const Order CastDisruptionWeb;\n    extern const Order CastMindControl;\n    extern const Order DarkArchonMeld;\n    extern const Order CastFeedback;\n    extern const Order CastOpticalFlare;\n    extern const Order CastMaelstrom;\n    extern const Order JunkYardDog;\n    extern const Order Fatal;\n    extern const Order None;\n    extern const Order Unknown;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Player.h",
    "content": "#pragma once\n#include <set>\n#include <string>\n\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/PlayerType.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/Client/PlayerData.h>\n#include <BWAPI/Color.h>\nnamespace BWAPI\n{\n  class Unit;\n  class Force;\n\n  /** Each player in a match will have his or her own player instance. There is also a neutral player which\n   * owns all the neutral units. */\n  class Player\n  {\n    public :\n      /** Returns a unique ID for the player. */\n      virtual int getID() const = 0;\n\n      /** Returns the name of the player. */\n      virtual std::string getName() const = 0;\n\n      /** Returns the set of units the player own. Note that units loaded into Terran dropships, Terran\n       * bunkers, Terran refineries, Protoss assimilators, and Zerg extractors are not yet included in the\n       * set. */\n      virtual const std::set<Unit*>& getUnits() const = 0;\n\n      /** Returns the race of the player. */\n      virtual Race getRace() const = 0;\n\n      /** Returns the type of the player. */\n      virtual PlayerType getType() const = 0;\n\n      /** Returns the force the player is on. */\n      virtual Force* getForce() const = 0;\n\n      /** Returns true if other player is an ally of this player. */\n      virtual bool isAlly(Player* player) const = 0;\n\n      /** Returns true if other player is an enemy of this player. */\n      virtual bool isEnemy(Player* player) const = 0;\n\n      /** Returns true if the player is the neutral player. */\n      virtual bool isNeutral() const = 0;\n\n      /** Returns the starting location of the player. If complete map information is disabled, this function\n       * will return TilePositions::Unknown for enemy players. For the complete set of starting locations for\n       * the current map, see Game::getStartLocations. */\n      virtual TilePosition getStartLocation() const = 0;\n\n      /** Returns true if the player has achieved victory. */\n      virtual bool isVictorious() const = 0;\n\n      /** Returns true if the player has been defeated. */\n      virtual bool isDefeated() const = 0;\n\n      /** Returns true if the player left the game. */\n      virtual bool leftGame() const = 0;\n\n      /** Returns the amount of minerals the player has. */\n      virtual int minerals() const = 0;\n\n      /** Returns the amount of vespene gas the player has. */\n      virtual int gas() const = 0;\n\n      /** Returns the cumulative amount of minerals the player has mined up to this point (including the 50\n       * minerals at the start of the game). */\n      virtual int cumulativeMinerals() const = 0;\n\n      /** Returns the cumulative amount of gas the player has harvested up to this point. */\n      virtual int cumulativeGas() const = 0;\n\n      // TODO: ground methods\n      /** Returns the total amount of supply the player has. If a race is provided, the total supply for the\n       * given race will be returned, otherwise the player's initial race will be used. Supply counts returned\n       * by BWAPI are double what you would expect to see from playing the game. This is because zerglings\n       * take up 0.5 in-game supply. */\n      virtual int supplyTotal() const = 0;\n      virtual int supplyTotal(Race race) const = 0;\n\n      /** Returns how much of the supply is actually being used by units. If a race is provided, the used\n       * supply for the given race will be returned, otherwise the player's initial race will be used. Supply\n       * counts returned by BWAPI are double what you would expect to see from playing the game. This is\n       * because zerglings take up 0.5 in-game supply. */\n      virtual int supplyUsed() const = 0;\n      virtual int supplyUsed(Race race) const = 0;\n\n      /** Returns the number of all units of the given type. */\n      virtual int allUnitCount(UnitType unit) const = 0;\n\n      /** Returns the number of completed units of the given type. */\n      virtual int completedUnitCount(UnitType unit) const = 0;\n\n      /** Returns the number of incomplete units of the given type. */\n      virtual int incompleteUnitCount(UnitType unit) const = 0;\n\n      /** Returns the number of dead units of the given type. */\n      virtual int deadUnitCount(UnitType unit) const = 0;\n\n      /** Returns the number of killed units of the given type. */\n      virtual int killedUnitCount(UnitType unit) const = 0;\n\n      /** Returns the player's current upgrade level of the given upgrade. To order a unit to upgrade a given\n       * upgrade type, see Unit::upgrade. */\n      virtual int  getUpgradeLevel(UpgradeType upgrade) const = 0;\n\n      /** Returns true if the player has finished researching the given tech. To order a unit to research a\n       * given tech type, see Unit::research. */\n      virtual bool hasResearched(TechType tech) const = 0;\n\n      /** Returns true if the player is researching the given tech. To order a unit to research a given tech\n       * type, see Unit::reseach. */\n      virtual bool isResearching(TechType tech) const = 0;\n\n      /** Returns true if the player is upgrading the given upgrade. To order a unit to upgrade a given\n       * upgrade type, see Unit::upgrade. */\n      virtual bool isUpgrading(UpgradeType upgrade) const = 0;\n\n      /** Returns the max energy of the given unit type, taking into account upgrades */\n      virtual int maxEnergy(UnitType unit) const = 0;\n\n      /** Returns the color of the player for drawing */\n      virtual BWAPI::Color getColor() const = 0;\n\n      /** Returns the color of the player for text messages */\n      virtual int getTextColor() const = 0;\n  };\n};\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/PlayerType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class PlayerType\n  {\n    public:\n      PlayerType();\n      PlayerType(int id);\n      PlayerType(const PlayerType& other);\n      PlayerType& operator=(const PlayerType& other);\n      bool operator==(const PlayerType& other) const;\n      bool operator!=(const PlayerType& other) const;\n      bool operator<(const PlayerType& other) const;\n\n      /** Returns the unique ID for this player type. */\n      int getID() const;\n\n      /** Returns the name of the player type. For example PlayerTypes::Computer.getName() will return an\n       * std::string object containing \"Computer\". */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace PlayerTypes\n  {\n    /** Given the name of a player type, this function will return the playertype. For example:\n     *  PlayerTypes::getPlayerType(\"Human\") will return PlayerTypes::Human. */\n    PlayerType getPlayerType(std::string name);\n\n    /** Returns the set of all the PlayerTypes. */\n    std::set<PlayerType>& allPlayerTypes();\n    void init();\n    extern const PlayerType None;\n    extern const PlayerType Computer;\n    extern const PlayerType Player;\n    extern const PlayerType RescuePassive;\n    extern const PlayerType EitherPreferComputer;\n    extern const PlayerType EitherPreferHuman;\n    extern const PlayerType Neutral;\n    extern const PlayerType Closed;\n    extern const PlayerType PlayerLeft;\n    extern const PlayerType ComputerLeft;\n    extern const PlayerType Unknown;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Position.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  class TilePosition;\n\n  // TODO: Add doxygen documentation\n  class Position\n  {\n    public :\n      Position();\n      explicit Position(const TilePosition& position);\n      Position(int x, int y);\n      bool operator == (const Position& position) const;\n      bool operator != (const Position& position) const;\n      bool operator  < (const Position& position) const;\n      bool isValid() const;\n      Position operator+(const Position& position) const;\n      Position operator-(const Position& position) const;\n      Position& makeValid();\n      Position& operator+=(const Position& position);\n      Position& operator-=(const Position& position);\n      double getDistance(const Position& position) const;\n      double getApproxDistance(const Position& position) const;\n      double getLength() const;\n      int& x();\n      int& y();\n      int x() const;\n      int y() const;\n    private :\n      int _x;\n      int _y;\n  };\n  namespace Positions\n  {\n    extern const Position Invalid;\n    extern const Position None;\n    extern const Position Unknown;\n  }\n};\n\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Race.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class UnitType;\n  class Race\n  {\n    public:\n      Race();\n      Race(int id);\n      Race(const Race& other);\n      Race& operator=(const Race& other);\n      bool operator==(const Race& other) const;\n      bool operator!=(const Race& other) const;\n      bool operator<(const Race& other) const;\n\n      /** Returns a unique ID for this race. */\n      int getID() const;\n\n      /** Returns the name of the race. For example Races::Terran.getName() will return a std::string object\n       * containing \"Terran\". */\n      std::string getName() const;\n\n      /** Returns the worker unit type for the given race. For example Races::Protoss.getWorker() will return\n       * a pointer to UnitTypes::Protoss_Probe. */\n      UnitType getWorker() const;\n\n      /** Returns the center unit type for the given race. For example Races::Terran.getCenter() will return a\n       * pointer to UnitTypes::Terran_Command_Center. While there are three center types for Zerg\n       * (Hatchery, Lair, and Hive), Races::Zerg.getCenter() will only return a pointer to\n       * UnitTypes::Zerg_Hatchery, since it is the unit type needed to make a new center. */\n      UnitType getCenter() const;\n\n      /** Returns the refinery unit type for the given race. For example: Races::Zerg.getRefinery() will\n       * return a pointer to UnitTypes::Zerg_Extractor?. */\n      UnitType getRefinery() const;\n\n      /** Returns the transport unit type for the given race. For example: Races::Protoss.getTransport() will\n       * return a pointer to UnitTypes::Protoss_Shuttle. */\n      UnitType getTransport() const;\n\n      /** Returns the main supply provider unit type for the given race. For example:\n       * Races::Terran.getSupplyProvider() will return a pointer to UnitTypes::Terran_Supply_Depot?. */\n      UnitType getSupplyProvider() const;\n    private:\n      int id;\n  };\n  namespace Races\n  {\n    /** Given the name of a race, this function will return the race type. For example:\n     * Races::getRace(\"Zerg\") will return Races::Zerg. */\n    Race getRace(std::string name);\n\n    /** Returns the set of all the races, which are listed below. */\n    std::set<Race>& allRaces();\n    void init();\n    extern const Race Zerg;\n    extern const Race Terran;\n    extern const Race Protoss;\n    extern const Race Random;\n    extern const Race Other;\n    extern const Race None;\n    extern const Race Unknown;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/TechType.h",
    "content": "#pragma once\n\n#include <string>\n#include <set>\n#include <BWAPI/Race.h>\nnamespace BWAPI\n{\n  class UnitType;\n  class WeaponType;\n  class TechType\n  {\n    public:\n      TechType();\n      TechType(int id);\n      TechType(const TechType& other);\n      TechType& operator=(const TechType& other);\n      bool operator==(const TechType& other) const;\n      bool operator!=(const TechType& other) const;\n      bool operator<(const TechType& other) const;\n      /** Returns the unique ID for this tech type. */\n      int getID() const;\n\n      /** Returns the name of the tech type. */\n      std::string getName() const;\n\n      /** Returns the race that uses the TechType. For example, TechTypes::Scanner_Sweep?.getRace() will\n       * return Races::Terran. */\n      Race getRace() const;\n\n      /** Returns the mineral cost of the tech type. */\n      int mineralPrice() const;\n\n      /** Returns the vespene gas price of the tech type. */\n      int gasPrice() const;\n\n      /** Returns the number of frames needed to research the tech type. */\n      int researchTime() const;\n\n      /** Returns the amount of energy used each time this tech type is used. */\n      int energyUsed() const;\n\n      /** Returns the type of unit that researches this tech type. If this tech type is available for free\n       * (does not need to be researched), then this method will return UnitTypes::None. */\n      UnitType whatResearches() const;\n\n      /** Returns the corresponding weapon for this tech type, or TechTypes::None if no corresponding weapon\n       * exists. For example, TechTypes::Dark_Swarm.getWeapon() will return a pointer to\n       * WeaponTypes::Dark_Swarm. */\n      WeaponType getWeapon() const;\n\n      /** Returns the set of units that can use this tech type. Usually this will just be a set of one unit\n       * type, however in some cases, such as TechTypes::Burrowing, several unit types will be returned. */\n      const std::set<UnitType>& whatUses() const;\n    private:\n      int id;\n  };\n  namespace TechTypes\n  {\n    /** Given a string, this will return the tech type. */\n    TechType getTechType(std::string name);\n\n    /** Returns the set of all the TechTypes. */\n    std::set<TechType>& allTechTypes();\n    void init();\n    extern const TechType Stim_Packs;\n    extern const TechType Lockdown;\n    extern const TechType EMP_Shockwave;\n    extern const TechType Spider_Mines;\n    extern const TechType Scanner_Sweep;\n    extern const TechType Tank_Siege_Mode;\n    extern const TechType Defensive_Matrix;\n    extern const TechType Irradiate;\n    extern const TechType Yamato_Gun;\n    extern const TechType Cloaking_Field;\n    extern const TechType Personnel_Cloaking;\n    extern const TechType Burrowing;\n    extern const TechType Infestation;\n    extern const TechType Spawn_Broodlings;\n    extern const TechType Dark_Swarm;\n    extern const TechType Plague;\n    extern const TechType Consume;\n    extern const TechType Ensnare;\n    extern const TechType Parasite;\n    extern const TechType Psionic_Storm;\n    extern const TechType Hallucination;\n    extern const TechType Recall;\n    extern const TechType Stasis_Field;\n    extern const TechType Archon_Warp;\n    extern const TechType Restoration;\n    extern const TechType Disruption_Web;\n    extern const TechType Mind_Control;\n    extern const TechType Dark_Archon_Meld;\n    extern const TechType Feedback;\n    extern const TechType Optical_Flare;\n    extern const TechType Maelstrom;\n    extern const TechType Lurker_Aspect;\n    extern const TechType Healing;\n    extern const TechType None;\n    extern const TechType Unknown;\n    extern const TechType Nuclear_Strike;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/TilePosition.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  class Position;\n\n  // TODO: Add doxygen documentation\n  class TilePosition\n  {\n    public :\n      TilePosition();\n      explicit TilePosition(const Position& position);\n      TilePosition(int x, int y);\n      bool operator == (const TilePosition& TilePosition) const;\n      bool operator != (const TilePosition& TilePosition) const;\n      bool operator  < (const TilePosition& TilePosition) const;\n      bool isValid() const;\n      TilePosition operator+(const TilePosition& position) const;\n      TilePosition operator-(const TilePosition& position) const;\n      TilePosition& makeValid();\n      TilePosition& operator+=(const TilePosition& position);\n      TilePosition& operator-=(const TilePosition& position);\n      double getDistance(const TilePosition& position) const;\n      double getLength() const;\n      int& x();\n      int& y();\n      int x() const;\n      int y() const;\n    private :\n      int _x;\n      int _y;\n  };\n  namespace TilePositions\n  {\n    extern const TilePosition Invalid;\n    extern const TilePosition None;\n    extern const TilePosition Unknown;\n  }\n};\n\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/Unit.h",
    "content": "#pragma once\n\n#include <list>\n\n#include <BWAPI/Order.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/UnitCommand.h>\n#include <BWAPI/Client/UnitData.h>\nnamespace BWAPI\n{\n  class Player;\n\n  /** The Unit class is used to get information about individual units as well as issue orders to units. Each\n   * unit in the game has a unique Unit object, and Unit objects are not deleted until the end of the match\n   * (so you don't need to worry about unit pointers becoming invalid).\n   *\n   * Every Unit in the game is either accessible or inaccessible. To determine if an AI can access a\n   * particular unit, BWAPI checks to see if Flag::CompleteMapInformation? is enabled. So there are two cases\n   * to consider - either the flag is enabled, or it is disabled:\n   *\n   * If Flag::CompleteMapInformation? is disabled, then a unit is accessible if and only if it is visible.\n   * Note also that some properties of visible enemy units will not be made available to the AI (such as the\n   * contents of visible enemy dropships). If a unit is not visible, Unit::exists will return false,\n   * regardless of whether or not the unit exists. This is because absolutely no state information on\n   * invisible enemy units is made available to the AI. To determine if an enemy unit has been destroyed, the\n   * AI must watch for AIModule::onUnitDestroy messages from BWAPI, which is only called for visible units\n   * which get destroyed.\n   *\n   * If Flag::CompleteMapInformation? is enabled, then all units that exist in the game are accessible, and\n   * Unit::exists is accurate for all units. Similarly AIModule::onUnitDestroy messages are generated for all\n   * units that get destroyed, not just visible ones.\n   *\n   * If a Unit is not accessible, in general the only the getInitial__ functions will be available to the AI.\n   * However for units that were owned by the player, getPlayer and getType will continue to work for units\n   * that have been destroyed. */\n  class Unit\n  {\n    public:\n      /** Returns a unique ID for this unit. It simply casts the unit's address as an integer, since each unit\n       * has a unique address. */\n      virtual int getID() const = 0;\n\n      /** Returns a pointer to the player that owns this unit. */\n      virtual Player* getPlayer() const = 0;\n\n      /** Returns the current type of the unit. */\n      virtual UnitType getType() const = 0;\n\n      /** Returns the position of the unit on the map. */\n      virtual Position getPosition() const = 0;\n\n      /** Returns the build tile position of the unit on the map. Useful if the unit is a building. The tile\n       * position is of the top left corner of the building. */\n      virtual TilePosition getTilePosition() const = 0;\n\n      /** Returns the direction the unit is facing, measured in radians. An angle of 0 means the unit is\n       * facing east. */\n      virtual double getAngle() const = 0;\n\n      /** Returns the x component of the unit's velocity, measured in pixels per frame. */\n      virtual double getVelocityX() const = 0;\n\n      /** Returns the y component of the unit's velocity, measured in pixels per frame. */\n      virtual double getVelocityY() const = 0;\n\n      /** Returns the unit's current amount of hit points. */\n      virtual int getHitPoints() const = 0;\n\n      /** Returns the unit's current amount of shields. */\n      virtual int getShields() const = 0;\n\n      /** Returns the unit's current amount of energy. */\n      virtual int getEnergy() const = 0;\n\n      /** Returns the unit's current amount of containing resources. Useful for determining how much minerals\n       * are left in a mineral patch, or how much gas is left in a geyser\n       * (can also be called on a refinery/assimilator/extractor). */\n      virtual int getResources() const = 0;\n\n      /** Retrieves the group ID of a resource. Can be used to identify which resources belong to an expansion. */\n      virtual int getResourceGroup() const = 0;\n\n      /** Returns the edge-to-edge distance between the current unit and the target unit. */\n      virtual double getDistance(Unit* target) const = 0;\n\n      /** Returns the distance from the edge of the current unit to the target position. */\n      virtual double getDistance(Position target) const = 0;\n\n      /** Returns true if the unit is able to move to the target unit */\n      virtual bool hasPath(Unit* target) const = 0;\n\n      /** Returns true if the unit is able to move to the target position */\n      virtual bool hasPath(Position target) const = 0;\n\n      /** Retrieves the frame of the last successful order. Frame is comparable to Game::getFrameCount(). */\n      virtual int getLastOrderFrame() const = 0;\n\n      /** Returns the player's current upgrade level for the given upgrade, if the unit is affected by this\n       * upgrade.*/\n      virtual int getUpgradeLevel(UpgradeType upgrade) const = 0;\n\n      /** Returns the initial type of the unit or Unknown if it wasn't a neutral unit at the beginning of the\n       * game. */\n      virtual UnitType getInitialType() const = 0;\n\n      /** Returns the initial position of the unit on the map, or Positions::Unknown if the unit wasn't a\n       * neutral unit at the beginning of the game. */\n      virtual Position getInitialPosition() const = 0;\n\n      /** Returns the initial build tile position of the unit on the map, or TilePositions::Unknown if the\n       * unit wasn't a neutral unit at the beginning of the game. The tile position is of the top left corner\n       * of the building. */\n      virtual TilePosition getInitialTilePosition() const = 0;\n\n      /** Returns the unit's initial amount of hit points, or 0 if it wasn't a neutral unit at the beginning\n       * of the game. */\n      virtual int getInitialHitPoints() const = 0;\n\n      /** Returns the unit's initial amount of containing resources, or 0 if the unit wasn't a neutral unit\n       * at the beginning of the game. */\n      virtual int getInitialResources() const = 0;\n\n      /** Returns the unit's current kill count. */\n      virtual int getKillCount() const = 0;\n\n      /** Returns the number of interceptors the Protoss Carrier has. */\n      virtual int getInterceptorCount() const = 0;\n\n      /** Returns the number of scarabs in the Protoss Reaver. */\n      virtual int getScarabCount() const = 0;\n\n      /** Returns the number of spider mines in the Terran Vulture. */\n      virtual int getSpiderMineCount() const = 0;\n\n      /** Returns unit's ground weapon cooldown. It is 0 if the unit is ready to attack. */\n      virtual int getGroundWeaponCooldown() const = 0;\n\n      /** Returns unit's air weapon cooldown. It is 0 if the unit is ready to attack. */\n      virtual int getAirWeaponCooldown() const = 0;\n\n      /** Returns unit's ground weapon cooldown. It is 0 if the unit is ready cast a spell. */\n      virtual int getSpellCooldown() const = 0;\n\n      /** Returns the remaining hit points of the defense matrix. Initially a defense Matrix has 250 points.\n       * \\see Unit::getDefenseMatrixTimer, Unit::isDefenseMatrixed. */\n      virtual int getDefenseMatrixPoints() const = 0;\n\n      /** Returns the time until the defense matrix wears off. 0 -> No defense Matrix present. */\n      virtual int getDefenseMatrixTimer() const = 0;\n\n      /** Returns the time until the ensnare effect wears off. 0 -> No ensnare effect present. */\n      virtual int getEnsnareTimer() const = 0;\n\n      /** Returns the time until the radiation wears off. 0 -> No radiation present. */\n      virtual int getIrradiateTimer() const = 0;\n\n      /** Returns the time until the lockdown wears off. 0 -> No lockdown present. */\n      virtual int getLockdownTimer() const = 0;\n\n      /** Returns the time until the maelstrom wears off. 0 -> No maelstrom present. */\n      virtual int getMaelstromTimer() const = 0;\n\n      // TODO: add doc\n      virtual int getOrderTimer() const = 0;\n\n      /** Returns the time until the plague wears off. 0 -> No plague present. */\n      virtual int getPlagueTimer() const = 0;\n\n      /** Returns the amount of time until the unit is removed, or 0 if the unit does not have a remove timer.\n       * Used to determine how much time remains before hallucinated units, dark swarm, etc have until they\n       * are removed. */\n      virtual int getRemoveTimer() const = 0;\n\n      /** Returns the time until the stasis field wears off. 0 -> No stasis field present. */\n      virtual int getStasisTimer() const = 0;\n\n      /** Returns the time until the stimpack wears off. 0 -> No stimpack boost present. */\n      virtual int getStimTimer() const = 0;\n\n      /** Returns the building type a worker is about to construct. If the unit is a morphing Zerg unit or an\n       * incomplete building, this returns the UnitType the unit is about to become upon completion.*/\n      virtual UnitType getBuildType() const = 0;\n\n     /** Returns the list of units queued up to be trained.\n       * \\see Unit::train, Unit::cancelTrain, Unit::isTraining. */\n      virtual std::list<UnitType > getTrainingQueue() const = 0;\n\n      /** Returns the tech that the unit is currently researching. If the unit is not researching anything,\n       * TechTypes::None is returned.\n       * \\see Unit::research, Unit::cancelResearch, Unit::isResearching, Unit::getRemainingResearchTime. */\n      virtual TechType getTech() const = 0;\n\n      /** Returns the upgrade that the unit is currently upgrading. If the unit is not upgrading anything,\n       * UpgradeTypes::None is returned.\n       * \\see Unit::upgrade, Unit::cancelUpgrade, Unit::isUpgrading, Unit::getRemainingUpgradeTime. */\n      virtual UpgradeType getUpgrade() const = 0;\n\n      /** Returns the remaining build time of a unit/building that is being constructed. */\n      virtual int getRemainingBuildTime() const = 0;\n\n      /** Returns the remaining time of the unit that is currently being trained. If the unit is a Hatchery,\n       * Lair, or Hive, this returns the amount of time until the next larva spawns, or 0 if the unit already\n       * has 3 larva. */\n      virtual int getRemainingTrainTime() const = 0;\n\n      /** Returns the amount of time until the unit is done researching its current tech. If the unit is not\n       * researching anything, 0 is returned.\n       * \\see Unit::research, Unit::cancelResearch, Unit::isResearching, Unit::getTech. */\n      virtual int getRemainingResearchTime() const = 0;\n\n      /** Returns the amount of time until the unit is done upgrading its current upgrade. If the unit is not\n       * upgrading anything, 0 is returned.\n       * \\see Unit::upgrade, Unit::cancelUpgrade, Unit::isUpgrading, Unit::getUpgrade. */\n      virtual int getRemainingUpgradeTime() const = 0;\n\n      /** If the unit is an SCV that is constructing a building, this will return the building it is\n       * constructing. If the unit is a Terran building that is being constructed, this will return the SCV\n       * that is constructing it. */\n      virtual Unit* getBuildUnit() const = 0;\n\n      /** Generally returns the appropriate target unit after issuing an order that accepts a target unit\n       * (i.e. attack, repair, gather, follow, etc.). To check for a target that has been acquired\n       * automatically (without issuing an order) see getOrderTarget. */\n      virtual Unit* getTarget() const = 0;\n\n      /** Returns the target position the unit is moving to (provided a valid path to the target position\n       * exists). */\n      virtual Position getTargetPosition() const = 0;\n\n      // TODO: add doc\n      virtual Order getOrder() const = 0;\n\n      /** This is usually set when the low level unit AI acquires a new target automatically. For example if\n       * an enemy probe comes in range of your marine, the marine will start attacking it, and getOrderTarget\n       * will be set in this case, but not getTarget. */\n      virtual Unit* getOrderTarget() const = 0;\n      virtual Order getSecondaryOrder() const = 0;\n\n      /** Returns the position the building is rallied to. If the building does not produce units,\n       * Positions::None is returned.\n       * \\see Unit::setRallyPoint, Unit::getRallyUnit. */\n      virtual Position getRallyPosition() const = 0;\n\n      /** Returns the unit the building is rallied to. If the building is not rallied to any unit, NULL is\n       * returned.\n       * \\see Unit::setRallyPoint, Unit::getRallyPosition. */\n      virtual Unit* getRallyUnit() const = 0;\n\n      /** Returns the add-on of this unit, or NULL if the unit doesn't have an add-on. */\n      virtual Unit* getAddon() const = 0;\n\n      /** Returns the corresponding connected nydus canal of this unit, or NULL if the unit does not have a\n       * connected nydus canal. */\n      virtual Unit* getNydusExit() const = 0;\n\n      /** Returns the power up the unit is holding, or NULL if the unit is not holding a power up */\n      virtual Unit* getPowerUp() const = 0;\n\n      /** Returns the dropship, shuttle, overlord, or bunker that is this unit is loaded in to. */\n      virtual Unit* getTransport() const = 0;\n\n      /** Returns a list of the units loaded into a Terran Bunker, Terran Dropship, Protoss Shuttle, or Zerg\n       * Overlord. */\n      virtual std::set<Unit*> getLoadedUnits() const = 0;\n\n      /** For Protoss Interceptors, this returns the Carrier unit this Interceptor is controlled by. For all\n       * other unit types this function returns NULL. */\n      virtual Unit* getCarrier() const = 0;\n\n      /** Returns the set of interceptors controlled by this unit. If the unit has no interceptors, or is not\n       * a Carrier, this function returns an empty set. */\n      virtual std::set<Unit*> getInterceptors() const = 0;\n\n      /** For Zerg Larva, this returns the Hatchery, Lair, or Hive unit this Larva was spawned from. For all\n       * other unit types this function returns NULL. */\n      virtual Unit* getHatchery() const = 0;\n\n      /** Returns the set of larva spawned by this unit. If the unit has no larva, or is not a Hatchery, Lair,\n       * or Hive, this function returns an empty set. Equivalent to clicking \"Select Larva\" from the Starcraft\n       * GUI. */\n      virtual std::set<Unit*> getLarva() const = 0;\n\n      /**\n       * 3 cases to consider:\n       *\n       * - If exists() returns true, the unit exists.\n       * - If exists() returns false and the unit is owned by self(), then the unit does not exist.\n       * - If exists() returns false and the unit is not owned by self(), then the unit may or may not exist.\n       *\n       * \\see Unit::isVisible.\n       * */\n      virtual bool exists() const = 0;\n\n      /* Returns true if the Nuclear Missile Silo has a nuke */\n      virtual bool hasNuke() const = 0;\n\n      /** Returns true if the unit is currently accelerating. */\n      virtual bool isAccelerating() const = 0;\n\n      // TODO: add doc\n      virtual bool isAttacking() const = 0;\n\n      /** Returns true if the unit is being constructed. Always true for incomplete Protoss and Zerg\n       * buildings, and true for incomplete Terran buildings that have an SCV constructing them. If the SCV\n       * halts construction, isBeingConstructed will return false.\n       *\n       * \\see Unit::build, Unit::cancelConstruction, Unit::haltConstruction, Unit::isConstructing. */\n      virtual bool isBeingConstructed() const = 0;\n\n      /** Returns true if the unit is a mineral patch or refinery that is being gathered. */\n      virtual bool isBeingGathered() const = 0;\n\n      /** Returns true if the unit is currently being healed by a Terran Medic, or repaired by a Terran SCV. */\n      virtual bool isBeingHealed() const = 0;\n\n      /** Returns true if the unit is currently blind from a Medic's Optical Flare. */\n      virtual bool isBlind() const = 0;\n\n      /** Returns true if the unit is currently braking/slowing down. */\n      virtual bool isBraking() const = 0;\n\n      /** Returns true if the unit is a Zerg unit that is current burrowed.\n       * \\see Unit::burrow, Unit::unburrow. */\n      virtual bool isBurrowed() const = 0;\n\n      /** Returns true if the unit is a worker that is carrying gas.\n       * \\see Unit::returnCargo, Unit::isGatheringGas. */\n      virtual bool isCarryingGas() const = 0;\n\n      /** Returns true if the unit is a worker that is carrying minerals.\n       * \\see Unit::returnCargo, Unit::isGatheringMinerals. */\n      virtual bool isCarryingMinerals() const = 0;\n\n      /** Returns true if the unit is cloaked.\n       * \\see Unit::cloak, Unit::decloak. */\n      virtual bool isCloaked() const = 0;\n\n      /** Returns true if the unit has been completed. */\n      virtual bool isCompleted() const = 0;\n\n      /** Returns true when a unit has been issued an order to build a structure and is moving to the build\n       * location. Also returns true for Terran SCVs while they construct a building.\n       * \\see Unit::build, Unit::cancelConstruction, Unit::haltConstruction, Unit::isBeingConstructed. */\n      virtual bool isConstructing() const = 0;\n\n      /** Returns true if the unit has a defense matrix from a Terran Science Vessel. */\n      virtual bool isDefenseMatrixed() const = 0;\n\n      /** Returns true if the unit is detected. */\n      virtual bool isDetected() const = 0;\n\n      /** Returns true if the unit has been ensnared by a Zerg Queen. */\n      virtual bool isEnsnared() const = 0;\n\n      /** Returns true if the unit is following another unit.\n       * \\see Unit::follow, Unit::getTarget. */\n      virtual bool isFollowing() const = 0;\n\n      /** Returns true if the unit is in one of the four states for gathering gas (MoveToGas, WaitForGas,\n       * HarvestGas, ReturnGas).\n       * \\see Unit::isCarryingGas. */\n      virtual bool isGatheringGas() const = 0;\n\n      /** Returns true if the unit is in one of the four states for gathering minerals (MoveToMinerals,\n       * WaitForMinerals, MiningMinerals, ReturnMinerals).\n       * \\see Unit::isCarryingMinerals. */\n      virtual bool isGatheringMinerals() const = 0;\n\n      /** Returns true for hallucinated units, false for normal units. Returns true for hallucinated enemy\n       * units only if Complete Map Information is enabled.\n       * \\see Unit::getRemoveTimer. */\n      virtual bool isHallucination() const = 0;\n\n      /** Returns true if the unit is holding position\n       * \\see Unit::holdPosition. */\n      virtual bool isHoldingPosition() const = 0;\n\n      /** Returns true if the unit is not doing anything.\n       * \\see Unit::stop. */\n      virtual bool isIdle() const = 0;\n\n      /** Returns true if the unit can be interrupted. */\n      virtual bool isInterruptible() const = 0;\n\n      /** Returns true if the unit is being irradiated by a Terran Science Vessel.\n       * \\see Unit::getIrradiateTimer. */\n      virtual bool isIrradiated() const = 0;\n\n      /** Returns true if the unit is a Terran building that is currently lifted off the ground.\n       * \\see Unit::lift,Unit::land. */\n      virtual bool isLifted() const = 0;\n\n      /** Return true if the unit is loaded into a Terran Bunker, Terran Dropship, Protoss Shuttle, or Zerg\n       * Overlord.\n       * \\see Unit::load, Unit::unload, Unit::unloadAll. */\n      virtual bool isLoaded() const = 0;\n\n      /** Returns true if the unit is locked down by a Terran Ghost.\n       *  \\see Unit::getLockdownTimer. */\n      virtual bool isLockedDown() const = 0;\n\n      /** Returns true if the unit is being maelstrommed.\n       * \\see Unit::getMaelstromTimer. */\n      virtual bool isMaelstrommed() const = 0;\n\n      /** Returns true if the unit is a zerg unit that is morphing.\n       * \\see Unit::morph, Unit::cancelMorph, Unit::getBuildType, Unit::getRemainingBuildTime. */\n      virtual bool isMorphing() const = 0;\n\n      /** Returns true if the unit is moving.\n       * \\see Unit::attackMove, Unit::stop. */\n      virtual bool isMoving() const = 0;\n\n      /** Returns true if the unit has been parasited by some other player. */\n      virtual bool isParasited() const = 0;\n\n      /** Returns true if the unit is patrolling between two positions.\n       * \\see Unit::patrol. */\n      virtual bool isPatrolling() const = 0;\n\n      /** Returns true if the unit has been plagued by a Zerg Defiler.\n       * \\see Unit::getPlagueTimer. */\n      virtual bool isPlagued() const = 0;\n\n      /** Returns true if the unit is a Terran SCV that is repairing or moving to repair another unit. */\n      virtual bool isRepairing() const = 0;\n\n      /** Returns true if the unit is a building that is researching tech. See TechTypes for the complete list\n       * of available techs in Broodwar.\n       * \\see Unit::research, Unit::cancelResearch, Unit::getTech, Unit::getRemainingResearchTime. */\n      virtual bool isResearching() const = 0;\n\n      /** Returns true if the unit has been selected by the user via the starcraft GUI. Only available if you\n       * enable Flag::UserInput during AIModule::onStart.\n       * \\see Game::getSelectedUnits. */\n      virtual bool isSelected() const = 0;\n\n      /** Returns true if the unit is a Terran Siege Tank that is currently in Siege mode.\n       * \\see Unit::siege, Unit::unsiege. */\n      virtual bool isSieged() const = 0;\n\n      /** Returns true if the unit is starting to attack.\n       * \\see Unit::attackUnit, Unit::getGroundWeaponCooldown, Unit::getAirWeaponCooldown. */\n      virtual bool isStartingAttack() const = 0;\n\n      /** Returns true if the unit has been stasised by a Protoss Arbiter.\n       * \\see Unit::getStasisTimer. */\n      virtual bool isStasised() const = 0;\n\n      /** Returns true if the unit is currently stimmed.\n       * \\see Unit::getStimTimer. */\n      virtual bool isStimmed() const = 0;\n\n      /** Returns true if the unit is being pushed off of another unit */\n      virtual bool isStuck() const = 0;\n\n      /** Returns true if the unit is training units (i.e. a Barracks training Marines).\n       * \\see Unit::train, Unit::getTrainingQueue, Unit::cancelTrain, Unit::getRemainingTrainTime. */\n      virtual bool isTraining() const = 0;\n\n      /** Returns true if the unit is under a Protoss Psionic Storm. */\n      virtual bool isUnderStorm() const = 0;\n\n      /** Returns true if the unit is a Protoss building that is unpowered because no pylons are in range. */\n      virtual bool isUnpowered() const = 0;\n\n      /** Returns true if the unit is a building that is upgrading. See UpgradeTypes for the complete list\n       * of available upgrades in Broodwar.\n       * \\see Unit::upgrade, Unit::cancelUpgrade, Unit::getUpgrade, Unit::getRemainingUpgradeTime. */\n      virtual bool isUpgrading() const = 0;\n\n      /** Returns true if the unit is visible. If the CompleteMapInformation?  cheat flag is enabled, existing\n       * units hidden by the fog of war will be accessible, but isVisible will still return false.\n       * \\see Unit::exists. */\n      virtual bool isVisible() const = 0;\n      virtual bool isVisible(Player* player) const = 0;\n\n      /** Takes any unit command and calls the corresponding order that will execute it */\n      virtual bool issueCommand(UnitCommand command) = 0;\n\n      /** Orders the unit to attack move to the specified location. */\n      virtual bool attackMove(Position target) = 0;\n\n      /** Orders the unit to attack the specified unit. */\n      virtual bool attackUnit(Unit* target) = 0;\n\n      /** Orders the unit to build the given unit type at the given position. Note that if the player does not\n       * have enough resources when the unit attempts to place the building down, the order will fail. The\n       * tile position specifies where the top left corner of the building will be placed. */\n      virtual bool build(TilePosition target, UnitType type) = 0;\n\n      /** Orders the unit to build the given addon. The unit must be a Terran building that can have an addon\n       * and the specified unit type must be an addon unit type. */\n      virtual bool buildAddon(UnitType type) = 0;\n\n      /** Orders this unit to add the specified unit type to the training queue. Note that the player must\n       * have sufficient resources to train. If you wish to make units from a hatchery, use getLarva to get\n       * the larva associated with the hatchery and then call morph on the larva you want to morph. This\n       * command can also be used to make interceptors and scarabs. */\n      virtual bool train(UnitType type) = 0;\n\n      /** Orders the unit to morph into the specified unit type. Returns false if given a wrong type.\n       * \\see Unit::cancelMorph, Unit::isMorphing. */\n      virtual bool morph(UnitType type) = 0;\n\n      /** Orders the unit to research the given tech type.\n       * \\see Unit::cancelResearch, Unit::Unit#isResearching, Unit::getRemainingResearchTime, Unit::getTech. */\n      virtual bool research(TechType tech) = 0;\n\n      /** Orders the unit to upgrade the given upgrade type.\n       * \\see Unit::cancelUpgrade, Unit::Unit#isUpgrading, Unit::getRemainingUpgradeTime, Unit::getUpgrade. */\n      virtual bool upgrade(UpgradeType upgrade) = 0;\n\n      /** Orders the unit to set its rally position to the specified position.\n       * \\see Unit::getRallyPosition, Unit::getRallyUnit. */\n      virtual bool setRallyPoint(Position target) = 0;\n\n      /** Orders the unit to set its rally unit to the specified unit.\n       * \\see Unit::setRallyPosition, Unit::getRallyPosition, Unit::getRallyUnit. */\n      virtual bool setRallyPoint(Unit* target) = 0;\n\n      /** Orders the unit to move from its current position to the specified position.\n       * \\see Unit::isMoving.  */\n      virtual bool move(Position target) = 0;\n\n      /** Orders the unit to patrol between its current position and the specified position.\n       * \\see Unit::isPatrolling.  */\n      virtual bool patrol(Position target) = 0;\n\n      /** Orders the unit to hold its position.*/\n      virtual bool holdPosition() = 0;\n\n      /** Orders the unit to stop. */\n      virtual bool stop() = 0;\n\n      /** Orders the unit to follow the specified unit.\n       * \\see Unit::isFollowing. */\n      virtual bool follow(Unit* target) = 0;\n\n      /** Orders the unit to gather the specified unit (must be mineral or refinery type).\n       * \\see Unit::isGatheringGas, Unit::isGatheringMinerals. */\n      virtual bool gather(Unit* target) = 0;\n\n      /** Orders the unit to return its cargo to a nearby resource depot such as a Command Center. Only\n       * workers that are carrying minerals or gas can be ordered to return cargo.\n       * \\see Unit::isCarryingGas, Unit::isCarryingMinerals. */\n      virtual bool returnCargo() = 0;\n\n      /** Orders the unit to repair the specified unit. Only Terran SCVs can be ordered to repair, and the\n       * target must be a mechanical Terran unit or building.\n       * \\see Unit::isRepairing. */\n      virtual bool repair(Unit* target) = 0;\n\n      /** Orders the unit to burrow. Either the unit must be a Zerg Lurker, or the unit must be a Zerg ground\n       * unit and burrow tech must be researched.\n       * \\see: Unit::unburrow, Unit::isBurrowed. */\n      virtual bool burrow() = 0;\n\n      /** Orders the burrowed unit to unburrow.\n       * \\see: Unit::burrow, Unit::isBurrowed.\n       * */\n      virtual bool unburrow() = 0;\n\n      /** Orders the unit to cloak.\n       * \\see: Unit::decloak, Unit::isCloaked. */\n      virtual bool cloak() = 0;\n\n      /** Orders the unit to decloak.\n       * \\see: Unit::cloak, Unit::isCloaked. */\n      virtual bool decloak() = 0;\n\n      /** Orders the unit to siege. Note: unit must be a Terran siege tank.\n       * \\see Unit::unsiege, Unit::isSieged. */\n      virtual bool siege() = 0;\n\n      /** Orders the unit to unsiege. Note: unit must be a Terran siege tank.\n       * \\see: Unit::unsiege, Unit::isSieged. */\n      virtual bool unsiege() = 0;\n\n      /** Orders the unit to lift. Note: unit must be a Terran building that can be lifted.\n       * \\see Unit::land, Unit::isLifted.  */\n      virtual bool lift() = 0;\n\n      /** Orders the unit to land. Note: unit must be a Terran building that is currently lifted.\n       * \\see Unit::lift, Unit::isLifted. */\n      virtual bool land(TilePosition target) = 0;\n\n      /** Orders the unit to load the target unit.\n       * \\see Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */\n      virtual bool load(Unit* target) = 0;\n\n      /** Orders the unit to unload the target unit.\n       * \\see Unit::load, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */\n      virtual bool unload(Unit* target) = 0;\n\n      /** Orders the unit to unload all loaded units at the unit's current position.\n       * \\see Unit::load, Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */\n      virtual bool unloadAll() = 0;\n\n      /** Orders the unit to unload all loaded units at the specified location. Unit should be a Terran\n       * Dropship, Protoss Shuttle, or Zerg Overlord. If the unit is a Terran Bunker, the units will be\n       * unloaded right outside the bunker, like in the first version of unloadAll.\n       * \\see Unit::load, Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */\n      virtual bool unloadAll(Position target) = 0;\n\n      /** Works like the right click in the GUI. */\n      virtual bool rightClick(Position target) = 0;\n\n      /** Works like the right click in the GUI. Right click on a mineral patch to order a worker to mine,\n       * right click on an enemy to attack it. */\n      virtual bool rightClick(Unit* target) = 0;\n\n      /** Orders the SCV to stop constructing the building, and the building is left in a partially complete\n       * state until it is canceled, destroyed, or completed.\n       * \\see Unit::isConstructing. */\n      virtual bool haltConstruction() = 0;\n\n      /** Orders the building to stop being constructed.\n       * \\see Unit::beingConstructed. */\n      virtual bool cancelConstruction() = 0;\n\n      /** Orders the unit to stop making the addon. */\n      virtual bool cancelAddon() = 0;\n\n      /** Orders the unit to remove the specified unit from its training queue.\n       * \\see Unit::train, Unit::cancelTrain, Unit::isTraining, Unit::getTrainingQueue. */\n      virtual bool cancelTrain(int slot = -2) = 0;\n\n      /** Orders the unit to stop morphing.\n       * \\see Unit::morph, Unit::isMorphing. */\n      virtual bool cancelMorph() = 0;\n\n      /** Orders the unit to cancel a research in progress.\n       * \\see Unit::research, Unit::isResearching, Unit::getTech. */\n      virtual bool cancelResearch() = 0;\n\n      /** Orders the unit to cancel an upgrade in progress.\n       * \\see Unit::upgrade, Unit::isUpgrading, Unit::getUpgrade. */\n      virtual bool cancelUpgrade() = 0;\n\n      /** Orders the unit to use a tech not requiring a target (ie Stim Pack). Returns true if it is a valid\n       * tech. */\n      virtual bool useTech(TechType tech) = 0;\n\n      /** Orders the unit to use a tech requiring a position target (ie Dark Swarm). Returns true if it is a\n       * valid tech.*/\n      virtual bool useTech(TechType tech, Position target) = 0;\n\n      /** Orders the unit to use a tech requiring a unit target (ie Irradiate). Returns true if it is a valid\n       * tech.*/\n      virtual bool useTech(TechType tech, Unit* target) = 0;\n\n      /** Sets the unit's custom client info. The client is responsible for deallocation. */\n      virtual void setClientInfo(void* clientinfo) = 0;\n\n      /** Returns the unit's custom client info. The client is responsible for deallocation. */\n      virtual void* getClientInfo() const = 0;\n  };\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/UnitCommand.h",
    "content": "#pragma once\n\n#include <BWAPI/UnitCommandType.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/UnitType.h>\n\nnamespace BWAPI\n{\n  class Unit;\n  class UnitCommand\n  {\n    public:\n      UnitCommand() : target(NULL), x(0), y(0), extra(0) { type = UnitCommandTypes::None; }\n      UnitCommand(Unit* source, UnitCommandType _type, Unit* _target, int _x, int _y, int _extra) : unit(source), type(_type), target(_target), x(_x), y(_y), extra(_extra) {}\n\n      static UnitCommand attackMove(Unit* unit, Position target);\n      static UnitCommand attackUnit(Unit* unit, Unit* target);\n      static UnitCommand build(Unit* unit, TilePosition target, UnitType type);\n      static UnitCommand buildAddon(Unit* unit, UnitType type);\n      static UnitCommand train(Unit* unit, UnitType type);\n      static UnitCommand morph(Unit* unit, UnitType type);\n      static UnitCommand research(Unit* unit, TechType tech);\n      static UnitCommand upgrade(Unit* unit, UpgradeType upgrade);\n      static UnitCommand setRallyPosition(Unit* unit, Position target);\n      static UnitCommand setRallyUnit(Unit* unit, Unit* target);\n      static UnitCommand move(Unit* unit, Position target);\n      static UnitCommand patrol(Unit* unit, Position target);\n      static UnitCommand holdPosition(Unit* unit);\n      static UnitCommand stop(Unit* unit);\n      static UnitCommand follow(Unit* unit, Unit* target);\n      static UnitCommand gather(Unit* unit, Unit* target);\n      static UnitCommand returnCargo(Unit* unit);\n      static UnitCommand repair(Unit* unit, Unit* target);\n      static UnitCommand burrow(Unit* unit);\n      static UnitCommand unburrow(Unit* unit);\n      static UnitCommand cloak(Unit* unit);\n      static UnitCommand decloak(Unit* unit);\n      static UnitCommand siege(Unit* unit);\n      static UnitCommand unsiege(Unit* unit);\n      static UnitCommand lift(Unit* unit);\n      static UnitCommand land(Unit* unit, TilePosition target);\n      static UnitCommand load(Unit* unit, Unit* target);\n      static UnitCommand unload(Unit* unit, Unit* target);\n      static UnitCommand unloadAll(Unit* unit);\n      static UnitCommand unloadAll(Unit* unit, Position target);\n      static UnitCommand rightClick(Unit* unit, Position target);\n      static UnitCommand rightClick(Unit* unit, Unit* target);\n      static UnitCommand haltConstruction(Unit* unit);\n      static UnitCommand cancelConstruction(Unit* unit);\n      static UnitCommand cancelAddon(Unit* unit);\n      static UnitCommand cancelTrain(Unit* unit, int slot = -2);\n      static UnitCommand cancelMorph(Unit* unit);\n      static UnitCommand cancelResearch(Unit* unit);\n      static UnitCommand cancelUpgrade(Unit* unit);\n      static UnitCommand useTech(Unit* unit,TechType tech);\n      static UnitCommand useTech(Unit* unit,TechType tech, Position target);\n      static UnitCommand useTech(Unit* unit,TechType tech, Unit* target);\n      Unit* unit;\n      UnitCommandType type;\n      Unit* target;\n      int x;\n      int y;\n      int extra;\n  };\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/UnitCommandType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class UnitCommandType\n  {\n    public:\n      UnitCommandType();\n      UnitCommandType(int id);\n      UnitCommandType(const UnitCommandType& other);\n      UnitCommandType& operator=(const UnitCommandType& other);\n      bool operator==(const UnitCommandType& other) const;\n      bool operator!=(const UnitCommandType& other) const;\n      bool operator<(const UnitCommandType& other) const;\n\n      /** Returns a unique ID for this UnitCommandType. */\n      int getID() const;\n\n      /** Returns the string corresponding to the UnitCommandType object. For example,\n       * UnitCommandTypes::Set_Rally_Position.getName() returns std::string(\"Set Rally Position\")*/\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace UnitCommandTypes\n  {\n    /** Given a string, this function returns the command type it refers to. For example,\n     * UnitCommandTypes::getUnitCommandType(\"Attack Position\") returns UnitCommandTypes::Attack_Position. */\n    UnitCommandType getUnitCommandType(std::string name);\n\n    /** Returns the set of all the sizes, which are listed below: */\n    std::set<UnitCommandType>& allUnitCommandTypes();\n    void init();\n    extern const UnitCommandType Attack_Move;\n    extern const UnitCommandType Attack_Unit;\n    extern const UnitCommandType Build;\n    extern const UnitCommandType Build_Addon;\n    extern const UnitCommandType Train;\n    extern const UnitCommandType Morph;\n    extern const UnitCommandType Research;\n    extern const UnitCommandType Upgrade;\n    extern const UnitCommandType Set_Rally_Position;\n    extern const UnitCommandType Set_Rally_Unit;\n    extern const UnitCommandType Move;\n    extern const UnitCommandType Patrol;\n    extern const UnitCommandType Hold_Position;\n    extern const UnitCommandType Stop;\n    extern const UnitCommandType Follow;\n    extern const UnitCommandType Gather;\n    extern const UnitCommandType Return_Cargo;\n    extern const UnitCommandType Repair;\n    extern const UnitCommandType Burrow;\n    extern const UnitCommandType Unburrow;\n    extern const UnitCommandType Cloak;\n    extern const UnitCommandType Decloak;\n    extern const UnitCommandType Siege;\n    extern const UnitCommandType Unsiege;\n    extern const UnitCommandType Lift;\n    extern const UnitCommandType Land;\n    extern const UnitCommandType Load;\n    extern const UnitCommandType Unload;\n    extern const UnitCommandType Unload_All;\n    extern const UnitCommandType Unload_All_Position;\n    extern const UnitCommandType Right_Click_Position;\n    extern const UnitCommandType Right_Click_Unit;\n    extern const UnitCommandType Halt_Construction;\n    extern const UnitCommandType Cancel_Construction;\n    extern const UnitCommandType Cancel_Addon;\n    extern const UnitCommandType Cancel_Train;\n    extern const UnitCommandType Cancel_Train_Slot;\n    extern const UnitCommandType Cancel_Morph;\n    extern const UnitCommandType Cancel_Research;\n    extern const UnitCommandType Cancel_Upgrade;\n    extern const UnitCommandType Use_Tech;\n    extern const UnitCommandType Use_Tech_Position;\n    extern const UnitCommandType Use_Tech_Unit;\n    extern const UnitCommandType None;\n    extern const UnitCommandType Unknown;\n  }\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/UnitSizeType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class UnitSizeType\n  {\n    public:\n      UnitSizeType();\n      UnitSizeType(int id);\n      UnitSizeType(const UnitSizeType& other);\n      UnitSizeType& operator=(const UnitSizeType& other);\n      bool operator==(const UnitSizeType& other) const;\n      bool operator!=(const UnitSizeType& other) const;\n      bool operator<(const UnitSizeType& other) const;\n\n      /** Returns a unique ID for this UnitSizeType. */\n      int getID() const;\n\n      /** Returns the string corresponding to the UnitSizeType object. For example,\n       * UnitSizeTypes::Medium.getName() returns std::string(\"Medium\")*/\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace UnitSizeTypes\n  {\n    /** Given a string, this function returns the size type it refers to. For example,\n     * UnitSizeTypes::getUnitSizeType(\"Small\") returns UnitSizeTypes::Small. */\n    UnitSizeType getUnitSizeType(std::string name);\n\n    /** Returns the set of all the sizes, which are listed below: */\n    std::set<UnitSizeType>& allUnitSizeTypes();\n    void init();\n    extern const UnitSizeType Independent;\n    extern const UnitSizeType Small;\n    extern const UnitSizeType Medium;\n    extern const UnitSizeType Large;\n    extern const UnitSizeType None;\n    extern const UnitSizeType Unknown;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/UnitType.h",
    "content": "#pragma once\n#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/Race.h>\n#include <BWAPI/UnitSizeType.h>\n\nnamespace BWAPI\n{\n  class TechType;\n  class UpgradeType;\n  class WeaponType;\n\n  /** The UnitType class is used to get information about a particular type of unit, such as the build time\n   * of a Lurker, or the mineral price of an Ultralisk. TODO Add the unittype table from the wiki*/\n  class UnitType\n  {\n    public:\n      UnitType();\n      UnitType(int id);\n      UnitType(const UnitType& other);\n      UnitType& operator=(const UnitType& other);\n      bool operator==(const UnitType& other) const;\n      bool operator!=(const UnitType& other) const;\n      bool operator<(const UnitType& other) const;\n\n      /** Returns a unique ID for this unit type. */\n      int getID() const;\n\n      /** Returns the name of the unit. */\n      std::string getName() const;\n\n      /** Returns the race that the unit belongs to. For example UnitTypes::Terran_SCV.getRace() will return\n       * Races::Terran. */\n      Race getRace() const;\n\n      /** Returns what builds this unit type. The second number will usually be 1 unless the unit type is\n       * Protoss_Archon or Protoss_Dark_Archon. Units that cannot be created, such as critters and mineral\n       * fields, will return a pair where the unit type is UnitTypes::None, and the second component is 0.\n       *\n       * Example: UnitTypes::Terran_Marine.whatBuilds() will return an std::pair, where the first component\n       * is UnitTypes::Terran_Barracks. */\n      const std::pair< UnitType, int > whatBuilds() const;\n\n      /** Returns the units the player is required to have before it can train or build the given unit type.\n       *\n       * Example: UnitTypes::Terran_Battlecruiser.requiredUnits() will return a map of three keys:\n       * UnitTypes::Terran_Starport, UnitTypes::Terran_Control_Tower, and UnitTypes::Terran_Physics_Lab. */\n      const std::map< UnitType, int >& requiredUnits() const;\n\n      /** Included in the API for completeness, since the only units that actually needs tech to be trained\n       * are the Zerg_Lurker and Zerg_Lurker_Egg. The tech type needed is TechTypes::Lurker_Aspect. */\n      TechType requiredTech() const;\n\n      /** Returns the tech used to cloak the unit, or TechTypes::None if the unit cannot cloak or is\n          permanently cloaked */\n      TechType cloakingTech() const;\n\n      /** Returns the set of tech types this unit can use, provided the tech types have been researched and\n       * the unit has enough energy. */\n      const std::set< TechType >& abilities() const;\n\n      /** Returns the set of upgrade types that can affect this unit. */\n      const std::set< UpgradeType >& upgrades() const;\n\n      /** Returns the upgrade that increase's the unit's armor, or UpgradeTypes::None if no upgrade\n       * increase's this unit's armor. For example UnitTypes::Terran_Marine.armorUpgrade() will return a\n       * pointer to UpgradeTypes::Terran_Infantry_Armor. */\n      UpgradeType armorUpgrade() const;\n\n      /** Returns the maximum amount of hit points the unit type can have. */\n      int maxHitPoints() const;\n\n      /** Returns the maximum amount of shields the unit type can have. */\n      int maxShields() const;\n\n      /** Returns the maximum amount of energy the unit type can have. */\n      int maxEnergy() const;\n\n      /** Returns the amount of armor the non-upgraded unit type has. */\n      int armor() const;\n\n      /** Returns the mineral price of the unit.\n       *\n       * Example: UnitTypes::Siege_Tank_Tank_Mode.mineralPrice() returns 150. */\n      int mineralPrice() const;\n\n      /** UnitTypes::Siege_Tank_Tank_Mode.gasPrice() returns 100. */\n      int gasPrice() const;\n\n      /** Returns the number of frames needed to make this unit type. */\n      int buildTime() const;\n\n      /** Returns the amount of supply used by this unit. Supply counts returned by BWAPI are double what you\n       *  would expect to see from playing the game. This is because zerglings take up 0.5 in-game supply. */\n      int supplyRequired() const;\n\n      /** Returns the amount of supply produced by this unit (i.e. for a Protoss_Pylon). Supply counts\n       * returned by BWAPI are double what you would expect to see from playing the game. This is because\n       * zerglings take up 0.5 in-game supply. */\n      int supplyProvided() const;\n\n      /** Returns the amount of space this unit type takes up inside a bunker or transport unit. */\n      int spaceRequired() const;\n\n      /** Returns the amount of space this unit type provides. */\n      int spaceProvided() const;\n\n      /** Returns the score which is used to determine the total scores in the after-game stats screen. */\n      int buildScore() const;\n\n      /** Returns the score which is used to determine the total scores in the after-game stats screen. */\n      int destroyScore() const;\n\n      /** Returns the size of the unit - either Small, Medium, Large, or Independent. */\n      UnitSizeType size() const;\n\n      /** Returns the tile width of the unit. Useful for determining the size of buildings. For example\n       * UnitTypes::Terran_Supply_Depot.tileWidth() will return 3. */\n      int tileWidth() const;\n\n      /** Returns the tile height of the unit. Useful for determining the size of buildings. For example\n       * UnitTypes::Terran_Supply_Depot.tileHeight() will return 2. */\n      int tileHeight() const;\n\n      /** Distance from the center of the unit to the left edge of the unit, measured in pixels. */\n      int dimensionLeft() const;\n\n      /** Distance from the center of the unit to the top edge of the unit, measured in pixels. */\n      int dimensionUp() const;\n\n      /** Distance from the center of the unit to the right edge of the unit, measured in pixels. */\n      int dimensionRight() const;\n\n      /** Distance from the center of the unit to the bottom edge of the unit, measured in pixels. */\n      int dimensionDown() const;\n\n      /** Returns the range at which the unit will start targeting enemy units, measured in pixels. */\n      int seekRange() const;\n\n      /** Returns how far the un-upgraded unit type can see into the fog of war, measured in pixels. */\n      int sightRange() const;\n\n      /** Returns the unit's ground weapon. */\n      WeaponType groundWeapon() const;\n\n      // TODO: add doc\n      int maxGroundHits() const;\n\n      /** Returns the unit's air weapon. */\n      WeaponType airWeapon() const;\n\n      // TODO: add doc\n      int maxAirHits() const;\n\n      /** Returns the unit's non-upgraded top speed in pixels per frame. For Terran buildings that can lift\n       * off and the Zerg Infested Command Center, this returns how fast the building moves when it is\n       * lifted. */\n      double topSpeed() const;\n\n      /** Returns how fast the unit can accelerate to its top speed. What units this quantity is measured in\n       * is currently unknown. */\n      int acceleration() const;\n\n      /** Related to how fast the unit can halt. What units this quantity is measured in is currently\n       * unknown. */\n      int haltDistance() const;\n\n      /** Related to how fast the unit can turn. What units this quantity is measured in is currently\n       * unknown. */\n      int turnRadius() const;\n\n      /** Returns true if the unit can train other units. For example, UnitTypes::Terran_Barracks.canProduce()\n       * will return true, while UnitTypes::Terran_Marine?.canProduce() will return false. This is also true\n       * for two non-building units: Protoss Carrier (can produce interceptors) and Protoss Reaver\n       * (can produce scarabs). */\n      bool canProduce() const;\n\n      /** Returns true if the unit can attack (either ground or air). Returns false for units that can only\n       * inflict damage via special abilities (such as Protoss High Templar). */\n      bool canAttack() const;\n\n      /** Returns true if the unit can move. Note that buildings will return false, even Terran buildings\n       * which can move once lifted. */\n      bool canMove() const;\n\n      /** Returns true for flying/air units. */\n      bool isFlyer() const;\n\n      /** Returns true for units that regenerate health (i.e. zerg units). */\n      bool regeneratesHP() const;\n\n      /** Returns true if the unit type is capable of casting spells / using technology. */\n      bool isSpellcaster() const;\n\n      /** Returns true for the two units that are permanently cloaked - Protoss Observer and Protoss Dark\n       * Templar. */\n      bool hasPermanentCloak() const;\n\n      /** Returns true for units that cannot be destroyed (i.e. Terran Nuclear Missile, Mineral Field,\n       * Vespene Geyser, etc) */\n      bool isInvincible() const;\n\n      /** Returns true if the unit is organic, such as a Terran Marine. */\n      bool isOrganic() const;\n\n      /** Returns true if the unit is mechanical such as a Terran Vulture. */\n      bool isMechanical() const;\n\n      /** Returns true for the four robotic Protoss units - Probe, Shuttle, Reaver, and Observer. */\n      bool isRobotic() const;\n\n      /** Returns true for the seven units that can detect cloaked units - Terran Science Vessel, Spell\n       * Scanner Sweep, Zerg Overlord, Protoss Observer, Terran Missile Turret, Zerg Spore Colony, and Protoss\n       * Photon Cannon. */\n      bool isDetector() const;\n\n      /** Returns true for the five units that hold resources - Mineral Field, Vespene Geyser,\n       * Terran Refinery, Zerg Extractor, and Protoss Assimilator. */\n      bool isResourceContainer() const;\n\n      /** Returns true for the five units that can accept resources - Terran Command Center, Protoss Nexus,\n       * Zerg Hatchery, Zerg Lair, and Zerg Hive. */\n      bool isResourceDepot() const;\n\n      /** Returns true for Terran Refinery, Zerg Extractor, and Protoss Assimilator. */\n      bool isRefinery() const;\n\n      /** Returns true for Protoss Probe, Terran SCV, and Zerg Drone. */\n      bool isWorker() const;\n\n      /** Returns true for buildings that must be near a pylon to be constructed. */\n      bool requiresPsi() const;\n\n      /** Returns true for buildings that can only be built on zerg creep. */\n      bool requiresCreep() const;\n\n      /** Returns true for Zergling and Scourge. */\n      bool isTwoUnitsInOneEgg() const;\n\n      /** Returns true for Zerg Lurker and units that can burrow when burrow tech is researched. */\n      bool isBurrowable() const;\n\n      /** Returns true for units that can be cloaked - Terran Ghost and Terran Wraith. Does not include units\n       * which have permanent cloak (Protoss Observer and Protoss Dark Templar). */\n      bool isCloakable() const;\n\n      /** Returns true if the unit is a building (also true for mineral field and vespene geyser). */\n      bool isBuilding() const;\n\n      /** Returns true if the unit is an add-on, such as a Terran Comsat Station. */\n      bool isAddon() const;\n\n      /** Returns true for Terran buildings that can lift off (i.e. Barracks). */\n      bool isFlyingBuilding() const;\n\n      /** Returns true if the unit is neutral, such as a critter or mineral field. */\n      bool isNeutral() const;\n\n      /** Returns true if the unit is a Hero unit. */\n      bool isHero() const;\n\n      /** Returns true if the unit is a Powerup unit. */\n      bool isPowerup() const;\n\n      /** Returns true if the unit is a regular Beacon. */\n      bool isBeacon() const;\n\n      /** Returns true if the unit is a flag Beacon. */\n      bool isFlagBeacon() const;\n\n      /** Returns true if the unit is a special building. */\n      bool isSpecialBuilding() const;\n\n      /** Returns true if the unit is a spell unit. */\n      bool isSpell() const;\n\n      /** Returns true if the unit produces larva. */\n      bool producesLarva() const;\n\n    private:\n      int id;\n  };\n  namespace UnitTypes\n  {\n\n    /** Given the name of a unit type, this function will return the unit type.\n     * For example, UnitTypes::getUnitType(\"Terran Marine\") will return UnitTypes::Terran_Marine. */\n    UnitType getUnitType(std::string name);\n\n    /** Returns the set of all the UnitTypes. */\n    std::set<UnitType>& allUnitTypes();\n    void init();\n    extern const UnitType Terran_Marine;\n    extern const UnitType Hero_Jim_Raynor_Marine;\n    extern const UnitType Terran_Ghost;\n    extern const UnitType Hero_Sarah_Kerrigan;\n    extern const UnitType Hero_Samir_Duran;\n    extern const UnitType Hero_Infested_Duran;\n    extern const UnitType Hero_Alexei_Stukov;\n    extern const UnitType Terran_Vulture;\n    extern const UnitType Hero_Jim_Raynor_Vulture;\n    extern const UnitType Terran_Goliath;\n    extern const UnitType Hero_Alan_Schezar;\n    extern const UnitType Terran_Siege_Tank_Tank_Mode;\n    extern const UnitType Hero_Edmund_Duke_Tank_Mode;\n    extern const UnitType Terran_SCV;\n    extern const UnitType Terran_Wraith;\n    extern const UnitType Hero_Tom_Kazansky;\n    extern const UnitType Terran_Science_Vessel;\n    extern const UnitType Hero_Magellan;\n    extern const UnitType Terran_Dropship;\n    extern const UnitType Terran_Battlecruiser;\n    extern const UnitType Hero_Arcturus_Mengsk;\n    extern const UnitType Hero_Hyperion;\n    extern const UnitType Hero_Norad_II;\n    extern const UnitType Hero_Gerard_DuGalle;\n    extern const UnitType Terran_Vulture_Spider_Mine;\n    extern const UnitType Terran_Nuclear_Missile;\n    extern const UnitType Terran_Siege_Tank_Siege_Mode;\n    extern const UnitType Hero_Edmund_Duke_Siege_Mode;\n    extern const UnitType Terran_Firebat;\n    extern const UnitType Hero_Gui_Montag;\n    extern const UnitType Spell_Scanner_Sweep;\n    extern const UnitType Terran_Medic;\n    extern const UnitType Terran_Civilian;\n    extern const UnitType Zerg_Larva;\n    extern const UnitType Zerg_Egg;\n    extern const UnitType Zerg_Zergling;\n    extern const UnitType Hero_Devouring_One;\n    extern const UnitType Hero_Infested_Kerrigan;\n    extern const UnitType Zerg_Hydralisk;\n    extern const UnitType Hero_Hunter_Killer;\n    extern const UnitType Zerg_Ultralisk;\n    extern const UnitType Hero_Torrasque;\n    extern const UnitType Zerg_Broodling;\n    extern const UnitType Zerg_Drone;\n    extern const UnitType Zerg_Overlord;\n    extern const UnitType Hero_Yggdrasill;\n    extern const UnitType Zerg_Mutalisk;\n    extern const UnitType Hero_Kukulza_Mutalisk;\n    extern const UnitType Zerg_Guardian;\n    extern const UnitType Hero_Kukulza_Guardian;\n    extern const UnitType Zerg_Queen;\n    extern const UnitType Hero_Matriarch;\n    extern const UnitType Zerg_Defiler;\n    extern const UnitType Hero_Unclean_One;\n    extern const UnitType Zerg_Scourge;\n    extern const UnitType Zerg_Infested_Terran;\n    extern const UnitType Terran_Valkyrie;\n    extern const UnitType Zerg_Cocoon;\n    extern const UnitType Protoss_Corsair;\n    extern const UnitType Hero_Raszagal;\n    extern const UnitType Protoss_Dark_Templar;\n    extern const UnitType Hero_Dark_Templar;\n    extern const UnitType Hero_Zeratul;\n    extern const UnitType Zerg_Devourer;\n    extern const UnitType Protoss_Dark_Archon;\n    extern const UnitType Protoss_Probe;\n    extern const UnitType Protoss_Zealot;\n    extern const UnitType Hero_Fenix_Zealot;\n    extern const UnitType Protoss_Dragoon;\n    extern const UnitType Hero_Fenix_Dragoon;\n    extern const UnitType Protoss_High_Templar;\n    extern const UnitType Hero_Tassadar;\n    extern const UnitType Hero_Aldaris;\n    extern const UnitType Protoss_Archon;\n    extern const UnitType Hero_Tassadar_Zeratul_Archon;\n    extern const UnitType Protoss_Shuttle;\n    extern const UnitType Protoss_Scout;\n    extern const UnitType Hero_Mojo;\n    extern const UnitType Hero_Artanis;\n    extern const UnitType Protoss_Arbiter;\n    extern const UnitType Hero_Danimoth;\n    extern const UnitType Protoss_Carrier;\n    extern const UnitType Hero_Gantrithor;\n    extern const UnitType Protoss_Interceptor;\n    extern const UnitType Protoss_Reaver;\n    extern const UnitType Hero_Warbringer;\n    extern const UnitType Protoss_Observer;\n    extern const UnitType Protoss_Scarab;\n    extern const UnitType Critter_Rhynadon;\n    extern const UnitType Critter_Bengalaas;\n    extern const UnitType Critter_Scantid;\n    extern const UnitType Critter_Kakaru;\n    extern const UnitType Critter_Ragnasaur;\n    extern const UnitType Critter_Ursadon;\n    extern const UnitType Zerg_Lurker_Egg;\n    extern const UnitType Zerg_Lurker;\n    extern const UnitType Spell_Disruption_Web;\n    extern const UnitType Terran_Command_Center;\n    extern const UnitType Terran_Comsat_Station;\n    extern const UnitType Terran_Nuclear_Silo;\n    extern const UnitType Terran_Supply_Depot;\n    extern const UnitType Terran_Refinery;\n    extern const UnitType Terran_Barracks;\n    extern const UnitType Terran_Academy;\n    extern const UnitType Terran_Factory;\n    extern const UnitType Terran_Starport;\n    extern const UnitType Terran_Control_Tower;\n    extern const UnitType Terran_Science_Facility;\n    extern const UnitType Terran_Covert_Ops;\n    extern const UnitType Terran_Physics_Lab;\n    extern const UnitType Terran_Machine_Shop;\n    extern const UnitType Terran_Engineering_Bay;\n    extern const UnitType Terran_Armory;\n    extern const UnitType Terran_Missile_Turret;\n    extern const UnitType Terran_Bunker;\n    extern const UnitType Special_Crashed_Norad_II;\n    extern const UnitType Special_Ion_Cannon;\n    extern const UnitType Zerg_Infested_Command_Center;\n    extern const UnitType Zerg_Hatchery;\n    extern const UnitType Zerg_Lair;\n    extern const UnitType Zerg_Hive;\n    extern const UnitType Zerg_Nydus_Canal;\n    extern const UnitType Zerg_Hydralisk_Den;\n    extern const UnitType Zerg_Defiler_Mound;\n    extern const UnitType Zerg_Greater_Spire;\n    extern const UnitType Zerg_Queens_Nest;\n    extern const UnitType Zerg_Evolution_Chamber;\n    extern const UnitType Zerg_Ultralisk_Cavern;\n    extern const UnitType Zerg_Spire;\n    extern const UnitType Zerg_Spawning_Pool;\n    extern const UnitType Zerg_Creep_Colony;\n    extern const UnitType Zerg_Spore_Colony;\n    extern const UnitType Zerg_Sunken_Colony;\n    extern const UnitType Special_Overmind_With_Shell;\n    extern const UnitType Special_Overmind;\n    extern const UnitType Zerg_Extractor;\n    extern const UnitType Special_Mature_Chrysalis;\n    extern const UnitType Special_Cerebrate;\n    extern const UnitType Special_Cerebrate_Daggoth;\n    extern const UnitType Protoss_Nexus;\n    extern const UnitType Protoss_Robotics_Facility;\n    extern const UnitType Protoss_Pylon;\n    extern const UnitType Protoss_Assimilator;\n    extern const UnitType Protoss_Observatory;\n    extern const UnitType Protoss_Gateway;\n    extern const UnitType Protoss_Photon_Cannon;\n    extern const UnitType Protoss_Citadel_of_Adun;\n    extern const UnitType Protoss_Cybernetics_Core;\n    extern const UnitType Protoss_Templar_Archives;\n    extern const UnitType Protoss_Forge;\n    extern const UnitType Protoss_Stargate;\n    extern const UnitType Special_Stasis_Cell_Prison;\n    extern const UnitType Protoss_Fleet_Beacon;\n    extern const UnitType Protoss_Arbiter_Tribunal;\n    extern const UnitType Protoss_Robotics_Support_Bay;\n    extern const UnitType Protoss_Shield_Battery;\n    extern const UnitType Special_Khaydarin_Crystal_Form;\n    extern const UnitType Special_Protoss_Temple;\n    extern const UnitType Special_XelNaga_Temple;\n    extern const UnitType Resource_Mineral_Field;\n    extern const UnitType Resource_Vespene_Geyser;\n    extern const UnitType Special_Warp_Gate;\n    extern const UnitType Special_Psi_Disrupter;\n    extern const UnitType Special_Power_Generator;\n    extern const UnitType Special_Overmind_Cocoon;\n    extern const UnitType Special_Zerg_Beacon;\n    extern const UnitType Special_Terran_Beacon;\n    extern const UnitType Special_Protoss_Beacon;\n    extern const UnitType Special_Zerg_Flag_Beacon;\n    extern const UnitType Special_Terran_Flag_Beacon;\n    extern const UnitType Special_Protoss_Flag_Beacon;\n    extern const UnitType Spell_Dark_Swarm;\n    extern const UnitType Powerup_Uraj_Crystal;\n    extern const UnitType Powerup_Khalis_Crystal;\n    extern const UnitType Powerup_Flag;\n    extern const UnitType Powerup_Young_Chrysalis;\n    extern const UnitType Powerup_Psi_Emitter;\n    extern const UnitType Powerup_Data_Disk;\n    extern const UnitType Powerup_Khaydarin_Crystal;\n    extern const UnitType None;\n    extern const UnitType Unknown;\n\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/UpgradeType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\n#include <BWAPI/Race.h>\nnamespace BWAPI\n{\n  class UnitType;\n  class UpgradeType\n  {\n    public:\n      UpgradeType();\n      UpgradeType(int id);\n      UpgradeType(const UpgradeType& other);\n      UpgradeType& operator=(const UpgradeType& other);\n      bool operator==(const UpgradeType& other) const;\n      bool operator!=(const UpgradeType& other) const;\n      bool operator<(const UpgradeType& other) const;\n\n      /** Returns the unique ID for this upgrade type. */\n      int getID() const;\n\n      /** Returns the name for the upgrade type. */\n      std::string getName() const;\n\n      /** Returns the race the upgrade is for. For example, UpgradeTypes::Terran_Infantry_Armor.getRace()\n       * will return Races::Terran. */\n      Race getRace() const;\n\n      /** Returns the mineral price for the first upgrade. */\n      int mineralPrice() const;\n\n      /** Returns the amount that the mineral price increases for each additional upgrade. */\n      int mineralPriceFactor() const;\n\n      /** Returns the vespene gas price for the first upgrade. */\n      int gasPrice() const;\n\n      /** Returns the amount that the vespene gas price increases for each additional upgrade. */\n      int gasPriceFactor() const;\n\n      /** Returns the number of frames needed to research the first upgrade. */\n      int upgradeTime() const;\n\n      /** Returns the number of frames that the upgrade time increases for each additional upgrade. */\n      int upgradeTimeFactor() const;\n\n      /** Returns the maximum number of times the upgrade can be researched. */\n      int maxRepeats() const;\n\n      /** Returns the type of unit that researches the upgrade. */\n      UnitType whatUpgrades() const;\n\n      /** Returns the set of units that are affected by this upgrade. */\n      const std::set<UnitType>& whatUses() const;\n    private:\n      int id;\n  };\n  namespace UpgradeTypes\n  {\n    /** Given a string, this will return the upgrade type. */\n    UpgradeType getUpgradeType(std::string name);\n\n    /** Returns the set of all the UpgradeTypes. */\n    std::set<UpgradeType>& allUpgradeTypes();\n    void init();\n    extern const UpgradeType Terran_Infantry_Armor;\n    extern const UpgradeType Terran_Vehicle_Plating;\n    extern const UpgradeType Terran_Ship_Plating;\n    extern const UpgradeType Zerg_Carapace;\n    extern const UpgradeType Zerg_Flyer_Carapace;\n    extern const UpgradeType Protoss_Ground_Armor;\n    extern const UpgradeType Protoss_Air_Armor;\n    extern const UpgradeType Terran_Infantry_Weapons;\n    extern const UpgradeType Terran_Vehicle_Weapons;\n    extern const UpgradeType Terran_Ship_Weapons;\n    extern const UpgradeType Zerg_Melee_Attacks;\n    extern const UpgradeType Zerg_Missile_Attacks;\n    extern const UpgradeType Zerg_Flyer_Attacks;\n    extern const UpgradeType Protoss_Ground_Weapons;\n    extern const UpgradeType Protoss_Air_Weapons;\n    extern const UpgradeType Protoss_Plasma_Shields;\n    extern const UpgradeType U_238_Shells;\n    extern const UpgradeType Ion_Thrusters;\n    extern const UpgradeType Titan_Reactor;\n    extern const UpgradeType Ocular_Implants;\n    extern const UpgradeType Moebius_Reactor;\n    extern const UpgradeType Apollo_Reactor;\n    extern const UpgradeType Colossus_Reactor;\n    extern const UpgradeType Ventral_Sacs;\n    extern const UpgradeType Antennae;\n    extern const UpgradeType Pneumatized_Carapace;\n    extern const UpgradeType Metabolic_Boost;\n    extern const UpgradeType Adrenal_Glands;\n    extern const UpgradeType Muscular_Augments;\n    extern const UpgradeType Grooved_Spines;\n    extern const UpgradeType Gamete_Meiosis;\n    extern const UpgradeType Metasynaptic_Node;\n    extern const UpgradeType Singularity_Charge;\n    extern const UpgradeType Leg_Enhancements;\n    extern const UpgradeType Scarab_Damage;\n    extern const UpgradeType Reaver_Capacity;\n    extern const UpgradeType Gravitic_Drive;\n    extern const UpgradeType Sensor_Array;\n    extern const UpgradeType Gravitic_Boosters;\n    extern const UpgradeType Khaydarin_Amulet;\n    extern const UpgradeType Apial_Sensors;\n    extern const UpgradeType Gravitic_Thrusters;\n    extern const UpgradeType Carrier_Capacity;\n    extern const UpgradeType Khaydarin_Core;\n    extern const UpgradeType Argus_Jewel;\n    extern const UpgradeType Argus_Talisman;\n    extern const UpgradeType Caduceus_Reactor;\n    extern const UpgradeType Chitinous_Plating;\n    extern const UpgradeType Anabolic_Synthesis;\n    extern const UpgradeType Charon_Boosters;\n    extern const UpgradeType None;\n    extern const UpgradeType Unknown;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI/WeaponType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class TechType;\n  class UpgradeType;\n  class DamageType;\n  class ExplosionType;\n  class WeaponType\n  {\n    public:\n      WeaponType();\n      WeaponType(int id);\n      WeaponType(const WeaponType& other);\n      WeaponType& operator=(const WeaponType& other);\n      bool operator==(const WeaponType& other) const;\n      bool operator!=(const WeaponType& other) const;\n      bool operator<(const WeaponType& other) const;\n\n      /** Returns a unique ID for this weapon type. */\n      int getID() const;\n\n      /** Returns the name of the weapon. */\n      std::string getName() const;\n\n      /** Returns the tech type that must be researched before this weapon can be used, or TechTypes::None if\n       * no tech type is required. */\n      TechType getTech() const;\n\n      /** Returns the unit that can use this weapon. */\n      UnitType whatUses() const;\n\n      /** Returns the amount of damage that this weapon deals per attack. */\n      int damageAmount() const;\n\n      // TODO: add doc\n      int damageBonus() const;\n\n      /** Returns the amount of cooldown time between attacks. */\n      int damageCooldown() const;\n\n      /** Returns the amount that the damage increases per upgrade.\n       * \\see WeaponType::upgradeType. */\n      int damageFactor() const;\n\n      /** Returns the upgrade type that can be upgraded to increase the attack damage. */\n      UpgradeType upgradeType() const;\n\n      /** Returns the type of damage that this weapon uses (i.e. concussive, normal, explosive, etc). */\n      DamageType damageType() const;\n\n      /** Returns the type of explosion that this weapon uses. */\n      ExplosionType explosionType() const;\n\n      /** Returns the minimum attack range of the weapon, measured in pixels, 0 for most things except\n       * WeaponTypes::Arclite_Shock_Cannon (the weapon of the Terran Siege Tank in Siege Mode). */\n      int minRange() const;\n\n      /** Returns the maximum attack range of the weapon, measured in pixels. */\n      int maxRange() const;\n\n      /** Inner radius used in splash damage calculations. */\n      int innerSplashRadius() const;\n\n      /** Median radius used in splash damage calculations. */\n      int medianSplashRadius() const;\n\n      /** Outer radius used in splash damage calculations. */\n      int outerSplashRadius() const;\n\n      /** Returns true if this weapon can attack air units. */\n      bool targetsAir() const;\n\n      // TODO: group these methods\n      /** Returns true if this weapon can attack ground units. */\n      bool targetsGround() const;\n      bool targetsMechanical() const;\n      bool targetsOrganic() const;\n      bool targetsNonBuilding() const;\n      bool targetsNonRobotic() const;\n      bool targetsTerrain() const;\n      bool targetsOrgOrMech() const;\n      bool targetsOwn() const;\n    private:\n      int id;\n  };\n  namespace WeaponTypes\n  {\n    /** Given the name of a weapon, this will return the corresponding weapon type object. */\n    WeaponType getWeaponType(std::string name);\n\n    /** Returns the set of all the WeaponTypes. */\n    std::set<WeaponType>& allWeaponTypes();\n\n    /** Returns the set of all normal weapons in WeaponTypes. */\n    std::set<WeaponType>& normalWeaponTypes();\n\n    /** Returns the set of all special weapons in WeaponTypes. */\n    std::set<WeaponType>& specialWeaponTypes();\n    void init();\n    extern const WeaponType Gauss_Rifle;\n    extern const WeaponType Gauss_Rifle_Jim_Raynor;\n    extern const WeaponType C_10_Canister_Rifle;\n    extern const WeaponType C_10_Canister_Rifle_Sarah_Kerrigan;\n    extern const WeaponType C_10_Canister_Rifle_Samir_Duran;\n    extern const WeaponType C_10_Canister_Rifle_Infested_Duran;\n    extern const WeaponType C_10_Canister_Rifle_Alexei_Stukov;\n    extern const WeaponType Fragmentation_Grenade;\n    extern const WeaponType Fragmentation_Grenade_Jim_Raynor;\n    extern const WeaponType Spider_Mines;\n    extern const WeaponType Twin_Autocannons;\n    extern const WeaponType Twin_Autocannons_Alan_Schezar;\n    extern const WeaponType Hellfire_Missile_Pack;\n    extern const WeaponType Hellfire_Missile_Pack_Alan_Schezar;\n    extern const WeaponType Arclite_Cannon;\n    extern const WeaponType Arclite_Cannon_Edmund_Duke;\n    extern const WeaponType Fusion_Cutter;\n    extern const WeaponType Gemini_Missiles;\n    extern const WeaponType Gemini_Missiles_Tom_Kazansky;\n    extern const WeaponType Burst_Lasers;\n    extern const WeaponType Burst_Lasers_Tom_Kazansky;\n    extern const WeaponType ATS_Laser_Battery;\n    extern const WeaponType ATS_Laser_Battery_Hero;\n    extern const WeaponType ATS_Laser_Battery_Hyperion;\n    extern const WeaponType ATA_Laser_Battery;\n    extern const WeaponType ATA_Laser_Battery_Hero;\n    extern const WeaponType ATA_Laser_Battery_Hyperion;\n    extern const WeaponType Flame_Thrower;\n    extern const WeaponType Flame_Thrower_Gui_Montag;\n    extern const WeaponType Arclite_Shock_Cannon;\n    extern const WeaponType Arclite_Shock_Cannon_Edmund_Duke;\n    extern const WeaponType Longbolt_Missile;\n    extern const WeaponType Claws;\n    extern const WeaponType Claws_Devouring_One;\n    extern const WeaponType Claws_Infested_Kerrigan;\n    extern const WeaponType Needle_Spines;\n    extern const WeaponType Needle_Spines_Hunter_Killer;\n    extern const WeaponType Kaiser_Blades;\n    extern const WeaponType Kaiser_Blades_Torrasque;\n    extern const WeaponType Toxic_Spores;\n    extern const WeaponType Spines;\n    extern const WeaponType Acid_Spore;\n    extern const WeaponType Acid_Spore_Kukulza;\n    extern const WeaponType Glave_Wurm;\n    extern const WeaponType Glave_Wurm_Kukulza;\n    extern const WeaponType Seeker_Spores;\n    extern const WeaponType Subterranean_Tentacle;\n    extern const WeaponType Suicide_Infested_Terran;\n    extern const WeaponType Suicide_Scourge;\n    extern const WeaponType Particle_Beam;\n    extern const WeaponType Psi_Blades;\n    extern const WeaponType Psi_Blades_Fenix;\n    extern const WeaponType Phase_Disruptor;\n    extern const WeaponType Phase_Disruptor_Fenix;\n    extern const WeaponType Psi_Assault;\n    extern const WeaponType Psionic_Shockwave;\n    extern const WeaponType Psionic_Shockwave_TZ_Archon;\n    extern const WeaponType Dual_Photon_Blasters;\n    extern const WeaponType Dual_Photon_Blasters_Mojo;\n    extern const WeaponType Dual_Photon_Blasters_Artanis;\n    extern const WeaponType Anti_Matter_Missiles;\n    extern const WeaponType Anti_Matter_Missiles_Mojo;\n    extern const WeaponType Anti_Matter_Missiles_Artanis;\n    extern const WeaponType Phase_Disruptor_Cannon;\n    extern const WeaponType Phase_Disruptor_Cannon_Danimoth;\n    extern const WeaponType Pulse_Cannon;\n    extern const WeaponType STS_Photon_Cannon;\n    extern const WeaponType STA_Photon_Cannon;\n    extern const WeaponType Scarab;\n    extern const WeaponType Neutron_Flare;\n    extern const WeaponType Halo_Rockets;\n    extern const WeaponType Corrosive_Acid;\n    extern const WeaponType Subterranean_Spines;\n    extern const WeaponType Warp_Blades;\n    extern const WeaponType Warp_Blades_Hero;\n    extern const WeaponType Warp_Blades_Zeratul;\n\n    extern const WeaponType Yamato_Gun;\n    extern const WeaponType Nuclear_Strike;\n    extern const WeaponType Lockdown;\n    extern const WeaponType EMP_Shockwave;\n    extern const WeaponType Irradiate;\n    extern const WeaponType Parasite;\n    extern const WeaponType Spawn_Broodlings;\n    extern const WeaponType Ensnare;\n    extern const WeaponType Dark_Swarm;\n    extern const WeaponType Plague;\n    extern const WeaponType Consume;\n    extern const WeaponType Stasis_Field;\n    extern const WeaponType Psionic_Storm;\n    extern const WeaponType Disruption_Web;\n    extern const WeaponType Restoration;\n    extern const WeaponType Mind_Control;\n    extern const WeaponType Feedback;\n    extern const WeaponType Optical_Flare;\n    extern const WeaponType Maelstrom;\n\n    extern const WeaponType None;\n    extern const WeaponType Unknown;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI.cpp",
    "content": "#include <BWAPI.h>\n\nnamespace BWAPI\n{\n    Game * Broodwar;\n}\n\nvoid BWAPI::BWAPI_init()\n{\n  BWAPI::Races::init();\n  BWAPI::DamageTypes::init();\n  BWAPI::ExplosionTypes::init();\n  BWAPI::Orders::init();\n  BWAPI::TechTypes::init();\n  BWAPI::PlayerTypes::init();\n  BWAPI::UpgradeTypes::init();\n  BWAPI::WeaponTypes::init();\n  BWAPI::UnitSizeTypes::init();\n  BWAPI::UnitCommandTypes::init();\n  BWAPI::UnitTypes::init();\n  BWAPI::BulletTypes::init();\n  BWAPI::Errors::init();\n  BWAPI::Colors::init();\n  BWAPI::GameTypes::init();\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BWAPI.h",
    "content": "#include <BWAPI/AIModule.h>\n#include <BWAPI/Bullet.h>\n#include <BWAPI/BulletType.h>\n#include <BWAPI/Color.h>\n#include <BWAPI/Constants.h>\n#include <BWAPI/CoordinateType.h>\n#include <BWAPI/DamageType.h>\n#include <BWAPI/Error.h>\n#include <BWAPI/Event.h>\n#include <BWAPI/EventType.h>\n#include <BWAPI/ExplosionType.h>\n#include <BWAPI/Flag.h>\n#include <BWAPI/Force.h>\n#include <BWAPI/Game.h>\n#include <BWAPI/GameType.h>\n#include <BWAPI/Input.h>\n#include <BWAPI/Latency.h>\n#include <BWAPI/Order.h>\n#include <BWAPI/Player.h>\n#include <BWAPI/PlayerType.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/Unit.h>\n#include <BWAPI/UnitCommand.h>\n#include <BWAPI/UnitCommandType.h>\n#include <BWAPI/UnitSizeType.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/WeaponType.h>\n\nnamespace BWAPI\n{\n  /** You have to call this from your AIModule Dllmain function.\n   *\n   * \\code\n   * BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)\n   * {\n   *   switch (ul_reason_for_call)\n   *   {\n   *     case DLL_PROCESS_ATTACH:\n   *       BWAPI::BWAPI_init();\n   *       break;\n   *     case DLL_PROCESS_DETACH:\n   *       break;\n   *   }\n   *\n   *   return TRUE;\n   * }\n   * \\endcode */\n  void BWAPI_init();\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Bitmap.cpp",
    "content": "#include <BWAPI/Bitmap.h>\n\nnamespace BWAPI\n{\n  BitmapProxy::BitmapProxy(unsigned char *data, unsigned short width, unsigned short height, int x)\n  :data(data)\n  ,width(width)\n  ,height(height)\n  ,x(x)\n  {}\n\n  Color BitmapProxy::operator[](int y)\n  {\n    unsigned int offs = y * this->width + this->x;\n    if ( offs < (unsigned int)(this->width * this->height) )\n      return Color(this->data[offs]);\n    return Color(0);\n  }\n\n  BitmapProxy Bitmap::operator[](int x)\n  {\n    return BitmapProxy(this->data, this->wid, this->ht, x);\n  }\n\n  unsigned short Bitmap::getWidth()\n  {\n    return this->wid;\n  }\n\n  unsigned short Bitmap::getHeight()\n  {\n    return this->ht;\n  }\n}\n\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/BulletType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/BulletType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingBulletType = true;\n  std::string bulletTypeName[211];\n  std::map<std::string, BulletType> bulletTypeMap;\n  std::set< BulletType > bulletTypeSet;\n  namespace BulletTypes\n  {\n    const BulletType Melee(0);\n    const BulletType Fusion_Cutter_Hit(141);\n    const BulletType Gauss_Rifle_Hit(142);\n    const BulletType C_10_Canister_Rifle_Hit(143);\n    const BulletType Gemini_Missiles(144);\n    const BulletType Fragmentation_Grenade(145);\n    const BulletType Longbolt_Missile(146);\n    const BulletType ATS_ATA_Laser_Battery(148);\n    const BulletType Burst_Lasers(149);\n    const BulletType Arclite_Shock_Cannon_Hit(150);\n    const BulletType EMP_Missile(151);\n    const BulletType Dual_Photon_Blasters_Hit(152);\n    const BulletType Particle_Beam_Hit(153);\n    const BulletType Anti_Matter_Missile(154);\n    const BulletType Pulse_Cannon(155);\n    const BulletType Psionic_Shockwave_Hit(156);\n    const BulletType Psionic_Storm(157);\n    const BulletType Yamato_Gun(158);\n    const BulletType Phase_Disruptor(159);\n    const BulletType STA_STS_Cannon_Overlay(160);\n    const BulletType Sunken_Colony_Tentacle(161);\n    const BulletType Acid_Spore(163);\n    const BulletType Glave_Wurm(165);\n    const BulletType Seeker_Spores(166);\n    const BulletType Queen_Spell_Carrier(167);\n    const BulletType Plague_Cloud(168);\n    const BulletType Consume(169);\n    const BulletType Needle_Spine_Hit(171);\n    const BulletType Invisible(172);\n    const BulletType Optical_Flare_Grenade(201);\n    const BulletType Halo_Rockets(202);\n    const BulletType Subterranean_Spines(203);\n    const BulletType Corrosive_Acid_Shot(204);\n    const BulletType Neutron_Flare(206);\n    const BulletType None(209);\n    const BulletType Unknown(210);\n\n    void init()\n    {\n      bulletTypeName[Melee.getID()]                    = \"Melee\";\n      bulletTypeName[Fusion_Cutter_Hit.getID()]        = \"Fusion Cutter Hit\";\n      bulletTypeName[Gauss_Rifle_Hit.getID()]          = \"Gauss Rifle Hit\";\n      bulletTypeName[C_10_Canister_Rifle_Hit.getID()]  = \"C-10 Canister Rifle Hit\";\n      bulletTypeName[Gemini_Missiles.getID()]          = \"Gemini Missiles\";\n      bulletTypeName[Fragmentation_Grenade.getID()]    = \"Fragmentation Grenade\";\n      bulletTypeName[Longbolt_Missile.getID()]         = \"Longbolt Missile\";\n      bulletTypeName[ATS_ATA_Laser_Battery.getID()]    = \"ATS ATA Laser Battery\";\n      bulletTypeName[Burst_Lasers.getID()]             = \"Burst Lasers\";\n      bulletTypeName[Arclite_Shock_Cannon_Hit.getID()] = \"Arclite Shock Cannon Hit\";\n      bulletTypeName[EMP_Missile.getID()]              = \"EMP Missile\";\n      bulletTypeName[Dual_Photon_Blasters_Hit.getID()] = \"Dual Photon Blasters Hit\";\n      bulletTypeName[Particle_Beam_Hit.getID()]        = \"Particle Beam Hit\";\n      bulletTypeName[Anti_Matter_Missile.getID()]      = \"Anti-Matter Missile\";\n      bulletTypeName[Pulse_Cannon.getID()]             = \"Pulse Cannon\";\n      bulletTypeName[Psionic_Shockwave_Hit.getID()]    = \"Psionic Shockwave Hit\";\n      bulletTypeName[Psionic_Storm.getID()]            = \"Psionic Storm\";\n      bulletTypeName[Yamato_Gun.getID()]               = \"Yamato Gun\";\n      bulletTypeName[Phase_Disruptor.getID()]          = \"Phase Disruptor\";\n      bulletTypeName[STA_STS_Cannon_Overlay.getID()]   = \"STA STS Cannon Overlay\";\n      bulletTypeName[Sunken_Colony_Tentacle.getID()]   = \"Sunken Colony Tentacle\";\n      bulletTypeName[Acid_Spore.getID()]               = \"Acid Spore\";\n      bulletTypeName[Glave_Wurm.getID()]               = \"Glave Wurm\";\n      bulletTypeName[Seeker_Spores.getID()]            = \"Seeker Spores\";\n      bulletTypeName[Queen_Spell_Carrier.getID()]      = \"Queen Spell Carrier\";\n      bulletTypeName[Plague_Cloud.getID()]             = \"Plague Cloud\";\n      bulletTypeName[Consume.getID()]                  = \"Consume\";\n      bulletTypeName[Needle_Spine_Hit.getID()]         = \"Needle Spine Hit\";\n      bulletTypeName[Invisible.getID()]                = \"Invisible\";\n      bulletTypeName[Optical_Flare_Grenade.getID()]    = \"Optical Flare Grenade\";\n      bulletTypeName[Halo_Rockets.getID()]             = \"Halo Rockets\";\n      bulletTypeName[Subterranean_Spines.getID()]      = \"Subterranean Spines\";\n      bulletTypeName[Corrosive_Acid_Shot.getID()]      = \"Corrosive Acid Shot\";\n      bulletTypeName[Neutron_Flare.getID()]            = \"Neutron Flare\";\n      bulletTypeName[None.getID()]                     = \"None\";\n      bulletTypeName[Unknown.getID()]                  = \"Unknown\";\n\n      bulletTypeSet.insert(Melee);\n      bulletTypeSet.insert(Fusion_Cutter_Hit);\n      bulletTypeSet.insert(Gauss_Rifle_Hit);\n      bulletTypeSet.insert(C_10_Canister_Rifle_Hit);\n      bulletTypeSet.insert(Gemini_Missiles);\n      bulletTypeSet.insert(Fragmentation_Grenade);\n      bulletTypeSet.insert(Longbolt_Missile);\n      bulletTypeSet.insert(ATS_ATA_Laser_Battery);\n      bulletTypeSet.insert(Burst_Lasers);\n      bulletTypeSet.insert(Arclite_Shock_Cannon_Hit);\n      bulletTypeSet.insert(EMP_Missile);\n      bulletTypeSet.insert(Dual_Photon_Blasters_Hit);\n      bulletTypeSet.insert(Particle_Beam_Hit);\n      bulletTypeSet.insert(Anti_Matter_Missile);\n      bulletTypeSet.insert(Pulse_Cannon);\n      bulletTypeSet.insert(Psionic_Shockwave_Hit);\n      bulletTypeSet.insert(Psionic_Storm);\n      bulletTypeSet.insert(Yamato_Gun);\n      bulletTypeSet.insert(Phase_Disruptor);\n      bulletTypeSet.insert(STA_STS_Cannon_Overlay);\n      bulletTypeSet.insert(Sunken_Colony_Tentacle);\n      bulletTypeSet.insert(Acid_Spore);\n      bulletTypeSet.insert(Glave_Wurm);\n      bulletTypeSet.insert(Seeker_Spores);\n      bulletTypeSet.insert(Queen_Spell_Carrier);\n      bulletTypeSet.insert(Plague_Cloud);\n      bulletTypeSet.insert(Consume);\n      bulletTypeSet.insert(Needle_Spine_Hit);\n      bulletTypeSet.insert(Invisible);\n      bulletTypeSet.insert(Optical_Flare_Grenade);\n      bulletTypeSet.insert(Halo_Rockets);\n      bulletTypeSet.insert(Subterranean_Spines);\n      bulletTypeSet.insert(Corrosive_Acid_Shot);\n      bulletTypeSet.insert(Neutron_Flare);\n      bulletTypeSet.insert(None);\n      bulletTypeSet.insert(Unknown);\n\n      foreach(BulletType i, bulletTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        bulletTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingBulletType = false;\n    }\n  }\n\n  BulletType::BulletType()\n  {\n    this->id = BulletTypes::None.id;\n  }\n  BulletType::BulletType(int id)\n  {\n    this->id = id;\n    if (!initializingBulletType && (id < 0 || id >= 211 || bulletTypeName[id].length() == 0))\n      this->id = BulletTypes::Unknown.id;\n  }\n  BulletType::BulletType(const BulletType& other)\n  {\n    this->id = other.id;\n  }\n  BulletType& BulletType::operator=(const BulletType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool BulletType::operator==(const BulletType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool BulletType::operator!=(const BulletType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool BulletType::operator<(const BulletType& other) const\n  {\n    return this->id < other.id;\n  }\n  int BulletType::getID() const\n  {\n    return this->id;\n  }\n  std::string BulletType::getName() const\n  {\n    return bulletTypeName[this->id];\n  }\n  BulletType BulletTypes::getBulletType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, BulletType>::iterator i = bulletTypeMap.find(name);\n    if (i == bulletTypeMap.end())\n      return BulletTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<BulletType>& BulletTypes::allBulletTypes()\n  {\n    return bulletTypeSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Color.cpp",
    "content": "#include <BWAPI/Color.h>\n#include <list>\n#include <Util/Foreach.h>\nnamespace BWAPI\n{\n  int palette[256] = {0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,\n                      0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x3a003a, 0x190019,\n                      0x2c2418, 0x482414, 0x5c2c14, 0x703014, 0x683c24, 0x7c4018, 0x784c2c, 0xa80808,\n                      0x8c5430, 0x846044, 0xa0541c, 0xc44c18, 0xbc6824, 0xb4703c, 0xd06420, 0xdc9434,\n                      0xe09454, 0xecc454, 0x344428, 0x406c3c, 0x486c50, 0x4c8050, 0x508c5c, 0x5ca078,\n                      0x000018, 0x001034, 0x000850, 0x243448, 0x304054, 0x14347c, 0x344c6c, 0x405874,\n                      0x48688c, 0x00709c, 0x5880a4, 0x4068d4, 0x18acb8, 0x2424fc, 0x6494bc, 0x70a8cc,\n                      0x8cc0d8, 0x94dcf4, 0xacdce8, 0xacfcfc, 0xccf8f8, 0xfcfc00, 0xf4e490, 0xfcfcc0,\n                      0x0c0c0c, 0x181410, 0x1c1c20, 0x282830, 0x383024, 0x383c44, 0x4c4030, 0x4c4c4c,\n                      0x5c5040, 0x585858, 0x686868, 0x78846c, 0x68946c, 0x74a47c, 0x98948c, 0x90b894,\n                      0x98c4a8, 0xb0b0b0, 0xacccb0, 0xc4c0bc, 0xcce0d0, 0xf0f0f0, 0x1c1008, 0x28180c,\n                      0x341008, 0x34200c, 0x381020, 0x342820, 0x443408, 0x483018, 0x600000, 0x542820,\n                      0x504014, 0x5c5414, 0x840404, 0x684c34, 0x7c3830, 0x706420, 0x7c5050, 0xa4341c,\n                      0x946c00, 0x985c40, 0x8c8034, 0x987454, 0xb85444, 0xb09018, 0xb0745c, 0xf40404,\n                      0xc87854, 0xfc6854, 0xe0a484, 0xfc9468, 0xfccc2c, 0x10fc18, 0x0c0020, 0x1c1c2c,\n                      0x24244c, 0x282c68, 0x2c3084, 0x2018b8, 0x343cac, 0x686894, 0x6490fc, 0x7cacfc,\n                      0x00e4fc, 0x9c9040, 0xa89454, 0xbca45c, 0xccb860, 0xe8d880, 0xecc4b0, 0xfcfc38,\n                      0xfcfc7c, 0xfcfca4, 0x080808, 0x101010, 0x181818, 0x282828, 0x343434, 0x4c3c38,\n                      0x444444, 0x484858, 0x585868, 0x746838, 0x78645c, 0x60607c, 0x847474, 0x84849c,\n                      0xac8c7c, 0xac9894, 0x9090b8, 0xb8b8e8, 0xf88c14, 0x10543c, 0x209070, 0x2cb494,\n                      0x042064, 0x481c50, 0x083498, 0x683078, 0x88409c, 0x0c48cc, 0xbcb834, 0xdcdc3c,\n                      0x100000, 0x240000, 0x340000, 0x480000, 0x601804, 0x8c2808, 0xc81818, 0xe02c2c,\n                      0xe82020, 0xe85014, 0xfc2020, 0xe87824, 0xf8ac3c, 0x001400, 0x002800, 0x004400,\n                      0x006400, 0x088008, 0x249824, 0x3c9c3c, 0x58b058, 0x68b868, 0x80c480, 0x94d494,\n                      0x0c1424, 0x243c64, 0x305084, 0x385c94, 0x4874b4, 0x5484c4, 0x6094d4, 0x78b4ec,\n                      0x141008, 0x18140c, 0x242c0c, 0x101018, 0x141420, 0x2c2c40, 0x444c68, 0x040404,\n                      0x1c1810, 0x201c14, 0x24201c, 0x30281c, 0x40382c, 0x544838, 0x685c4c, 0x907c64,\n                      0x282014, 0x302814, 0x342c18, 0x382c1c, 0x3c301c, 0x443824, 0x544430, 0x0c1004,\n                      0x141804, 0x181c08, 0x1c2008, 0x20240c, 0x2c3410, 0x343c10, 0x404810, 0x202030,\n                      0x28283c, 0x303448, 0x141414, 0x20181c, 0x282018, 0x241c24, 0x282424, 0x302c2c,\n                      0x3c2c34, 0x3c383c, 0x483c30, 0x443440, 0x503c48, 0x5c5034, 0x2323ff, 0x2323ff,\n                      0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff\n                     };\n  namespace Colors\n  {\n    const Color Red(111);\n    const Color Blue(165);\n    const Color Teal(159);\n    const Color Purple(156);\n    const Color Orange(179);\n    const Color Brown(19);\n    const Color White(255);\n    const Color Yellow(135);\n    const Color Green(117);\n    const Color Cyan(128);\n    \n    const Color Black(0);\n    const Color Grey(74);\n\n    std::list<int> cell[8][8][8];\n    void init()\n    {\n      for(int i = 0; i < 256; ++i)\n      {\n        int redCell   = (palette[i] >> 21) & 0x07;\n        int greenCell = (palette[i] >> 13) & 0x07;\n        int blueCell  = (palette[i] >> 5)  & 0x07;\n        cell[redCell][greenCell][blueCell].push_back(i);\n      }\n    }\n  }\n  int min(int a, int b)\n  {\n    return a < b ? a : b;\n  }\n  int max(int a, int b)\n  {\n    return a > b ? a : b;\n  }\n  Color::Color()\n  {\n    this->id = 0;\n  }\n  Color::Color(int id)\n  {\n    this->id = id;\n  }\n  Color::Color(const Color& other)\n  {\n    this->id = other.id;\n  }\n  Color::Color(int red, int green, int blue)\n  {\n    int redCell    = red   >> 5;\n    int greenCell  = green >> 5;\n    int blueCell   = blue  >> 5;\n    int redCellS   = max(redCell   - 1, 0);\n    int redCellF   = min(redCell   + 1, 7);\n    int greenCellS = max(greenCell - 1, 0);\n    int greenCellF = min(greenCell + 1, 7);\n    int blueCellS  = max(blueCell  - 1, 0);\n    int blueCellF  = min(blueCell  + 1, 7);\n    int min_dist   = 3 * 256 * 256;\n    int best_id    = -1;\n    for(int rc = redCellS; rc <= redCellF; ++rc)\n    {\n      for(int gc = greenCellS; gc <= greenCellF; ++gc)\n      {\n        for(int bc = blueCellS; bc <= blueCellF; ++bc)\n        {\n          foreach(int id, Colors::cell[rc][gc][bc])\n          {\n            int ired   = (palette[id] >> 16) & 0xFF;\n            int igreen = (palette[id] >> 8)  & 0xFF;\n            int iblue  = (palette[id] >> 0)  & 0xFF;\n            int distance = (red - ired) * (red - ired) + (green - igreen) * (green - igreen) + (blue - iblue) * (blue - iblue);\n            if (distance < min_dist)\n            {\n              min_dist = distance;\n              best_id  = id;\n            }\n          }\n        }\n      }\n    }\n    if (best_id == -1)\n    {\n      int min_dist = 3 * 256 * 256;\n      int best_id = -1;\n      for(int id = 0; id < 255; ++id)\n      {\n        int ired   = (palette[id] >> 16) & 0xFF;\n        int igreen = (palette[id] >> 8)  & 0xFF;\n        int iblue  = (palette[id] >> 0)  & 0xFF;\n        int distance = (red - ired) * (red - ired) + (green - igreen) * (green - igreen) + (blue - iblue) * (blue - iblue);\n        if (distance < min_dist)\n        {\n          min_dist = distance;\n          best_id = id;\n        }\n      }\n    }\n    this->id = best_id;\n  }\n  Color& Color::operator=(const Color& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool Color::operator==(const Color& other) const\n  {\n    return palette[this->id] == palette[other.id];\n  }\n  bool Color::operator!=(const Color& other) const\n  {\n    return palette[this->id] != palette[other.id];\n  }\n  bool Color::operator<(const Color& other) const\n  {\n    return this->id < other.id;\n  }\n  int Color::getID() const\n  {\n    return this->id;\n  }\n  int Color::red() const\n  {\n    return (palette[this->id] >> 16) & 0xFF;\n  }\n  int Color::green() const\n  {\n    return (palette[this->id] >> 8) & 0xFF;\n  }\n  int Color::blue() const\n  {\n    return palette[this->id] & 0xFF;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Common.cpp",
    "content": "#include \"Common.h\"\n\nnamespace BWAPI\n{\n  void fixName(std::string *name)\n  {\n    for(unsigned int j = 0; j < name->length(); ++j)\n    {\n      if ( (*name)[j] == ' ')\n        (*name)[j] = '_';\n      if ( (*name)[j] >= 'a' && (*name)[j] <= 'z')\n        (*name)[j] += 'A'-'a';\n    }\n  }\n\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Common.h",
    "content": "#pragma once\n#include <string>\n\nnamespace BWAPI\n{\n  void fixName(std::string *name);\n\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/DamageType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/DamageType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingDamageType = true;\n  std::string damageTypeName[7];\n  std::map<std::string, DamageType> damageTypeMap;\n  std::set< DamageType > damageTypeSet;\n  namespace DamageTypes\n  {\n    const DamageType Independent(0);\n    const DamageType Explosive(1);\n    const DamageType Concussive(2);\n    const DamageType Normal(3);\n    const DamageType Ignore_Armor(4);\n    const DamageType None(5);\n    const DamageType Unknown(6);\n\n    void init()\n    {\n      damageTypeName[Independent.getID()]  = \"Independent\";\n      damageTypeName[Explosive.getID()]    = \"Explosive\";\n      damageTypeName[Concussive.getID()]   = \"Concussive\";\n      damageTypeName[Normal.getID()]       = \"Normal\";\n      damageTypeName[Ignore_Armor.getID()] = \"Ignore Armor\";\n      damageTypeName[None.getID()]         = \"None\";\n      damageTypeName[Unknown.getID()]      = \"Unknown\";\n\n      damageTypeSet.insert(Independent);\n      damageTypeSet.insert(Explosive);\n      damageTypeSet.insert(Concussive);\n      damageTypeSet.insert(Normal);\n      damageTypeSet.insert(Ignore_Armor);\n      damageTypeSet.insert(None);\n      damageTypeSet.insert(Unknown);\n\n      foreach(DamageType i, damageTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        damageTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingDamageType = false;\n    }\n  }\n  DamageType::DamageType()\n  {\n    this->id = DamageTypes::None.id;\n  }\n  DamageType::DamageType(int id)\n  {\n    this->id = id;\n    if (!initializingDamageType && (id < 0 || id >= 7))\n      this->id = DamageTypes::Unknown.id;\n  }\n  DamageType::DamageType(const DamageType& other)\n  {\n    this->id = other.id;\n  }\n  DamageType& DamageType::operator=(const DamageType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool DamageType::operator==(const DamageType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool DamageType::operator!=(const DamageType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool DamageType::operator<(const DamageType& other) const\n  {\n    return this->id < other.id;\n  }\n  int DamageType::getID() const\n  {\n    return this->id;\n  }\n  std::string DamageType::getName() const\n  {\n    return damageTypeName[this->id];\n  }\n\n  DamageType DamageTypes::getDamageType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, DamageType>::iterator i = damageTypeMap.find(name);\n    if (i == damageTypeMap.end())\n      return DamageTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<DamageType>& DamageTypes::allDamageTypes()\n  {\n    return damageTypeSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Error.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/Error.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingError = true;\n  std::string errorName[25];\n  std::map<std::string, Error> errorMap;\n  std::set< Error > errorSet;\n  namespace Errors\n  {\n    const Error Unit_Does_Not_Exist(0);\n    const Error Unit_Not_Visible(1);\n    const Error Unit_Not_Owned(2);\n    const Error Unit_Busy(3);\n    const Error Incompatible_UnitType(4);\n    const Error Incompatible_TechType(5);\n    const Error Incompatible_State(6);\n    const Error Already_Researched(7);\n    const Error Fully_Upgraded(8);\n    const Error Currently_Researching(9);\n    const Error Currently_Upgrading(10);\n    const Error Insufficient_Minerals(11);\n    const Error Insufficient_Gas(12);\n    const Error Insufficient_Supply(13);\n    const Error Insufficient_Energy(14);\n    const Error Insufficient_Tech(15);\n    const Error Insufficient_Ammo(16);\n    const Error Insufficient_Space(17);\n    const Error Unbuildable_Location(18);\n    const Error Unreachable_Location(19);\n    const Error Out_Of_Range(20);\n    const Error Unable_To_Hit(21);\n    const Error Access_Denied(22);\n    const Error None(23);\n    const Error Unknown(24);\n\n    void init()\n    {\n      errorName[Unit_Does_Not_Exist.getID()]   = \"Unit Does Not Exist\";\n      errorName[Unit_Not_Visible.getID()]      = \"Unit Not Visible\";\n      errorName[Unit_Not_Owned.getID()]        = \"Unit Not Owned\";\n      errorName[Unit_Busy.getID()]             = \"Unit Busy\";\n      errorName[Incompatible_UnitType.getID()] = \"Incompatible UnitType\";\n      errorName[Incompatible_TechType.getID()] = \"Incompatible TechType\";\n      errorName[Incompatible_State.getID()]    = \"Incompatible State\";\n      errorName[Already_Researched.getID()]    = \"Already Researched\";\n      errorName[Fully_Upgraded.getID()]        = \"Fully Upgraded\";\n      errorName[Currently_Researching.getID()] = \"Currently Researching\";\n      errorName[Currently_Upgrading.getID()]   = \"Currently Upgrading\";\n      errorName[Insufficient_Minerals.getID()] = \"Insufficient Minerals\";\n      errorName[Insufficient_Gas.getID()]      = \"Insufficient Gas\";\n      errorName[Insufficient_Supply.getID()]   = \"Insufficient Supply\";\n      errorName[Insufficient_Energy.getID()]   = \"Insufficient Energy\";\n      errorName[Insufficient_Tech.getID()]     = \"Insufficient Tech\";\n      errorName[Insufficient_Ammo.getID()]     = \"Insufficient Ammo\";\n      errorName[Insufficient_Space.getID()]    = \"Insufficient Space\";\n      errorName[Unbuildable_Location.getID()]  = \"Unbuildable Location\";\n      errorName[Unreachable_Location.getID()]  = \"Unreachable Location\";\n      errorName[Out_Of_Range.getID()]          = \"Out Of Range\";\n      errorName[Unable_To_Hit.getID()]         = \"Unable To Hit\";\n      errorName[Access_Denied.getID()]         = \"Access Denied\";\n      errorName[None.getID()]                  = \"None\";\n      errorName[Unknown.getID()]               = \"Unknown\";\n\n      errorSet.insert(Unit_Does_Not_Exist);\n      errorSet.insert(Unit_Not_Visible);\n      errorSet.insert(Unit_Not_Owned);\n      errorSet.insert(Unit_Busy);\n      errorSet.insert(Incompatible_UnitType);\n      errorSet.insert(Incompatible_TechType);\n      errorSet.insert(Incompatible_State);\n      errorSet.insert(Already_Researched);\n      errorSet.insert(Fully_Upgraded);\n      errorSet.insert(Currently_Researching);\n      errorSet.insert(Currently_Upgrading);\n      errorSet.insert(Insufficient_Minerals);\n      errorSet.insert(Insufficient_Gas);\n      errorSet.insert(Insufficient_Supply);\n      errorSet.insert(Insufficient_Energy);\n      errorSet.insert(Insufficient_Tech);\n      errorSet.insert(Insufficient_Ammo);\n      errorSet.insert(Insufficient_Space);\n      errorSet.insert(Unbuildable_Location);\n      errorSet.insert(Unreachable_Location);\n      errorSet.insert(Out_Of_Range);\n      errorSet.insert(Unable_To_Hit);\n      errorSet.insert(Access_Denied);\n      errorSet.insert(None);\n      errorSet.insert(Unknown);\n\n      foreach(Error i, errorSet)\n      {\n        std::string name = i.toString();\n        fixName(&name);\n        errorMap.insert(std::make_pair(name, i));\n      }\n      initializingError = false;\n    }\n  }\n\n  Error::Error()\n  {\n    this->id = Errors::None.id;\n  }\n  Error::Error(int id)\n  {\n    this->id = id;\n    if (!initializingError && (id < 0 || id >= 25))\n      this->id = Errors::Unknown.id;\n  }\n  Error::Error(const Error& other)\n  {\n    this->id = other.id;\n  }\n  Error& Error::operator=(const Error& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool Error::operator==(const Error& other) const\n  {\n    return this->id == other.id;\n  }\n  bool Error::operator!=(const Error& other) const\n  {\n    return this->id != other.id;\n  }\n  bool Error::operator<(const Error& other) const\n  {\n    return this->id < other.id;\n  }\n  int Error::getID() const\n  {\n    return this->id;\n  }\n  std::string Error::toString() const\n  {\n    return errorName[this->id];\n  }\n  Error Errors::getError(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, Error>::iterator i = errorMap.find(name);\n    if (i == errorMap.end())\n      return Errors::Unknown;\n    return (*i).second;\n  }\n  std::set<Error>& Errors::allErrors()\n  {\n    return errorSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Event.cpp",
    "content": "#include <BWAPI/Event.h>\nnamespace BWAPI\n{\n  Event::Event() : type(EventType::None), position(Positions::None), text(\"\"), unit(NULL), player(NULL), isWinner(false)\n  {\n  }\n  bool Event::operator==(const Event& other)\n  {\n    return (type     == other.type &&\n            position == other.position &&\n            text     == other.text &&\n            unit     == other.unit &&\n            player   == other.player &&\n            isWinner == other.isWinner);\n  }\n  Event Event::MatchStart()\n  {\n    Event e;\n    e.type = EventType::MatchStart;\n    return e;\n  }\n  Event Event::MatchEnd(bool isWinner)\n  {\n    Event e;\n    e.type     = EventType::MatchEnd;\n    e.isWinner = isWinner;\n    return e;\n  }\n  Event Event::MatchFrame()\n  {\n    Event e;\n    e.type = EventType::MatchFrame;\n    return e;\n  }\n  Event Event::MenuFrame()\n  {\n    Event e;\n    e.type = EventType::MenuFrame;\n    return e;\n  }\n  Event Event::SendText(std::string text)\n  {\n    Event e;\n    e.type = EventType::SendText;\n    e.text = text;\n    return e;\n  }\n  Event Event::ReceiveText(Player* player, std::string text)\n  {\n    Event e;\n    e.type   = EventType::ReceiveText;\n    e.player = player;\n    e.text   = text;\n    return e;\n  }\n  Event Event::PlayerLeft(Player* player)\n  {\n    Event e;\n    e.type   = EventType::PlayerLeft;\n    e.player = player;\n    return e;\n  }\n  Event Event::NukeDetect(Position target)\n  {\n    Event e;\n    e.type     = EventType::NukeDetect;\n    e.position = target;\n    return e;\n  }\n  Event Event::UnitDiscover(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitDiscover;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitEvade(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitEvade;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitShow(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitShow;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitHide(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitHide;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitCreate(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitCreate;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitDestroy(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitDestroy;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitMorph(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitMorph;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitRenegade(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitRenegade;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::SaveGame(std::string gameName)\n  {\n    Event e;\n    e.type = EventType::SaveGame;\n    e.text = gameName;\n    return e;\n  }\n}"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/ExplosionType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/ExplosionType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingExplosionType = true;\n  std::string explosionTypeName[26];\n  std::map<std::string, ExplosionType> explosionTypeMap;\n  std::set< ExplosionType > explosionTypeSet;\n  namespace ExplosionTypes\n  {\n    const ExplosionType None(0);\n    const ExplosionType Normal(1);\n    const ExplosionType Radial_Splash(2);\n    const ExplosionType Enemy_Splash(3);\n    const ExplosionType Lockdown(4);\n    const ExplosionType Nuclear_Missile(5);\n    const ExplosionType Parasite(6);\n    const ExplosionType Broodlings(7);\n    const ExplosionType EMP_Shockwave(8);\n    const ExplosionType Irradiate(9);\n    const ExplosionType Ensnare(10);\n    const ExplosionType Plague(11);\n    const ExplosionType Stasis_Field(12);\n    const ExplosionType Dark_Swarm(13);\n    const ExplosionType Consume(14);\n    const ExplosionType Yamato_Gun(15);\n    const ExplosionType Restoration(16);\n    const ExplosionType Disruption_Web(17);\n    const ExplosionType Corrosive_Acid(18);\n    const ExplosionType Mind_Control(19);\n    const ExplosionType Feedback(20);\n    const ExplosionType Optical_Flare(21);\n    const ExplosionType Maelstrom(22);\n    const ExplosionType Air_Splash(24);\n    const ExplosionType Unknown(25);\n\n    void init()\n    {\n      explosionTypeName[None.getID()]            = \"None\";\n      explosionTypeName[Normal.getID()]          = \"Normal\";\n      explosionTypeName[Radial_Splash.getID()]   = \"Radial Splash\";\n      explosionTypeName[Enemy_Splash.getID()]    = \"Enemy Splash\";\n      explosionTypeName[Lockdown.getID()]        = \"Lockdown\";\n      explosionTypeName[Nuclear_Missile.getID()] = \"Nuclear Missile\";\n      explosionTypeName[Parasite.getID()]        = \"Parasite\";\n      explosionTypeName[Broodlings.getID()]      = \"Broodlings\";\n      explosionTypeName[EMP_Shockwave.getID()]   = \"EMP Shockwave\";\n      explosionTypeName[Irradiate.getID()]       = \"Irradiate\";\n      explosionTypeName[Ensnare.getID()]         = \"Ensnare\";\n      explosionTypeName[Plague.getID()]          = \"Plague\";\n      explosionTypeName[Stasis_Field.getID()]    = \"Stasis Field\";\n      explosionTypeName[Dark_Swarm.getID()]      = \"Dark Swarm\";\n      explosionTypeName[Consume.getID()]         = \"Consume\";\n      explosionTypeName[Yamato_Gun.getID()]      = \"Yamato Gun\";\n      explosionTypeName[Restoration.getID()]     = \"Restoration\";\n      explosionTypeName[Disruption_Web.getID()]  = \"Disruption Web\";\n      explosionTypeName[Corrosive_Acid.getID()]  = \"Corrosive Acid\";\n      explosionTypeName[Mind_Control.getID()]    = \"Mind Control\";\n      explosionTypeName[Feedback.getID()]        = \"Feedback\";\n      explosionTypeName[Optical_Flare.getID()]   = \"Optical Flare\";\n      explosionTypeName[Maelstrom.getID()]       = \"Maelstrom\";\n      explosionTypeName[Air_Splash.getID()]      = \"Air Splash\";\n      explosionTypeName[Unknown.getID()]         = \"Unknown\";\n\n      explosionTypeSet.insert(None);\n      explosionTypeSet.insert(Normal);\n      explosionTypeSet.insert(Radial_Splash);\n      explosionTypeSet.insert(Enemy_Splash);\n      explosionTypeSet.insert(Lockdown);\n      explosionTypeSet.insert(Nuclear_Missile);\n      explosionTypeSet.insert(Parasite);\n      explosionTypeSet.insert(Broodlings);\n      explosionTypeSet.insert(EMP_Shockwave);\n      explosionTypeSet.insert(Irradiate);\n      explosionTypeSet.insert(Ensnare);\n      explosionTypeSet.insert(Plague);\n      explosionTypeSet.insert(Stasis_Field);\n      explosionTypeSet.insert(Dark_Swarm);\n      explosionTypeSet.insert(Consume);\n      explosionTypeSet.insert(Yamato_Gun);\n      explosionTypeSet.insert(Restoration);\n      explosionTypeSet.insert(Disruption_Web);\n      explosionTypeSet.insert(Corrosive_Acid);\n      explosionTypeSet.insert(Mind_Control);\n      explosionTypeSet.insert(Feedback);\n      explosionTypeSet.insert(Optical_Flare);\n      explosionTypeSet.insert(Maelstrom);\n      explosionTypeSet.insert(Air_Splash);\n      explosionTypeSet.insert(Unknown);\n\n      foreach(ExplosionType i, explosionTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        explosionTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingExplosionType = false;\n    }\n  }\n  ExplosionType::ExplosionType()\n  {\n    this->id = ExplosionTypes::None.id;\n  }\n  ExplosionType::ExplosionType(int id)\n  {\n    this->id = id;\n    if (!initializingExplosionType && (id < 0 || id >= 26))\n      this->id = ExplosionTypes::Unknown.id;\n  }\n  ExplosionType::ExplosionType(const ExplosionType& other)\n  {\n    this->id = other.id;\n  }\n  ExplosionType& ExplosionType::operator=(const ExplosionType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool ExplosionType::operator==(const ExplosionType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool ExplosionType::operator!=(const ExplosionType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool ExplosionType::operator<(const ExplosionType& other) const\n  {\n    return this->id < other.id;\n  }\n  int ExplosionType::getID() const\n  {\n    return this->id;\n  }\n  std::string ExplosionType::getName() const\n  {\n    return explosionTypeName[this->id];\n  }\n\n  ExplosionType ExplosionTypes::getExplosionType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, ExplosionType>::iterator i = explosionTypeMap.find(name);\n    if (i == explosionTypeMap.end())\n      return ExplosionTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<ExplosionType>& ExplosionTypes::allExplosionTypes()\n  {\n    return explosionTypeSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/GameType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/GameType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingGameType = true;\n  std::string gameTypeName[35];\n  std::map<std::string, GameType> gameTypeMap;\n  std::set< GameType > gameTypeSet;\n  namespace GameTypes\n  {\n    const GameType Melee(2);\n    const GameType Free_For_All(3);\n    const GameType One_on_One(4);\n    const GameType Capture_The_Flag(5);\n    const GameType Greed(6);\n    const GameType Slaughter(7);\n    const GameType Sudden_Death(8);\n    const GameType Ladder(9);\n    const GameType Use_Map_Settings(10);\n    const GameType Team_Melee(11);\n    const GameType Team_Free_For_All(12);\n    const GameType Team_Capture_The_Flag(13);\n    const GameType Top_vs_Bottom(15);\n    const GameType Pro_Gamer_League(32);\n    const GameType None(33);\n    const GameType Unknown(34);\n\n    void init()\n    {\n      gameTypeName[Melee.getID()]                 = \"Melee\";\n      gameTypeName[Free_For_All.getID()]          = \"Free For All\";\n      gameTypeName[One_on_One.getID()]            = \"One on One\";\n      gameTypeName[Capture_The_Flag.getID()]      = \"Capture The Flag\";\n      gameTypeName[Greed.getID()]                 = \"Greed\";\n      gameTypeName[Slaughter.getID()]             = \"Slaughter\";\n      gameTypeName[Sudden_Death.getID()]          = \"Sudden Death\";\n      gameTypeName[Ladder.getID()]                = \"Ladder\";\n      gameTypeName[Use_Map_Settings.getID()]      = \"Use Map Settings\";\n      gameTypeName[Team_Melee.getID()]            = \"Team Melee\";\n      gameTypeName[Team_Free_For_All.getID()]     = \"Team Free For All\";\n      gameTypeName[Team_Capture_The_Flag.getID()] = \"Team Capture The Flag\";\n      gameTypeName[Top_vs_Bottom.getID()]         = \"Top vs Bottom\";\n      gameTypeName[Pro_Gamer_League.getID()]      = \"Pro Gamer League\";\n      gameTypeName[None.getID()]                  = \"None\";\n      gameTypeName[Unknown.getID()]               = \"Unknown\";\n\n      gameTypeSet.insert(Melee);\n      gameTypeSet.insert(Free_For_All);\n      gameTypeSet.insert(One_on_One);\n      gameTypeSet.insert(Capture_The_Flag);\n      gameTypeSet.insert(Greed);\n      gameTypeSet.insert(Slaughter);\n      gameTypeSet.insert(Sudden_Death);\n      gameTypeSet.insert(Ladder);\n      gameTypeSet.insert(Use_Map_Settings);\n      gameTypeSet.insert(Team_Melee);\n      gameTypeSet.insert(Team_Free_For_All);\n      gameTypeSet.insert(Team_Capture_The_Flag);\n      gameTypeSet.insert(Top_vs_Bottom);\n      gameTypeSet.insert(Pro_Gamer_League);\n      gameTypeSet.insert(None);\n      gameTypeSet.insert(Unknown);\n\n      foreach(GameType i, gameTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        gameTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingGameType = false;\n    }\n  }\n  GameType::GameType()\n  {\n    this->id = GameTypes::None.id;\n  }\n  GameType::GameType(int id)\n  {\n    this->id = id;\n    if (!initializingGameType && (id < 0 || id >= 35 || gameTypeName[id].length() == 0))\n      this->id = GameTypes::Unknown.id;\n  }\n  GameType::GameType(const GameType& other)\n  {\n    this->id = other.id;\n  }\n  GameType& GameType::operator=(const GameType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool GameType::operator==(const GameType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool GameType::operator!=(const GameType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool GameType::operator<(const GameType& other) const\n  {\n    return this->id < other.id;\n  }\n  int GameType::getID() const\n  {\n    return this->id;\n  }\n  std::string GameType::getName() const\n  {\n    return gameTypeName[this->id];\n  }\n  GameType GameTypes::getGameType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, GameType>::iterator i = gameTypeMap.find(name);\n    if (i == gameTypeMap.end()) return GameTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<GameType>& GameTypes::allGameTypes()\n  {\n    return gameTypeSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Order.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/Order.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingOrder = true;\n  std::string orderName[191];\n  std::map<std::string, Order> orderMap;\n  std::set< Order > orderSet;\n  namespace Orders\n  {\n    const Order Die(0);\n    const Order Stop(1);\n    const Order Guard(2);\n    const Order PlayerGuard(3);\n    const Order TurretGuard(4);\n    const Order BunkerGuard(5);\n    const Order Move(6);\n    const Order AttackUnit(10);\n    const Order AttackTile(12);\n    const Order Hover(13);\n    const Order AttackMove(14);\n    const Order InfestedCommandCenter(15);\n    const Order UnusedNothing(16);\n    const Order UnusedPowerup(17);\n    const Order TowerGuard(18);\n    const Order VultureMine(20);\n    const Order Nothing(23);\n    const Order Nothing3(24);\n    const Order CastInfestation(27);\n    const Order InfestingCommandCenter(29);\n    const Order PlaceBuilding(30);\n    const Order BuildProtoss2(32);\n    const Order ConstructingBuilding(33);\n    const Order Repair(34);\n    const Order PlaceAddon(36);\n    const Order BuildAddon(37);\n    const Order Train(38);\n    const Order RallyPointUnit(39);\n    const Order RallyPointTile(40);\n    const Order ZergBirth(41);\n    const Order ZergUnitMorph(42);\n    const Order ZergBuildingMorph(43);\n    const Order IncompleteBuilding(44);\n    const Order BuildNydusExit(46);\n    const Order EnterNydusCanal(47);\n    const Order Follow(49);\n    const Order Carrier(50);\n    const Order ReaverCarrierMove(51);\n    const Order CarrierIgnore2(55);\n    const Order Reaver(58);\n    const Order TrainFighter(63);\n    const Order InterceptorAttack(64);\n    const Order ScarabAttack(65);\n    const Order RechargeShieldsUnit(66);\n    const Order RechargeShieldsBattery(67);\n    const Order ShieldBattery(68);\n    const Order InterceptorReturn(69);\n    const Order BuildingLand(71);\n    const Order BuildingLiftOff(72);\n    const Order DroneLiftOff(73);\n    const Order LiftingOff(74);\n    const Order ResearchTech(75);\n    const Order Upgrade(76);\n    const Order Larva(77);\n    const Order SpawningLarva(78);\n    const Order Harvest1(79);\n    const Order Harvest2(80);\n    const Order MoveToGas(81);\n    const Order WaitForGas(82);\n    const Order HarvestGas(83);\n    const Order ReturnGas(84);\n    const Order MoveToMinerals(85);\n    const Order WaitForMinerals(86);\n    const Order MiningMinerals(87);\n    const Order Harvest3(88);\n    const Order Harvest4(89);\n    const Order ReturnMinerals(90);\n    const Order Interrupted(91);\n    const Order EnterTransport(92);\n    const Order PickupIdle(93);\n    const Order PickupTransport(94);\n    const Order PickupBunker(95);\n    const Order Pickup4(96);\n    const Order PowerupIdle(97);\n    const Order Sieging(98);\n    const Order Unsieging(99);\n    const Order InitCreepGrowth(101);\n    const Order SpreadCreep(102);\n    const Order StoppingCreepGrowth(103);\n    const Order GuardianAspect(104);\n    const Order ArchonWarp(105);\n    const Order CompletingArchonsummon(106);\n    const Order HoldPosition(107);\n    const Order Cloak(109);\n    const Order Decloak(110);\n    const Order Unload(111);\n    const Order MoveUnload(112);\n    const Order FireYamatoGun(113);\n    const Order CastLockdown(115);\n    const Order Burrowing(116);\n    const Order Burrowed(117);\n    const Order Unburrowing(118);\n    const Order CastDarkSwarm(119);\n    const Order CastParasite(120);\n    const Order CastSpawnBroodlings(121);\n    const Order CastEMPShockwave(122);\n    const Order NukeWait(123);\n    const Order NukeTrain(124);\n    const Order NukeLaunch(125);\n    const Order NukeUnit(127);\n    const Order CastNuclearStrike(128);\n    const Order NukeTrack(129);\n    const Order CloakNearbyUnits(131);\n    const Order PlaceMine(132);\n    const Order RightClickAction(133);\n    const Order CastRecall(137);\n    const Order TeleporttoLocation(138);\n    const Order CastScannerSweep(139);\n    const Order Scanner(140);\n    const Order CastDefensiveMatrix(141);\n    const Order CastPsionicStorm(142);\n    const Order CastIrradiate(143);\n    const Order CastPlague(144);\n    const Order CastConsume(145);\n    const Order CastEnsnare(146);\n    const Order CastStasisField(147);\n    const Order CastHallucination(148);\n    const Order Hallucination2(149);\n    const Order ResetCollision(150);\n    const Order Patrol(152);\n    const Order CTFCOPInit(153);\n    const Order CTFCOP1(154);\n    const Order CTFCOP2(155);\n    const Order ComputerAI(156);\n    const Order AtkMoveEP(157);\n    const Order HarassMove(158);\n    const Order AIPatrol(159);\n    const Order GuardPost(160);\n    const Order RescuePassive(161);\n    const Order Neutral(162);\n    const Order ComputerReturn(163);\n    const Order SelfDestrucing(165);\n    const Order Critter(166);\n    const Order HiddenGun(167);\n    const Order OpenDoor(168);\n    const Order CloseDoor(169);\n    const Order HideTrap(170);\n    const Order RevealTrap(171);\n    const Order Enabledoodad(172);\n    const Order Disabledoodad(173);\n    const Order Warpin(174);\n    const Order Medic(175);\n    const Order MedicHeal1(176);\n    const Order HealMove(177);\n    const Order MedicHeal2(179);\n    const Order CastRestoration(180);\n    const Order CastDisruptionWeb(181);\n    const Order CastMindControl(182);\n    const Order DarkArchonMeld(183);\n    const Order CastFeedback(184);\n    const Order CastOpticalFlare(185);\n    const Order CastMaelstrom(186);\n    const Order JunkYardDog(187);\n    const Order Fatal(188);\n    const Order None(189);\n    const Order Unknown(190);\n\n    void init()\n    {\n      orderName[Die.getID()]                    = \"Die\";\n      orderName[Stop.getID()]                   = \"Stop\";\n      orderName[Guard.getID()]                  = \"Guard\";\n      orderName[PlayerGuard.getID()]            = \"PlayerGuard\";\n      orderName[TurretGuard.getID()]            = \"TurretGuard\";\n      orderName[BunkerGuard.getID()]            = \"BunkerGuard\";\n      orderName[Move.getID()]                   = \"Move\";\n      orderName[AttackUnit.getID()]             = \"AttackUnit\";\n      orderName[AttackTile.getID()]             = \"AttackTile\";\n      orderName[Hover.getID()]                  = \"Hover\";\n      orderName[AttackMove.getID()]             = \"AttackMove\";\n      orderName[InfestedCommandCenter.getID()]  = \"InfestedCommandCenter\";\n      orderName[UnusedNothing.getID()]          = \"UnusedNothing\";\n      orderName[UnusedPowerup.getID()]          = \"UnusedPowerup\";\n      orderName[TowerGuard.getID()]             = \"TowerGuard\";\n      orderName[VultureMine.getID()]            = \"VultureMine\";\n      orderName[Nothing.getID()]                = \"Nothing\";\n      orderName[Nothing3.getID()]               = \"Nothing3\";\n      orderName[CastInfestation.getID()]        = \"CastInfestation\";\n      orderName[InfestingCommandCenter.getID()] = \"InfestingCommandCenter\";\n      orderName[PlaceBuilding.getID()]          = \"PlaceBuilding\";\n      orderName[BuildProtoss2.getID()]          = \"BuildProtoss2\";\n      orderName[ConstructingBuilding.getID()]   = \"ConstructingBuilding\";\n      orderName[Repair.getID()]                 = \"Repair\";\n      orderName[PlaceAddon.getID()]             = \"PlaceAddon\";\n      orderName[BuildAddon.getID()]             = \"BuildAddon\";\n      orderName[Train.getID()]                  = \"Train\";\n      orderName[RallyPointUnit.getID()]         = \"RallyPointUnit\";\n      orderName[RallyPointTile.getID()]         = \"RallyPointTile\";\n      orderName[ZergBirth.getID()]              = \"ZergBirth\";\n      orderName[ZergUnitMorph.getID()]          = \"ZergUnitMorph\";\n      orderName[ZergBuildingMorph.getID()]      = \"ZergBuildingMorph\";\n      orderName[IncompleteBuilding.getID()]     = \"IncompleteBuilding\";\n      orderName[BuildNydusExit.getID()]         = \"BuildNydusExit\";\n      orderName[EnterNydusCanal.getID()]        = \"EnterNydusCanal\";\n      orderName[Follow.getID()]                 = \"Follow\";\n      orderName[Carrier.getID()]                = \"Carrier\";\n      orderName[ReaverCarrierMove.getID()]      = \"ReaverCarrierMove\";\n      orderName[CarrierIgnore2.getID()]         = \"CarrierIgnore2\";\n      orderName[Reaver.getID()]                 = \"Reaver\";\n      orderName[TrainFighter.getID()]           = \"TrainFighter\";\n      orderName[InterceptorAttack.getID()]      = \"InterceptorAttack\";\n      orderName[ScarabAttack.getID()]           = \"ScarabAttack\";\n      orderName[RechargeShieldsUnit.getID()]    = \"RechargeShieldsUnit\";\n      orderName[RechargeShieldsBattery.getID()] = \"RechargeShieldsBattery\";\n      orderName[ShieldBattery.getID()]          = \"ShieldBattery\";\n      orderName[InterceptorReturn.getID()]      = \"InterceptorReturn\";\n      orderName[BuildingLand.getID()]           = \"BuildingLand\";\n      orderName[BuildingLiftOff.getID()]        = \"BuildingLiftOff\";\n      orderName[DroneLiftOff.getID()]           = \"DroneLiftOff\";\n      orderName[LiftingOff.getID()]             = \"LiftingOff\";\n      orderName[ResearchTech.getID()]           = \"ResearchTech\";\n      orderName[Upgrade.getID()]                = \"Upgrade\";\n      orderName[Larva.getID()]                  = \"Larva\";\n      orderName[SpawningLarva.getID()]          = \"SpawningLarva\";\n      orderName[Harvest1.getID()]               = \"Harvest1\";\n      orderName[Harvest2.getID()]               = \"Harvest2\";\n      orderName[MoveToGas.getID()]              = \"MoveToGas\";\n      orderName[WaitForGas.getID()]             = \"WaitForGas\";\n      orderName[HarvestGas.getID()]             = \"HarvestGas\";\n      orderName[ReturnGas.getID()]              = \"ReturnGas\";\n      orderName[MoveToMinerals.getID()]         = \"MoveToMinerals\";\n      orderName[WaitForMinerals.getID()]        = \"WaitForMinerals\";\n      orderName[MiningMinerals.getID()]         = \"MiningMinerals\";\n      orderName[Harvest3.getID()]               = \"Harvest3\";\n      orderName[Harvest4.getID()]               = \"Harvest4\";\n      orderName[ReturnMinerals.getID()]         = \"ReturnMinerals\";\n      orderName[Interrupted.getID()]            = \"Interrupted\";\n      orderName[EnterTransport.getID()]         = \"EnterTransport\";\n      orderName[PickupIdle.getID()]             = \"PickupIdle\";\n      orderName[PickupTransport.getID()]        = \"PickupTransport\";\n      orderName[PickupBunker.getID()]           = \"PickupBunker\";\n      orderName[Pickup4.getID()]                = \"Pickup4\";\n      orderName[PowerupIdle.getID()]            = \"PowerupIdle\";\n      orderName[Sieging.getID()]                = \"Sieging\";\n      orderName[Unsieging.getID()]              = \"Unsieging\";\n      orderName[InitCreepGrowth.getID()]        = \"InitCreepGrowth\";\n      orderName[SpreadCreep.getID()]            = \"SpreadCreep\";\n      orderName[StoppingCreepGrowth.getID()]    = \"StoppingCreepGrowth\";\n      orderName[GuardianAspect.getID()]         = \"GuardianAspect\";\n      orderName[ArchonWarp.getID()]             = \"ArchonWarp\";\n      orderName[CompletingArchonsummon.getID()] = \"CompletingArchonsummon\";\n      orderName[HoldPosition.getID()]           = \"HoldPosition\";\n      orderName[Cloak.getID()]                  = \"Cloak\";\n      orderName[Decloak.getID()]                = \"Decloak\";\n      orderName[Unload.getID()]                 = \"Unload\";\n      orderName[MoveUnload.getID()]             = \"MoveUnload\";\n      orderName[FireYamatoGun.getID()]          = \"FireYamatoGun\";\n      orderName[CastLockdown.getID()]           = \"CastLockdown\";\n      orderName[Burrowing.getID()]              = \"Burrowing\";\n      orderName[Burrowed.getID()]               = \"Burrowed\";\n      orderName[Unburrowing.getID()]            = \"Unburrowing\";\n      orderName[CastDarkSwarm.getID()]          = \"CastDarkSwarm\";\n      orderName[CastParasite.getID()]           = \"CastParasite\";\n      orderName[CastSpawnBroodlings.getID()]    = \"CastSpawnBroodlings\";\n      orderName[CastEMPShockwave.getID()]       = \"CastEMPShockwave\";\n      orderName[NukeWait.getID()]               = \"NukeWait\";\n      orderName[NukeTrain.getID()]              = \"NukeTrain\";\n      orderName[NukeLaunch.getID()]             = \"NukeLaunch\";\n      orderName[NukeUnit.getID()]               = \"NukeUnit\";\n      orderName[CastNuclearStrike.getID()]      = \"CastNuclearStrike\";\n      orderName[NukeTrack.getID()]              = \"NukeTrack\";\n      orderName[CloakNearbyUnits.getID()]       = \"CloakNearbyUnits\";\n      orderName[PlaceMine.getID()]              = \"PlaceMine\";\n      orderName[RightClickAction.getID()]       = \"RightClickAction\";\n      orderName[CastRecall.getID()]             = \"CastRecall\";\n      orderName[TeleporttoLocation.getID()]     = \"TeleporttoLocation\";\n      orderName[CastScannerSweep.getID()]       = \"CastScannerSweep\";\n      orderName[Scanner.getID()]                = \"Scanner\";\n      orderName[CastDefensiveMatrix.getID()]    = \"CastDefensiveMatrix\";\n      orderName[CastPsionicStorm.getID()]       = \"CastPsionicStorm\";\n      orderName[CastIrradiate.getID()]          = \"CastIrradiate\";\n      orderName[CastPlague.getID()]             = \"CastPlague\";\n      orderName[CastConsume.getID()]            = \"CastConsume\";\n      orderName[CastEnsnare.getID()]            = \"CastEnsnare\";\n      orderName[CastStasisField.getID()]        = \"CastStasisField\";\n      orderName[CastHallucination.getID()]      = \"CastHallucination\";\n      orderName[Hallucination2.getID()]         = \"Hallucination2\";\n      orderName[ResetCollision.getID()]         = \"ResetCollision\";\n      orderName[Patrol.getID()]                 = \"Patrol\";\n      orderName[CTFCOPInit.getID()]             = \"CTFCOPInit\";\n      orderName[CTFCOP1.getID()]                = \"CTFCOP1\";\n      orderName[CTFCOP2.getID()]                = \"CTFCOP2\";\n      orderName[ComputerAI.getID()]             = \"ComputerAI\";\n      orderName[AtkMoveEP.getID()]              = \"AtkMoveEP\";\n      orderName[HarassMove.getID()]             = \"HarassMove\";\n      orderName[AIPatrol.getID()]               = \"AIPatrol\";\n      orderName[GuardPost.getID()]              = \"GuardPost\";\n      orderName[RescuePassive.getID()]          = \"RescuePassive\";\n      orderName[Neutral.getID()]                = \"Neutral\";\n      orderName[ComputerReturn.getID()]         = \"ComputerReturn\";\n      orderName[SelfDestrucing.getID()]         = \"SelfDestrucing\";\n      orderName[Critter.getID()]                = \"Critter\";\n      orderName[HiddenGun.getID()]              = \"HiddenGun\";\n      orderName[OpenDoor.getID()]               = \"OpenDoor\";\n      orderName[CloseDoor.getID()]              = \"CloseDoor\";\n      orderName[HideTrap.getID()]               = \"HideTrap\";\n      orderName[RevealTrap.getID()]             = \"RevealTrap\";\n      orderName[Enabledoodad.getID()]           = \"Enabledoodad\";\n      orderName[Disabledoodad.getID()]          = \"Disabledoodad\";\n      orderName[Warpin.getID()]                 = \"Warpin\";\n      orderName[Medic.getID()]                  = \"Medic\";\n      orderName[MedicHeal1.getID()]             = \"MedicHeal1\";\n      orderName[HealMove.getID()]               = \"HealMove\";\n      orderName[MedicHeal2.getID()]             = \"MedicHeal2\";\n      orderName[CastRestoration.getID()]        = \"CastRestoration\";\n      orderName[CastDisruptionWeb.getID()]      = \"CastDisruptionWeb\";\n      orderName[CastMindControl.getID()]        = \"CastMindControl\";\n      orderName[DarkArchonMeld.getID()]         = \"DarkArchonMeld\";\n      orderName[CastFeedback.getID()]           = \"CastFeedback\";\n      orderName[CastOpticalFlare.getID()]       = \"CastOpticalFlare\";\n      orderName[CastMaelstrom.getID()]          = \"CastMaelstrom\";\n      orderName[JunkYardDog.getID()]            = \"JunkYardDog\";\n      orderName[Fatal.getID()]                  = \"Fatal\";\n      orderName[None.getID()]                   = \"None\";\n      orderName[Unknown.getID()]                = \"Unknown\";\n\n      orderSet.insert(Die);\n      orderSet.insert(Stop);\n      orderSet.insert(Guard);\n      orderSet.insert(PlayerGuard);\n      orderSet.insert(TurretGuard);\n      orderSet.insert(BunkerGuard);\n      orderSet.insert(Move);\n      orderSet.insert(AttackUnit);\n      orderSet.insert(AttackTile);\n      orderSet.insert(Hover);\n      orderSet.insert(AttackMove);\n      orderSet.insert(InfestedCommandCenter);\n      orderSet.insert(UnusedNothing);\n      orderSet.insert(UnusedPowerup);\n      orderSet.insert(TowerGuard);\n      orderSet.insert(VultureMine);\n      orderSet.insert(Nothing);\n      orderSet.insert(Nothing3);\n      orderSet.insert(CastInfestation);\n      orderSet.insert(InfestingCommandCenter);\n      orderSet.insert(PlaceBuilding);\n      orderSet.insert(BuildProtoss2);\n      orderSet.insert(ConstructingBuilding);\n      orderSet.insert(Repair);\n      orderSet.insert(PlaceAddon);\n      orderSet.insert(BuildAddon);\n      orderSet.insert(Train);\n      orderSet.insert(RallyPointUnit);\n      orderSet.insert(RallyPointTile);\n      orderSet.insert(ZergBirth);\n      orderSet.insert(ZergUnitMorph);\n      orderSet.insert(ZergBuildingMorph);\n      orderSet.insert(IncompleteBuilding);\n      orderSet.insert(BuildNydusExit);\n      orderSet.insert(EnterNydusCanal);\n      orderSet.insert(Follow);\n      orderSet.insert(Carrier);\n      orderSet.insert(ReaverCarrierMove);\n      orderSet.insert(CarrierIgnore2);\n      orderSet.insert(Reaver);\n      orderSet.insert(TrainFighter);\n      orderSet.insert(InterceptorAttack);\n      orderSet.insert(ScarabAttack);\n      orderSet.insert(RechargeShieldsUnit);\n      orderSet.insert(RechargeShieldsBattery);\n      orderSet.insert(ShieldBattery);\n      orderSet.insert(InterceptorReturn);\n      orderSet.insert(BuildingLand);\n      orderSet.insert(BuildingLiftOff);\n      orderSet.insert(DroneLiftOff);\n      orderSet.insert(LiftingOff);\n      orderSet.insert(ResearchTech);\n      orderSet.insert(Upgrade);\n      orderSet.insert(Larva);\n      orderSet.insert(SpawningLarva);\n      orderSet.insert(Harvest1);\n      orderSet.insert(Harvest2);\n      orderSet.insert(MoveToGas);\n      orderSet.insert(WaitForGas);\n      orderSet.insert(HarvestGas);\n      orderSet.insert(ReturnGas);\n      orderSet.insert(MoveToMinerals);\n      orderSet.insert(WaitForMinerals);\n      orderSet.insert(MiningMinerals);\n      orderSet.insert(Harvest3);\n      orderSet.insert(Harvest4);\n      orderSet.insert(ReturnMinerals);\n      orderSet.insert(Interrupted);\n      orderSet.insert(EnterTransport);\n      orderSet.insert(PickupIdle);\n      orderSet.insert(PickupTransport);\n      orderSet.insert(PickupBunker);\n      orderSet.insert(Pickup4);\n      orderSet.insert(PowerupIdle);\n      orderSet.insert(Sieging);\n      orderSet.insert(Unsieging);\n      orderSet.insert(InitCreepGrowth);\n      orderSet.insert(SpreadCreep);\n      orderSet.insert(StoppingCreepGrowth);\n      orderSet.insert(GuardianAspect);\n      orderSet.insert(ArchonWarp);\n      orderSet.insert(CompletingArchonsummon);\n      orderSet.insert(HoldPosition);\n      orderSet.insert(Cloak);\n      orderSet.insert(Decloak);\n      orderSet.insert(Unload);\n      orderSet.insert(MoveUnload);\n      orderSet.insert(FireYamatoGun);\n      orderSet.insert(CastLockdown);\n      orderSet.insert(Burrowing);\n      orderSet.insert(Burrowed);\n      orderSet.insert(Unburrowing);\n      orderSet.insert(CastDarkSwarm);\n      orderSet.insert(CastParasite);\n      orderSet.insert(CastSpawnBroodlings);\n      orderSet.insert(CastEMPShockwave);\n      orderSet.insert(NukeWait);\n      orderSet.insert(NukeTrain);\n      orderSet.insert(NukeLaunch);\n      orderSet.insert(NukeUnit);\n      orderSet.insert(CastNuclearStrike);\n      orderSet.insert(NukeTrack);\n      orderSet.insert(CloakNearbyUnits);\n      orderSet.insert(PlaceMine);\n      orderSet.insert(RightClickAction);\n      orderSet.insert(CastRecall);\n      orderSet.insert(TeleporttoLocation);\n      orderSet.insert(CastScannerSweep);\n      orderSet.insert(Scanner);\n      orderSet.insert(CastDefensiveMatrix);\n      orderSet.insert(CastPsionicStorm);\n      orderSet.insert(CastIrradiate);\n      orderSet.insert(CastPlague);\n      orderSet.insert(CastConsume);\n      orderSet.insert(CastEnsnare);\n      orderSet.insert(CastStasisField);\n      orderSet.insert(CastHallucination);\n      orderSet.insert(Hallucination2);\n      orderSet.insert(ResetCollision);\n      orderSet.insert(Patrol);\n      orderSet.insert(CTFCOPInit);\n      orderSet.insert(CTFCOP1);\n      orderSet.insert(CTFCOP2);\n      orderSet.insert(ComputerAI);\n      orderSet.insert(AtkMoveEP);\n      orderSet.insert(HarassMove);\n      orderSet.insert(AIPatrol);\n      orderSet.insert(GuardPost);\n      orderSet.insert(RescuePassive);\n      orderSet.insert(Neutral);\n      orderSet.insert(ComputerReturn);\n      orderSet.insert(SelfDestrucing);\n      orderSet.insert(Critter);\n      orderSet.insert(HiddenGun);\n      orderSet.insert(OpenDoor);\n      orderSet.insert(CloseDoor);\n      orderSet.insert(HideTrap);\n      orderSet.insert(RevealTrap);\n      orderSet.insert(Enabledoodad);\n      orderSet.insert(Disabledoodad);\n      orderSet.insert(Warpin);\n      orderSet.insert(Medic);\n      orderSet.insert(MedicHeal1);\n      orderSet.insert(HealMove);\n      orderSet.insert(MedicHeal2);\n      orderSet.insert(CastRestoration);\n      orderSet.insert(CastDisruptionWeb);\n      orderSet.insert(CastMindControl);\n      orderSet.insert(DarkArchonMeld);\n      orderSet.insert(CastFeedback);\n      orderSet.insert(CastOpticalFlare);\n      orderSet.insert(CastMaelstrom);\n      orderSet.insert(JunkYardDog);\n      orderSet.insert(Fatal);\n      orderSet.insert(None);\n      orderSet.insert(Unknown);\n\n      foreach(Order i, orderSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        orderMap.insert(std::make_pair(name, i));\n      }\n      initializingOrder = false;\n    }\n  }\n\n  Order::Order()\n  {\n    this->id = Orders::None.id;\n  }\n  Order::Order(int id)\n  {\n    this->id = id;\n    if (!initializingOrder && (id < 0 || id >= 191 || orderName[id].length() == 0))\n      this->id = Orders::Unknown.id;\n  }\n  Order::Order(const Order& other)\n  {\n    this->id = other.id;\n  }\n  Order& Order::operator=(const Order& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool Order::operator==(const Order& other) const\n  {\n    return this->id == other.id;\n  }\n  bool Order::operator!=(const Order& other) const\n  {\n    return this->id != other.id;\n  }\n  bool Order::operator<(const Order& other) const\n  {\n    return this->id < other.id;\n  }\n  int Order::getID() const\n  {\n    return this->id;\n  }\n  std::string Order::getName() const\n  {\n    return orderName[this->id];\n  }\n  Order Orders::getOrder(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, Order>::iterator i = orderMap.find(name);\n    if (i == orderMap.end())\n      return Orders::Unknown;\n    return (*i).second;\n  }\n  std::set<Order>& Orders::allOrders()\n  {\n    return orderSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/PlayerType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/PlayerType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingPlayerType = true;\n  std::string playerTypeName[13];\n  std::map<std::string, PlayerType> playerTypeMap;\n  std::set< PlayerType > playerTypeSet;\n  namespace PlayerTypes\n  {\n    const PlayerType None(0);\n    const PlayerType Computer(1);\n    const PlayerType Player(2);\n    const PlayerType RescuePassive(3);\n    const PlayerType EitherPreferComputer(5);\n    const PlayerType EitherPreferHuman(6);\n    const PlayerType Neutral(7);\n    const PlayerType Closed(8);\n    const PlayerType PlayerLeft(10);\n    const PlayerType ComputerLeft(11);\n    const PlayerType Unknown(12);\n\n    void init()\n    {\n      playerTypeName[None.getID()]                 = \"None\";\n      playerTypeName[Computer.getID()]             = \"Computer\";\n      playerTypeName[Player.getID()]               = \"Player\";\n      playerTypeName[RescuePassive.getID()]        = \"RescuePassive\";\n      playerTypeName[EitherPreferComputer.getID()] = \"EitherPreferComputer\";\n      playerTypeName[EitherPreferHuman.getID()]    = \"EitherPreferHuman\";\n      playerTypeName[Neutral.getID()]              = \"Neutral\";\n      playerTypeName[Closed.getID()]               = \"Closed\";\n      playerTypeName[PlayerLeft.getID()]           = \"PlayerLeft\";\n      playerTypeName[ComputerLeft.getID()]         = \"ComputerLeft\";\n      playerTypeName[Unknown.getID()]              = \"Unknown\";\n\n      playerTypeSet.insert(None);\n      playerTypeSet.insert(Computer);\n      playerTypeSet.insert(Player);\n      playerTypeSet.insert(RescuePassive);\n      playerTypeSet.insert(EitherPreferComputer);\n      playerTypeSet.insert(EitherPreferHuman);\n      playerTypeSet.insert(Neutral);\n      playerTypeSet.insert(Closed);\n      playerTypeSet.insert(PlayerLeft);\n      playerTypeSet.insert(ComputerLeft);\n      playerTypeSet.insert(Unknown);\n\n      foreach(PlayerType i, playerTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        playerTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingPlayerType = false;\n    }\n  }\n  PlayerType::PlayerType()\n  {\n    this->id = PlayerTypes::None.id;\n  }\n  PlayerType::PlayerType(int id)\n  {\n    this->id = id;\n    if (!initializingPlayerType && (id < 0 || id >= 13 || playerTypeName[id].length() == 0) )\n      this->id = PlayerTypes::Unknown.id;\n  }\n  PlayerType::PlayerType(const PlayerType& other)\n  {\n    this->id = other.id;\n  }\n  PlayerType& PlayerType::operator=(const PlayerType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool PlayerType::operator==(const PlayerType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool PlayerType::operator!=(const PlayerType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool PlayerType::operator<(const PlayerType& other) const\n  {\n    return this->id < other.id;\n  }\n  int PlayerType::getID() const\n  {\n    return this->id;\n  }\n  std::string PlayerType::getName() const\n  {\n    return playerTypeName[this->id];\n  }\n  PlayerType PlayerTypes::getPlayerType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, PlayerType>::iterator i = playerTypeMap.find(name);\n    if (i == playerTypeMap.end())\n      return PlayerTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<PlayerType>& PlayerTypes::allPlayerTypes()\n  {\n    return playerTypeSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Position.cpp",
    "content": "#include <BWAPI/Constants.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/Game.h>\n\n#include <math.h>\n#include <stdlib.h>\n\nnamespace BWAPI\n{\n  namespace Positions\n  {\n    const Position Invalid(32000, 32000);\n    const Position None(32000, 32032);\n    const Position Unknown(32000, 32064);\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  Position::Position()\n      : _x(0)\n      , _y(0)\n  {\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  Position::Position(const TilePosition& position)\n      : _x(position.x()*TILE_SIZE)\n      , _y(position.y()*TILE_SIZE)\n  {\n  }\n  //----------------------------------------------- DESTRUCTOR -----------------------------------------------\n  Position::Position(int x, int y)\n      : _x(x)\n      , _y(y)\n  {\n  }\n  //---------------------------------------------- OPERATOR == -----------------------------------------------\n  bool Position::operator == (const Position& position) const\n  {\n    return this->x() == position.x() &&\n           this->y() == position.y();\n  }\n  //---------------------------------------------- OPERATOR != -----------------------------------------------\n  bool Position::operator != (const Position& position) const\n  {\n    return this->x() != position.x() ||\n           this->y() != position.y();\n  }\n  //---------------------------------------------- OPERATOR < ------------------------------------------------\n  bool Position::operator  < (const Position& position) const\n  {\n    return this->x() < position.x() ||\n           (this->x() == position.x() && this->y() < position.y());\n  }\n  //---------------------------------------------- IS VALID --------------------------------------------------\n  bool Position::isValid() const\n  {\n    return (_x >= 0 && _y >= 0 && _x < Broodwar->mapWidth()*32 && _y < Broodwar->mapHeight()*32);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  Position Position::operator+(const Position& position) const\n  {\n    return Position(this->x() + position.x(), this->y() + position.y());\n  }\n  //----------------------------------------------------------------------------------------------------------\n  Position Position::operator-(const Position& position) const\n  {\n    return Position(this->x() - position.x(), this->y() - position.y());\n  }\n  //-------------------------------------------- MAKE VALID --------------------------------------------------\n  Position& Position::makeValid()\n  {\n    if (_x > Broodwar->mapWidth()*32 - 1)\n      _x = Broodwar->mapWidth()*32 - 1;\n    if (_y > Broodwar->mapHeight()*32 - 1)\n      _y = Broodwar->mapHeight()*32 - 1;\n    if (_x < 0)\n      _x = 0;\n    if (_y < 0)\n      _y = 0;\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  Position& Position::operator+=(const Position& position)\n  {\n    this->x() += position.x();\n    this->y() += position.y();\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  Position& Position::operator-=(const Position& position)\n  {\n    this->x() -= position.x();\n    this->y() -= position.y();\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double Position::getDistance(const Position& position) const\n  {\n    return ((*this) - position).getLength();\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double Position::getApproxDistance(const Position& position) const\n  {\n    double min = abs(this->x() - position.x());\n    double max = abs(this->y() - position.y());\n    if (max < min)\n    {\n      double temp = min;\n      min = max;\n      max = temp;\n    }\n    if (min < max*0.25)\n      return max;\n    return min*0.4 + max*0.9;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double Position::getLength() const\n  {\n    double x = this->x();\n    double y = this->y();\n    return sqrt(x * x + y * y);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int& Position::x()\n  {\n    return this->_x;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int& Position::y()\n  {\n    return this->_y;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int Position::x() const\n  {\n    return this->_x;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int Position::y() const\n  {\n    return this->_y;\n  }\n  //----------------------------------------------------------------------------------------------------------\n};\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Race.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/Race.h>\n#include <BWAPI/UnitType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingRace = true;\n  class RaceInternal\n  {\n    public:\n      void set(const char* name, UnitType worker, UnitType center, UnitType refinery, UnitType transport, UnitType supplyProvider)\n      {\n        if (initializingRace)\n        {\n          this->name           = name;\n          this->worker         = worker;\n          this->center         = center;\n          this->refinery       = refinery;\n          this->transport      = transport;\n          this->supplyProvider = supplyProvider;\n        }\n      }\n      std::string name;\n      UnitType worker;\n      UnitType center;\n      UnitType refinery;\n      UnitType transport;\n      UnitType supplyProvider;\n  };\n  RaceInternal raceData[7];\n  std::map<std::string, Race> raceMap;\n  std::set< Race > raceSet;\n  namespace Races\n  {\n    const Race Zerg(0);\n    const Race Terran(1);\n    const Race Protoss(2);\n    const Race Random(3);\n    const Race Other(4);\n    const Race None(5);\n    const Race Unknown(6);\n\n    void init()\n    {\n      raceData[Zerg.getID()].set(   \"Zerg\",    UnitTypes::Zerg_Drone,    UnitTypes::Zerg_Hatchery,         UnitTypes::Zerg_Extractor,      UnitTypes::Zerg_Overlord,   UnitTypes::Zerg_Overlord);\n      raceData[Terran.getID()].set( \"Terran\",  UnitTypes::Terran_SCV,    UnitTypes::Terran_Command_Center, UnitTypes::Terran_Refinery,     UnitTypes::Terran_Dropship, UnitTypes::Terran_Supply_Depot);\n      raceData[Protoss.getID()].set(\"Protoss\", UnitTypes::Protoss_Probe, UnitTypes::Protoss_Nexus,         UnitTypes::Protoss_Assimilator, UnitTypes::Protoss_Shuttle, UnitTypes::Protoss_Pylon);\n      raceData[Random.getID()].set( \"Random\",  UnitTypes::Unknown,       UnitTypes::Unknown,               UnitTypes::Unknown,             UnitTypes::Unknown,         UnitTypes::Unknown);\n      raceData[Other.getID()].set(  \"Other\",   UnitTypes::Unknown,       UnitTypes::Unknown,               UnitTypes::Unknown,             UnitTypes::Unknown,         UnitTypes::Unknown);\n      raceData[None.getID()].set(   \"None\",    UnitTypes::None,          UnitTypes::None,                  UnitTypes::None,                UnitTypes::None,            UnitTypes::None);\n      raceData[Unknown.getID()].set(\"Unknown\", UnitTypes::Unknown,       UnitTypes::Unknown,               UnitTypes::Unknown,             UnitTypes::Unknown,         UnitTypes::Unknown);\n\n      raceSet.insert(Zerg);\n      raceSet.insert(Terran);\n      raceSet.insert(Protoss);\n      raceSet.insert(Other);\n      raceSet.insert(None);\n      raceSet.insert(Unknown);\n\n      foreach(Race i, raceSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        raceMap.insert(std::make_pair(name, i));\n      }\n      initializingRace = false;\n    }\n  }\n  Race::Race()\n  {\n    this->id = Races::None.id;\n  }\n  Race::Race(int id)\n  {\n    this->id = id;\n    if (!initializingRace && (id < 0 || id >= 7) )\n      this->id = Races::Unknown.id;\n  }\n  Race::Race(const Race& other)\n  {\n    this->id = other.id;\n  }\n  Race& Race::operator=(const Race& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool Race::operator==(const Race& other) const\n  {\n    return this->id == other.id;\n  }\n  bool Race::operator!=(const Race& other) const\n  {\n    return this->id != other.id;\n  }\n  bool Race::operator<(const Race& other) const\n  {\n    return this->id < other.id;\n  }\n  int Race::getID() const\n  {\n    return this->id;\n  }\n  std::string Race::getName() const\n  {\n    return raceData[this->id].name;\n  }\n  UnitType Race::getWorker() const\n  {\n    return raceData[this->id].worker;\n  }\n  UnitType Race::getCenter() const\n  {\n    return raceData[this->id].center;\n  }\n  UnitType Race::getRefinery() const\n  {\n    return raceData[this->id].refinery;\n  }\n  UnitType Race::getTransport() const\n  {\n    return raceData[this->id].transport;\n  }\n  UnitType Race::getSupplyProvider() const\n  {\n    return raceData[this->id].supplyProvider;\n  }\n  Race Races::getRace(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, Race>::iterator i = raceMap.find(name);\n    if (i == raceMap.end())\n      return Races::Unknown;\n    return (*i).second;\n  }\n  std::set<Race>& Races::allRaces()\n  {\n    return raceSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/TechType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/TechType.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/WeaponType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingTechType = true;\n  class TechTypeInternal\n  {\n    public:\n      TechTypeInternal() {valid = false;}\n      void set(const char* name, int mineralPrice, int gasPrice, int researchTime, int energyUsed, UnitType whatResearches, Race race, WeaponType weapon, UnitType whatUses1, UnitType whatUses2=UnitTypes::None, UnitType whatUses3=UnitTypes::None, UnitType whatUses4=UnitTypes::None, UnitType whatUses5=UnitTypes::None, UnitType whatUses6=UnitTypes::None)\n      {\n        this->name           = name;\n        this->mineralPrice   = mineralPrice;\n        this->gasPrice       = gasPrice;\n        this->researchTime   = researchTime;\n        this->energyUsed     = energyUsed;\n        this->whatResearches = whatResearches;\n        this->race           = race;\n        this->weapon         = weapon;\n        if (whatUses1 != UnitTypes::None)\n          this->whatUses.insert(whatUses1);\n\n        if (whatUses2 != UnitTypes::None)\n          this->whatUses.insert(whatUses2);\n\n        if (whatUses3 != UnitTypes::None)\n          this->whatUses.insert(whatUses3);\n\n        if (whatUses4 != UnitTypes::None)\n          this->whatUses.insert(whatUses4);\n\n        if (whatUses5 != UnitTypes::None)\n          this->whatUses.insert(whatUses5);\n\n        if (whatUses6 != UnitTypes::None)\n          this->whatUses.insert(whatUses6);\n\n        this->valid = true;\n      }\n      std::string name;\n      int mineralPrice;\n      int gasPrice;\n      int researchTime;\n      int energyUsed;\n      UnitType whatResearches;\n      Race race;\n      WeaponType weapon;\n      std::set<UnitType> whatUses;\n\n      bool valid;\n  };\n  TechTypeInternal techTypeData[47];\n  std::map<std::string, TechType> techTypeMap;\n  std::set< TechType > techTypeSet;\n  namespace TechTypes\n  {\n    const TechType Stim_Packs(0);\n    const TechType Lockdown(1);\n    const TechType EMP_Shockwave(2);\n    const TechType Spider_Mines(3);\n    const TechType Scanner_Sweep(4);\n    const TechType Tank_Siege_Mode(5);\n    const TechType Defensive_Matrix(6);\n    const TechType Irradiate(7);\n    const TechType Yamato_Gun(8);\n    const TechType Cloaking_Field(9);\n    const TechType Personnel_Cloaking(10);\n    const TechType Burrowing(11);\n    const TechType Infestation(12);\n    const TechType Spawn_Broodlings(13);\n    const TechType Dark_Swarm(14);\n    const TechType Plague(15);\n    const TechType Consume(16);\n    const TechType Ensnare(17);\n    const TechType Parasite(18);\n    const TechType Psionic_Storm(19);\n    const TechType Hallucination(20);\n    const TechType Recall(21);\n    const TechType Stasis_Field(22);\n    const TechType Archon_Warp(23);\n    const TechType Restoration(24);\n    const TechType Disruption_Web(25);\n    const TechType Mind_Control(27);\n    const TechType Dark_Archon_Meld(28);\n    const TechType Feedback(29);\n    const TechType Optical_Flare(30);\n    const TechType Maelstrom(31);\n    const TechType Lurker_Aspect(32);\n    const TechType Healing(34);\n    const TechType None(44);\n    const TechType Unknown(45);\n    const TechType Nuclear_Strike(46);\n\n    void init()\n    {\n      techTypeData[Stim_Packs.getID()].set(\"Stim Packs\"                ,100,100,1200,0  ,UnitTypes::Terran_Academy          ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Marine, UnitTypes::Terran_Firebat, UnitTypes::Hero_Jim_Raynor_Marine, UnitTypes::Hero_Gui_Montag);\n      techTypeData[Lockdown.getID()].set(\"Lockdown\"                    ,200,200,1500,100,UnitTypes::Terran_Covert_Ops       ,Races::Terran ,WeaponTypes::Lockdown        ,UnitTypes::Terran_Ghost, UnitTypes::Hero_Alexei_Stukov, UnitTypes::Hero_Infested_Duran, UnitTypes::Hero_Samir_Duran, UnitTypes::Hero_Sarah_Kerrigan);\n      techTypeData[EMP_Shockwave.getID()].set(\"EMP Shockwave\"          ,200,200,1800,100,UnitTypes::Terran_Science_Facility ,Races::Terran ,WeaponTypes::EMP_Shockwave   ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan);\n      techTypeData[Spider_Mines.getID()].set(\"Spider Mines\"            ,100,100,1200,0  ,UnitTypes::Terran_Machine_Shop     ,Races::Terran ,WeaponTypes::Spider_Mines    ,UnitTypes::Terran_Vulture, UnitTypes::Hero_Jim_Raynor_Vulture);\n      techTypeData[Scanner_Sweep.getID()].set(\"Scanner Sweep\"          ,0  ,0  ,0   ,50 ,UnitTypes::None                    ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Comsat_Station);\n      techTypeData[Tank_Siege_Mode.getID()].set(\"Tank Siege Mode\"      ,150,150,1200,0  ,UnitTypes::Terran_Machine_Shop     ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Siege_Tank_Tank_Mode, UnitTypes::Terran_Siege_Tank_Siege_Mode, UnitTypes::Hero_Edmund_Duke_Tank_Mode, UnitTypes::Hero_Edmund_Duke_Siege_Mode);\n      techTypeData[Defensive_Matrix.getID()].set(\"Defensive Matrix\"    ,0  ,0  ,0   ,100,UnitTypes::None                    ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan);\n      techTypeData[Irradiate.getID()].set(\"Irradiate\"                  ,200,200,1200,75 ,UnitTypes::Terran_Science_Facility ,Races::Terran ,WeaponTypes::Irradiate       ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan);\n      techTypeData[Yamato_Gun.getID()].set(\"Yamato Gun\"                ,100,100,1800,150,UnitTypes::Terran_Physics_Lab      ,Races::Terran ,WeaponTypes::Yamato_Gun      ,UnitTypes::Terran_Battlecruiser, UnitTypes::Hero_Gerard_DuGalle, UnitTypes::Hero_Hyperion, UnitTypes::Hero_Norad_II);\n      techTypeData[Cloaking_Field.getID()].set(\"Cloaking Field\"        ,150,150,1500,25 ,UnitTypes::Terran_Control_Tower    ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Wraith, UnitTypes::Hero_Tom_Kazansky);\n      techTypeData[Personnel_Cloaking.getID()].set(\"Personnel Cloaking\",100,100,1200,25 ,UnitTypes::Terran_Covert_Ops       ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Ghost, UnitTypes::Hero_Alexei_Stukov, UnitTypes::Hero_Infested_Duran, UnitTypes::Hero_Samir_Duran, UnitTypes::Hero_Sarah_Kerrigan, UnitTypes::Hero_Infested_Kerrigan);\n      techTypeData[Burrowing.getID()].set(\"Burrowing\"                  ,100,100,1200,0  ,UnitTypes::Zerg_Hatchery           ,Races::Zerg   ,WeaponTypes::None            ,UnitTypes::Zerg_Drone, UnitTypes::Zerg_Zergling, UnitTypes::Zerg_Hydralisk, UnitTypes::Zerg_Defiler, UnitTypes::Zerg_Infested_Terran, UnitTypes::Zerg_Lurker);\n      techTypeData[Infestation.getID()].set(\"Infestation\"              ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Zerg   ,WeaponTypes::None            ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch);\n      techTypeData[Spawn_Broodlings.getID()].set(\"Spawn Broodlings\"    ,100,100,1200,150,UnitTypes::Zerg_Queens_Nest        ,Races::Zerg   ,WeaponTypes::Spawn_Broodlings,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch);\n      techTypeData[Dark_Swarm.getID()].set(\"Dark Swarm\"                ,0  ,0  ,0   ,100,UnitTypes::None                    ,Races::Zerg   ,WeaponTypes::Dark_Swarm      ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One);\n      techTypeData[Plague.getID()].set(\"Plague\"                        ,200,200,1500,150,UnitTypes::Zerg_Defiler_Mound      ,Races::Zerg   ,WeaponTypes::Plague          ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One);\n      techTypeData[Consume.getID()].set(\"Consume\"                      ,100,100,1500,0  ,UnitTypes::Zerg_Defiler_Mound      ,Races::Zerg   ,WeaponTypes::Consume         ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One);\n      techTypeData[Ensnare.getID()].set(\"Ensnare\"                      ,100,100,1200,75 ,UnitTypes::Zerg_Queens_Nest        ,Races::Zerg   ,WeaponTypes::Ensnare         ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch);\n      techTypeData[Parasite.getID()].set(\"Parasite\"                    ,0  ,0  ,0   ,75 ,UnitTypes::None                    ,Races::Zerg   ,WeaponTypes::Parasite        ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch);\n      techTypeData[Psionic_Storm.getID()].set(\"Psionic Storm\"          ,200,200,1800,75 ,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Psionic_Storm   ,UnitTypes::Protoss_High_Templar, UnitTypes::Hero_Tassadar);\n      techTypeData[Hallucination.getID()].set(\"Hallucination\"          ,150,150,1200,100,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::None            ,UnitTypes::Protoss_High_Templar, UnitTypes::Hero_Tassadar);\n      techTypeData[Recall.getID()].set(\"Recall\"                        ,150,150,1800,150,UnitTypes::Protoss_Arbiter_Tribunal,Races::Protoss,WeaponTypes::None            ,UnitTypes::Protoss_Arbiter, UnitTypes::Hero_Danimoth);\n      techTypeData[Stasis_Field.getID()].set(\"Stasis Field\"            ,150,150,1500,100,UnitTypes::Protoss_Arbiter_Tribunal,Races::Protoss,WeaponTypes::Stasis_Field    ,UnitTypes::Protoss_Arbiter, UnitTypes::Hero_Danimoth);\n      techTypeData[Archon_Warp.getID()].set(\"Archon Warp\"              ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Protoss,WeaponTypes::None            ,UnitTypes::Protoss_High_Templar);\n      techTypeData[Restoration.getID()].set(\"Restoration\"              ,100,100,1200,50 ,UnitTypes::Terran_Academy          ,Races::Terran ,WeaponTypes::Restoration     ,UnitTypes::Terran_Medic);\n      techTypeData[Disruption_Web.getID()].set(\"Disruption Web\"        ,200,200,1200,125,UnitTypes::Protoss_Fleet_Beacon    ,Races::Protoss,WeaponTypes::Disruption_Web  ,UnitTypes::Protoss_Corsair, UnitTypes::Hero_Raszagal);\n      techTypeData[Mind_Control.getID()].set(\"Mind Control\"            ,200,200,1800,150,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Mind_Control    ,UnitTypes::Protoss_Dark_Archon);\n      techTypeData[Dark_Archon_Meld.getID()].set(\"Dark Archon Meld\"    ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Protoss,WeaponTypes::None            ,UnitTypes::Protoss_Dark_Templar);\n      techTypeData[Feedback.getID()].set(\"Feedback\"                    ,0  ,0  ,0   ,50 ,UnitTypes::None                    ,Races::Protoss,WeaponTypes::Feedback        ,UnitTypes::Protoss_Dark_Archon);\n      techTypeData[Optical_Flare.getID()].set(\"Optical Flare\"          ,100,100,1800,75 ,UnitTypes::Terran_Academy          ,Races::Terran ,WeaponTypes::Optical_Flare   ,UnitTypes::Terran_Medic);\n      techTypeData[Maelstrom.getID()].set(\"Maelstrom\"                  ,100,100,1500,100,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Maelstrom       ,UnitTypes::Protoss_Dark_Archon);\n      techTypeData[Lurker_Aspect.getID()].set(\"Lurker Aspect\"          ,200,200,1800,0  ,UnitTypes::Zerg_Hydralisk_Den      ,Races::Zerg   ,WeaponTypes::None            ,UnitTypes::Zerg_Lurker);\n      techTypeData[Healing.getID()].set(\"Healing\"                      ,0  ,0  ,0   ,1  ,UnitTypes::None                    ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Medic);\n      techTypeData[None.getID()].set(\"None\"                            ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::None   ,WeaponTypes::None            ,UnitTypes::None);\n      techTypeData[Unknown.getID()].set(\"Unknown\"                      ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Unknown,WeaponTypes::None            ,UnitTypes::None);\n      techTypeData[Nuclear_Strike.getID()].set(\"Nuclear Strike\"        ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Terran ,WeaponTypes::Nuclear_Strike  ,UnitTypes::Terran_Ghost);\n\n      techTypeSet.insert(Stim_Packs);\n      techTypeSet.insert(Lockdown);\n      techTypeSet.insert(EMP_Shockwave);\n      techTypeSet.insert(Spider_Mines);\n      techTypeSet.insert(Scanner_Sweep);\n      techTypeSet.insert(Tank_Siege_Mode);\n      techTypeSet.insert(Defensive_Matrix);\n      techTypeSet.insert(Irradiate);\n      techTypeSet.insert(Yamato_Gun);\n      techTypeSet.insert(Cloaking_Field);\n      techTypeSet.insert(Personnel_Cloaking);\n      techTypeSet.insert(Burrowing);\n      techTypeSet.insert(Infestation);\n      techTypeSet.insert(Spawn_Broodlings);\n      techTypeSet.insert(Dark_Swarm);\n      techTypeSet.insert(Plague);\n      techTypeSet.insert(Consume);\n      techTypeSet.insert(Ensnare);\n      techTypeSet.insert(Parasite);\n      techTypeSet.insert(Psionic_Storm);\n      techTypeSet.insert(Hallucination);\n      techTypeSet.insert(Recall);\n      techTypeSet.insert(Stasis_Field);\n      techTypeSet.insert(Archon_Warp);\n      techTypeSet.insert(Restoration);\n      techTypeSet.insert(Disruption_Web);\n      techTypeSet.insert(Mind_Control);\n      techTypeSet.insert(Dark_Archon_Meld);\n      techTypeSet.insert(Feedback);\n      techTypeSet.insert(Optical_Flare);\n      techTypeSet.insert(Maelstrom);\n      techTypeSet.insert(Lurker_Aspect);\n      techTypeSet.insert(Healing);\n      techTypeSet.insert(None);\n      techTypeSet.insert(Unknown);\n      techTypeSet.insert(Nuclear_Strike);\n\n      foreach(TechType i, techTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        techTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingTechType = false;\n    }\n  }\n  TechType::TechType()\n  {\n    this->id = TechTypes::None.id;\n  }\n  TechType::TechType(int id)\n  {\n    this->id = id;\n    if (!initializingTechType && (id < 0 || id >= 47 || techTypeData[id].name.length() == 0))\n      this->id = TechTypes::Unknown.id;\n  }\n  TechType::TechType(const TechType& other)\n  {\n    this->id = other.id;\n  }\n  TechType& TechType::operator=(const TechType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool TechType::operator==(const TechType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool TechType::operator!=(const TechType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool TechType::operator<(const TechType& other) const\n  {\n    return this->id < other.id;\n  }\n  int TechType::getID() const\n  {\n    return this->id;\n  }\n  std::string TechType::getName() const\n  {\n    return techTypeData[this->id].name;\n  }\n  Race TechType::getRace() const\n  {\n    return techTypeData[this->id].race;\n  }\n  int TechType::mineralPrice() const\n  {\n    return techTypeData[this->id].mineralPrice;\n  }\n  int TechType::gasPrice() const\n  {\n    return techTypeData[this->id].gasPrice;\n  }\n  int TechType::researchTime() const\n  {\n    return techTypeData[this->id].researchTime;\n  }\n  int TechType::energyUsed() const\n  {\n    return techTypeData[this->id].energyUsed;\n  }\n  UnitType TechType::whatResearches() const\n  {\n    return techTypeData[this->id].whatResearches;\n  }\n  WeaponType TechType::getWeapon() const\n  {\n    return techTypeData[this->id].weapon;\n  }\n  const std::set<UnitType>& TechType::whatUses() const\n  {\n    return techTypeData[this->id].whatUses;\n  }\n  TechType TechTypes::getTechType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, TechType>::iterator i = techTypeMap.find(name);\n    if (i == techTypeMap.end()) \n      return TechTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<TechType>& TechTypes::allTechTypes()\n  {\n    return techTypeSet;\n  }\n}\n\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/TilePosition.cpp",
    "content": "#include <BWAPI/Constants.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/Game.h>\n\n#include <math.h>\n\nnamespace BWAPI\n{\n  namespace TilePositions\n  {\n    const TilePosition Invalid(1000, 1000);\n    const TilePosition None(1000, 1001);\n    const TilePosition Unknown(1000, 1002);\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  TilePosition::TilePosition()\n      : _x(0)\n      , _y(0)\n  {\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  TilePosition::TilePosition(int x, int y)\n      : _x(x)\n      , _y(y)\n  {\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  TilePosition::TilePosition(const Position& position)\n      : _x(position.x() / TILE_SIZE)\n      , _y(position.y() / TILE_SIZE)\n  {\n  }\n  //---------------------------------------------- OPERATOR == -----------------------------------------------\n  bool TilePosition::operator == (const TilePosition& TilePosition) const\n  {\n    return this->x() == TilePosition.x() &&\n           this->y() == TilePosition.y();\n  }\n  //---------------------------------------------- OPERATOR != -----------------------------------------------\n  bool TilePosition::operator != (const TilePosition& TilePosition) const\n  {\n    return this->x() != TilePosition.x() ||\n           this->y() != TilePosition.y();\n  }\n  //---------------------------------------------- OPERATOR < ------------------------------------------------\n  bool TilePosition::operator < (const TilePosition& TilePosition) const\n  {\n    return this->x() < TilePosition.x() ||\n           (this->x() == TilePosition.x() && this->y() < TilePosition.y());\n  }\n  //---------------------------------------------- IS VALID --------------------------------------------------\n  bool TilePosition::isValid() const\n  {\n    return (_x >= 0 && _y >= 0 && _x < Broodwar->mapWidth() && _y < Broodwar->mapHeight());\n  }\n  //----------------------------------------------------------------------------------------------------------\n  TilePosition TilePosition::operator+(const TilePosition& position) const\n  {\n    return TilePosition(this->x() + position.x(), this->y() + position.y());\n  }\n  //----------------------------------------------------------------------------------------------------------\n  TilePosition TilePosition::operator-(const TilePosition& position) const\n  {\n    return TilePosition(this->x() - position.x(), this->y() - position.y());\n  }\n  //-------------------------------------------- MAKE VALID --------------------------------------------------\n  TilePosition& TilePosition::makeValid()\n  {\n    if (_x > Broodwar->mapWidth() - 1)\n      _x = Broodwar->mapWidth() - 1;\n    if (_y > Broodwar->mapHeight() - 1)\n      _y = Broodwar->mapHeight() - 1;\n    if (_x < 0)\n      _x = 0;\n    if (_y < 0)\n      _y = 0;\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  TilePosition& TilePosition::operator+=(const TilePosition& position)\n  {\n    this->x() += position.x();\n    this->y() += position.y();\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  TilePosition& TilePosition::operator-=(const TilePosition& position)\n  {\n    this->x() -= position.x();\n    this->y() -= position.y();\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double TilePosition::getDistance(const TilePosition& position) const\n  {\n    return ((*this) - position).getLength();\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double TilePosition::getLength() const\n  {\n    double x = this->x();\n    double y = this->y();\n    return sqrt(x * x + y * y);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int& TilePosition::x()\n  {\n    return this->_x;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int& TilePosition::y()\n  {\n    return this->_y;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int TilePosition::x() const\n  {\n    return this->_x;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int TilePosition::y() const\n  {\n    return this->_y;\n  }\n  //----------------------------------------------------------------------------------------------------------\n};\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/UnitCommandType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/UnitCommandType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingUnitCommandType = true;\n  std::string unitCommandTypeName[45];\n  std::map<std::string, UnitCommandType> unitCommandTypeMap;\n  std::set< UnitCommandType > unitCommandTypeSet;\n  namespace UnitCommandTypes\n  {\n    const UnitCommandType Attack_Move(0);\n    const UnitCommandType Attack_Unit(1);\n    const UnitCommandType Build(2);\n    const UnitCommandType Build_Addon(3);\n    const UnitCommandType Train(4);\n    const UnitCommandType Morph(5);\n    const UnitCommandType Research(6);\n    const UnitCommandType Upgrade(7);\n    const UnitCommandType Set_Rally_Position(8);\n    const UnitCommandType Set_Rally_Unit(9);\n    const UnitCommandType Move(10);\n    const UnitCommandType Patrol(11);\n    const UnitCommandType Hold_Position(12);\n    const UnitCommandType Stop(13);\n    const UnitCommandType Follow(14);\n    const UnitCommandType Gather(15);\n    const UnitCommandType Return_Cargo(16);\n    const UnitCommandType Repair(17);\n    const UnitCommandType Burrow(18);\n    const UnitCommandType Unburrow(19);\n    const UnitCommandType Cloak(20);\n    const UnitCommandType Decloak(21);\n    const UnitCommandType Siege(22);\n    const UnitCommandType Unsiege(23);\n    const UnitCommandType Lift(24);\n    const UnitCommandType Land(25);\n    const UnitCommandType Load(26);\n    const UnitCommandType Unload(27);\n    const UnitCommandType Unload_All(28);\n    const UnitCommandType Unload_All_Position(29);\n    const UnitCommandType Right_Click_Position(30);\n    const UnitCommandType Right_Click_Unit(31);\n    const UnitCommandType Halt_Construction(32);\n    const UnitCommandType Cancel_Construction(33);\n    const UnitCommandType Cancel_Addon(34);\n    const UnitCommandType Cancel_Train(35);\n    const UnitCommandType Cancel_Train_Slot(36);\n    const UnitCommandType Cancel_Morph(37);\n    const UnitCommandType Cancel_Research(38);\n    const UnitCommandType Cancel_Upgrade(39);\n    const UnitCommandType Use_Tech(40);\n    const UnitCommandType Use_Tech_Position(41);\n    const UnitCommandType Use_Tech_Unit(42);\n    const UnitCommandType None(43);\n    const UnitCommandType Unknown(44);\n\n    void init()\n    {\n      unitCommandTypeName[Attack_Move.getID()]          = \"Attack Move\";\n      unitCommandTypeName[Attack_Unit.getID()]          = \"Attack Unit\";\n      unitCommandTypeName[Build.getID()]                = \"Build\";\n      unitCommandTypeName[Build_Addon.getID()]          = \"Build Addon\";\n      unitCommandTypeName[Train.getID()]                = \"Train\";\n      unitCommandTypeName[Morph.getID()]                = \"Morph\";\n      unitCommandTypeName[Research.getID()]             = \"Research\";\n      unitCommandTypeName[Upgrade.getID()]              = \"Upgrade\";\n      unitCommandTypeName[Set_Rally_Position.getID()]   = \"Set Rally Position\";\n      unitCommandTypeName[Set_Rally_Unit.getID()]       = \"Set Rally Unit\";\n      unitCommandTypeName[Move.getID()]                 = \"Move\";\n      unitCommandTypeName[Patrol.getID()]               = \"Patrol\";\n      unitCommandTypeName[Hold_Position.getID()]        = \"Hold Position\";\n      unitCommandTypeName[Stop.getID()]                 = \"Stop\";\n      unitCommandTypeName[Follow.getID()]               = \"Follow\";\n      unitCommandTypeName[Gather.getID()]               = \"Gather\";\n      unitCommandTypeName[Return_Cargo.getID()]         = \"Return Cargo\";\n      unitCommandTypeName[Repair.getID()]               = \"Repair\";\n      unitCommandTypeName[Burrow.getID()]               = \"Burrow\";\n      unitCommandTypeName[Unburrow.getID()]             = \"Unburrow\";\n      unitCommandTypeName[Cloak.getID()]                = \"Cloak\";\n      unitCommandTypeName[Decloak.getID()]              = \"Decloak\";\n      unitCommandTypeName[Siege.getID()]                = \"Siege\";\n      unitCommandTypeName[Unsiege.getID()]              = \"Unsiege\";\n      unitCommandTypeName[Lift.getID()]                 = \"Lift\";\n      unitCommandTypeName[Land.getID()]                 = \"Land\";\n      unitCommandTypeName[Load.getID()]                 = \"Load\";\n      unitCommandTypeName[Unload.getID()]               = \"Unload\";\n      unitCommandTypeName[Unload_All.getID()]           = \"Unload All\";\n      unitCommandTypeName[Unload_All_Position.getID()]  = \"Unload All Position\";\n      unitCommandTypeName[Right_Click_Position.getID()] = \"Right Click Position\";\n      unitCommandTypeName[Right_Click_Unit.getID()]     = \"Right Click Unit\";\n      unitCommandTypeName[Halt_Construction.getID()]    = \"Halt Construction\";\n      unitCommandTypeName[Cancel_Construction.getID()]  = \"Cancel Construction\";\n      unitCommandTypeName[Cancel_Addon.getID()]         = \"Cancel Addon\";\n      unitCommandTypeName[Cancel_Train.getID()]         = \"Cancel Train\";\n      unitCommandTypeName[Cancel_Train_Slot.getID()]    = \"Cancel Train Slot\";\n      unitCommandTypeName[Cancel_Morph.getID()]         = \"Cancel Morph\";\n      unitCommandTypeName[Cancel_Research.getID()]      = \"Cancel Research\";\n      unitCommandTypeName[Cancel_Upgrade.getID()]       = \"Cancel Upgrade\";\n      unitCommandTypeName[Use_Tech.getID()]             = \"Use Tech\";\n      unitCommandTypeName[Use_Tech_Position.getID()]    = \"Use Tech Position\";\n      unitCommandTypeName[Use_Tech_Unit.getID()]        = \"Use Tech Unit\";\n      unitCommandTypeName[None.getID()]                 = \"None\";\n      unitCommandTypeName[Unknown.getID()]              = \"Unknown\";\n\n      unitCommandTypeSet.insert(Attack_Move);\n      unitCommandTypeSet.insert(Attack_Unit);\n      unitCommandTypeSet.insert(Build);\n      unitCommandTypeSet.insert(Build_Addon);\n      unitCommandTypeSet.insert(Train);\n      unitCommandTypeSet.insert(Morph);\n      unitCommandTypeSet.insert(Research);\n      unitCommandTypeSet.insert(Upgrade);\n      unitCommandTypeSet.insert(Set_Rally_Position);\n      unitCommandTypeSet.insert(Set_Rally_Unit);\n      unitCommandTypeSet.insert(Move);\n      unitCommandTypeSet.insert(Patrol);\n      unitCommandTypeSet.insert(Hold_Position);\n      unitCommandTypeSet.insert(Stop);\n      unitCommandTypeSet.insert(Follow);\n      unitCommandTypeSet.insert(Gather);\n      unitCommandTypeSet.insert(Return_Cargo);\n      unitCommandTypeSet.insert(Repair);\n      unitCommandTypeSet.insert(Burrow);\n      unitCommandTypeSet.insert(Unburrow);\n      unitCommandTypeSet.insert(Cloak);\n      unitCommandTypeSet.insert(Decloak);\n      unitCommandTypeSet.insert(Siege);\n      unitCommandTypeSet.insert(Unsiege);\n      unitCommandTypeSet.insert(Lift);\n      unitCommandTypeSet.insert(Land);\n      unitCommandTypeSet.insert(Load);\n      unitCommandTypeSet.insert(Unload);\n      unitCommandTypeSet.insert(Unload_All);\n      unitCommandTypeSet.insert(Unload_All_Position);\n      unitCommandTypeSet.insert(Right_Click_Position);\n      unitCommandTypeSet.insert(Right_Click_Unit);\n      unitCommandTypeSet.insert(Halt_Construction);\n      unitCommandTypeSet.insert(Cancel_Construction);\n      unitCommandTypeSet.insert(Cancel_Addon);\n      unitCommandTypeSet.insert(Cancel_Train);\n      unitCommandTypeSet.insert(Cancel_Train_Slot);\n      unitCommandTypeSet.insert(Cancel_Morph);\n      unitCommandTypeSet.insert(Cancel_Research);\n      unitCommandTypeSet.insert(Cancel_Upgrade);\n      unitCommandTypeSet.insert(Use_Tech);\n      unitCommandTypeSet.insert(Use_Tech_Position);\n      unitCommandTypeSet.insert(Use_Tech_Unit);\n      unitCommandTypeSet.insert(None);\n      unitCommandTypeSet.insert(Unknown);\n\n      foreach(UnitCommandType i, unitCommandTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        unitCommandTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingUnitCommandType = false;\n    }\n  }\n  UnitCommandType::UnitCommandType()\n  {\n    this->id = UnitCommandTypes::None.id;\n  }\n  UnitCommandType::UnitCommandType(int id)\n  {\n    this->id = id;\n    if (!initializingUnitCommandType && (id < 0 || id >= 45))\n      this->id = UnitCommandTypes::Unknown.id;\n  }\n  UnitCommandType::UnitCommandType(const UnitCommandType& other)\n  {\n    this->id = other.id;\n  }\n  UnitCommandType& UnitCommandType::operator=(const UnitCommandType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool UnitCommandType::operator==(const UnitCommandType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool UnitCommandType::operator!=(const UnitCommandType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool UnitCommandType::operator<(const UnitCommandType& other) const\n  {\n    return this->id < other.id;\n  }\n  int UnitCommandType::getID() const\n  {\n    return this->id;\n  }\n  std::string UnitCommandType::getName() const\n  {\n    return unitCommandTypeName[this->id];\n  }\n  UnitCommandType UnitCommandTypes::getUnitCommandType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, UnitCommandType>::iterator i = unitCommandTypeMap.find(name);\n    if (i == unitCommandTypeMap.end())\n      return UnitCommandTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<UnitCommandType>& UnitCommandTypes::allUnitCommandTypes()\n  {\n    return unitCommandTypeSet;\n  }\n}\n\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/UnitSizeType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/UnitSizeType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingUnitSizeType = true;\n  std::string unitSizeTypeName[6];\n  std::map<std::string, UnitSizeType> unitSizeTypeMap;\n  std::set< UnitSizeType > unitSizeTypeSet;\n  namespace UnitSizeTypes\n  {\n    const UnitSizeType Independent(0);\n    const UnitSizeType Small(1);\n    const UnitSizeType Medium(2);\n    const UnitSizeType Large(3);\n    const UnitSizeType None(4);\n    const UnitSizeType Unknown(5);\n\n    void init()\n    {\n      unitSizeTypeName[Independent.getID()] = \"Independent\";\n      unitSizeTypeName[Small.getID()]       = \"Small\";\n      unitSizeTypeName[Medium.getID()]      = \"Medium\";\n      unitSizeTypeName[Large.getID()]       = \"Large\";\n      unitSizeTypeName[None.getID()]        = \"None\";\n      unitSizeTypeName[Unknown.getID()]     = \"Unknown\";\n\n      unitSizeTypeSet.insert(Independent);\n      unitSizeTypeSet.insert(Small);\n      unitSizeTypeSet.insert(Medium);\n      unitSizeTypeSet.insert(Large);\n      unitSizeTypeSet.insert(None);\n      unitSizeTypeSet.insert(Unknown);\n\n      foreach(UnitSizeType i, unitSizeTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        unitSizeTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingUnitSizeType = false;\n    }\n  }\n  UnitSizeType::UnitSizeType()\n  {\n    this->id = UnitSizeTypes::None.id;\n  }\n  UnitSizeType::UnitSizeType(int id)\n  {\n    this->id = id;\n    if (!initializingUnitSizeType && (id < 0 || id >= 6))\n      this->id = UnitSizeTypes::Unknown.id;\n  }\n  UnitSizeType::UnitSizeType(const UnitSizeType& other)\n  {\n    this->id = other.id;\n  }\n  UnitSizeType& UnitSizeType::operator=(const UnitSizeType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool UnitSizeType::operator==(const UnitSizeType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool UnitSizeType::operator!=(const UnitSizeType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool UnitSizeType::operator<(const UnitSizeType& other) const\n  {\n    return this->id < other.id;\n  }\n  int UnitSizeType::getID() const\n  {\n    return this->id;\n  }\n  std::string UnitSizeType::getName() const\n  {\n    return unitSizeTypeName[this->id];\n  }\n  UnitSizeType UnitSizeTypes::getUnitSizeType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, UnitSizeType>::iterator i = unitSizeTypeMap.find(name);\n    if (i == unitSizeTypeMap.end())\n      return UnitSizeTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<UnitSizeType>& UnitSizeTypes::allUnitSizeTypes()\n  {\n    return unitSizeTypeSet;\n  }\n}\n\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/UnitType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n\n#include <Util/Foreach.h>\n\n#include <BWAPI/UnitType.h>\n#include <BWAPI/WeaponType.h>\n#include <BWAPI/UnitSizeType.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/Race.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingUnitType = true;\n  class UnitTypeInternal\n  {\n    public:\n      UnitTypeInternal() {valid = false;}\n      void set(const char* name, Race race, bool isHero, UnitType whatBuilds, int whatBuildsAmt, UnitType requiredUnit1, UnitType requiredUnit2, TechType requiredTech, TechType ability1, TechType ability2, TechType ability3, TechType ability4, UpgradeType armorUpgrade, int maxHitPoints, int maxShields, int maxEnergy, int armor,  int mineralPrice, int gasPrice, int buildTime, int supplyRequired, int supplyProvided, int spaceRequired, int spaceProvided, int buildScore, int destroyScore, UnitSizeType unitSizeType, int tileWidth, int tileHeight, int dimensionLeft, int dimensionUp, int dimensionRight, int dimensionDown,  int seekRange, int sightRange, WeaponType groundWeapon, int maxGroundHits, WeaponType airWeapon, int maxAirHits, double topSpeed, int acceleration, int haltDistance, int turnRadius, bool canProduce, bool canMove, bool isFlyer, bool regeneratesHP, bool hasPermanentCloak, bool isInvincible, bool isOrganic, bool isMechanical, bool isRobotic, bool isDetector, bool isResourceContainer, bool isResourceDepot, bool isWorker, bool requiresPsi, bool requiresCreep, bool isTwoUnitsInOneEgg, bool isBurrowable, bool isCloakable, bool isBuilding, bool isAddon, bool isFlyingBuilding, bool isNeutral, bool isRefinery)\n      {\n        if (initializingUnitType)\n        {\n          this->name   = name;\n          this->race   = race;\n          this->isHero = isHero;\n\n          this->whatBuilds = std::make_pair(whatBuilds, whatBuildsAmt);\n\n          if ( whatBuilds != UnitTypes::None && whatBuildsAmt > 0 )\n            this->requiredUnits.insert(this->whatBuilds);\n\n          if ( requiredUnit1 != UnitTypes::None )\n            this->requiredUnits.insert(std::make_pair(requiredUnit1, 1));\n\n          if ( requiredUnit2 != UnitTypes::None )\n            this->requiredUnits.insert(std::make_pair(requiredUnit2, 1));\n\n          this->requiredTech = requiredTech;\n          if (ability1 != TechTypes::None)\n            this->abilities.insert(ability1);\n\n          if (ability2 != TechTypes::None)\n            this->abilities.insert(ability2);\n\n          if (ability3 != TechTypes::None)\n            this->abilities.insert(ability3);\n\n          if (ability4 != TechTypes::None)\n            this->abilities.insert(ability4);\n\n          this->cloakingTech = TechTypes::None;\n\n          if ( this->abilities.find(TechTypes::Cloaking_Field) != this->abilities.end() )\n            cloakingTech = TechTypes::Cloaking_Field;\n          if ( this->abilities.find(TechTypes::Personnel_Cloaking) != this->abilities.end() )\n            cloakingTech = TechTypes::Personnel_Cloaking;\n\n          this->armorUpgrade = armorUpgrade;\n          this->maxHitPoints = maxHitPoints;\n          this->maxShields   = maxShields;\n          this->maxEnergy    = maxEnergy;\n          this->armor        = armor;\n\n          this->mineralPrice = mineralPrice;\n          this->gasPrice     = gasPrice;\n          this->buildTime    = buildTime;\n\n          this->supplyRequired = supplyRequired;\n          this->supplyProvided = supplyProvided;\n          this->spaceRequired  = spaceRequired;\n          this->spaceProvided  = spaceProvided;\n          this->buildScore     = buildScore;\n          this->destroyScore   = destroyScore;\n\n          this->unitSizeType   = unitSizeType;\n          this->tileWidth      = tileWidth;\n          this->tileHeight     = tileHeight;\n          this->dimensionLeft  = dimensionLeft;\n          this->dimensionUp    = dimensionUp;\n          this->dimensionRight = dimensionRight;\n          this->dimensionDown  = dimensionDown;\n\n          this->seekRange     = seekRange;\n          this->sightRange    = sightRange;\n          this->groundWeapon  = groundWeapon;\n          this->maxGroundHits = maxGroundHits;\n          this->airWeapon     = airWeapon;\n          this->maxAirHits    = maxAirHits;\n\n          this->topSpeed     = topSpeed;\n          this->acceleration = acceleration;\n          this->haltDistance = haltDistance;\n          this->turnRadius   = turnRadius;\n\n          this->canProduce = canProduce;\n          this->canAttack  = groundWeapon != WeaponTypes::None || airWeapon != WeaponTypes::None;\n          this->canMove    = canMove;\n\n          this->isFlyer             = isFlyer;\n          this->regeneratesHP       = regeneratesHP;\n          this->isSpellcaster       = maxEnergy > 0;\n          this->hasPermanentCloak   = hasPermanentCloak;\n          this->isInvincible        = isInvincible;\n          this->isOrganic           = isOrganic;\n          this->isMechanical        = isMechanical;\n          this->isRobotic           = isRobotic;\n          this->isDetector          = isDetector;\n          this->isResourceContainer = isResourceContainer;\n          this->isResourceDepot     = isResourceDepot;\n          this->isWorker            = isWorker;\n          this->requiresPsi         = requiresPsi;\n          this->requiresCreep       = requiresCreep;\n          this->isTwoUnitsInOneEgg  = isTwoUnitsInOneEgg;\n          this->isBurrowable        = isBurrowable;\n          this->isCloakable         = isCloakable;\n          this->isBuilding          = isBuilding;\n          this->isAddon             = isAddon;\n          this->isFlyingBuilding    = isFlyingBuilding;\n          this->isNeutral           = isNeutral;\n          this->isRefinery          = isRefinery;\n\n          this->isSpecialBuilding = this->isBuilding && this->whatBuilds.second == 0;\n\n          this->valid = true;\n        }\n      }\n      std::string name;\n      Race        race;\n\n      std::pair<UnitType, int> whatBuilds;\n      std::map<UnitType, int>  requiredUnits;\n      TechType                 requiredTech;\n      TechType                 cloakingTech;\n      std::set<TechType>       abilities;\n      std::set<UpgradeType>    upgrades;\n      UpgradeType              armorUpgrade;\n\n      int maxHitPoints;\n      int maxShields;\n      int maxEnergy;\n      int armor;\n\n      int mineralPrice;\n      int gasPrice;\n      int buildTime;\n\n      int supplyRequired;\n      int supplyProvided;\n      int spaceRequired;\n      int spaceProvided;\n      int buildScore;\n      int destroyScore;\n\n      UnitSizeType unitSizeType;\n      int tileWidth;\n      int tileHeight;\n      int dimensionLeft;\n      int dimensionUp;\n      int dimensionRight;\n      int dimensionDown;\n\n      int seekRange;\n      int sightRange;\n      WeaponType groundWeapon;\n      int maxGroundHits;\n      WeaponType airWeapon;\n      int maxAirHits;\n\n      double topSpeed;\n      int acceleration;\n      int haltDistance;\n      int turnRadius;\n\n      bool canProduce;\n      bool canAttack;\n      bool canMove;\n      bool isFlyer;\n      bool regeneratesHP;\n      bool isSpellcaster;\n      bool hasPermanentCloak;\n      bool isInvincible;\n      bool isOrganic;\n      bool isMechanical;\n      bool isRobotic;\n      bool isDetector;\n      bool isResourceContainer;\n      bool isResourceDepot;\n      bool isWorker;\n      bool requiresPsi;\n      bool requiresCreep;\n      bool isTwoUnitsInOneEgg;\n      bool isBurrowable;\n      bool isCloakable;\n      bool isBuilding;\n      bool isAddon;\n      bool isFlyingBuilding;\n      bool isNeutral;\n      bool isRefinery;\n      bool isHero;\n      bool isSpecialBuilding;\n\n      bool valid;\n  };\n  UnitTypeInternal unitTypeData[245];\n  std::map<std::string, UnitType> unitTypeMap;\n  std::set< UnitType > unitTypeSet;\n  namespace UnitTypes\n  {\n    const UnitType Terran_Marine(0);\n    const UnitType Hero_Jim_Raynor_Marine(20);\n    const UnitType Terran_Ghost(1);\n    const UnitType Hero_Sarah_Kerrigan(16);\n    const UnitType Hero_Samir_Duran(99);\n    const UnitType Hero_Infested_Duran(104);\n    const UnitType Hero_Alexei_Stukov(100);\n    const UnitType Terran_Vulture(2);\n    const UnitType Hero_Jim_Raynor_Vulture(19);\n    const UnitType Terran_Goliath(3);\n    const UnitType Hero_Alan_Schezar(17);\n    const UnitType Terran_Siege_Tank_Tank_Mode(5);\n    const UnitType Hero_Edmund_Duke_Tank_Mode(23);\n    const UnitType Terran_SCV(7);\n    const UnitType Terran_Wraith(8);\n    const UnitType Hero_Tom_Kazansky(21);\n    const UnitType Terran_Science_Vessel(9);\n    const UnitType Hero_Magellan(22);\n    const UnitType Terran_Dropship(11);\n    const UnitType Terran_Battlecruiser(12);\n    const UnitType Hero_Arcturus_Mengsk(27);\n    const UnitType Hero_Hyperion(28);\n    const UnitType Hero_Norad_II(29);\n    const UnitType Hero_Gerard_DuGalle(102);\n    const UnitType Terran_Vulture_Spider_Mine(13);\n    const UnitType Terran_Nuclear_Missile(14);\n    const UnitType Terran_Siege_Tank_Siege_Mode(30);\n    const UnitType Hero_Edmund_Duke_Siege_Mode(25);\n    const UnitType Terran_Firebat(32);\n    const UnitType Hero_Gui_Montag(10);\n    const UnitType Spell_Scanner_Sweep(33);\n    const UnitType Terran_Medic(34);\n    const UnitType Terran_Civilian(15);\n    const UnitType Zerg_Larva(35);\n    const UnitType Zerg_Egg(36);\n    const UnitType Zerg_Zergling(37);\n    const UnitType Hero_Devouring_One(54);\n    const UnitType Hero_Infested_Kerrigan(51);\n    const UnitType Zerg_Hydralisk(38);\n    const UnitType Hero_Hunter_Killer(53);\n    const UnitType Zerg_Ultralisk(39);\n    const UnitType Hero_Torrasque(48);\n    const UnitType Zerg_Broodling(40);\n    const UnitType Zerg_Drone(41);\n    const UnitType Zerg_Overlord(42);\n    const UnitType Hero_Yggdrasill(57);\n    const UnitType Zerg_Mutalisk(43);\n    const UnitType Hero_Kukulza_Mutalisk(55);\n    const UnitType Zerg_Guardian(44);\n    const UnitType Hero_Kukulza_Guardian(56);\n    const UnitType Zerg_Queen(45);\n    const UnitType Hero_Matriarch(49);\n    const UnitType Zerg_Defiler(46);\n    const UnitType Hero_Unclean_One(52);\n    const UnitType Zerg_Scourge(47);\n    const UnitType Zerg_Infested_Terran(50);\n    const UnitType Terran_Valkyrie(58);\n    const UnitType Zerg_Cocoon(59);\n    const UnitType Protoss_Corsair(60);\n    const UnitType Hero_Raszagal(98);\n    const UnitType Protoss_Dark_Templar(61);\n    const UnitType Hero_Dark_Templar(74);\n    const UnitType Hero_Zeratul(75);\n    const UnitType Zerg_Devourer(62);\n    const UnitType Protoss_Dark_Archon(63);\n    const UnitType Protoss_Probe(64);\n    const UnitType Protoss_Zealot(65);\n    const UnitType Hero_Fenix_Zealot(77);\n    const UnitType Protoss_Dragoon(66);\n    const UnitType Hero_Fenix_Dragoon(78);\n    const UnitType Protoss_High_Templar(67);\n    const UnitType Hero_Tassadar(79);\n    const UnitType Hero_Aldaris(87);\n    const UnitType Protoss_Archon(68);\n    const UnitType Hero_Tassadar_Zeratul_Archon(76);\n    const UnitType Protoss_Shuttle(69);\n    const UnitType Protoss_Scout(70);\n    const UnitType Hero_Mojo(80);\n    const UnitType Hero_Artanis(88);\n    const UnitType Protoss_Arbiter(71);\n    const UnitType Hero_Danimoth(86);\n    const UnitType Protoss_Carrier(72);\n    const UnitType Hero_Gantrithor(82);\n    const UnitType Protoss_Interceptor(73);\n    const UnitType Protoss_Reaver(83);\n    const UnitType Hero_Warbringer(81);\n    const UnitType Protoss_Observer(84);\n    const UnitType Protoss_Scarab(85);\n    const UnitType Critter_Rhynadon(89);\n    const UnitType Critter_Bengalaas(90);\n    const UnitType Critter_Scantid(93);\n    const UnitType Critter_Kakaru(94);\n    const UnitType Critter_Ragnasaur(95);\n    const UnitType Critter_Ursadon(96);\n    const UnitType Zerg_Lurker_Egg(97);\n    const UnitType Zerg_Lurker(103);\n    const UnitType Spell_Disruption_Web(105);\n    const UnitType Terran_Command_Center(106);\n    const UnitType Terran_Comsat_Station(107);\n    const UnitType Terran_Nuclear_Silo(108);\n    const UnitType Terran_Supply_Depot(109);\n    const UnitType Terran_Refinery(110);\n    const UnitType Terran_Barracks(111);\n    const UnitType Terran_Academy(112);\n    const UnitType Terran_Factory(113);\n    const UnitType Terran_Starport(114);\n    const UnitType Terran_Control_Tower(115);\n    const UnitType Terran_Science_Facility(116);\n    const UnitType Terran_Covert_Ops(117);\n    const UnitType Terran_Physics_Lab(118);\n    const UnitType Terran_Machine_Shop(120);\n    const UnitType Terran_Engineering_Bay(122);\n    const UnitType Terran_Armory(123);\n    const UnitType Terran_Missile_Turret(124);\n    const UnitType Terran_Bunker(125);\n    const UnitType Special_Crashed_Norad_II(126);\n    const UnitType Special_Ion_Cannon(127);\n    const UnitType Zerg_Infested_Command_Center(130);\n    const UnitType Zerg_Hatchery(131);\n    const UnitType Zerg_Lair(132);\n    const UnitType Zerg_Hive(133);\n    const UnitType Zerg_Nydus_Canal(134);\n    const UnitType Zerg_Hydralisk_Den(135);\n    const UnitType Zerg_Defiler_Mound(136);\n    const UnitType Zerg_Greater_Spire(137);\n    const UnitType Zerg_Queens_Nest(138);\n    const UnitType Zerg_Evolution_Chamber(139);\n    const UnitType Zerg_Ultralisk_Cavern(140);\n    const UnitType Zerg_Spire(141);\n    const UnitType Zerg_Spawning_Pool(142);\n    const UnitType Zerg_Creep_Colony(143);\n    const UnitType Zerg_Spore_Colony(144);\n    const UnitType Zerg_Sunken_Colony(146);\n    const UnitType Special_Overmind_With_Shell(147);\n    const UnitType Special_Overmind(148);\n    const UnitType Zerg_Extractor(149);\n    const UnitType Special_Mature_Chrysalis(150);\n    const UnitType Special_Cerebrate(151);\n    const UnitType Special_Cerebrate_Daggoth(152);\n    const UnitType Protoss_Nexus(154);\n    const UnitType Protoss_Robotics_Facility(155);\n    const UnitType Protoss_Pylon(156);\n    const UnitType Protoss_Assimilator(157);\n    const UnitType Protoss_Observatory(159);\n    const UnitType Protoss_Gateway(160);\n    const UnitType Protoss_Photon_Cannon(162);\n    const UnitType Protoss_Citadel_of_Adun(163);\n    const UnitType Protoss_Cybernetics_Core(164);\n    const UnitType Protoss_Templar_Archives(165);\n    const UnitType Protoss_Forge(166);\n    const UnitType Protoss_Stargate(167);\n    const UnitType Special_Stasis_Cell_Prison(168);\n    const UnitType Protoss_Fleet_Beacon(169);\n    const UnitType Protoss_Arbiter_Tribunal(170);\n    const UnitType Protoss_Robotics_Support_Bay(171);\n    const UnitType Protoss_Shield_Battery(172);\n    const UnitType Special_Khaydarin_Crystal_Form(173);\n    const UnitType Special_Protoss_Temple(174);\n    const UnitType Special_XelNaga_Temple(175);\n    const UnitType Resource_Mineral_Field(176);\n    const UnitType Resource_Vespene_Geyser(188);\n    const UnitType Special_Warp_Gate(189);\n    const UnitType Special_Psi_Disrupter(190);\n    const UnitType Special_Power_Generator(200);\n    const UnitType Special_Overmind_Cocoon(201);\n    const UnitType Special_Zerg_Beacon(194);\n    const UnitType Special_Terran_Beacon(195);\n    const UnitType Special_Protoss_Beacon(196);\n    const UnitType Special_Zerg_Flag_Beacon(197);\n    const UnitType Special_Terran_Flag_Beacon(198);\n    const UnitType Special_Protoss_Flag_Beacon(199);\n    const UnitType Spell_Dark_Swarm(202);\n    const UnitType Powerup_Uraj_Crystal(128);\n    const UnitType Powerup_Khalis_Crystal(129);\n    const UnitType Powerup_Flag(215);\n    const UnitType Powerup_Young_Chrysalis(216);\n    const UnitType Powerup_Psi_Emitter(217);\n    const UnitType Powerup_Data_Disk(218);\n    const UnitType Powerup_Khaydarin_Crystal(219);\n    const UnitType None(228);\n    const UnitType Unknown(229);\n\n    void init()\n    {\n      unitTypeData[Terran_Marine.getID()].set(\"Terran Marine\", Races::Terran, 0, Terran_Barracks, 1, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 40, 0, 0, 0, 50, 0, 360, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 128, 224, WeaponTypes::Gauss_Rifle, 1, WeaponTypes::Gauss_Rifle, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Jim_Raynor_Marine.getID()].set(\"Hero Jim Raynor Marine\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 200, 0, 0, 3, 50, 0, 1, 0, 0, 1, 0, 0, 200, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 128, 224, WeaponTypes::Gauss_Rifle_Jim_Raynor, 1, WeaponTypes::Gauss_Rifle_Jim_Raynor, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Ghost.getID()].set(\"Terran Ghost\", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, Terran_Covert_Ops, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::Nuclear_Strike, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 45, 0, 200, 0, 25, 75, 750, 2, 0, 1, 0, 175, 350, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 288, WeaponTypes::C_10_Canister_Rifle, 1, WeaponTypes::C_10_Canister_Rifle, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Sarah_Kerrigan.getID()].set(\"Hero Sarah Kerrigan\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 250, 0, 250, 3, 50, 150, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Sarah_Kerrigan, 1, WeaponTypes::C_10_Canister_Rifle_Sarah_Kerrigan, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Samir_Duran.getID()].set(\"Hero Samir Duran\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 200, 0, 250, 2, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 320, WeaponTypes::C_10_Canister_Rifle_Samir_Duran, 1, WeaponTypes::C_10_Canister_Rifle_Samir_Duran, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Infested_Duran.getID()].set(\"Hero Infested Duran\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::Consume, TechTypes::None, UpgradeTypes::Zerg_Carapace, 300, 0, 250, 3, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Infested_Duran, 1, WeaponTypes::C_10_Canister_Rifle_Infested_Duran, 1, 4, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Alexei_Stukov.getID()].set(\"Hero Alexei Stukov\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 250, 0, 250, 3, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Alexei_Stukov, 1, WeaponTypes::C_10_Canister_Rifle_Alexei_Stukov, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Vulture.getID()].set(\"Terran Vulture\", Races::Terran, 0, Terran_Factory, 1, None, None, TechTypes::None, TechTypes::Spider_Mines, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 80, 0, 0, 0, 75, 0, 450, 4, 0, 2, 0, 75, 150, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 160, 256, WeaponTypes::Fragmentation_Grenade, 1, WeaponTypes::None, 0, 6.4, 100, 14569, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Jim_Raynor_Vulture.getID()].set(\"Hero Jim Raynor Vulture\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Spider_Mines, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 300, 0, 0, 3, 150, 0, 900, 0, 0, 2, 0, 0, 300, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 160, 256, WeaponTypes::Fragmentation_Grenade_Jim_Raynor, 1, WeaponTypes::None, 0, 6.4, 100, 14569, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Goliath.getID()].set(\"Terran Goliath\", Races::Terran, 0, Terran_Factory, 1, Terran_Armory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 125, 0, 0, 1, 100, 50, 600, 4, 0, 2, 0, 200, 400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 192, 256, WeaponTypes::Twin_Autocannons, 1, WeaponTypes::Hellfire_Missile_Pack, 1, 4.57, 1, 1, 17, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Alan_Schezar.getID()].set(\"Hero Alan Schezar\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 300, 0, 0, 3, 200, 100, 1200, 0, 0, 2, 0, 0, 800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 192, 256, WeaponTypes::Twin_Autocannons_Alan_Schezar, 1, WeaponTypes::Hellfire_Missile_Pack_Alan_Schezar, 1, 4.57, 1, 1, 17, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Siege_Tank_Tank_Mode.getID()].set(\"Terran Siege Tank Tank Mode\", Races::Terran, 0, Terran_Factory, 1, Terran_Machine_Shop, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 150, 0, 0, 1, 150, 100, 750, 4, 0, 4, 0, 350, 700, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::Arclite_Cannon, 1, WeaponTypes::None, 0, 4, 1, 1, 13, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Edmund_Duke_Tank_Mode.getID()].set(\"Hero Edmund Duke Tank Mode\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 400, 0, 0, 3, 300, 200, 1500, 0, 0, 4, 0, 0, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::Arclite_Cannon_Edmund_Duke, 1, WeaponTypes::None, 0, 4, 1, 1, 13, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_SCV.getID()].set(\"Terran SCV\", Races::Terran, 0, Terran_Command_Center, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 60, 0, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 224, WeaponTypes::Fusion_Cutter, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Wraith.getID()].set(\"Terran Wraith\", Races::Terran, 0, Terran_Starport, 1, None, None, TechTypes::None, TechTypes::Cloaking_Field, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 120, 0, 200, 0, 150, 100, 900, 4, 0, 255, 0, 400, 800, UnitSizeTypes::Large, 1, 1, 19, 15, 18, 14, 160, 224, WeaponTypes::Burst_Lasers, 1, WeaponTypes::Gemini_Missiles, 1, 6.67, 67, 21745, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Tom_Kazansky.getID()].set(\"Hero Tom Kazansky\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Cloaking_Field, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 500, 0, 250, 4, 400, 200, 1800, 0, 0, 255, 0, 0, 1600, UnitSizeTypes::Large, 1, 1, 19, 15, 18, 14, 160, 224, WeaponTypes::Burst_Lasers_Tom_Kazansky, 1, WeaponTypes::Gemini_Missiles_Tom_Kazansky, 1, 6.67, 67, 21745, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Science_Vessel.getID()].set(\"Terran Science Vessel\", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Science_Facility, TechTypes::None, TechTypes::EMP_Shockwave, TechTypes::Defensive_Matrix, TechTypes::Irradiate, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 200, 0, 200, 1, 100, 225, 1200, 4, 0, 255, 0, 625, 1250, UnitSizeTypes::Large, 2, 2, 32, 33, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 50, 5120, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Magellan.getID()].set(\"Hero Magellan\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::EMP_Shockwave, TechTypes::Defensive_Matrix, TechTypes::Irradiate, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 800, 0, 250, 4, 50, 600, 2400, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 2, 2, 32, 33, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 50, 5120, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Dropship.getID()].set(\"Terran Dropship\", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 150, 0, 0, 1, 100, 100, 750, 4, 0, 255, 8, 300, 600, UnitSizeTypes::Large, 2, 2, 24, 16, 24, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 5.47, 17, 37756, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Battlecruiser.getID()].set(\"Terran Battlecruiser\", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Physics_Lab, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 500, 0, 200, 3, 400, 300, 2000, 12, 0, 255, 0, 1200, 2400, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery, 1, WeaponTypes::ATA_Laser_Battery, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Arcturus_Mengsk.getID()].set(\"Hero Arcturus Mengsk\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 1000, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 256, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Hyperion.getID()].set(\"Hero Hyperion\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 850, 0, 250, 4, 800, 600, 2400, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hyperion, 1, WeaponTypes::ATA_Laser_Battery_Hyperion, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Norad_II.getID()].set(\"Hero Norad II\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 700, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Gerard_DuGalle.getID()].set(\"Hero Gerard DuGalle\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 700, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Vulture_Spider_Mine.getID()].set(\"Terran Vulture Spider Mine\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 20, 0, 0, 0, 1, 0, 1, 0, 0, 255, 0, 0, 25, UnitSizeTypes::Small, 1, 1, 7, 7, 7, 7, 96, 96, WeaponTypes::Spider_Mines, 1, WeaponTypes::None, 0, 16, 1, 1, 127, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Nuclear_Missile.getID()].set(\"Terran Nuclear Missile\", Races::Terran, 0, Terran_Nuclear_Silo, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100, 0, 0, 0, 200, 200, 1500, 16, 0, 255, 0, 800, 0, UnitSizeTypes::Independent, 1, 1, 7, 14, 7, 14, 0, 96, WeaponTypes::None, 0, WeaponTypes::None, 0, 33.33, 33, 1103213, 127, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Siege_Tank_Siege_Mode.getID()].set(\"Terran Siege Tank Siege Mode\", Races::Terran, 0, Terran_Factory, 1, Terran_Machine_Shop, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 150, 0, 0, 1, 150, 100, 750, 4, 0, 255, 0, 0, 700, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 384, 320, WeaponTypes::Arclite_Shock_Cannon, 1, WeaponTypes::None, 0, 0, 1, 1, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Edmund_Duke_Siege_Mode.getID()].set(\"Hero Edmund Duke Siege Mode\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 400, 0, 0, 3, 300, 200, 1500, 0, 0, 255, 0, 0, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 384, 320, WeaponTypes::Arclite_Shock_Cannon_Edmund_Duke, 1, WeaponTypes::None, 0, 0, 1, 1, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Firebat.getID()].set(\"Terran Firebat\", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 50, 0, 0, 1, 50, 25, 360, 2, 0, 1, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 11, 7, 11, 14, 96, 224, WeaponTypes::Flame_Thrower, 3, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Gui_Montag.getID()].set(\"Hero Gui Montag\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 160, 0, 0, 3, 100, 50, 720, 0, 0, 1, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 11, 7, 11, 14, 96, 224, WeaponTypes::Flame_Thrower_Gui_Montag, 3, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Spell_Scanner_Sweep.getID()].set(\"Spell Scanner Sweep\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 13, 13, 13, 17, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Medic.getID()].set(\"Terran Medic\", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, None, TechTypes::None, TechTypes::Restoration, TechTypes::Optical_Flare, TechTypes::Healing, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 60, 0, 200, 1, 50, 25, 450, 2, 0, 1, 0, 125, 250, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 288, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Civilian.getID()].set(\"Terran Civilian\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 40, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Larva.getID()].set(\"Zerg Larva\", Races::Zerg, 0, Zerg_Hatchery, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 25, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 8, 8, 7, 7, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 1, 1, 20, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Egg.getID()].set(\"Zerg Egg\", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 25, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Zergling.getID()].set(\"Zerg Zergling\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 35, 0, 0, 0, 50, 0, 420, 1, 0, 1, 0, 25, 50, UnitSizeTypes::Small, 1, 1, 8, 4, 7, 11, 96, 160, WeaponTypes::Claws, 1, WeaponTypes::None, 0, 5.49, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Devouring_One.getID()].set(\"Hero Devouring One\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 120, 0, 0, 3, 100, 0, 840, 0, 0, 1, 0, 0, 100, UnitSizeTypes::Small, 1, 1, 8, 4, 7, 11, 96, 160, WeaponTypes::Claws_Devouring_One, 1, WeaponTypes::None, 0, 5.49, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Infested_Kerrigan.getID()].set(\"Hero Infested Kerrigan\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Personnel_Cloaking, TechTypes::Ensnare, TechTypes::Psionic_Storm, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 400, 0, 250, 2, 200, 300, 1500, 0, 0, 1, 0, 0, 4000, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 96, 288, WeaponTypes::Claws_Infested_Kerrigan, 1, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Hydralisk.getID()].set(\"Zerg Hydralisk\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Hydralisk_Den, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 80, 0, 0, 0, 75, 25, 420, 2, 0, 2, 0, 125, 350, UnitSizeTypes::Medium, 1, 1, 10, 10, 10, 12, 128, 192, WeaponTypes::Needle_Spines, 1, WeaponTypes::Needle_Spines, 1, 3.66, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Hunter_Killer.getID()].set(\"Hero Hunter Killer\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 160, 0, 0, 2, 150, 50, 780, 0, 0, 2, 0, 0, 500, UnitSizeTypes::Medium, 1, 1, 10, 10, 10, 12, 128, 256, WeaponTypes::Needle_Spines_Hunter_Killer, 1, WeaponTypes::Needle_Spines_Hunter_Killer, 1, 3.66, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Ultralisk.getID()].set(\"Zerg Ultralisk\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Ultralisk_Cavern, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 400, 0, 0, 1, 200, 200, 900, 8, 0, 4, 0, 650, 1300, UnitSizeTypes::Large, 2, 2, 19, 16, 18, 15, 96, 224, WeaponTypes::Kaiser_Blades, 1, WeaponTypes::None, 0, 5.12, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Torrasque.getID()].set(\"Hero Torrasque\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 800, 0, 0, 4, 400, 400, 1800, 0, 0, 4, 0, 0, 2600, UnitSizeTypes::Large, 2, 2, 19, 16, 18, 15, 96, 224, WeaponTypes::Kaiser_Blades_Torrasque, 1, WeaponTypes::None, 0, 5.12, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Broodling.getID()].set(\"Zerg Broodling\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 30, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 25, UnitSizeTypes::Small, 1, 1, 9, 9, 9, 9, 96, 160, WeaponTypes::Toxic_Spores, 1, WeaponTypes::None, 0, 6, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Drone.getID()].set(\"Zerg Drone\", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 40, 0, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 224, WeaponTypes::Spines, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Overlord.getID()].set(\"Zerg Overlord\", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 200, 0, 0, 0, 100, 0, 600, 0, 16, 255, 8, 100, 200, UnitSizeTypes::Large, 2, 2, 25, 25, 24, 24, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0.83, 27, 840, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Yggdrasill.getID()].set(\"Hero Yggdrasill\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 1000, 0, 0, 4, 200, 0, 1200, 0, 60, 255, 8, 0, 400, UnitSizeTypes::Large, 2, 2, 25, 25, 24, 24, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0.83, 27, 840, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Mutalisk.getID()].set(\"Zerg Mutalisk\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 120, 0, 0, 0, 100, 100, 600, 4, 0, 255, 0, 300, 600, UnitSizeTypes::Small, 2, 2, 22, 22, 21, 21, 96, 224, WeaponTypes::Glave_Wurm, 1, WeaponTypes::Glave_Wurm, 1, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Kukulza_Mutalisk.getID()].set(\"Hero Kukulza Mutalisk\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 300, 0, 0, 3, 200, 200, 1200, 0, 0, 255, 0, 0, 1200, UnitSizeTypes::Small, 2, 2, 22, 22, 21, 21, 96, 224, WeaponTypes::Glave_Wurm_Kukulza, 1, WeaponTypes::Glave_Wurm_Kukulza, 1, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Guardian.getID()].set(\"Zerg Guardian\", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 150, 0, 0, 2, 50, 100, 600, 4, 0, 255, 0, 550, 1100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 256, 352, WeaponTypes::Acid_Spore, 1, WeaponTypes::None, 0, 2.5, 27, 7585, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Kukulza_Guardian.getID()].set(\"Hero Kukulza Guardian\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 400, 0, 0, 4, 100, 200, 1200, 0, 0, 255, 0, 0, 2200, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 256, 352, WeaponTypes::Acid_Spore_Kukulza, 1, WeaponTypes::None, 0, 2.5, 27, 7585, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Queen.getID()].set(\"Zerg Queen\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Queens_Nest, None, TechTypes::None, TechTypes::Infestation, TechTypes::Spawn_Broodlings, TechTypes::Ensnare, TechTypes::Parasite, UpgradeTypes::Zerg_Flyer_Carapace, 120, 0, 200, 0, 100, 100, 750, 4, 0, 255, 0, 400, 800, UnitSizeTypes::Medium, 2, 2, 24, 24, 23, 23, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Matriarch.getID()].set(\"Hero Matriarch\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Infestation, TechTypes::Spawn_Broodlings, TechTypes::Ensnare, TechTypes::Parasite, UpgradeTypes::Zerg_Flyer_Carapace, 300, 0, 250, 3, 200, 300, 1500, 0, 0, 255, 0, 0, 1600, UnitSizeTypes::Medium, 2, 2, 24, 24, 23, 23, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Defiler.getID()].set(\"Zerg Defiler\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Defiler_Mound, None, TechTypes::None, TechTypes::Burrowing, TechTypes::Dark_Swarm, TechTypes::Plague, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 80, 0, 200, 1, 50, 150, 750, 4, 0, 2, 0, 225, 450, UnitSizeTypes::Medium, 1, 1, 13, 12, 13, 12, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Unclean_One.getID()].set(\"Hero Unclean One\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::Dark_Swarm, TechTypes::Plague, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 250, 0, 250, 3, 50, 200, 1500, 0, 0, 2, 0, 0, 900, UnitSizeTypes::Medium, 1, 1, 13, 12, 13, 12, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Scourge.getID()].set(\"Zerg Scourge\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 25, 0, 0, 0, 25, 75, 450, 1, 0, 255, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 12, 12, 11, 11, 96, 160, WeaponTypes::None, 0, WeaponTypes::Suicide_Scourge, 1, 6.67, 107, 13616, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Infested_Terran.getID()].set(\"Zerg Infested Terran\", Races::Zerg, 0, Zerg_Infested_Command_Center, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 60, 0, 0, 0, 100, 50, 600, 2, 0, 1, 0, 200, 400, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 96, 160, WeaponTypes::Suicide_Infested_Terran, 1, WeaponTypes::None, 0, 5.82, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Valkyrie.getID()].set(\"Terran Valkyrie\", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Armory, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 200, 0, 0, 2, 250, 125, 750, 6, 0, 255, 0, 400, 800, UnitSizeTypes::Large, 2, 2, 24, 16, 24, 20, 192, 256, WeaponTypes::None, 0, WeaponTypes::Halo_Rockets, 4, 6.6, 65, 21901, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Cocoon.getID()].set(\"Zerg Cocoon\", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 1100, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Corsair.getID()].set(\"Protoss Corsair\", Races::Protoss, 0, Protoss_Stargate, 1, None, None, TechTypes::None, TechTypes::Disruption_Web, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 100, 80, 200, 1, 150, 100, 600, 4, 0, 255, 0, 350, 700, UnitSizeTypes::Medium, 1, 1, 18, 16, 17, 15, 288, 288, WeaponTypes::None, 0, WeaponTypes::Neutron_Flare, 1, 6.67, 67, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Raszagal.getID()].set(\"Hero Raszagal\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Disruption_Web, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 100, 60, 250, 0, 150, 100, 750, 0, 0, 255, 0, 0, 1300, UnitSizeTypes::Medium, 1, 1, 18, 16, 17, 15, 288, 288, WeaponTypes::None, 0, WeaponTypes::Neutron_Flare, 1, 6.67, 67, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Dark_Templar.getID()].set(\"Protoss Dark Templar\", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::Dark_Archon_Meld, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 40, 0, 1, 125, 100, 750, 4, 0, 2, 0, 325, 650, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Dark_Templar.getID()].set(\"Hero Dark Templar\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 40, 80, 0, 0, 150, 150, 750, 1, 0, 2, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades_Hero, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Zeratul.getID()].set(\"Hero Zeratul\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 60, 400, 0, 0, 100, 300, 1500, 0, 0, 2, 0, 0, 800, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades_Zeratul, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Devourer.getID()].set(\"Zerg Devourer\", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 250, 0, 0, 2, 150, 50, 600, 4, 0, 255, 0, 550, 1100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 224, 320, WeaponTypes::None, 0, WeaponTypes::Corrosive_Acid, 1, 5, 48, 17067, 30, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Dark_Archon.getID()].set(\"Protoss Dark Archon\", Races::Protoss, 0, Protoss_Dark_Templar, 2, None, None, TechTypes::None, TechTypes::Mind_Control, TechTypes::Feedback, TechTypes::Maelstrom, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 25, 200, 200, 1, 0, 0, 300, 8, 0, 4, 0, 650, 1300, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 224, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Probe.getID()].set(\"Protoss Probe\", Races::Protoss, 0, Protoss_Nexus, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 20, 20, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 256, WeaponTypes::Particle_Beam, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Zealot.getID()].set(\"Protoss Zealot\", Races::Protoss, 0, Protoss_Gateway, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 60, 0, 1, 100, 0, 600, 4, 0, 2, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 11, 5, 11, 13, 96, 224, WeaponTypes::Psi_Blades, 2, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Fenix_Zealot.getID()].set(\"Hero Fenix Zealot\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 240, 240, 0, 2, 200, 0, 1200, 0, 0, 2, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 11, 5, 11, 13, 96, 224, WeaponTypes::Psi_Blades_Fenix, 2, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Dragoon.getID()].set(\"Protoss Dragoon\", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 80, 0, 1, 125, 50, 750, 4, 0, 4, 0, 250, 500, UnitSizeTypes::Large, 1, 1, 15, 15, 16, 16, 128, 256, WeaponTypes::Phase_Disruptor, 1, WeaponTypes::Phase_Disruptor, 1, 5, 1, 1, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Fenix_Dragoon.getID()].set(\"Hero Fenix Dragoon\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 240, 240, 0, 3, 300, 100, 1500, 0, 0, 4, 0, 0, 1000, UnitSizeTypes::Large, 1, 1, 15, 15, 16, 16, 128, 256, WeaponTypes::Phase_Disruptor_Fenix, 1, WeaponTypes::Phase_Disruptor_Fenix, 1, 5, 1, 1, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_High_Templar.getID()].set(\"Protoss High Templar\", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::Psionic_Storm, TechTypes::Hallucination, TechTypes::Archon_Warp, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 40, 40, 200, 0, 50, 150, 750, 4, 0, 2, 0, 350, 700, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Tassadar.getID()].set(\"Hero Tassadar\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Psionic_Storm, TechTypes::Hallucination, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 300, 250, 2, 100, 300, 1500, 0, 0, 2, 0, 0, 1400, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::Psi_Assault, 1, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Aldaris.getID()].set(\"Hero Aldaris\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 300, 250, 2, 100, 300, 1500, 0, 0, 2, 0, 0, 1400, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::Psi_Assault, 1, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Archon.getID()].set(\"Protoss Archon\", Races::Protoss, 0, Protoss_High_Templar, 2, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 10, 350, 0, 0, 0, 0, 300, 8, 0, 4, 0, 700, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 96, 256, WeaponTypes::Psionic_Shockwave, 1, WeaponTypes::Psionic_Shockwave, 1, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Tassadar_Zeratul_Archon.getID()].set(\"Hero Tassadar Zeratul Archon\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 800, 0, 3, 0, 0, 600, 0, 0, 4, 0, 0, 2800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 96, 256, WeaponTypes::Psionic_Shockwave_TZ_Archon, 1, WeaponTypes::Psionic_Shockwave_TZ_Archon, 1, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Shuttle.getID()].set(\"Protoss Shuttle\", Races::Protoss, 0, Protoss_Robotics_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 80, 60, 0, 1, 200, 0, 900, 4, 0, 255, 8, 200, 400, UnitSizeTypes::Large, 2, 1, 20, 16, 19, 15, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 4.43, 17, 37756, 20, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Scout.getID()].set(\"Protoss Scout\", Races::Protoss, 0, Protoss_Stargate, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 150, 100, 0, 0, 275, 125, 1200, 6, 0, 255, 0, 650, 1300, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 256, WeaponTypes::Dual_Photon_Blasters, 1, WeaponTypes::Anti_Matter_Missiles, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Mojo.getID()].set(\"Hero Mojo\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 400, 400, 0, 3, 600, 300, 2400, 0, 0, 255, 0, 0, 2600, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 320, WeaponTypes::Dual_Photon_Blasters_Mojo, 1, WeaponTypes::Anti_Matter_Missiles_Mojo, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Artanis.getID()].set(\"Hero Artanis\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 250, 250, 0, 3, 600, 300, 2400, 0, 0, 255, 0, 0, 2400, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 320, WeaponTypes::Dual_Photon_Blasters_Artanis, 1, WeaponTypes::Anti_Matter_Missiles_Artanis, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Arbiter.getID()].set(\"Protoss Arbiter\", Races::Protoss, 0, Protoss_Stargate, 1, Protoss_Arbiter_Tribunal, None, TechTypes::None, TechTypes::Recall, TechTypes::Stasis_Field, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 200, 150, 200, 1, 100, 350, 2400, 8, 0, 255, 0, 1025, 2050, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 160, 288, WeaponTypes::Phase_Disruptor_Cannon, 1, WeaponTypes::Phase_Disruptor_Cannon, 1, 5, 33, 24824, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Danimoth.getID()].set(\"Hero Danimoth\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Recall, TechTypes::Stasis_Field, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 600, 500, 250, 3, 50, 1000, 4800, 0, 0, 255, 0, 0, 4100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 160, 288, WeaponTypes::Phase_Disruptor_Cannon_Danimoth, 1, WeaponTypes::Phase_Disruptor_Cannon_Danimoth, 1, 5, 33, 24824, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Carrier.getID()].set(\"Protoss Carrier\", Races::Protoss, 0, Protoss_Stargate, 1, Protoss_Fleet_Beacon, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 300, 150, 0, 4, 350, 250, 2100, 12, 0, 255, 0, 950, 1900, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 256, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Gantrithor.getID()].set(\"Hero Gantrithor\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 800, 500, 0, 4, 700, 600, 4200, 0, 0, 255, 0, 0, 3800, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 256, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Interceptor.getID()].set(\"Protoss Interceptor\", Races::Protoss, 0, Protoss_Carrier, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 40, 40, 0, 0, 25, 0, 300, 0, 0, 255, 0, 30, 60, UnitSizeTypes::Small, 1, 1, 8, 8, 7, 7, 128, 192, WeaponTypes::Pulse_Cannon, 1, WeaponTypes::Pulse_Cannon, 1, 13.33, 427, 13640, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Reaver.getID()].set(\"Protoss Reaver\", Races::Protoss, 0, Protoss_Robotics_Facility, 1, Protoss_Robotics_Support_Bay, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 80, 0, 0, 200, 100, 1050, 8, 0, 4, 0, 400, 800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1.78, 1, 1, 20, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Warbringer.getID()].set(\"Hero Warbringer\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 200, 400, 0, 3, 400, 200, 1800, 0, 0, 4, 0, 0, 1600, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1.78, 1, 1, 20, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Observer.getID()].set(\"Protoss Observer\", Races::Protoss, 0, Protoss_Robotics_Facility, 1, Protoss_Observatory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 40, 20, 0, 0, 25, 75, 600, 2, 0, 255, 0, 225, 450, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Scarab.getID()].set(\"Protoss Scarab\", Races::Protoss, 0, Protoss_Reaver, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 20, 10, 0, 0, 15, 0, 105, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Small, 1, 1, 2, 2, 2, 2, 128, 160, WeaponTypes::Scarab, 1, WeaponTypes::None, 0, 16, 1, 1, 27, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Critter_Rhynadon.getID()].set(\"Critter Rhynadon\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Bengalaas.getID()].set(\"Critter Bengalaas\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Scantid.getID()].set(\"Critter Scantid\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Kakaru.getID()].set(\"Critter Kakaru\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 16, 51200, 14, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Ragnasaur.getID()].set(\"Critter Ragnasaur\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Ursadon.getID()].set(\"Critter Ursadon\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Zerg_Lurker_Egg.getID()].set(\"Zerg Lurker Egg\", Races::Zerg, 0, Zerg_Hydralisk, 1, None, None, TechTypes::Lurker_Aspect, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 500, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Lurker.getID()].set(\"Zerg Lurker\", Races::Zerg, 0, Zerg_Hydralisk, 1, None, None, TechTypes::Lurker_Aspect, TechTypes::Lurker_Aspect, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 125, 0, 0, 1, 50, 100, 600, 4, 0, 4, 0, 250, 500, UnitSizeTypes::Medium, 1, 1, 15, 15, 16, 16, 192, 256, WeaponTypes::Subterranean_Spines, 1, WeaponTypes::None, 0, 5.82, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Spell_Disruption_Web.getID()].set(\"Spell Disruption Web\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 250, 250, 2400, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 4, 3, 60, 40, 59, 39, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Terran_Command_Center.getID()].set(\"Terran Command Center\", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 400, 0, 1800, 0, 20, 255, 0, 400, 1200, UnitSizeTypes::Large, 4, 3, 58, 41, 58, 41, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Comsat_Station.getID()].set(\"Terran Comsat Station\", Races::Terran, 0, Terran_Command_Center, 1, Terran_Academy, None, TechTypes::None, TechTypes::Scanner_Sweep, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 200, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 37, 16, 31, 25, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Nuclear_Silo.getID()].set(\"Terran Nuclear Silo\", Races::Terran, 0, Terran_Command_Center, 1, Terran_Science_Facility, Terran_Covert_Ops, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 100, 100, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 37, 16, 31, 25, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Supply_Depot.getID()].set(\"Terran Supply Depot\", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 0, 1, 100, 0, 600, 0, 16, 255, 0, 50, 150, UnitSizeTypes::Large, 3, 2, 38, 22, 38, 26, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Terran_Refinery.getID()].set(\"Terran Refinery\", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 100, 0, 600, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 4, 2, 56, 32, 56, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1);\n      unitTypeData[Terran_Barracks.getID()].set(\"Terran Barracks\", Races::Terran, 0, Terran_SCV, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1000, 0, 0, 1, 150, 0, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 4, 3, 48, 40, 56, 32, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Academy.getID()].set(\"Terran Academy\", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 150, 0, 1200, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 32, 44, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Terran_Factory.getID()].set(\"Terran Factory\", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1250, 0, 0, 1, 200, 100, 1200, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 4, 3, 56, 40, 56, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Starport.getID()].set(\"Terran Starport\", Races::Terran, 0, Terran_SCV, 1, Terran_Factory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1300, 0, 0, 1, 150, 100, 1050, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 4, 3, 48, 40, 48, 38, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Control_Tower.getID()].set(\"Terran Control Tower\", Races::Terran, 0, Terran_Starport, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Science_Facility.getID()].set(\"Terran Science Facility\", Races::Terran, 0, Terran_SCV, 1, Terran_Starport, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 150, 900, 0, 0, 255, 0, 275, 825, UnitSizeTypes::Large, 4, 3, 48, 38, 48, 38, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Covert_Ops.getID()].set(\"Terran Covert Ops\", Races::Terran, 0, Terran_Science_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Physics_Lab.getID()].set(\"Terran Physics Lab\", Races::Terran, 0, Terran_Science_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Machine_Shop.getID()].set(\"Terran Machine Shop\", Races::Terran, 0, Terran_Factory, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 39, 24, 31, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Engineering_Bay.getID()].set(\"Terran Engineering Bay\", Races::Terran, 0, Terran_SCV, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 125, 0, 900, 0, 0, 255, 0, 65, 195, UnitSizeTypes::Large, 4, 3, 48, 32, 48, 28, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Armory.getID()].set(\"Terran Armory\", Races::Terran, 0, Terran_SCV, 1, Terran_Factory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 100, 50, 1200, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Terran_Missile_Turret.getID()].set(\"Terran Missile Turret\", Races::Terran, 0, Terran_SCV, 1, Terran_Engineering_Bay, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 200, 0, 0, 0, 75, 0, 450, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 2, 2, 16, 32, 16, 16, 224, 352, WeaponTypes::None, 0, WeaponTypes::Longbolt_Missile, 1, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Terran_Bunker.getID()].set(\"Terran Bunker\", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 350, 0, 0, 1, 100, 0, 450, 0, 0, 255, 4, 50, 150, UnitSizeTypes::Large, 3, 2, 32, 24, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Crashed_Norad_II.getID()].set(\"Special Crashed Norad II\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 700, 0, 0, 1, 800, 600, 4800, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Ion_Cannon.getID()].set(\"Special Ion Cannon\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 200, 0, 900, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Infested_Command_Center.getID()].set(\"Zerg Infested Command Center\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 1, 1, 1800, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 58, 41, 58, 41, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Zerg_Hatchery.getID()].set(\"Zerg Hatchery\", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1250, 0, 0, 1, 300, 0, 1800, 0, 2, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Lair.getID()].set(\"Zerg Lair\", Races::Zerg, 0, Zerg_Hatchery, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1800, 0, 0, 1, 150, 100, 1500, 0, 2, 255, 0, 100, 1200, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Hive.getID()].set(\"Zerg Hive\", Races::Zerg, 0, Zerg_Lair, 1, Zerg_Queens_Nest, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 200, 150, 1800, 0, 2, 255, 0, 100, 1500, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Nydus_Canal.getID()].set(\"Zerg Nydus Canal\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 0, 0, 1, 150, 0, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Hydralisk_Den.getID()].set(\"Zerg Hydralisk Den\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 50, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 32, 40, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Defiler_Mound.getID()].set(\"Zerg Defiler Mound\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 100, 900, 0, 0, 255, 0, 150, 450, UnitSizeTypes::Large, 4, 2, 48, 32, 48, 4, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Greater_Spire.getID()].set(\"Zerg Greater Spire\", Races::Zerg, 0, Zerg_Spire, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1000, 0, 0, 1, 100, 150, 1800, 0, 0, 255, 0, 200, 1350, UnitSizeTypes::Large, 2, 2, 28, 32, 28, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Queens_Nest.getID()].set(\"Zerg Queens Nest\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Lair, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 150, 100, 900, 0, 0, 255, 0, 175, 525, UnitSizeTypes::Large, 3, 2, 38, 28, 32, 28, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Evolution_Chamber.getID()].set(\"Zerg Evolution Chamber\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hatchery, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 75, 0, 600, 0, 0, 255, 0, 40, 120, UnitSizeTypes::Large, 3, 2, 44, 32, 32, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Ultralisk_Cavern.getID()].set(\"Zerg Ultralisk Cavern\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 150, 200, 1200, 0, 0, 255, 0, 275, 825, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Spire.getID()].set(\"Zerg Spire\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Lair, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 200, 150, 1800, 0, 0, 255, 0, 250, 750, UnitSizeTypes::Large, 2, 2, 28, 32, 28, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Spawning_Pool.getID()].set(\"Zerg Spawning Pool\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hatchery, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 200, 0, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 3, 2, 36, 28, 40, 18, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Creep_Colony.getID()].set(\"Zerg Creep Colony\", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 400, 0, 0, 0, 75, 0, 300, 0, 0, 255, 0, 40, 120, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Spore_Colony.getID()].set(\"Zerg Spore Colony\", Races::Zerg, 0, Zerg_Creep_Colony, 1, Zerg_Creep_Colony, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 400, 0, 0, 0, 50, 0, 300, 0, 0, 255, 0, 25, 195, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 224, 320, WeaponTypes::None, 0, WeaponTypes::Seeker_Spores, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Sunken_Colony.getID()].set(\"Zerg Sunken Colony\", Races::Zerg, 0, Zerg_Creep_Colony, 1, Zerg_Creep_Colony, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 300, 0, 0, 2, 50, 0, 300, 0, 0, 255, 0, 40, 240, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 224, 320, WeaponTypes::Subterranean_Tentacle, 1, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Overmind_With_Shell.getID()].set(\"Special Overmind With Shell\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 5000, 0, 0, 1, 1, 1, 1, 0, 0, 255, 0, 0, 10000, UnitSizeTypes::Large, 5, 3, 80, 32, 79, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Overmind.getID()].set(\"Special Overmind\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 1, 1, 1, 0, 0, 255, 0, 0, 10000, UnitSizeTypes::Large, 5, 3, 80, 32, 79, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Extractor.getID()].set(\"Zerg Extractor\", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 0, 600, 0, 0, 255, 0, 25, 75, UnitSizeTypes::Large, 4, 2, 64, 32, 63, 31, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1);\n      unitTypeData[Special_Mature_Chrysalis.getID()].set(\"Special Mature Chrysalis\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Cerebrate.getID()].set(\"Special Cerebrate\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Cerebrate_Daggoth.getID()].set(\"Special Cerebrate Daggoth\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Nexus.getID()].set(\"Protoss Nexus\", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 750, 0, 1, 400, 0, 1800, 0, 18, 255, 0, 400, 1200, UnitSizeTypes::Large, 4, 3, 56, 39, 56, 39, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Robotics_Facility.getID()].set(\"Protoss Robotics Facility\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 200, 1200, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 3, 2, 36, 16, 40, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Pylon.getID()].set(\"Protoss Pylon\", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 300, 300, 0, 0, 100, 0, 450, 0, 16, 255, 0, 50, 150, UnitSizeTypes::Large, 2, 2, 16, 12, 16, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Assimilator.getID()].set(\"Protoss Assimilator\", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 100, 0, 600, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 4, 2, 48, 32, 48, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1);\n      unitTypeData[Protoss_Observatory.getID()].set(\"Protoss Observatory\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Robotics_Facility, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 250, 0, 1, 50, 100, 450, 0, 0, 255, 0, 175, 525, UnitSizeTypes::Large, 3, 2, 44, 16, 44, 28, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Gateway.getID()].set(\"Protoss Gateway\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Nexus, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 150, 0, 900, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 4, 3, 48, 32, 48, 40, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Photon_Cannon.getID()].set(\"Protoss Photon Cannon\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Forge, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100, 100, 0, 0, 150, 0, 750, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 2, 2, 20, 16, 20, 16, 224, 352, WeaponTypes::STS_Photon_Cannon, 1, WeaponTypes::STA_Photon_Cannon, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Citadel_of_Adun.getID()].set(\"Protoss Citadel of Adun\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 150, 100, 900, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 3, 2, 24, 24, 40, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Cybernetics_Core.getID()].set(\"Protoss Cybernetics Core\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Gateway, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 0, 900, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 24, 40, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Templar_Archives.getID()].set(\"Protoss Templar Archives\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Citadel_of_Adun, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 150, 200, 900, 0, 0, 255, 0, 250, 750, UnitSizeTypes::Large, 3, 2, 32, 24, 32, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Forge.getID()].set(\"Protoss Forge\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Nexus, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 550, 550, 0, 1, 150, 0, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 36, 24, 36, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Stargate.getID()].set(\"Protoss Stargate\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 600, 0, 1, 150, 150, 1050, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 48, 40, 48, 32, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Stasis_Cell_Prison.getID()].set(\"Special Stasis Cell Prison\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 150, 0, 1, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 4, 3, 64, 48, 63, 47, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Fleet_Beacon.getID()].set(\"Protoss Fleet Beacon\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Stargate, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 300, 200, 900, 0, 0, 255, 0, 350, 1050, UnitSizeTypes::Large, 3, 2, 40, 32, 47, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Arbiter_Tribunal.getID()].set(\"Protoss Arbiter Tribunal\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 150, 900, 0, 0, 255, 0, 450, 1350, UnitSizeTypes::Large, 3, 2, 44, 28, 44, 28, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Robotics_Support_Bay.getID()].set(\"Protoss Robotics Support Bay\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Robotics_Facility, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 150, 100, 450, 0, 0, 255, 0, 125, 375, UnitSizeTypes::Large, 3, 2, 32, 32, 32, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Shield_Battery.getID()].set(\"Protoss Shield Battery\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Gateway, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 200, 200, 200, 1, 100, 0, 450, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 3, 2, 32, 16, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Khaydarin_Crystal_Form.getID()].set(\"Special Khaydarin Crystal Form\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 1, 250, 0, 1, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 4, 3, 64, 48, 63, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Protoss_Temple.getID()].set(\"Special Protoss Temple\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 250, 0, 1, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 7, 3, 112, 48, 111, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_XelNaga_Temple.getID()].set(\"Special XelNaga Temple\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 5000, 0, 0, 1, 1500, 500, 4800, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 5, 4, 80, 34, 79, 63, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Resource_Mineral_Field.getID()].set(\"Resource Mineral Field\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 10, 10, UnitSizeTypes::Independent, 2, 1, 32, 16, 31, 15, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0);\n      unitTypeData[Resource_Vespene_Geyser.getID()].set(\"Resource Vespene Geyser\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 10, 10, UnitSizeTypes::Independent, 4, 2, 64, 32, 63, 31, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0);\n      unitTypeData[Special_Warp_Gate.getID()].set(\"Special Warp Gate\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 700, 0, 0, 1, 600, 200, 2400, 0, 0, 255, 0, 0, 2000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Psi_Disrupter.getID()].set(\"Special Psi Disrupter\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 1000, 400, 4800, 0, 0, 255, 0, 0, 3600, UnitSizeTypes::Large, 5, 3, 80, 38, 69, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Power_Generator.getID()].set(\"Special Power Generator\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 1, 200, 50, 2400, 0, 0, 255, 0, 0, 600, UnitSizeTypes::Large, 4, 3, 56, 28, 63, 43, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Overmind_Cocoon.getID()].set(\"Special Overmind Cocoon\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 1000, 500, 2400, 0, 0, 255, 0, 0, 4000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Zerg_Beacon.getID()].set(\"Special Zerg Beacon\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 250, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Terran_Beacon.getID()].set(\"Special Terran Beacon\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 50, 50, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Protoss_Beacon.getID()].set(\"Special Protoss Beacon\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 100, 100, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Zerg_Flag_Beacon.getID()].set(\"Special Zerg Flag Beacon\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 250, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Terran_Flag_Beacon.getID()].set(\"Special Terran Flag Beacon\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 50, 50, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Protoss_Flag_Beacon.getID()].set(\"Special Protoss Flag Beacon\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 100, 100, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Spell_Dark_Swarm.getID()].set(\"Spell Dark Swarm\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 250, 200, 2400, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 5, 5, 80, 80, 79, 79, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Powerup_Uraj_Crystal.getID()].set(\"Powerup Uraj Crystal\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Khalis_Crystal.getID()].set(\"Powerup Khalis Crystal\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Flag.getID()].set(\"Powerup Flag\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Young_Chrysalis.getID()].set(\"Powerup Young Chrysalis\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Psi_Emitter.getID()].set(\"Powerup Psi Emitter\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Data_Disk.getID()].set(\"Powerup Data Disk\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Khaydarin_Crystal.getID()].set(\"Powerup Khaydarin Crystal\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[None.getID()].set(\"None\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, UnitSizeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Unknown.getID()].set(\"Unknown\", Races::Unknown, 0, Unknown, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, UnitSizeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n\n      foreach(UpgradeType i, UpgradeTypes::allUpgradeTypes())\n      {\n        foreach (UnitType ut, i.whatUses())\n          unitTypeData[ut.getID()].upgrades.insert(i);\n      }\n\n      unitTypeSet.insert(Terran_Marine);\n      unitTypeSet.insert(Hero_Jim_Raynor_Marine);\n      unitTypeSet.insert(Terran_Ghost);\n      unitTypeSet.insert(Hero_Sarah_Kerrigan);\n      unitTypeSet.insert(Hero_Samir_Duran);\n      unitTypeSet.insert(Hero_Infested_Duran);\n      unitTypeSet.insert(Hero_Alexei_Stukov);\n      unitTypeSet.insert(Terran_Vulture);\n      unitTypeSet.insert(Hero_Jim_Raynor_Vulture);\n      unitTypeSet.insert(Terran_Goliath);\n      unitTypeSet.insert(Hero_Alan_Schezar);\n      unitTypeSet.insert(Terran_Siege_Tank_Tank_Mode);\n      unitTypeSet.insert(Hero_Edmund_Duke_Tank_Mode);\n      unitTypeSet.insert(Terran_SCV);\n      unitTypeSet.insert(Terran_Wraith);\n      unitTypeSet.insert(Hero_Tom_Kazansky);\n      unitTypeSet.insert(Terran_Science_Vessel);\n      unitTypeSet.insert(Hero_Magellan);\n      unitTypeSet.insert(Terran_Dropship);\n      unitTypeSet.insert(Terran_Battlecruiser);\n      unitTypeSet.insert(Hero_Arcturus_Mengsk);\n      unitTypeSet.insert(Hero_Hyperion);\n      unitTypeSet.insert(Hero_Norad_II);\n      unitTypeSet.insert(Hero_Gerard_DuGalle);\n      unitTypeSet.insert(Terran_Vulture_Spider_Mine);\n      unitTypeSet.insert(Terran_Nuclear_Missile);\n      unitTypeSet.insert(Terran_Siege_Tank_Siege_Mode);\n      unitTypeSet.insert(Hero_Edmund_Duke_Siege_Mode);\n      unitTypeSet.insert(Terran_Firebat);\n      unitTypeSet.insert(Hero_Gui_Montag);\n      unitTypeSet.insert(Spell_Scanner_Sweep);\n      unitTypeSet.insert(Terran_Medic);\n      unitTypeSet.insert(Terran_Civilian);\n      unitTypeSet.insert(Zerg_Larva);\n      unitTypeSet.insert(Zerg_Egg);\n      unitTypeSet.insert(Zerg_Zergling);\n      unitTypeSet.insert(Hero_Devouring_One);\n      unitTypeSet.insert(Hero_Infested_Kerrigan);\n      unitTypeSet.insert(Zerg_Hydralisk);\n      unitTypeSet.insert(Hero_Hunter_Killer);\n      unitTypeSet.insert(Zerg_Ultralisk);\n      unitTypeSet.insert(Hero_Torrasque);\n      unitTypeSet.insert(Zerg_Broodling);\n      unitTypeSet.insert(Zerg_Drone);\n      unitTypeSet.insert(Zerg_Overlord);\n      unitTypeSet.insert(Hero_Yggdrasill);\n      unitTypeSet.insert(Zerg_Mutalisk);\n      unitTypeSet.insert(Hero_Kukulza_Mutalisk);\n      unitTypeSet.insert(Zerg_Guardian);\n      unitTypeSet.insert(Hero_Kukulza_Guardian);\n      unitTypeSet.insert(Zerg_Queen);\n      unitTypeSet.insert(Hero_Matriarch);\n      unitTypeSet.insert(Zerg_Defiler);\n      unitTypeSet.insert(Hero_Unclean_One);\n      unitTypeSet.insert(Zerg_Scourge);\n      unitTypeSet.insert(Zerg_Infested_Terran);\n      unitTypeSet.insert(Terran_Valkyrie);\n      unitTypeSet.insert(Zerg_Cocoon);\n      unitTypeSet.insert(Protoss_Corsair);\n      unitTypeSet.insert(Hero_Raszagal);\n      unitTypeSet.insert(Protoss_Dark_Templar);\n      unitTypeSet.insert(Hero_Dark_Templar);\n      unitTypeSet.insert(Hero_Zeratul);\n      unitTypeSet.insert(Zerg_Devourer);\n      unitTypeSet.insert(Protoss_Dark_Archon);\n      unitTypeSet.insert(Protoss_Probe);\n      unitTypeSet.insert(Protoss_Zealot);\n      unitTypeSet.insert(Hero_Fenix_Zealot);\n      unitTypeSet.insert(Protoss_Dragoon);\n      unitTypeSet.insert(Hero_Fenix_Dragoon);\n      unitTypeSet.insert(Protoss_High_Templar);\n      unitTypeSet.insert(Hero_Tassadar);\n      unitTypeSet.insert(Hero_Aldaris);\n      unitTypeSet.insert(Protoss_Archon);\n      unitTypeSet.insert(Hero_Tassadar_Zeratul_Archon);\n      unitTypeSet.insert(Protoss_Shuttle);\n      unitTypeSet.insert(Protoss_Scout);\n      unitTypeSet.insert(Hero_Mojo);\n      unitTypeSet.insert(Hero_Artanis);\n      unitTypeSet.insert(Protoss_Arbiter);\n      unitTypeSet.insert(Hero_Danimoth);\n      unitTypeSet.insert(Protoss_Carrier);\n      unitTypeSet.insert(Hero_Gantrithor);\n      unitTypeSet.insert(Protoss_Interceptor);\n      unitTypeSet.insert(Protoss_Reaver);\n      unitTypeSet.insert(Hero_Warbringer);\n      unitTypeSet.insert(Protoss_Observer);\n      unitTypeSet.insert(Protoss_Scarab);\n      unitTypeSet.insert(Critter_Rhynadon);\n      unitTypeSet.insert(Critter_Bengalaas);\n      unitTypeSet.insert(Critter_Scantid);\n      unitTypeSet.insert(Critter_Kakaru);\n      unitTypeSet.insert(Critter_Ragnasaur);\n      unitTypeSet.insert(Critter_Ursadon);\n      unitTypeSet.insert(Zerg_Lurker_Egg);\n      unitTypeSet.insert(Zerg_Lurker);\n      unitTypeSet.insert(Spell_Disruption_Web);\n      unitTypeSet.insert(Terran_Command_Center);\n      unitTypeSet.insert(Terran_Comsat_Station);\n      unitTypeSet.insert(Terran_Nuclear_Silo);\n      unitTypeSet.insert(Terran_Supply_Depot);\n      unitTypeSet.insert(Terran_Refinery);\n      unitTypeSet.insert(Terran_Barracks);\n      unitTypeSet.insert(Terran_Academy);\n      unitTypeSet.insert(Terran_Factory);\n      unitTypeSet.insert(Terran_Starport);\n      unitTypeSet.insert(Terran_Control_Tower);\n      unitTypeSet.insert(Terran_Science_Facility);\n      unitTypeSet.insert(Terran_Covert_Ops);\n      unitTypeSet.insert(Terran_Physics_Lab);\n      unitTypeSet.insert(Terran_Machine_Shop);\n      unitTypeSet.insert(Terran_Engineering_Bay);\n      unitTypeSet.insert(Terran_Armory);\n      unitTypeSet.insert(Terran_Missile_Turret);\n      unitTypeSet.insert(Terran_Bunker);\n      unitTypeSet.insert(Special_Crashed_Norad_II);\n      unitTypeSet.insert(Special_Ion_Cannon);\n      unitTypeSet.insert(Zerg_Infested_Command_Center);\n      unitTypeSet.insert(Zerg_Hatchery);\n      unitTypeSet.insert(Zerg_Lair);\n      unitTypeSet.insert(Zerg_Hive);\n      unitTypeSet.insert(Zerg_Nydus_Canal);\n      unitTypeSet.insert(Zerg_Hydralisk_Den);\n      unitTypeSet.insert(Zerg_Defiler_Mound);\n      unitTypeSet.insert(Zerg_Greater_Spire);\n      unitTypeSet.insert(Zerg_Queens_Nest);\n      unitTypeSet.insert(Zerg_Evolution_Chamber);\n      unitTypeSet.insert(Zerg_Ultralisk_Cavern);\n      unitTypeSet.insert(Zerg_Spire);\n      unitTypeSet.insert(Zerg_Spawning_Pool);\n      unitTypeSet.insert(Zerg_Creep_Colony);\n      unitTypeSet.insert(Zerg_Spore_Colony);\n      unitTypeSet.insert(Zerg_Sunken_Colony);\n      unitTypeSet.insert(Special_Overmind_With_Shell);\n      unitTypeSet.insert(Special_Overmind);\n      unitTypeSet.insert(Zerg_Extractor);\n      unitTypeSet.insert(Special_Mature_Chrysalis);\n      unitTypeSet.insert(Special_Cerebrate);\n      unitTypeSet.insert(Special_Cerebrate_Daggoth);\n      unitTypeSet.insert(Protoss_Nexus);\n      unitTypeSet.insert(Protoss_Robotics_Facility);\n      unitTypeSet.insert(Protoss_Pylon);\n      unitTypeSet.insert(Protoss_Assimilator);\n      unitTypeSet.insert(Protoss_Observatory);\n      unitTypeSet.insert(Protoss_Gateway);\n      unitTypeSet.insert(Protoss_Photon_Cannon);\n      unitTypeSet.insert(Protoss_Citadel_of_Adun);\n      unitTypeSet.insert(Protoss_Cybernetics_Core);\n      unitTypeSet.insert(Protoss_Templar_Archives);\n      unitTypeSet.insert(Protoss_Forge);\n      unitTypeSet.insert(Protoss_Stargate);\n      unitTypeSet.insert(Special_Stasis_Cell_Prison);\n      unitTypeSet.insert(Protoss_Fleet_Beacon);\n      unitTypeSet.insert(Protoss_Arbiter_Tribunal);\n      unitTypeSet.insert(Protoss_Robotics_Support_Bay);\n      unitTypeSet.insert(Protoss_Shield_Battery);\n      unitTypeSet.insert(Special_Khaydarin_Crystal_Form);\n      unitTypeSet.insert(Special_Protoss_Temple);\n      unitTypeSet.insert(Special_XelNaga_Temple);\n      unitTypeSet.insert(Resource_Mineral_Field);\n      unitTypeSet.insert(Resource_Vespene_Geyser);\n      unitTypeSet.insert(Special_Warp_Gate);\n      unitTypeSet.insert(Special_Psi_Disrupter);\n      unitTypeSet.insert(Special_Power_Generator);\n      unitTypeSet.insert(Special_Overmind_Cocoon);\n      unitTypeSet.insert(Special_Zerg_Beacon);\n      unitTypeSet.insert(Special_Terran_Beacon);\n      unitTypeSet.insert(Special_Protoss_Beacon);\n      unitTypeSet.insert(Special_Zerg_Flag_Beacon);\n      unitTypeSet.insert(Special_Terran_Flag_Beacon);\n      unitTypeSet.insert(Special_Protoss_Flag_Beacon);\n      unitTypeSet.insert(Spell_Dark_Swarm);\n      unitTypeSet.insert(Powerup_Uraj_Crystal);\n      unitTypeSet.insert(Powerup_Khalis_Crystal);\n      unitTypeSet.insert(Powerup_Flag);\n      unitTypeSet.insert(Powerup_Young_Chrysalis);\n      unitTypeSet.insert(Powerup_Psi_Emitter);\n      unitTypeSet.insert(Powerup_Data_Disk);\n      unitTypeSet.insert(Powerup_Khaydarin_Crystal);\n      unitTypeSet.insert(None);\n      unitTypeSet.insert(Unknown);\n\n      foreach(UnitType i, unitTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        unitTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingUnitType = false;\n    }\n  }\n  UnitType::UnitType()\n  {\n    this->id = UnitTypes::None.id;\n  }\n  UnitType::UnitType(int id)\n  {\n    this->id = id;\n    if (!initializingUnitType && (id < 0 || id >= 230 || !unitTypeData[id].valid))\n      this->id = UnitTypes::Unknown.id;\n  }\n  UnitType::UnitType(const UnitType& other)\n  {\n    this->id = other.id;\n  }\n  UnitType& UnitType::operator=(const UnitType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool UnitType::operator==(const UnitType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool UnitType::operator!=(const UnitType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool UnitType::operator<(const UnitType& other) const\n  {\n    return this->id < other.id;\n  }\n  int UnitType::getID() const\n  {\n    return this->id;\n  }\n  std::string UnitType::getName() const\n  {\n    return unitTypeData[this->id].name;\n  }\n  Race UnitType::getRace() const\n  {\n    return unitTypeData[this->id].race;\n  }\n  const std::pair<  UnitType, int> UnitType::whatBuilds() const\n  {\n    return unitTypeData[this->id].whatBuilds;\n  }\n  const std::map<  UnitType, int >& UnitType::requiredUnits() const\n  {\n    return unitTypeData[this->id].requiredUnits;\n  }\n  TechType UnitType::requiredTech() const\n  {\n    return unitTypeData[this->id].requiredTech;\n  }\n  TechType UnitType::cloakingTech() const\n  {\n    return unitTypeData[this->id].cloakingTech;\n  }\n  const std::set< TechType >& UnitType::abilities() const\n  {\n    return unitTypeData[this->id].abilities;\n  }\n  const std::set< UpgradeType >& UnitType::upgrades() const\n  {\n    return unitTypeData[this->id].upgrades;\n  }\n  UpgradeType UnitType::armorUpgrade() const\n  {\n    return unitTypeData[this->id].armorUpgrade;\n  }\n  int UnitType::maxHitPoints() const\n  {\n    return unitTypeData[this->id].maxHitPoints;\n  }\n  int UnitType::maxShields() const\n  {\n    return unitTypeData[this->id].maxShields;\n  }\n  int UnitType::maxEnergy() const\n  {\n    return unitTypeData[this->id].maxEnergy;\n  }\n  int UnitType::armor() const\n  {\n    return unitTypeData[this->id].armor;\n  }\n  int UnitType::mineralPrice() const\n  {\n    return unitTypeData[this->id].mineralPrice;\n  }\n  int UnitType::gasPrice() const\n  {\n    return unitTypeData[this->id].gasPrice;\n  }\n  int UnitType::buildTime() const\n  {\n    return unitTypeData[this->id].buildTime;\n  }\n  int UnitType::supplyRequired() const\n  {\n    return unitTypeData[this->id].supplyRequired;\n  }\n  int UnitType::supplyProvided() const\n  {\n    return unitTypeData[this->id].supplyProvided;\n  }\n  int UnitType::spaceRequired() const\n  {\n    return unitTypeData[this->id].spaceRequired;\n  }\n  int UnitType::spaceProvided() const\n  {\n    return unitTypeData[this->id].spaceProvided;\n  }\n  int UnitType::buildScore() const\n  {\n    return unitTypeData[this->id].buildScore;\n  }\n  int UnitType::destroyScore() const\n  {\n    return unitTypeData[this->id].destroyScore;\n  }\n  UnitSizeType UnitType::size() const\n  {\n    return unitTypeData[this->id].unitSizeType;\n  }\n  int UnitType::tileWidth() const\n  {\n    return unitTypeData[this->id].tileWidth;\n  }\n  int UnitType::tileHeight() const\n  {\n    return unitTypeData[this->id].tileHeight;\n  }\n  int UnitType::dimensionLeft() const\n  {\n    return unitTypeData[this->id].dimensionLeft;\n  }\n  int UnitType::dimensionUp() const\n  {\n    return unitTypeData[this->id].dimensionUp;\n  }\n  int UnitType::dimensionRight() const\n  {\n    return unitTypeData[this->id].dimensionRight;\n  }\n  int UnitType::dimensionDown() const\n  {\n    return unitTypeData[this->id].dimensionDown;\n  }\n  int UnitType::seekRange() const\n  {\n    return unitTypeData[this->id].seekRange;\n  }\n  int UnitType::sightRange() const\n  {\n    return unitTypeData[this->id].sightRange;\n  }\n  WeaponType UnitType::groundWeapon() const\n  {\n    return unitTypeData[this->id].groundWeapon;\n  }\n  int UnitType::maxGroundHits() const\n  {\n    return unitTypeData[this->id].maxGroundHits;\n  }\n  WeaponType UnitType::airWeapon() const\n  {\n    return unitTypeData[this->id].airWeapon;\n  }\n  int UnitType::maxAirHits() const\n  {\n    return unitTypeData[this->id].maxAirHits;\n  }\n  double UnitType::topSpeed() const\n  {\n    return unitTypeData[this->id].topSpeed;\n  }\n  int UnitType::acceleration() const\n  {\n    return unitTypeData[this->id].acceleration;\n  }\n  int UnitType::haltDistance() const\n  {\n    return unitTypeData[this->id].haltDistance;\n  }\n  int UnitType::turnRadius() const\n  {\n    return unitTypeData[this->id].turnRadius;\n  }\n  bool UnitType::canProduce() const\n  {\n    return unitTypeData[this->id].canProduce;\n  }\n  bool UnitType::canAttack() const\n  {\n    return unitTypeData[this->id].canAttack;\n  }\n  bool UnitType::canMove() const\n  {\n    return unitTypeData[this->id].canMove;\n  }\n  bool UnitType::isFlyer() const\n  {\n    return unitTypeData[this->id].isFlyer;\n  }\n  bool UnitType::regeneratesHP() const\n  {\n    return unitTypeData[this->id].regeneratesHP;\n  }\n  bool UnitType::isSpellcaster() const\n  {\n    return unitTypeData[this->id].isSpellcaster;\n  }\n  bool UnitType::hasPermanentCloak() const\n  {\n    return unitTypeData[this->id].hasPermanentCloak;\n  }\n  bool UnitType::isInvincible() const\n  {\n    return unitTypeData[this->id].isInvincible;\n  }\n  bool UnitType::isOrganic() const\n  {\n    return unitTypeData[this->id].isOrganic;\n  }\n  bool UnitType::isMechanical() const\n  {\n    return unitTypeData[this->id].isMechanical;\n  }\n  bool UnitType::isRobotic() const\n  {\n    return unitTypeData[this->id].isRobotic;\n  }\n  bool UnitType::isDetector() const\n  {\n    return unitTypeData[this->id].isDetector;\n  }\n  bool UnitType::isResourceContainer() const\n  {\n    return unitTypeData[this->id].isResourceContainer;\n  }\n  bool UnitType::isResourceDepot() const\n  {\n    return unitTypeData[this->id].isResourceDepot;\n  }\n  bool UnitType::isRefinery() const\n  {\n    return unitTypeData[this->id].isRefinery;\n  }\n  bool UnitType::isWorker() const\n  {\n    return unitTypeData[this->id].isWorker;\n  }\n  bool UnitType::requiresPsi() const\n  {\n    return unitTypeData[this->id].requiresPsi;\n  }\n  bool UnitType::requiresCreep() const\n  {\n    return unitTypeData[this->id].requiresCreep;\n  }\n  bool UnitType::isTwoUnitsInOneEgg() const\n  {\n    return unitTypeData[this->id].isTwoUnitsInOneEgg;\n  }\n  bool UnitType::isBurrowable() const\n  {\n    return unitTypeData[this->id].isBurrowable;\n  }\n  bool UnitType::isCloakable() const\n  {\n    return unitTypeData[this->id].isCloakable;\n  }\n  bool UnitType::isBuilding() const\n  {\n    return unitTypeData[this->id].isBuilding;\n  }\n  bool UnitType::isAddon() const\n  {\n    return unitTypeData[this->id].isAddon;\n  }\n  bool UnitType::isFlyingBuilding() const\n  {\n    return unitTypeData[this->id].isFlyingBuilding;\n  }\n  bool UnitType::isNeutral() const\n  {\n    return unitTypeData[this->id].isNeutral;\n  }\n  bool UnitType::isHero() const\n  {\n    return unitTypeData[this->id].isHero ||\n           this->id == UnitTypes::Hero_Dark_Templar.id ||\n           this->id == UnitTypes::Terran_Civilian.id;\n  }\n  bool UnitType::isPowerup() const\n  {\n    return this->id == UnitTypes::Powerup_Uraj_Crystal.id ||\n           this->id == UnitTypes::Powerup_Khalis_Crystal.id ||\n           (this->id >= UnitTypes::Powerup_Flag.id && this->id < UnitTypes::None.id);\n  }\n  bool UnitType::isBeacon() const\n  {\n    return this->id == UnitTypes::Special_Zerg_Beacon.id ||\n           this->id == UnitTypes::Special_Terran_Beacon.id ||\n           this->id == UnitTypes::Special_Protoss_Beacon.id;\n  }\n  bool UnitType::isFlagBeacon() const\n  {\n    return this->id == UnitTypes::Special_Zerg_Flag_Beacon.id ||\n           this->id == UnitTypes::Special_Terran_Flag_Beacon.id ||\n           this->id == UnitTypes::Special_Protoss_Flag_Beacon.id;\n  }\n  bool UnitType::isSpecialBuilding() const\n  {\n    return unitTypeData[this->id].isSpecialBuilding && this->id != UnitTypes::Zerg_Infested_Command_Center.id;\n  }\n  bool UnitType::isSpell() const\n  {\n    return this->id == UnitTypes::Spell_Dark_Swarm.id ||\n           this->id == UnitTypes::Spell_Disruption_Web.id ||\n           this->id == UnitTypes::Spell_Scanner_Sweep.id;\n  }\n  bool UnitType::producesLarva() const\n  {\n    return this->id == UnitTypes::Zerg_Hatchery.id || \n           this->id == UnitTypes::Zerg_Lair.id     || \n           this->id == UnitTypes::Zerg_Hive.id;\n  }\n  UnitType UnitTypes::getUnitType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, UnitType>::iterator i = unitTypeMap.find(name);\n    if (i == unitTypeMap.end())\n      return UnitTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<UnitType>& UnitTypes::allUnitTypes()\n  {\n    return unitTypeSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/UpgradeType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/UnitType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingUpgradeType = true;\n  class UpgradeTypeInternal\n  {\n    public:\n      UpgradeTypeInternal() {valid = false;}\n      void set(const char* name, int mineralPriceBase, int mineralPriceFactor, int gasPriceBase, int gasPriceFactor, int upgradeTimeBase, int upgradeTimeFactor, BWAPI::UnitType whatUpgrades, Race race, BWAPI::UnitType whatUses, int maxRepeats)\n      {\n        if (initializingUpgradeType)\n        {\n          this->name               = name;\n          this->mineralPriceBase   = mineralPriceBase;\n          this->mineralPriceFactor = mineralPriceFactor;\n          this->gasPriceBase       = gasPriceBase;\n          this->gasPriceFactor     = gasPriceFactor;\n          this->upgradeTimeBase    = upgradeTimeBase;\n          this->upgradeTimeFactor  = upgradeTimeFactor;\n          this->whatUpgrades       = whatUpgrades;\n          this->race               = race;\n          if (whatUses != UnitTypes::None)\n            this->whatUses.insert(whatUses);\n\n          this->maxRepeats = maxRepeats;\n          this->valid      = true;\n        }\n      }\n      std::string name;\n      int mineralPriceBase;\n      int mineralPriceFactor;\n      int gasPriceBase;\n      int gasPriceFactor;\n      int upgradeTimeBase;\n      int upgradeTimeFactor;\n      BWAPI::UnitType whatUpgrades;\n      Race race;\n      int maxRepeats;\n      std::set<BWAPI::UnitType> whatUses;\n      bool valid;\n  };\n  UpgradeTypeInternal upgradeTypeData[63];\n  std::map<std::string, UpgradeType> upgradeTypeMap;\n  std::set< UpgradeType > upgradeTypeSet;\n  namespace UpgradeTypes\n  {\n    const UpgradeType Terran_Infantry_Armor(0);\n    const UpgradeType Terran_Vehicle_Plating(1);\n    const UpgradeType Terran_Ship_Plating(2);\n    const UpgradeType Zerg_Carapace(3);\n    const UpgradeType Zerg_Flyer_Carapace(4);\n    const UpgradeType Protoss_Ground_Armor(5);\n    const UpgradeType Protoss_Air_Armor(6);\n    const UpgradeType Terran_Infantry_Weapons(7);\n    const UpgradeType Terran_Vehicle_Weapons(8);\n    const UpgradeType Terran_Ship_Weapons(9);\n    const UpgradeType Zerg_Melee_Attacks(10);\n    const UpgradeType Zerg_Missile_Attacks(11);\n    const UpgradeType Zerg_Flyer_Attacks(12);\n    const UpgradeType Protoss_Ground_Weapons(13);\n    const UpgradeType Protoss_Air_Weapons(14);\n    const UpgradeType Protoss_Plasma_Shields(15);\n    const UpgradeType U_238_Shells(16);\n    const UpgradeType Ion_Thrusters(17);\n    const UpgradeType Titan_Reactor(19);\n    const UpgradeType Ocular_Implants(20);\n    const UpgradeType Moebius_Reactor(21);\n    const UpgradeType Apollo_Reactor(22);\n    const UpgradeType Colossus_Reactor(23);\n    const UpgradeType Ventral_Sacs(24);\n    const UpgradeType Antennae(25);\n    const UpgradeType Pneumatized_Carapace(26);\n    const UpgradeType Metabolic_Boost(27);\n    const UpgradeType Adrenal_Glands(28);\n    const UpgradeType Muscular_Augments(29);\n    const UpgradeType Grooved_Spines(30);\n    const UpgradeType Gamete_Meiosis(31);\n    const UpgradeType Metasynaptic_Node(32);\n    const UpgradeType Singularity_Charge(33);\n    const UpgradeType Leg_Enhancements(34);\n    const UpgradeType Scarab_Damage(35);\n    const UpgradeType Reaver_Capacity(36);\n    const UpgradeType Gravitic_Drive(37);\n    const UpgradeType Sensor_Array(38);\n    const UpgradeType Gravitic_Boosters(39);\n    const UpgradeType Khaydarin_Amulet(40);\n    const UpgradeType Apial_Sensors(41);\n    const UpgradeType Gravitic_Thrusters(42);\n    const UpgradeType Carrier_Capacity(43);\n    const UpgradeType Khaydarin_Core(44);\n    const UpgradeType Argus_Jewel(47);\n    const UpgradeType Argus_Talisman(49);\n    const UpgradeType Caduceus_Reactor(51);\n    const UpgradeType Chitinous_Plating(52);\n    const UpgradeType Anabolic_Synthesis(53);\n    const UpgradeType Charon_Boosters(54);\n    const UpgradeType None(61);\n    const UpgradeType Unknown(62);\n\n    void init()\n    {\n      upgradeTypeData[Terran_Infantry_Armor.getID()].set(\"Terran Infantry Armor\"    , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Engineering_Bay      , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].set(\"Terran Vehicle Plating\"  , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Armory               , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Ship_Plating.getID()].set(\"Terran Ship Plating\"        , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Terran_Armory               , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Carapace.getID()].set(\"Zerg Carapace\"                    , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber      , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].set(\"Zerg Flyer Carapace\"        , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Zerg_Spire                  , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].set(\"Protoss Ground Armor\"      , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Protoss_Forge               , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Air_Armor.getID()].set(\"Protoss Air Armor\"            , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Protoss_Cybernetics_Core    , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Infantry_Weapons.getID()].set(\"Terran Infantry Weapons\", 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Engineering_Bay      , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].set(\"Terran Vehicle Weapons\"  , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Armory               , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Ship_Weapons.getID()].set(\"Terran Ship Weapons\"        , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Terran_Armory               , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Melee_Attacks.getID()].set(\"Zerg Melee Attacks\"          , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber      , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Missile_Attacks.getID()].set(\"Zerg Missile Attacks\"      , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber      , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Flyer_Attacks.getID()].set(\"Zerg Flyer Attacks\"          , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Zerg_Spire                  , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Ground_Weapons.getID()].set(\"Protoss Ground Weapons\"  , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Protoss_Forge               , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].set(\"Protoss Air Weapons\"        , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Protoss_Cybernetics_Core    , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].set(\"Protoss Plasma Shields\"  , 200, 100, 200, 100, 4000, 480, UnitTypes::Protoss_Forge               , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[U_238_Shells.getID()].set(\"U-238 Shells\"                      , 150, 0  , 150, 0  , 1500, 0  , UnitTypes::Terran_Academy              , Races::Terran , UnitTypes::Terran_Marine        , 1);\n      upgradeTypeData[Ion_Thrusters.getID()].set(\"Ion Thrusters\"                    , 100, 0  , 100, 0  , 1500, 0  , UnitTypes::Terran_Machine_Shop         , Races::Terran , UnitTypes::Terran_Vulture       , 1);\n      upgradeTypeData[Titan_Reactor.getID()].set(\"Titan Reactor\"                    , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Terran_Science_Facility     , Races::Terran , UnitTypes::Terran_Science_Vessel, 1);\n      upgradeTypeData[Ocular_Implants.getID()].set(\"Ocular Implants\"                , 100, 0  , 100, 0  , 2500, 0  , UnitTypes::Terran_Covert_Ops           , Races::Terran , UnitTypes::Terran_Ghost         , 1);\n      upgradeTypeData[Moebius_Reactor.getID()].set(\"Moebius Reactor\"                , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Terran_Covert_Ops           , Races::Terran , UnitTypes::Terran_Ghost         , 1);\n      upgradeTypeData[Apollo_Reactor.getID()].set(\"Apollo Reactor\"                  , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Terran_Control_Tower        , Races::Terran , UnitTypes::Terran_Wraith        , 1);\n      upgradeTypeData[Colossus_Reactor.getID()].set(\"Colossus Reactor\"              , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Terran_Physics_Lab          , Races::Terran , UnitTypes::Terran_Battlecruiser , 1);\n      upgradeTypeData[Ventral_Sacs.getID()].set(\"Ventral Sacs\"                      , 200, 0  , 200, 0  , 2400, 0  , UnitTypes::Zerg_Lair                   , Races::Zerg   , UnitTypes::Zerg_Overlord        , 1);\n      upgradeTypeData[Antennae.getID()].set(\"Antennae\"                              , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Zerg_Lair                   , Races::Zerg   , UnitTypes::Zerg_Overlord        , 1);\n      upgradeTypeData[Pneumatized_Carapace.getID()].set(\"Pneumatized Carapace\"      , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Zerg_Lair                   , Races::Zerg   , UnitTypes::Zerg_Overlord        , 1);\n      upgradeTypeData[Metabolic_Boost.getID()].set(\"Metabolic Boost\"                , 100, 0  , 100, 0  , 1500, 0  , UnitTypes::Zerg_Spawning_Pool          , Races::Zerg   , UnitTypes::Zerg_Zergling        , 1);\n      upgradeTypeData[Adrenal_Glands.getID()].set(\"Adrenal Glands\"                  , 200, 0  , 200, 0  , 1500, 0  , UnitTypes::Zerg_Spawning_Pool          , Races::Zerg   , UnitTypes::Zerg_Zergling        , 1);\n      upgradeTypeData[Muscular_Augments.getID()].set(\"Muscular Augments\"            , 150, 0  , 150, 0  , 1500, 0  , UnitTypes::Zerg_Hydralisk_Den          , Races::Zerg   , UnitTypes::Zerg_Hydralisk       , 1);\n      upgradeTypeData[Grooved_Spines.getID()].set(\"Grooved Spines\"                  , 150, 0  , 150, 0  , 1500, 0  , UnitTypes::Zerg_Hydralisk_Den          , Races::Zerg   , UnitTypes::Zerg_Hydralisk       , 1);\n      upgradeTypeData[Gamete_Meiosis.getID()].set(\"Gamete Meiosis\"                  , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Zerg_Queens_Nest            , Races::Zerg   , UnitTypes::Zerg_Queen           , 1);\n      upgradeTypeData[Metasynaptic_Node.getID()].set(\"Metasynaptic Node\"            , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Zerg_Defiler_Mound          , Races::Zerg   , UnitTypes::Zerg_Defiler         , 1);\n      upgradeTypeData[Singularity_Charge.getID()].set(\"Singularity Charge\"          , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Protoss_Cybernetics_Core    , Races::Protoss, UnitTypes::Protoss_Dragoon      , 1);\n      upgradeTypeData[Leg_Enhancements.getID()].set(\"Leg Enhancements\"              , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Protoss_Citadel_of_Adun     , Races::Protoss, UnitTypes::Protoss_Zealot       , 1);\n      upgradeTypeData[Scarab_Damage.getID()].set(\"Scarab Damage\"                    , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Scarab       , 1);\n      upgradeTypeData[Reaver_Capacity.getID()].set(\"Reaver Capacity\"                , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Reaver       , 1);\n      upgradeTypeData[Gravitic_Drive.getID()].set(\"Gravitic Drive\"                  , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Shuttle      , 1);\n      upgradeTypeData[Sensor_Array.getID()].set(\"Sensor Array\"                      , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Protoss_Observatory         , Races::Protoss, UnitTypes::Protoss_Observer     , 1);\n      upgradeTypeData[Gravitic_Boosters.getID()].set(\"Gravitic Boosters\"            , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Protoss_Observatory         , Races::Protoss, UnitTypes::Protoss_Observer     , 1);\n      upgradeTypeData[Khaydarin_Amulet.getID()].set(\"Khaydarin Amulet\"              , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Protoss_Templar_Archives    , Races::Protoss, UnitTypes::Protoss_High_Templar , 1);\n      upgradeTypeData[Apial_Sensors.getID()].set(\"Apial Sensors\"                    , 100, 0  , 100, 0  , 2500, 0  , UnitTypes::Protoss_Fleet_Beacon        , Races::Protoss, UnitTypes::Protoss_Scout        , 1);\n      upgradeTypeData[Gravitic_Thrusters.getID()].set(\"Gravitic Thrusters\"          , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Protoss_Fleet_Beacon        , Races::Protoss, UnitTypes::Protoss_Scout        , 1);\n      upgradeTypeData[Carrier_Capacity.getID()].set(\"Carrier Capacity\"              , 100, 0  , 100, 0  , 1500, 0  , UnitTypes::Protoss_Fleet_Beacon        , Races::Protoss, UnitTypes::Protoss_Carrier      , 1);\n      upgradeTypeData[Khaydarin_Core.getID()].set(\"Khaydarin Core\"                  , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Protoss_Arbiter_Tribunal    , Races::Protoss, UnitTypes::Protoss_Arbiter      , 1);\n      upgradeTypeData[Argus_Jewel.getID()].set(\"Argus Jewel\"                        , 100, 0  , 100, 0  , 2500, 0  , UnitTypes::Protoss_Fleet_Beacon        , Races::Protoss, UnitTypes::Protoss_Corsair      , 1);\n      upgradeTypeData[Argus_Talisman.getID()].set(\"Argus Talisman\"                  , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Protoss_Templar_Archives    , Races::Protoss, UnitTypes::Protoss_Dark_Archon  , 1);\n      upgradeTypeData[Caduceus_Reactor.getID()].set(\"Caduceus Reactor\"              , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Terran_Academy              , Races::Terran , UnitTypes::Terran_Medic         , 1);\n      upgradeTypeData[Chitinous_Plating.getID()].set(\"Chitinous Plating\"            , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Zerg_Ultralisk_Cavern       , Races::Zerg   , UnitTypes::Zerg_Ultralisk       , 1);\n      upgradeTypeData[Anabolic_Synthesis.getID()].set(\"Anabolic Synthesis\"          , 200, 0  , 200, 0  , 2000, 0  , UnitTypes::Zerg_Ultralisk_Cavern       , Races::Zerg   , UnitTypes::Zerg_Ultralisk       , 1);\n      upgradeTypeData[Charon_Boosters.getID()].set(\"Charon Boosters\"                , 100, 0  , 100, 0  , 2000, 0  , UnitTypes::Terran_Machine_Shop         , Races::Terran , UnitTypes::Terran_Goliath       , 1);\n      upgradeTypeData[None.getID()].set(\"None\"                                      , 0  , 0  , 0  , 0  , 0   , 0  , UnitTypes::None                        , Races::None   , UnitTypes::None                 , 0);\n      upgradeTypeData[Unknown.getID()].set(\"Unknown\"                                , 0  , 0  , 0  , 0  , 0   , 0  , UnitTypes::None                        , Races::Unknown, UnitTypes::None                 , 0);\n\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Firebat);\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Ghost);\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Marine);\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Medic);\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_SCV);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Goliath);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Siege_Mode);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Tank_Mode);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Vulture);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Battlecruiser);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Dropship);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Science_Vessel);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Valkyrie);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Wraith);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Broodling);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Defiler);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Drone);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Hydralisk);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Infested_Terran);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Larva);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Lurker);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Ultralisk);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Zergling);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Devourer);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Guardian);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Mutalisk);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Overlord);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Queen);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Scourge);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Archon);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Archon);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_High_Templar);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Probe);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Reaver);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Zealot);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Carrier);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Corsair);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Observer);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Scout);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Shuttle);\n      upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Firebat);\n      upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Ghost);\n      upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Marine);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Goliath);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Siege_Mode);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Tank_Mode);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Vulture);\n      upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Battlecruiser);\n      upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Valkyrie);\n      upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Wraith);\n      upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Broodling);\n      upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Ultralisk);\n      upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Zergling);\n      upgradeTypeData[Zerg_Missile_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Hydralisk);\n      upgradeTypeData[Zerg_Missile_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Lurker);\n      upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Devourer);\n      upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Guardian);\n      upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Mutalisk);\n      upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar);\n      upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon);\n      upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Zealot);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Corsair);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Scout);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter_Tribunal);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Archon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Assimilator);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Carrier);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Citadel_of_Adun);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Corsair);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Cybernetics_Core);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Archon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Fleet_Beacon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Forge);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Gateway);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_High_Templar);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Nexus);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Observatory);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Observer);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Photon_Cannon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Probe);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Pylon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Reaver);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Robotics_Facility);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Robotics_Support_Bay);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Scarab);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Scout);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Shield_Battery);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Shuttle);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Stargate);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Templar_Archives);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Zealot);\n\n      upgradeTypeSet.insert(Terran_Infantry_Armor);\n      upgradeTypeSet.insert(Terran_Vehicle_Plating);\n      upgradeTypeSet.insert(Terran_Ship_Plating);\n      upgradeTypeSet.insert(Zerg_Carapace);\n      upgradeTypeSet.insert(Zerg_Flyer_Carapace);\n      upgradeTypeSet.insert(Protoss_Ground_Armor);\n      upgradeTypeSet.insert(Protoss_Air_Armor);\n      upgradeTypeSet.insert(Terran_Infantry_Weapons);\n      upgradeTypeSet.insert(Terran_Vehicle_Weapons);\n      upgradeTypeSet.insert(Terran_Ship_Weapons);\n      upgradeTypeSet.insert(Zerg_Melee_Attacks);\n      upgradeTypeSet.insert(Zerg_Missile_Attacks);\n      upgradeTypeSet.insert(Zerg_Flyer_Attacks);\n      upgradeTypeSet.insert(Protoss_Ground_Weapons);\n      upgradeTypeSet.insert(Protoss_Air_Weapons);\n      upgradeTypeSet.insert(Protoss_Plasma_Shields);\n      upgradeTypeSet.insert(U_238_Shells);\n      upgradeTypeSet.insert(Ion_Thrusters);\n      upgradeTypeSet.insert(Titan_Reactor);\n      upgradeTypeSet.insert(Ocular_Implants);\n      upgradeTypeSet.insert(Moebius_Reactor);\n      upgradeTypeSet.insert(Apollo_Reactor);\n      upgradeTypeSet.insert(Colossus_Reactor);\n      upgradeTypeSet.insert(Ventral_Sacs);\n      upgradeTypeSet.insert(Antennae);\n      upgradeTypeSet.insert(Pneumatized_Carapace);\n      upgradeTypeSet.insert(Metabolic_Boost);\n      upgradeTypeSet.insert(Adrenal_Glands);\n      upgradeTypeSet.insert(Muscular_Augments);\n      upgradeTypeSet.insert(Grooved_Spines);\n      upgradeTypeSet.insert(Gamete_Meiosis);\n      upgradeTypeSet.insert(Metasynaptic_Node);\n      upgradeTypeSet.insert(Singularity_Charge);\n      upgradeTypeSet.insert(Leg_Enhancements);\n      upgradeTypeSet.insert(Scarab_Damage);\n      upgradeTypeSet.insert(Reaver_Capacity);\n      upgradeTypeSet.insert(Gravitic_Drive);\n      upgradeTypeSet.insert(Sensor_Array);\n      upgradeTypeSet.insert(Gravitic_Boosters);\n      upgradeTypeSet.insert(Khaydarin_Amulet);\n      upgradeTypeSet.insert(Apial_Sensors);\n      upgradeTypeSet.insert(Gravitic_Thrusters);\n      upgradeTypeSet.insert(Carrier_Capacity);\n      upgradeTypeSet.insert(Khaydarin_Core);\n      upgradeTypeSet.insert(Argus_Jewel);\n      upgradeTypeSet.insert(Argus_Talisman);\n      upgradeTypeSet.insert(Caduceus_Reactor);\n      upgradeTypeSet.insert(Chitinous_Plating);\n      upgradeTypeSet.insert(Anabolic_Synthesis);\n      upgradeTypeSet.insert(Charon_Boosters);\n      upgradeTypeSet.insert(None);\n      upgradeTypeSet.insert(Unknown);\n\n      foreach(UpgradeType i, upgradeTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        upgradeTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingUpgradeType = false;\n    }\n  }\n  UpgradeType::UpgradeType()\n  {\n    this->id = UpgradeTypes::None.id;\n  }\n  UpgradeType::UpgradeType(int id)\n  {\n    this->id = id;\n    if (!initializingUpgradeType && (id < 0 || id >= 63 || !upgradeTypeData[id].valid) )\n      this->id = UpgradeTypes::Unknown.id;\n  }\n  UpgradeType::UpgradeType(const UpgradeType& other)\n  {\n    this->id = other.id;\n  }\n  UpgradeType& UpgradeType::operator=(const UpgradeType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool UpgradeType::operator==(const UpgradeType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool UpgradeType::operator!=(const UpgradeType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool UpgradeType::operator<(const UpgradeType& other) const\n  {\n    return this->id < other.id;\n  }\n  int UpgradeType::getID() const\n  {\n    return this->id;\n  }\n  std::string UpgradeType::getName() const\n  {\n    return upgradeTypeData[this->id].name;\n  }\n  Race UpgradeType::getRace() const\n  {\n    return upgradeTypeData[this->id].race;\n  }\n  int UpgradeType::mineralPrice() const\n  {\n    return upgradeTypeData[this->id].mineralPriceBase;\n  }\n  int UpgradeType::mineralPriceFactor() const\n  {\n    return upgradeTypeData[this->id].mineralPriceFactor;\n  }\n  int UpgradeType::gasPrice() const\n  {\n    return upgradeTypeData[this->id].gasPriceBase;\n  }\n  int UpgradeType::gasPriceFactor() const\n  {\n    return upgradeTypeData[this->id].gasPriceFactor;\n  }\n  int UpgradeType::upgradeTime() const\n  {\n    return upgradeTypeData[this->id].upgradeTimeBase;\n  }\n  int UpgradeType::upgradeTimeFactor() const\n  {\n    return upgradeTypeData[this->id].upgradeTimeFactor;\n  }\n  UnitType UpgradeType::whatUpgrades() const\n  {\n    return upgradeTypeData[this->id].whatUpgrades;\n  }\n  const std::set<UnitType>& UpgradeType::whatUses() const\n  {\n    return upgradeTypeData[this->id].whatUses;\n  }\n  int UpgradeType::maxRepeats() const\n  {\n    return upgradeTypeData[this->id].maxRepeats;\n  }\n  UpgradeType UpgradeTypes::getUpgradeType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, UpgradeType>::iterator i = upgradeTypeMap.find(name);\n    if (i == upgradeTypeMap.end())\n      return UpgradeTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<UpgradeType>& UpgradeTypes::allUpgradeTypes()\n  {\n    return upgradeTypeSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Bitmask.h",
    "content": "#pragma once\n/** Custom help classes not connected with the project */\nnamespace Util\n{\n  /** \n   * Representation of list of bool values using binary.\n   * Size of the bitmask is always the same as Type (so it can be mapped in bw structurs)\n   * This also means, that the bitmas has sizeof(Type)*8 values.\n   */\n  template <class Type>\n  class BitMask\n  {\n    public :\n      bool getBit(Type bit) const;\n      void setBit(Type bit, bool val);\n    Type value;\n  };\n  //------------------------------------------------ GET BIT -------------------------------------------------\n  template <class Type>\n  bool BitMask<Type>::getBit(Type bit) const\n  {\n    return (value & bit) != 0;\n  }\n  //------------------------------------------------ SET BIT -------------------------------------------------\n  template <class Type>\n  void BitMask<Type>::setBit(Type bit, bool val)\n  {\n    if (val)\n      value |= bit;\n    else\n      value &= ~bit;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Exceptions.cpp",
    "content": "#include \"Exceptions.h\"\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nGeneralException::GeneralException(const std::string &message)\n:message(message)\n{\n}\n//----------------------------------------------- GET MESSAGE ------------------------------------------------\nconst std::string GeneralException::getMessage(void)\n{\n  return this->message;\n}\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nFileException::FileException(const std::string &message) : GeneralException(message)\n{\n}\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nConfigException::ConfigException(const std::string &message) : GeneralException(message)\n{\n}\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nXmlException::XmlException(const std::string& message, const std::string& fileName, const long lineNumber) \n:GeneralException(message)\n,fileName(fileName)\n,lineNumber(lineNumber)\n{\n}\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nParseException::ParseException(const std::string& message)\n:GeneralException(message)\n{\n}\n//------------------------------------------------------------------------------------------------------------\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Exceptions.h",
    "content": "#pragma once\n#include <string>\nclass MultiString;\n/**\n * Represents any exception that can be thrown during to program run,\n * it doesn't contain expressions that can be thrown by tinyXml\n */\nclass GeneralException\n{\n  private :\n    /**\n     * Represents the property key of the exception message, but in some special\n     *   cases, the messageKey can contain the message itself\n     */\n   std::string message;\n  public:\n    /** Creates exception with the specified message */\n    GeneralException(const std::string &messageKey);\n    const std::string getMessage(void);\n};\n\n/**\n * Can be thrown when the configuration files are invalid, or contain invalid\n * information.\n */\nclass ConfigException : public GeneralException\n{\n  public :\n    ConfigException(const std::string &message);\n};\n\n/** Can be thrown when some required files are not found. */\nclass FileException : public GeneralException\n{\n  public :\n   FileException(const std::string &message);\n};\n\n/** Can be thrown when the xml file structure is invalid. */\nclass XmlException : public GeneralException\n{\n    std::string fileName;\n    long lineNumber;\n  public :\n    XmlException(const std::string& message, const std::string& fileName = \"\", const long lineNumber = 0);\n};\n\n/** Can be thrown during parsin (non integer paremters that should be numbers for example) */\nclass ParseException : public GeneralException\n{\n  public :\n    ParseException(const std::string& message);\n};\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/FileLogger.cpp",
    "content": "#include \"FileLogger.h\"\n\n#include <ctime>\n\nnamespace Util\n{\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  FileLogger::FileLogger(const std::string& fileName, Util::LogLevel::Enum logLevel, bool showTime)\n  :Logger(logLevel)\n  ,fileName(fileName + \".log\")\n  ,showTime(showTime)\n  {\n  }\n  //------------------------------------------------- FLUSH --------------------------------------------------\n  bool FileLogger::flush(const char* data)\n  {\n    FILE *f = fopen(fileName.c_str(),\"at\");\n    if (!f)\n      return false;\n    if (showTime)\n    {\n      char time[9];\n      _strtime(time);\n      fprintf(f, \"%s \", time);\n    }\n    fprintf(f, \"%s \\n\", data);\n    fclose(f);\n    return true;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/FileLogger.h",
    "content": "#pragma once\n\n#include \"Logger.h\"\n\nnamespace Util\n{\n  /** Mutation of logger that prints messages to file. */\n  class FileLogger : public Logger\n  {\n    public :\n      FileLogger(const std::string& fileName, Util::LogLevel::Enum logLevel, bool showTime = true);\n    protected :\n      virtual bool flush(const char* data);\n    private :\n      std::string fileName;\n      bool showTime;\n  };\n}  \n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Foreach.h",
    "content": "#pragma once\n\n#define foreach(element, collection) for (element : collection)\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Gnu.h",
    "content": "#pragma once\n\n#ifdef __GNUC__\n#include <string.h>\n\n#define fprintf_s fprintf\n#define sprintf_s snprintf\n#define vsnprintf_s(buf, s1, s2, fmt, ap) vsnprintf(buf, s1, fmt, ap)\n#define memcpy_s(dest, ds, src, ss) memcpy(dest, src, ss)\n\ninline void strcpy_s(char* dest, size_t size, char* src) {\n    size_t s = strlen(src);\n    if(s > size - 1) {\n        s = size - 1;\n    }\n    memcpy(dest, src, s);\n    dest[s] = 0;\n}\n#endif\n\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/LogLevel.h",
    "content": "\nnamespace Util\n{\n  /** The level of detail of the log. */\n  namespace LogLevel\n  {\n    enum Enum\n    {\n      DontLog       = 0, /**< No logs will be printed by logger with this logLevel specification. Shouldn't be used by the Logger#log for obvious reasons. */\n      Critical      = 1, /**< Mostly errors, very important. */\n      Important     = 2, /**< Bigger events. */\n      Normal        = 2, /**< Normal events, like commands ordered etc. */\n      Commmon       = 3, /**< Common things. */\n      Detailed      = 4, /**< Detailed events mainly for investigation of problems. */\n      MicroDetailed = 5  /**< Super often occuring event's like calling common functions etc, used mainly for searching bugs. */\n    };\n  }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Logger.cpp",
    "content": "#include \"Logger.h\"\n\n#include <stdio.h>\n#include <stdarg.h>\n\n#include \"FileLogger.h\"\n#include \"Foreach.h\"\n#include \"Gnu.h\"\n\nnamespace Util\n{\n  Logger* Logger::globalLog = new FileLogger(\"global\", LogLevel::MicroDetailed);\n  char Logger::buffer[BUFFER_SIZE];\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  Logger::Logger(LogLevel::Enum levelToLog)\n  :levelToLog(levelToLog)\n  {\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  Logger::~Logger()\n  {\n    for (std::list<Logger*>::iterator i = this->connectedLoggers.begin();\n         i != this->connectedLoggers.end();\n         ++i)\n      delete *i;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::log(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Normal, ap);\n    va_end(ap);\n    return true;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logDetailed(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Detailed, ap);\n    va_end(ap);\n    return true;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logCommon(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Commmon, ap);\n    va_end(ap);\n    return true;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logImportant(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Important, ap);\n    va_end(ap);\n    return true;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logCritical(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Critical, ap);\n    va_end(ap);\n    return true;\n  }  \n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logInternal(const char* message, LogLevel::Enum logLevel, va_list ap)\n  {\n    if (logLevel > this->levelToLog)\n      return true;\n\n    vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE, message, ap); \n    this->flushInternal(buffer);\n    \n    if (globalLog != NULL &&\n        this != globalLog)\n      globalLog->logInternal(message, logLevel, ap);\n    return true;\n  }\n  //-------------------------------------------- REGISTER LOGGER ---------------------------------------------\n  void Logger::registerLogger(Logger* logger)\n  {\n    this->connectedLoggers.push_back(logger);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  bool Logger::flushInternal(const char* buffer)\n  {\n    foreach (Logger* i, this->connectedLoggers)\n     i->flush(buffer);\n    return this->flush(buffer);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  \n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Logger.h",
    "content": "#pragma once\n\n#include <stdio.h>\n#include <cstdarg>\n#include <string>\n#include <list>\n\n#include \"LogLevel.h\"\n\nnamespace Util\n{\n  /** \n   * Utility for logging debug output.\n   * This class defines abstract logger interface, every descentant needs to define the flush function to be\n   * instantiable.\n   * Every kind of log should have it's own instance of this class, don't log different things to same log.\n   * Different log instances can be later used to combine different logs with different detailLevels.\n   */\n  class Logger\n  {\n    public :\n      /**\n       * Creates new logger.\n       * @param levelToLog All log inputs with less importancy will be not\n       *        logged in this log\n       */\n      Logger(LogLevel::Enum levelToLog);\n      virtual ~Logger();\n      /**\n       * Logs the message using printf formatting style.\n       * This function use Normal Log level.\n       * @param message message to be logged.\n       * @param ... Parameters of the printf style format.\n       */\n      bool log         (const char* message, ...);\n      bool logDetailed (const char* message, ...);\n      bool logCommon   (const char* message, ...);\n      bool logImportant(const char* message, ...);\n      bool logCritical (const char* message, ...);      \n      void registerLogger(Logger* logger);\n      /** Every log message will be also posted to this global log. */\n      static Logger* globalLog;\n      static bool deleteLogsAtStart;\n    protected :\n      virtual bool flush(const char* data) = 0;\n      bool flushInternal(const char* data);      \n    private :\n      bool logInternal(const char* message, LogLevel::Enum, va_list ap);\n      LogLevel::Enum levelToLog;\n      static const unsigned int BUFFER_SIZE = 2048;\n      static char buffer[BUFFER_SIZE];\n      std::list<Logger*> connectedLoggers;\n  };\n};\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/RectangleArray.h",
    "content": "#pragma once\n\n#include <stdio.h>\n#include <string.h>\n#include \"Exceptions.h\"\n\nnamespace Util\n{\n  /**\n   * Template used for work with dynamically initialized array with dimension 2.\n   */\n  template <class Type>\n  class RectangleArray\n   {\n     public :\n       /**\n        * Creates the array with the specified proportions.\n        * @param width Width of the new array.\n        * @param height Height of the new array.\n        */\n       RectangleArray(unsigned int width = 1, unsigned int height = 1, Type* data = NULL);\n       /** Copy constructor */\n       RectangleArray(const RectangleArray<Type>& rectangleArray);\n       /** Destorys the array and deletes all content of array. */\n       ~RectangleArray(void);\n       /**\n        * Gets the width of the array.\n        * @return width of the array.\n        */\n       unsigned int getWidth(void) const;\n       /**\n        * Gets the height of the array.\n        * @return height of the array.\n        */\n       unsigned int getHeight(void) const;\n       /**\n        * Gets item of the array on the specified position.\n        * @param x horizontal index of the array position.\n        * @param y vertical index of the array position.\n        * @return item on the specified position.\n        */\n       Type* getItem(unsigned int x, unsigned int y);\n       inline Type* operator[](int i) { return this->getColumn(i); }\n       inline Type const * const operator[](int i) const {return this->getColumn(i); }\n       /**\n        * Sets item of the array on the specified position.\n        * @param x horizontal index of the array position.\n        * @param y vertical index of the array position.\n        * @param item new value of the field.\n        */\n       void setItem(unsigned int x, unsigned int y, Type *item);\n       void resize(unsigned int width, unsigned int height);\n       void printToFile(FILE* f);\n       void saveToFile(const std::string& fileName);\n       /** Sets all fields of the array to the specified value */\n       void setTo(const Type& value);\n       void setBorderTo(const Type& value);\n     private :\n       bool owner;\n       /** width of array */\n       unsigned int width;\n       /** height of array */\n       unsigned int height;\n       /** Array data, stored as linear array of size width*height */\n       Type *data;\n       /** Pointers to begins of lines*/\n       Type **columns;\n       /**\n        * Gets data item on the specified index\n        * @param index index of the data to be returned.\n        */\n       Type getData(unsigned int index);\n       /**\n        * Gets the pointer in data to the beginning of line with the specified\n        * index.\n        * @param index index of the line.\n        */\n       Type *getColumn(unsigned int index);\n       /**\n        * Gets the pointer in data to the beginning of line with the specified\n        * index.\n        * @param index index of the line.\n        */\n       const Type *getColumn(unsigned int index) const;\n       /**\n        * Sets the width of the array.\n        * @param width New width of the array.\n        */\n       void setWidth(unsigned int width);\n       /**\n        * Sets the height of the array.\n        * @param height New height of the array.\n        */\n       void setHeight(unsigned int height);       \n   };\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  template <class Type>\n  RectangleArray<Type>::RectangleArray(unsigned int width, unsigned int height, Type* data)\n  {\n    this->setWidth(width);\n    this->setHeight(height);\n    this->owner = (data == NULL);\n    if (this->owner)\n      this->data = new Type[this->getWidth()*this->getHeight()];\n    else\n      this->data = data;\n\n    columns = new Type*[this->getWidth()];\n    unsigned int i = 0;\n    for (unsigned int position = 0;i < width; i ++,position += height)\n      columns[i] = &this->data[position];\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  template <class Type>\n  RectangleArray<Type>::RectangleArray(const RectangleArray<Type>& rectangleArray)\n  :owner(true)\n  {\n    this->setWidth(rectangleArray.getWidth());\n    this->setHeight(rectangleArray.getHeight());\n    this->data = new Type[this->getWidth()*this->getHeight()];\n    columns = new Type*[this->getWidth()];\n    \n    unsigned int i = 0;\n    for (unsigned int position = 0;i < width; i ++,position += height)\n      columns[i] = &data[position];\n    memcpy(this->data, rectangleArray.data, sizeof(Type)*this->getWidth()*this->getHeight());\n  }\n  //----------------------------------------------- DESTRUCTOR -----------------------------------------------\n  template <class Type>\n  RectangleArray<Type>::~RectangleArray(void)\n  {\n     delete [] columns;\n     if (this->owner)\n       delete [] data;\n  }\n  //----------------------------------------------- GET WIDTH ------------------------------------------------\n  template <class Type>\n  unsigned int RectangleArray<Type>::getWidth(void) const\n  {\n    return this->width;\n  }\n  //----------------------------------------------- SET WIDTH ------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setWidth(unsigned int width)\n  {\n    this->width = width;\n  }\n  //----------------------------------------------- GET HEIGHT -----------------------------------------------\n  template <class Type>\n  unsigned int RectangleArray<Type>::getHeight(void) const\n  {\n    return this->height;\n  }\n  //----------------------------------------------- SET HEIGHT -----------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setHeight(unsigned int height)\n  {\n    this->height = height;\n  }\n  //------------------------------------------------ GET ITEM ------------------------------------------------\n  template <class Type>\n  Type* RectangleArray<Type>::getItem(unsigned int x, unsigned int y)\n  {\n    return this->getColumn(x)[y];\n  }\n  //------------------------------------------------ SET ITEM ------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setItem(unsigned int x, unsigned int y, Type* item)\n  {\n    this->getColumn(x)[y] = item;\n  }\n  //------------------------------------------------ GET LINE ------------------------------------------------\n  template <class Type>\n  Type* RectangleArray<Type>::getColumn(unsigned int index)\n  {\n    return columns[index];\n  }\n  //------------------------------------------------ GET LINE ------------------------------------------------\n  template <class Type>\n  const Type* RectangleArray<Type>::getColumn(unsigned int index) const\n  {\n    return columns[index];\n  }\n  //------------------------------------------------- RESIZE -------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::resize(unsigned int width, unsigned int height)\n  {\n    if (!this->owner)\n      throw GeneralException(\"Can't resize array that doesn't own the data\");\n    if (this->getWidth() == width &&\n        this->getHeight() == height)\n      return;\n\n    delete [] this->columns;\n    delete [] this->data;  \n\n    this->setWidth(width);\n    this->setHeight(height);\n\n    this->data = new Type[this->width * this->height];\n\n    this->columns = new Type*[this->width];\n    unsigned int i = 0;\n    for (unsigned int position = 0;i < this->width; i ++,position += this->height)\n      columns[i] = &data[position];\n  }\n  //--------------------------------------------- PRINT TO FILE ----------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::printToFile(FILE* f)\n  {\n    for (unsigned int y = 0; y < this->getHeight(); y++)\n    {\n      for (unsigned int x = 0; x < this->getWidth(); x++)\n      {\n        char ch = this->getColumn(x)[y];\n        fprintf(f, \"%c\", ch);\n      }\n      fprintf(f, \"\\n\");\n    }\n  }\n  //---------------------------------------------- SAVE TO FILE ----------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::saveToFile(const std::string& fileName)\n  {\n    FILE* f = fopen(fileName.c_str(), \"wt\");\n    if (!f)\n      throw FileException(\"RectangleArray::saveToFile Couldn't open file \" + fileName + \"for writing\");\n    this->printToFile(f);\n    fclose(f);\n  }\n  //------------------------------------------------- SET TO -------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setTo(const Type& value)\n  {\n    for (unsigned int i = 0; i < this->getWidth()*this->getHeight(); i++)\n      this->data[i] = value;\n  }\n  //--------------------------------------------- SET BORDER TO ----------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setBorderTo(const Type& value)\n  {\n    for (unsigned int i = 0; i < this->width; i++)\n    {\n      this->getColumn(i)[0] = value;\n      this->getColumn(i)[this->height - 1] = value;\n    }\n    for (unsigned int i = 0; i < this->height; i++)\n    {\n      this->getColumn(0)[i] = value;\n      this->getColumn(this->width - 1)[i] = value;\n    }    \n  }\n  //----------------------------------------------------------------------------------------------------------\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/RegionQuadTree.h",
    "content": "#pragma once\n\n#include <list>\n\nnamespace Util\n{\n  /**\n   * Structure representing 2D space containing objects of the specified type. This structure is optimised for\n   * effective way of finding of objects in certain area. The top level of the structure contains single list\n   * of all objects included, it divides into 2-4 partitions containing lists of units on respective quoters\n   * of the space, and so on until sthe width/height size is reached. The structure works with list of\n   * pointers of the type and doesn't act as owner, so removing items or deleting the whole quad tree will not\n   * result in delatation of contained items.\n   */\n  template <class Type>\n  class RegionQuadTree\n   {\n     public :\n       /**\n        * Creates the quad tree with the specified dimensions.\n        * @param width Width of the highest detail level partition.\n        * @param height Height of the highest detail level partition.\n        */\n       RegionQuadTree(unsigned int width = 1, unsigned int height = 1);\n       /** Destorys the array, but doesn't delete inserted objects. */\n       ~RegionQuadTree(void);\n       /**\n        * Gets the width of the array.\n        * @return width of the array.\n        */\n       unsigned int getWidth(void) const;\n       /**\n        * Gets the height of the array.\n        * @return height of the array.\n        */\n       unsigned int getHeight(void) const;\n       /**\n        * Gets list of items in the specified region.\n        * @param x horizontal index of the region.\n        * @param y vertical index of the region.\n        * @return list of items on the specified region\n        */\n       std::list<Type*>* getItems(unsigned int x, unsigned int y, unsigned int level = 0);\n       /**\n        * Sets item of the array on the specified position.\n        * @param x horizontal index of the array position.\n        * @param y vertical index of the array position.\n        * @param item new value of the field.\n        */\n       void addItem(unsigned int x, unsigned int y, Type *item);\n       void clear(unsigned int x, unsigned int y);\n     private :\n       /** width of array */\n       unsigned int width;\n       /** height of array */\n       unsigned int height;\n       /** array of rectangle arrays of lists of objects. \n        * The 1. item of the array corresponds with the lowest (most detailed) level of the region resolution.\n        * Every other level correspons to 4 times less detailed resolution.\n        */\n       RectangleArray<std::list<Type*> >* data;\n       /** depth = log2(max(width,height)), but is here for optimalisation reasons. */\n       unsigned int depth;\n   };\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  template <class Type>\n  RegionQuadTree<Type>::RegionQuadTree(unsigned int width, unsigned int height)\n  :width(width)\n  ,height(height)\n  ,depth(ceil(log2(max(width,height)))\n  {\n    this->data = new RectangleArray<std::list<Type*> >[depth];\n    unsigned int localWidth = width;\n    unsigned int localHeight = height;\n    for (unsigned int i = 0; i < this->depth; i++)\n    {\n      this->data[i].resize(localWidth, localHeight);\n      localWidth = (localWidth >= 2) (localWidth+1)/2 : 1;\n      localHeight = (localHeight >=2) (localHeight+1)/2 : 1;\n    }\n  }\n  //----------------------------------------------- DESTRUCTOR -----------------------------------------------\n  template <class Type>\n  RectangleArray<Type>::~RectangleArray(void)\n  {\n    delete [] data;\n  }\n  //----------------------------------------------- GET WIDTH ------------------------------------------------\n  template <class Type>\n  unsigned int RectangleArray<Type>::getWidth(void) const\n  {\n    return this->width;\n  }\n  //----------------------------------------------- SET WIDTH ------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setWidth(unsigned int width)\n  {\n    this->width = width;\n  }\n  //----------------------------------------------- GET HEIGHT -----------------------------------------------\n  template <class Type>\n  unsigned int RectangleArray<Type>::getHeight(void) const\n  {\n    return this->height;\n  }\n  //------------------------------------------------ GET ITEM ------------------------------------------------\n  template <class Type>\n  std::list<Type*>* getItems(unsigned int x, unsigned int y, unsigned int level = 0);\n  {\n    return this->data[level][x][y];\n  }\n  //------------------------------------------------ ADD ITEM ------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::addItem(unsigned int x, unsigned int y, Type* item)\n  {\n    for (unsigned int i = 0; i < this->depth; i++)\n      this->data[i][x<<i][y<<i].push_bach(item);\n  }\n  //------------------------------------------------- CLEAR --------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::clear(unsigned int x, unsigned int y)\n  {\n    for (unsigned int i = 0; i < this->depth; i++)\n      this->data[i][x<<i][y<<i].clear();\n  }  \n  //----------------------------------------------------------------------------------------------------------\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Strings.cpp",
    "content": "#include \"Strings.h\"\n\n#include <math.h>\n#include <stdarg.h>\n\n#include \"Exceptions.h\"\n#include \"Gnu.h\"\n\nnamespace Util\n{\n  //--------------------------------------------- INT TO STRING ----------------------------------------------\n  std::string Strings::intToString(long value)\n  {\n    if (value == 0)\n      return \"0\";\n    std::string returnValue;\n    while (value != 0)\n    {\n      returnValue = (char) (48+(value % 10)) + returnValue;\n      value/=10;\n    }\n    if (value >= 0)\n      return returnValue;\n    else\n      return \"-\" + returnValue;\n  }\n  //--------------------------------------------- STRING TO INT ----------------------------------------------\n  unsigned long Strings::stringToInt(const std::string &input, const unsigned long begin, const int distance)\n  {\n    unsigned long returnValue = 0;\n    for (unsigned long i = begin; i < distance + begin && i < input.size();i++)\n    {\n      if (!isdigit(input[i]))\n        throw ParseException::ParseException(\"Strings::stringToInt - String \" + input + \" is not a number.\");\n      returnValue*=10;\n      returnValue += (input[i] - '0');\n    }\n    return returnValue;\n  }\n  //---------------------------------------- STRING TO VARIABLE NAME -----------------------------------------\n  std::string Strings::stringToVariableName(const std::string &input)\n  {\n    std::string variableName;\n    for(unsigned int i=0;i<input.length();i++)\n    {\n      if (input[i]==' ')\n      {\n        variableName.push_back('_');\n      }\n      else if(input[i]=='\\'')\n      {\n      }\n      else if(input[i]=='\\\"')\n      {\n      }\n      else if(input[i]=='-')\n      {\n        variableName.push_back('_');\n      }\n      else\n      {\n        variableName.push_back(input[i]);\n      }\n    }\n    return variableName;\n  }\n  //--------------------------------------------- STRING TO FILE ---------------------------------------------\n  void Strings::stringToFile(const std::string &input,FILE* f)\n  {\n    size_t length = input.size();\n    fwrite(&length,sizeof(unsigned long),1,f);\n    fwrite(input.c_str(),length*sizeof(char),1,f);\n  }\n  //---------------------------------------------- SAVE TO FILE ----------------------------------------------\n  void Strings::saveToFile(const std::string &input,const std::string &fileName)\n  {\n     FILE *f = fopen(fileName.c_str(), \"wt\");\n     fwrite(input.c_str(),input.length()*sizeof(char),1,f);\n     fclose(f);\n  }\n  //--------------------------------------------- LOAD FROM FILE ---------------------------------------------\n  std::string Strings::loadFromFile(FILE* f)\n  {\n    unsigned long Length;\n    fread(&Length,sizeof(unsigned long),1,f);\n    char* Buffer = new char[Length + 1];\n    Buffer[Length] = 0;\n    if (Length != 0)\n      fread(Buffer,Length*sizeof(char),1,f);\n    std::string ReturnValue = Buffer;;\n    delete [] Buffer;\n    return ReturnValue;\n  }\n  //------------------------------------------- BEGINS WIHT NUMBER -------------------------------------------\n  bool Strings::beginsWithNumber(const std::string &input)\n  {\n    if (input.length() >= 1)\n      return input[0]>='0' && input[0]<= '9';\n    return false;\n  }\n  //-------------------------------------------- ENDS WITH NUMBER --------------------------------------------\n  bool Strings::endsWithNumber(const std::string &input)\n  {\n    if (input.length() >= 1)\n      return input[input.length() - 1]>='0' && input[input.length() - 1] <= '9';\n    return false;\n  }\n  //--------------------------------------------- LOAD FROM FILE ---------------------------------------------\n\n  void Strings::loadFromFile(const std::string &fileName, std::string &target,const long bufferSize)\n  {\n    char* buffer = new char[bufferSize];\n    FILE* f = fopen(fileName.c_str(),\"rt\");\n    size_t fileSize;\n    if (f)\n    {\n      fileSize = fread(buffer,1,bufferSize,f);\n      fclose(f);\n      buffer[fileSize] = 0;\n      target = buffer;\n    }\n    else\n      throw new FileException(\"Couldn't open file \" + fileName);\n    delete [] buffer;\n  }\n  //------------------------------------------------ TRIM ALL ------------------------------------------------\n  std::string Strings::trimAll(std::string input)\n  {\n    size_t length = input.size();\n    char* buffer = new char[length + 1];\n    long pos = 0;\n    for (size_t i = 0;i < length;i++)\n    {\n      if (!isspace(input[i]))\n      {\n        buffer[pos] = input[i];\n        pos++;\n      }\n    }\n    buffer[pos] = 0;\n    std::string returnValue = buffer;\n    delete [] buffer;\n    return returnValue;\n  }\n  //------------------------------------------------ TRIM ALL ------------------------------------------------\n  std::string Strings::trim(std::string input)\n  {\n    size_t i, j;\n    for (i = 0; i < input.length() && isspace(input[i]);i++);\n    if (i == input.length())\n      return  \"\";\n    for (j = input.length() - 1; j > 0 && isspace(input[j]);j--);\n    if (i == 0 && j == input.length())\n      return input;\n    else\n      return input.substr(i,j - i + 1);\n  }\n\n  char Strings::buffer[STRING_UTIL_BUFFER_SIZE];\n  //----------------------------------------------- READ LINE ------------------------------------------------\n  std::string Strings::readLine(FILE* f)\n  {\n    std::string result;\n    readNextBlock:\n    int position = 0;\n    fread(buffer, sizeof(char), 1, f);\n    while (buffer[position] != 13 && buffer[position] != 10 && position < STRING_UTIL_BUFFER_SIZE - 1 && !feof(f))\n    {\n      position++;\n      fread(&buffer[position], 1, 1,f);\n    }\n\n    if (buffer[position] == 13 || buffer[position] == 10 || feof(f))\n    {\n      buffer[position] = 0;\n      result.append(buffer);\n      return result;\n    }\n    else\n    {\n      buffer[position + 1] = 0;\n      result.append(buffer);\n      goto readNextBlock;\n    }\n  }\n  //----------------------------------------------------------------------------------------------------------\n  const std::string& Strings::dereferenceString(const std::string* const input)\n  {\n    return *input;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  RectangleArray<char> Strings::makeBorder(const RectangleArray<char>& input, bool coordinates)\n  {\n    int leftBorder = (int)log10((float)input.getHeight()) + 2;\n    int topBorder = 3;\n    RectangleArray<char> returnValue = RectangleArray<char>(input.getWidth() + leftBorder*2, input.getHeight() + topBorder*2);\n    for (unsigned int x = 0; x < returnValue.getWidth(); x++)\n      for (unsigned int y = 0; y < returnValue.getHeight(); y++)  \n        returnValue[x][y] = ' ';\n    Strings::makeWindow(returnValue,\n                        leftBorder - 1, \n                        topBorder - 1,\n                        input.getWidth() + 2, \n                        input.getHeight() + 2);      \n    for (unsigned int x = 0; x < input.getWidth(); x++)\n      for (unsigned int y = 0; y < input.getHeight(); y++)  \n        returnValue[x + leftBorder ][y + topBorder] = input[x][y];\n    for (unsigned int i = 0; i < input.getWidth(); i+=10)\n    {\n      Strings::printTo(returnValue, Strings::intToString(i), i + leftBorder, 0);\n      Strings::printTo(returnValue, Strings::intToString(i), i + leftBorder, returnValue.getHeight() - 1);\n    }\n    for (unsigned int i = 0; i < input.getWidth(); i++)\n    {\n      Strings::printTo(returnValue, Strings::intToString(i%10), i + leftBorder, 1);\n      Strings::printTo(returnValue, Strings::intToString(i%10), i + leftBorder, returnValue.getHeight() - 2);\n    }\n    \n    for (unsigned int i = 0; i < input.getHeight(); i++)\n    {\n      Strings::printTo(returnValue, Strings::intToString(i), 0 , i + topBorder);\n      Strings::printTo(returnValue, Strings::intToString(i), leftBorder + input.getWidth() + 1, i + topBorder);\n    }\n\n    return returnValue;\n  }\n  char Strings::FrameCharacters[2][6] = \n  {\n    {\n      char(205),\n      char(186),\n      char(201),\n      char(187),\n      char(200),\n      char(188)\n    },\n    {\n      char(196),\n      char(179),\n      char(218),\n      char(191),\n      char(192),\n      char(217)\n    }\n  };\n   \n  //----------------------------------------------------------------------------------------------------------\n  void Strings::makeWindow(RectangleArray<char>& input, \n                           unsigned int x, \n                           unsigned int y, \n                           unsigned int width, \n                           unsigned int height, \n                           unsigned int frameType)\n  {\n    for (unsigned int i = x + 1; i < x + width - 1 && x < input.getWidth(); i++)\n    {\n      input[i][y] = Strings::FrameCharacters[frameType][0];\n      input[i][y + height - 1] = Strings::FrameCharacters[frameType][0];\n    }\n    \n    for (unsigned int i = y + 1; i < y + height - 1 && y < input.getHeight(); i++)\n    {\n      input[x][i] = Strings::FrameCharacters[frameType][1];\n      input[x + width - 1][i] = Strings::FrameCharacters[frameType][1];\n    }\n    input[x][y] = Strings::FrameCharacters[frameType][2];\n    input[x + width - 1][y] = Strings::FrameCharacters[frameType][3];\n    input[x][y + height - 1] = Strings::FrameCharacters[frameType][4];\n    input[x + width - 1][y + height- 1] = Strings::FrameCharacters[frameType][5];\n  }\n  //------------------------------------------------ PRINT TO ------------------------------------------------\n  void Strings::printTo(RectangleArray<char>& input, \n                           const std::string& text, \n                           unsigned int x, \n                           unsigned int y)\n  {\n    for (unsigned int i = 0; text[i] != 0; i++)\n      input[x + i][y] = text[i];\n  }\n  //---------------------------------------------- SPLIT STRING ----------------------------------------------\n  std::vector<std::string> Strings::splitString(const std::string& input,\n                                                const std::string& delimiters)\n  {\n    // Skip delims at beginning, find start of first token\n    std::string::size_type lastPos = input.find_first_not_of(delimiters, 0);\n    // Find next delimiter @ end of token\n    std::string::size_type pos = input.find_first_of(delimiters, lastPos);\n\n    // output vector\n    std::vector<std::string> tokens;\n\n    while (std::string::npos != pos || std::string::npos != lastPos)\n    {\n      // Found a token, add it to the vector.\n      tokens.push_back(input.substr(lastPos, pos - lastPos));\n      // Skip delims.  Note the \"not_of\". this is beginning of token\n      lastPos = input.find_first_not_of(delimiters, pos);\n      // Find next delimiter at end of token.\n      pos = input.find_first_of(delimiters, lastPos);\n    }\n    return tokens;\n  }\n  //----------------------------------------------- GET BINARY ------------------------------------------------\n  template <class Type>\n  std::string Strings::getBinary(Type value)\n  {\n   std::string result;\n    for (int i = 0; i < sizeof(Type)*8; i++)\n      if (value  & (1 << (sizeof(Type)*8-1-i)))\n         result += \"1\";\n      else\n         result += \"0\";\n    return result;\n  }\n //----------------------------------------------- SKIP SPACE ------------------------------------------------\n void Strings::skipSpace(const std::string& text, size_t& position)\n {\n   while (isspace(text[position]))\n     position ++;\n }\n //------------------------------------------------ READ WORD ------------------------------------------------\n std::string Strings::readWord(const std::string& text, size_t& position)\n {\n   std::string result;\n   while (isalpha(text[position]))\n   {\n     result += text[position];\n     position++;\n   }\n  return result;  \n }\n //------------------------------------------------ READ WORD ------------------------------------------------\n std::string Strings::readNumber(const std::string& text, size_t& position)\n {\n   std::string result;\n   while (isdigit(text[position]) || text[position] == '.')\n   {\n     result += text[position];\n     position++;\n   }\n  return result;  \n }  \n const int BUFFER_SIZE = 4096;\n char buffer[BUFFER_SIZE];\n //-----------------------------------------------------------------------------------------------------------\n std::string Strings::ssprintf(const char* format, ...)\n {\n    va_list ap;\n    va_start(ap, format);\n    vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE, format, ap); \n    va_end(ap);\n    return buffer;\n }\n //-----------------------------------------------------------------------------------------------------------\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Strings.h",
    "content": "#pragma once\n#define STRING_UTIL_BUFFER_SIZE 100\n\n#include <string>\n#include <vector>\n\n#include \"RectangleArray.h\"\n\nnamespace Util\n{\n  /** Collection of std::string utilities */\n  class Strings\n   {\n     private :\n       /** The class is abstract, so it has private constructor */\n       Strings(void);\n       static char buffer[STRING_UTIL_BUFFER_SIZE];\n     public :\n       /**\n        * Gets textual representation of the specified number.\n        * @param value Number to be converted to std::string.\n        * @return Textual representation of the specified number.\n        */\n       static std::string intToString(long value);\n       /**\n        * Converts textual representation of number to number.\n        * @param input String containing number representation.\n        * @param begin Position of the first caracter of the number in the input\n        *        std::string.\n        * @param distance Maximum count of characters to read.\n        * @return Returns textual representation of the specified std::string.\n        * @throws ParseException if the text can't be converted to integer\n        *         (non-numerical characters)\n        */\n       static unsigned long stringToInt(const std::string &input, const unsigned long begin = 0, const int distance = 9);\n       static std::string stringToVariableName(const std::string &input);\n       static void stringToFile(const std::string &input, FILE* f);\n       static void saveToFile(const std::string &input, const std::string &fileName);\n       static bool beginsWithNumber(const std::string &input);\n       static bool endsWithNumber(const std::string &input);\n       static std::string loadFromFile(FILE* f);\n       static void loadFromFile(const std::string &fileName,std::string &Target,const long bufferSize);\n       static std::string UTF8ToWindows1250(const std::string &input);\n       static std::string Windows1250ToUTF8(const std::string &input);\n       static std::string trimAll(std::string input);\n       static std::string trim(std::string input);\n       static std::string replace(const std::string &input, MultiString* values, const std::string &replacement);\n       static RectangleArray<char> makeBorder(const RectangleArray<char>& input, bool coordinates = true);\n       static char FrameCharacters[2][6];\n       static void makeWindow(RectangleArray<char>& input, \n                              unsigned int x, \n                              unsigned int y, \n                              unsigned int width, \n                              unsigned int height, \n                              unsigned int frameType = 0);\n       static void printTo(RectangleArray<char>& input, const std::string& text, unsigned int x, unsigned int y);\n       /**\n        * Reads one line from the input stream.\n        * @param f Input stream.\n        * @return Content of the line.\n        */\n       static std::string readLine(FILE* f);\n       static const std::string& dereferenceString(const std::string* const input);\n       /**\n        * convert input string into vector of string tokens.\n        *\n        * @note consecutive delimiters will be treated as single delimiter\n        * @note delimiters are _not_ included in return data\n        *\n        * @param input string to be parsed\n        * @param delimiters list of delimiters.\n        * I was too lazy and took it from http://www.rosettacode.org/wiki/Tokenizing_A_String\n        */\n       static std::vector<std::string> splitString(const std::string& input,\n                                                   const std::string& delimiters = \" \\t\");\n       template <class Type>\n       std::string getBinary(Type value);\n       static void skipSpace(const std::string& text, size_t& position);\n       /** Reads words consting of alphaNumeric characters */\n       static std::string readWord(const std::string& text, size_t& position);\n       static std::string readNumber(const std::string& text, size_t& position);\n       static std::string ssprintf(const char* format, ...);\n   };\n }\n\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/Types.h",
    "content": "#pragma once\n\ntypedef unsigned char      u8;\ntypedef signed char        s8;\n\ntypedef unsigned short     u16;\ntypedef signed short       s16;\n\ntypedef unsigned int       u32;\ntypedef signed int         s32;\n\ntypedef unsigned long long u64;\ntypedef signed long long s64;\n\ntypedef u8              _UNKNOWN;\n\ntypedef unsigned char   BYTE;\ntypedef unsigned short  WORD;\ntypedef unsigned long   DWORD;\ntypedef void*           PVOID;\ntypedef int             BOOL;\ntypedef void*           HANDLE;\n\n#ifdef NULL\n#undef NULL\n#endif\n#define NULL 0\n\n#define ever (;;)\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/sha1.cpp",
    "content": "/*\nCopyright (c) 2009, Micael Hildenborg\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Micael Hildenborg nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, ACTIONS, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/*\nContributors:\nGustav\nSeveral members in the gamedev.se forum.\n*/\n \n#include \"sha1.h\"\n#include <string.h>\n\nnamespace sha1\n{\n        namespace // local\n        {\n                inline const unsigned int rol(const unsigned int num, const unsigned int cnt)\n                {\n                        return((num << cnt) | (num >> (32-cnt)));\n                }\n \n                void innerHash(unsigned int *result, unsigned int *w)\n                {\n                        unsigned int save[5];\n                        save[0]=result[0];\n                        save[1]=result[1];\n                        save[2]=result[2];\n                        save[3]=result[3];\n                        save[4]=result[4];\n\n                        #define a result[0]\n                        #define b result[1]\n                        #define c result[2]\n                        #define d result[3]\n                        #define e result[4]\n \n                        int j=0;\n                        #define sha1macro(func,val) \\\n                                {const unsigned int t = rol(a, 5)+(func)+e+val+w[j]; \\\n                                e = d; d = c; \\\n                                c = rol(b, 30); \\\n                                b = a; a = t;}\n                        while(j<16)\n                        {\n                                sha1macro((b&c)|(~b&d),0x5A827999)\n                                j++;\n                        }\n                        while(j<20)\n                        {\n                                w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1);\n                                sha1macro((b&c)|(~b&d),0x5A827999)\n                                j++;\n                        }\n                        while(j<40)\n                        {\n                                w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1);\n                                sha1macro(b^c^d,0x6ED9EBA1)\n                                j++;\n                        }\n                        while(j<60)\n                        {\n                                w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1);\n                                sha1macro((b&c)|(b&d)|(c&d),0x8F1BBCDC)\n                                j++;\n                        }\n                        while(j<80)\n                        {\n                                w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1);\n                                sha1macro(b^c^d,0xCA62C1D6)\n                                j++;\n                        }\n                        #undef sha1macro\n                        #undef a\n                        #undef b\n                        #undef c\n                        #undef d\n                        #undef e\n\n                        result[0]+=save[0];\n                        result[1]+=save[1];\n                        result[2]+=save[2];\n                        result[3]+=save[3];\n                        result[4]+=save[4];\n                }\n        }\n\n        void calc(const void *src, const int bytelength, unsigned char *hash)\n        {\n                // Init the result array, and create references to the five unsigned integers for better readabillity.\n                unsigned int result[5]={0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0};\n\n                const unsigned char *sarray=(const unsigned char*)src;\n                // The variables\n                unsigned int w[80];\n                int j,i,i1;\n                j=0;\n                // Loop through all complete 64byte blocks.\n                for(i=0,i1=64; i<=(bytelength-64); i=i1,i1+=64) \n                {\n                        int k=0;\n                        for(j=i;j<i1;j+=4)\n                        {\n                                // This line will swap endian on big endian and keep endian on little endian.\n                                w[k++]=(unsigned int)sarray[j+3]|(((unsigned int)sarray[j+2])<<8)|(((unsigned int)sarray[j+1])<<16)|(((unsigned int)sarray[j])<<24);\n                        }\n                        innerHash(result,w);\n                }\n                // fill in reminder\n                i1=bytelength-i;\n                memset(w,0,sizeof(unsigned int)*16);\n                for(j=0;j<i1;j++)\n                {\n                        w[j>>2]|=(unsigned int)sarray[j+i]<<((3-(j&3))<<3);\n                }\n                w[j>>2]|=0x80<<((3-(j&3))<<3);\n                if(i1>=56)\n                {\n                        innerHash(result,w);\n                        memset(w,0,sizeof(unsigned int)*16);\n                }\n                w[15]=bytelength<<3;\n                innerHash(result,w);\n                // Store hash in result pointer, and make sure we get in in the correct order on both endian models.\n                for(i=20;--i>=0;) \n                {\n                        hash[i]=(result[i>>2]>>(((3-i)&0x3)<<3))&0xFF;\n                }\n        }\n\n        void toHexString(const unsigned char *hash, char *hexstring)\n        {\n                const char tab[]={\"0123456789abcdef\"};\n                for(int i=20;--i>=0;) \n                {\n                        hexstring[i<<1]=tab[(hash[i]>>4)&0xF];\n                        hexstring[(i<<1)+1]=tab[hash[i]&0xF];\n                }\n                hexstring[40]=0;\n        }\n}\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/Util/sha1.h",
    "content": "// sha1.h and sha1.cpp are from code.google.com/p/smallsha1/\n/*\nCopyright (c) 2009, Micael Hildenborg\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Micael Hildenborg nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, ACTIONS, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef SHA1_DEFINED\n#define SHA1_DEFINED\n\nnamespace sha1\n{\n        /**\n                @param src points to any kind of data to be hashed.\n                @param bytelength the number of bytes to hash from the src pointer.\n                @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.\n        */\n        void calc(const void *src, const int bytelength, unsigned char *hash);\n        /**\n                @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.\n                @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.\n        */\n        void toHexString(const unsigned char *hash, char *hexstring);\n}; // namespace sha1\n\n#endif // SHA1_DEFINED\n\n"
  },
  {
    "path": "BOSS/source/deprecated/bwapidata/include/WeaponType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/WeaponType.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/DamageType.h>\n#include <BWAPI/ExplosionType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingWeaponType = true;\n  class WeaponTypeInternal\n  {\n    public:\n      WeaponTypeInternal() {valid = false;}\n      void set(const char* name, TechType techType, int damageAmount, int damageBonus, int damageCooldown, int damageFactor, UpgradeType upgradeType, DamageType damageType, ExplosionType explosionType, int minRange, int maxRange, int innerSplashRadius, int medianSplashRadius, int outerSplashRadius, bool targetsAir, bool targetsGround, bool targetsMechanical, bool targetsOrganic, bool targetsNonBuilding, bool targetsNonRobotic, bool targetsTerrain, bool targetsOrgOrMech, bool targetsOwn, UnitType whatUses)\n      {\n        if (initializingWeaponType)\n        {\n          this->name               = name;\n          this->techType           = techType;\n          this->damageAmount       = damageAmount;\n          this->damageBonus        = damageBonus;\n          this->damageCooldown     = damageCooldown;\n          this->damageFactor       = damageFactor;\n          this->upgradeType        = upgradeType;\n          this->damageType         = damageType;\n          this->explosionType      = explosionType;\n          this->minRange           = minRange;\n          this->maxRange           = maxRange;\n          this->innerSplashRadius  = innerSplashRadius;\n          this->medianSplashRadius = medianSplashRadius;\n          this->outerSplashRadius  = outerSplashRadius;\n          this->targetsAir         = targetsAir;\n          this->targetsGround      = targetsGround;\n          this->targetsMechanical  = targetsMechanical;\n          this->targetsOrganic     = targetsOrganic;\n          this->targetsNonBuilding = targetsNonBuilding;\n          this->targetsNonRobotic  = targetsNonRobotic;\n          this->targetsTerrain     = targetsTerrain;\n          this->targetsOrgOrMech   = targetsOrgOrMech;\n          this->targetsOwn         = targetsOwn;\n          this->whatUses           = whatUses;\n          this->valid              = true;\n        }\n      }\n      std::string name;\n      TechType techType;\n      UnitType whatUses;\n      int damageAmount;\n      int damageBonus;\n      int damageCooldown;\n      int damageFactor;\n      UpgradeType upgradeType;\n      DamageType damageType;\n      ExplosionType explosionType;\n      int minRange;\n      int maxRange;\n      int innerSplashRadius;\n      int medianSplashRadius;\n      int outerSplashRadius;\n      bool targetsAir;\n      bool targetsGround;\n      bool targetsMechanical;\n      bool targetsOrganic;\n      bool targetsNonBuilding;\n      bool targetsNonRobotic;\n      bool targetsTerrain;\n      bool targetsOrgOrMech;\n      bool targetsOwn;\n      bool valid;\n  };\n  WeaponTypeInternal weaponTypeData[132];\n  std::map<std::string, WeaponType> weaponTypeMap;\n  std::set< WeaponType > weaponTypeSet;\n  std::set< WeaponType > specialWeaponTypeSet;\n  std::set< WeaponType > normalWeaponTypeSet;\n  namespace WeaponTypes\n  {\n    const WeaponType Gauss_Rifle(0);\n    const WeaponType Gauss_Rifle_Jim_Raynor(1);\n    const WeaponType C_10_Canister_Rifle(2);\n    const WeaponType C_10_Canister_Rifle_Sarah_Kerrigan(3);\n    const WeaponType C_10_Canister_Rifle_Samir_Duran(112);\n    const WeaponType C_10_Canister_Rifle_Infested_Duran(113);\n    const WeaponType C_10_Canister_Rifle_Alexei_Stukov(116);\n    const WeaponType Fragmentation_Grenade(4);\n    const WeaponType Fragmentation_Grenade_Jim_Raynor(5);\n    const WeaponType Spider_Mines(6);\n    const WeaponType Twin_Autocannons(7);\n    const WeaponType Twin_Autocannons_Alan_Schezar(9);\n    const WeaponType Hellfire_Missile_Pack(8);\n    const WeaponType Hellfire_Missile_Pack_Alan_Schezar(10);\n    const WeaponType Arclite_Cannon(11);\n    const WeaponType Arclite_Cannon_Edmund_Duke(12);\n    const WeaponType Fusion_Cutter(13);\n    const WeaponType Gemini_Missiles(15);\n    const WeaponType Gemini_Missiles_Tom_Kazansky(17);\n    const WeaponType Burst_Lasers(16);\n    const WeaponType Burst_Lasers_Tom_Kazansky(18);\n    const WeaponType ATS_Laser_Battery(19);\n    const WeaponType ATS_Laser_Battery_Hero(21);\n    const WeaponType ATS_Laser_Battery_Hyperion(23);\n    const WeaponType ATA_Laser_Battery(20);\n    const WeaponType ATA_Laser_Battery_Hero(22);\n    const WeaponType ATA_Laser_Battery_Hyperion(24);\n    const WeaponType Flame_Thrower(25);\n    const WeaponType Flame_Thrower_Gui_Montag(26);\n    const WeaponType Arclite_Shock_Cannon(27);\n    const WeaponType Arclite_Shock_Cannon_Edmund_Duke(28);\n    const WeaponType Longbolt_Missile(29);\n    const WeaponType Claws(35);\n    const WeaponType Claws_Devouring_One(36);\n    const WeaponType Claws_Infested_Kerrigan(37);\n    const WeaponType Needle_Spines(38);\n    const WeaponType Needle_Spines_Hunter_Killer(39);\n    const WeaponType Kaiser_Blades(40);\n    const WeaponType Kaiser_Blades_Torrasque(41);\n    const WeaponType Toxic_Spores(42);\n    const WeaponType Spines(43);\n    const WeaponType Acid_Spore(46);\n    const WeaponType Acid_Spore_Kukulza(47);\n    const WeaponType Glave_Wurm(48);\n    const WeaponType Glave_Wurm_Kukulza(49);\n    const WeaponType Seeker_Spores(52);\n    const WeaponType Subterranean_Tentacle(53);\n    const WeaponType Suicide_Infested_Terran(54);\n    const WeaponType Suicide_Scourge(55);\n    const WeaponType Particle_Beam(62);\n    const WeaponType Psi_Blades(64);\n    const WeaponType Psi_Blades_Fenix(65);\n    const WeaponType Phase_Disruptor(66);\n    const WeaponType Phase_Disruptor_Fenix(67);\n    const WeaponType Psi_Assault(69);\n    const WeaponType Psionic_Shockwave(70);\n    const WeaponType Psionic_Shockwave_TZ_Archon(71);\n    const WeaponType Dual_Photon_Blasters(73);\n    const WeaponType Dual_Photon_Blasters_Mojo(75);\n    const WeaponType Dual_Photon_Blasters_Artanis(114);\n    const WeaponType Anti_Matter_Missiles(74);\n    const WeaponType Anti_Matter_Missiles_Mojo(76);\n    const WeaponType Anti_Matter_Missiles_Artanis(115);\n    const WeaponType Phase_Disruptor_Cannon(77);\n    const WeaponType Phase_Disruptor_Cannon_Danimoth(78);\n    const WeaponType Pulse_Cannon(79);\n    const WeaponType STS_Photon_Cannon(80);\n    const WeaponType STA_Photon_Cannon(81);\n    const WeaponType Scarab(82);\n    const WeaponType Subterranean_Spines(109);\n    const WeaponType Warp_Blades(111);\n    const WeaponType Warp_Blades_Hero(86);\n    const WeaponType Warp_Blades_Zeratul(85);\n    const WeaponType Neutron_Flare(100);\n    const WeaponType Halo_Rockets(103);\n\n    const WeaponType Yamato_Gun(30);\n    const WeaponType Nuclear_Strike(31);\n    const WeaponType Lockdown(32);\n    const WeaponType EMP_Shockwave(33);\n    const WeaponType Irradiate(34);\n    const WeaponType Parasite(56);\n    const WeaponType Spawn_Broodlings(57);\n    const WeaponType Ensnare(58);\n    const WeaponType Dark_Swarm(59);\n    const WeaponType Plague(60);\n    const WeaponType Consume(61);\n    const WeaponType Stasis_Field(83);\n    const WeaponType Psionic_Storm(84);\n    const WeaponType Disruption_Web(101);\n    const WeaponType Restoration(102);\n    const WeaponType Corrosive_Acid(104);\n    const WeaponType Mind_Control(105);\n    const WeaponType Feedback(106);\n    const WeaponType Optical_Flare(107);\n    const WeaponType Maelstrom(108);\n    const WeaponType None(130);\n    const WeaponType Unknown(131);\n\n    void init()\n    {\n      weaponTypeData[Gauss_Rifle.getID()].set(\"Gauss Rifle\", TechTypes::None, 6, 1, 15, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Marine);\n      weaponTypeData[Gauss_Rifle_Jim_Raynor.getID()].set(\"Gauss Rifle (Jim Raynor)\", TechTypes::None, 18, 1, 15, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Jim_Raynor_Marine);\n      weaponTypeData[C_10_Canister_Rifle.getID()].set(\"C-10 Canister Rifle\", TechTypes::None, 10, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Ghost);\n      weaponTypeData[C_10_Canister_Rifle_Sarah_Kerrigan.getID()].set(\"C-10 Canister Rifle (Sarah Kerrigan)\", TechTypes::None, 30, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Sarah_Kerrigan);\n      weaponTypeData[C_10_Canister_Rifle_Samir_Duran.getID()].set(\"C-10 Canister Rifle (Samir Duran)\", TechTypes::None, 25, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Samir_Duran);\n      weaponTypeData[C_10_Canister_Rifle_Infested_Duran.getID()].set(\"C-10 Canister Rifle (Infested Duran)\", TechTypes::None, 25, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Infested_Duran);\n      weaponTypeData[C_10_Canister_Rifle_Alexei_Stukov.getID()].set(\"C-10 Canister Rifle (Alexei Stukov)\", TechTypes::None, 30, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alexei_Stukov);\n      weaponTypeData[Fragmentation_Grenade.getID()].set(\"Fragmentation Grenade\", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Vulture);\n      weaponTypeData[Fragmentation_Grenade_Jim_Raynor.getID()].set(\"Fragmentation Grenade (Jim Raynor)\", TechTypes::None, 30, 2, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Jim_Raynor_Vulture);\n      weaponTypeData[Spider_Mines.getID()].set(\"Spider Mines\", TechTypes::Spider_Mines, 125, 0, 22, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 0, 10, 50, 75, 100, 0, 1, 0, 0, 1, 0, 0, 0, 0, UnitTypes::Terran_Vulture_Spider_Mine);\n      weaponTypeData[Twin_Autocannons.getID()].set(\"Twin Autocannons\", TechTypes::None, 12, 1, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Goliath);\n      weaponTypeData[Twin_Autocannons_Alan_Schezar.getID()].set(\"Twin Autocannons (Alan Schezar)\", TechTypes::None, 24, 1, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alan_Schezar);\n      weaponTypeData[Hellfire_Missile_Pack.getID()].set(\"Hellfire Missile Pack\", TechTypes::None, 10, 2, 22, 2, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Goliath);\n      weaponTypeData[Hellfire_Missile_Pack_Alan_Schezar.getID()].set(\"Hellfire Missile Pack (Alan Schezar)\", TechTypes::None, 20, 1, 22, 2, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alan_Schezar);\n      weaponTypeData[Arclite_Cannon.getID()].set(\"Arclite Cannon\", TechTypes::None, 30, 3, 37, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Siege_Tank_Tank_Mode);\n      weaponTypeData[Arclite_Cannon_Edmund_Duke.getID()].set(\"Arclite Cannon (Edmund Duke)\", TechTypes::None, 70, 3, 37, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Edmund_Duke_Tank_Mode);\n      weaponTypeData[Fusion_Cutter.getID()].set(\"Fusion Cutter\", TechTypes::None, 5, 1, 15, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_SCV);\n      weaponTypeData[Gemini_Missiles.getID()].set(\"Gemini Missiles\", TechTypes::None, 20, 2, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Wraith);\n      weaponTypeData[Gemini_Missiles_Tom_Kazansky.getID()].set(\"Gemini Missiles (Tom Kazansky)\", TechTypes::None, 40, 2, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tom_Kazansky);\n      weaponTypeData[Burst_Lasers.getID()].set(\"Burst Lasers\", TechTypes::None, 8, 1, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Wraith);\n      weaponTypeData[Burst_Lasers_Tom_Kazansky.getID()].set(\"Burst Lasers (Tom Kazansky)\", TechTypes::None, 16, 1, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tom_Kazansky);\n      weaponTypeData[ATS_Laser_Battery.getID()].set(\"ATS Laser Battery\", TechTypes::None, 25, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser);\n      weaponTypeData[ATS_Laser_Battery_Hero.getID()].set(\"ATS Laser Battery (Hero)\", TechTypes::None, 50, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Norad_II);\n      weaponTypeData[ATS_Laser_Battery_Hyperion.getID()].set(\"ATS Laser Battery (Hyperion)\", TechTypes::None, 30, 3, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hyperion);\n      weaponTypeData[ATA_Laser_Battery.getID()].set(\"ATA Laser Battery\", TechTypes::None, 25, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser);\n      weaponTypeData[ATA_Laser_Battery_Hero.getID()].set(\"ATA Laser Battery (Hero)\", TechTypes::None, 50, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Norad_II);\n      weaponTypeData[ATA_Laser_Battery_Hyperion.getID()].set(\"ATA Laser Battery (Hyperion)\", TechTypes::None, 30, 3, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hyperion);\n      weaponTypeData[Flame_Thrower.getID()].set(\"Flame Thrower\", TechTypes::None, 8, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Enemy_Splash, 0, 32, 15, 20, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Firebat);\n      weaponTypeData[Flame_Thrower_Gui_Montag.getID()].set(\"Flame Thrower (Gui Montag)\", TechTypes::None, 16, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Enemy_Splash, 0, 32, 15, 20, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Firebat);\n      weaponTypeData[Arclite_Shock_Cannon.getID()].set(\"Arclite Shock Cannon\", TechTypes::None, 70, 5, 75, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 64, 384, 10, 25, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Siege_Tank_Siege_Mode);\n      weaponTypeData[Arclite_Shock_Cannon_Edmund_Duke.getID()].set(\"Arclite Shock Cannon (Edmund Duke)\", TechTypes::None, 150, 5, 75, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 64, 384, 10, 25, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Edmund_Duke_Siege_Mode);\n      weaponTypeData[Longbolt_Missile.getID()].set(\"Longbolt Missile\", TechTypes::None, 20, 0, 15, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Missile_Turret);\n      weaponTypeData[Yamato_Gun.getID()].set(\"Yamato Gun\", TechTypes::Yamato_Gun, 260, 0, 15, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Yamato_Gun, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser);\n      weaponTypeData[Nuclear_Strike.getID()].set(\"Nuclear Strike\", TechTypes::Nuclear_Strike, 600, 0, 1, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Nuclear_Missile, 0, 3, 128, 192, 256, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Ghost);\n      weaponTypeData[Lockdown.getID()].set(\"Lockdown\", TechTypes::Lockdown, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Concussive, ExplosionTypes::Lockdown, 0, 256, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, UnitTypes::Terran_Ghost);\n      weaponTypeData[EMP_Shockwave.getID()].set(\"EMP Shockwave\", TechTypes::EMP_Shockwave, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Concussive, ExplosionTypes::EMP_Shockwave, 0, 256, 64, 64, 64, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Science_Vessel);\n      weaponTypeData[Irradiate.getID()].set(\"Irradiate\", TechTypes::Irradiate, 250, 0, 75, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Irradiate, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Science_Vessel);\n      weaponTypeData[Claws.getID()].set(\"Claws\", TechTypes::None, 5, 1, 8, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Zergling);\n      weaponTypeData[Claws_Devouring_One.getID()].set(\"Claws (Devouring One)\", TechTypes::None, 10, 1, 8, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Devouring_One);\n      weaponTypeData[Claws_Infested_Kerrigan.getID()].set(\"Claws (Infested Kerrigan)\", TechTypes::None, 50, 1, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Infested_Kerrigan);\n      weaponTypeData[Needle_Spines.getID()].set(\"Needle Spines\", TechTypes::None, 10, 1, 15, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Hydralisk);\n      weaponTypeData[Needle_Spines_Hunter_Killer.getID()].set(\"Needle Spines (Hunter Killer)\", TechTypes::None, 20, 1, 15, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hunter_Killer);\n      weaponTypeData[Kaiser_Blades.getID()].set(\"Kaiser Blades\", TechTypes::None, 20, 3, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 25, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Ultralisk);\n      weaponTypeData[Kaiser_Blades_Torrasque.getID()].set(\"Kaiser Blades (Torrasque)\", TechTypes::None, 50, 3, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 25, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Torrasque);\n      weaponTypeData[Toxic_Spores.getID()].set(\"Toxic Spores\", TechTypes::None, 4, 1, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Broodling);\n      weaponTypeData[Spines.getID()].set(\"Spines\", TechTypes::None, 5, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Drone);\n      weaponTypeData[Acid_Spore.getID()].set(\"Acid Spore\", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 256, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Guardian);\n      weaponTypeData[Acid_Spore_Kukulza.getID()].set(\"Acid Spore (Kukulza)\", TechTypes::None, 40, 2, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 256, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Kukulza_Guardian);\n      weaponTypeData[Glave_Wurm.getID()].set(\"Glave Wurm\", TechTypes::None, 9, 1, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Mutalisk);\n      weaponTypeData[Glave_Wurm_Kukulza.getID()].set(\"Glave Wurm (Kukulza)\", TechTypes::None, 18, 1, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Kukulza_Mutalisk);\n      weaponTypeData[Seeker_Spores.getID()].set(\"Seeker Spores\", TechTypes::None, 15, 0, 15, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Spore_Colony);\n      weaponTypeData[Subterranean_Tentacle.getID()].set(\"Subterranean Tentacle\", TechTypes::None, 40, 0, 32, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Sunken_Colony);\n      weaponTypeData[Suicide_Infested_Terran.getID()].set(\"Suicide Infested Terran\", TechTypes::None, 500, 0, 1, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 0, 3, 20, 40, 60, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Infested_Terran);\n      weaponTypeData[Suicide_Scourge.getID()].set(\"Suicide Scourge\", TechTypes::None, 110, 0, 1, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Scourge);\n      weaponTypeData[Parasite.getID()].set(\"Parasite\", TechTypes::Parasite, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Parasite, 0, 384, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, UnitTypes::Zerg_Queen);\n      weaponTypeData[Spawn_Broodlings.getID()].set(\"Spawn Broodlings\", TechTypes::Spawn_Broodlings, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Broodlings, 0, 288, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, UnitTypes::Zerg_Queen);\n      weaponTypeData[Ensnare.getID()].set(\"Ensnare\", TechTypes::Ensnare, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Ensnare, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Zerg_Queen);\n      weaponTypeData[Dark_Swarm.getID()].set(\"Dark Swarm\", TechTypes::Dark_Swarm, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Dark_Swarm, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Defiler);\n      weaponTypeData[Plague.getID()].set(\"Plague\", TechTypes::Plague, 300, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Plague, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Zerg_Defiler);\n      weaponTypeData[Consume.getID()].set(\"Consume\", TechTypes::Consume, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Consume, 0, 16, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, UnitTypes::Zerg_Defiler);\n      weaponTypeData[Particle_Beam.getID()].set(\"Particle Beam\", TechTypes::None, 5, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Probe);\n      weaponTypeData[Psi_Blades.getID()].set(\"Psi Blades\", TechTypes::None, 8, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Zealot);\n      weaponTypeData[Psi_Blades_Fenix.getID()].set(\"Psi Blades (Fenix)\", TechTypes::None, 20, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Fenix_Zealot);\n      weaponTypeData[Phase_Disruptor.getID()].set(\"Phase Disruptor\", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Dragoon);\n      weaponTypeData[Phase_Disruptor_Fenix.getID()].set(\"Phase Disruptor (Fenix)\", TechTypes::None, 45, 2, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Fenix_Dragoon);\n      weaponTypeData[Psi_Assault.getID()].set(\"Psi Assault\", TechTypes::None, 20, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tassadar);\n      weaponTypeData[Psionic_Shockwave.getID()].set(\"Psionic Shockwave\", TechTypes::None, 30, 3, 20, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 64, 3, 15, 30, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Archon);\n      weaponTypeData[Psionic_Shockwave_TZ_Archon.getID()].set(\"Psionic Shockwave (Tassadar/Zeratul Archon)\", TechTypes::None, 60, 3, 20, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 64, 3, 15, 30, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tassadar_Zeratul_Archon);\n      weaponTypeData[Dual_Photon_Blasters.getID()].set(\"Dual Photon Blasters\", TechTypes::None, 8, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scout);\n      weaponTypeData[Dual_Photon_Blasters_Mojo.getID()].set(\"Dual Photon Blasters (Mojo)\", TechTypes::None, 20, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Mojo);\n      weaponTypeData[Dual_Photon_Blasters_Artanis.getID()].set(\"Dual Photon Blasters (Artanis)\", TechTypes::None, 20, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Artanis);\n      weaponTypeData[Anti_Matter_Missiles.getID()].set(\"Anti-Matter Missiles\", TechTypes::None, 14, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scout);\n      weaponTypeData[Anti_Matter_Missiles_Mojo.getID()].set(\"Anti-Matter Missiles (Mojo)\", TechTypes::None, 28, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Mojo);\n      weaponTypeData[Anti_Matter_Missiles_Artanis.getID()].set(\"Anti-Matter Missiles (Artanis)\", TechTypes::None, 28, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Artanis);\n      weaponTypeData[Phase_Disruptor_Cannon.getID()].set(\"Phase Disruptor Cannon\", TechTypes::None, 10, 1, 45, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Arbiter);\n      weaponTypeData[Phase_Disruptor_Cannon_Danimoth.getID()].set(\"Phase Disruptor Cannon (Danimoth)\", TechTypes::None, 20, 1, 45, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Danimoth);\n      weaponTypeData[Pulse_Cannon.getID()].set(\"Pulse Cannon\", TechTypes::None, 6, 1, 1, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Interceptor);\n      weaponTypeData[STS_Photon_Cannon.getID()].set(\"STS Photon Cannon\", TechTypes::None, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Photon_Cannon);\n      weaponTypeData[STA_Photon_Cannon.getID()].set(\"STA Photon Cannon\", TechTypes::None, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Photon_Cannon);\n      weaponTypeData[Scarab.getID()].set(\"Scarab\", TechTypes::None, 100, 25, 1, 1, UpgradeTypes::Scarab_Damage, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 128, 20, 40, 60, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scarab);\n      weaponTypeData[Stasis_Field.getID()].set(\"Stasis Field\", TechTypes::Stasis_Field, 0, 1, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Stasis_Field, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Arbiter);\n      weaponTypeData[Psionic_Storm.getID()].set(\"Psionic Storm\", TechTypes::Psionic_Storm, 14, 1, 45, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Radial_Splash, 0, 288, 48, 48, 48, 1, 1, 0, 0, 1, 0, 1, 0, 0, UnitTypes::Protoss_High_Templar);\n      weaponTypeData[Neutron_Flare.getID()].set(\"Neutron Flare\", TechTypes::None, 5, 1, 8, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Air_Splash, 0, 160, 5, 50, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Corsair);\n      weaponTypeData[Disruption_Web.getID()].set(\"Disruption Web\", TechTypes::Disruption_Web, 0, 0, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Disruption_Web, 0, 288, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Corsair);\n      weaponTypeData[Restoration.getID()].set(\"Restoration\", TechTypes::Restoration, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Restoration, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Medic);\n      weaponTypeData[Halo_Rockets.getID()].set(\"Halo Rockets\", TechTypes::None, 6, 1, 64, 2, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Air_Splash, 0, 192, 5, 50, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Valkyrie);\n      weaponTypeData[Corrosive_Acid.getID()].set(\"Corrosive Acid\", TechTypes::None, 25, 2, 100, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Explosive, ExplosionTypes::Corrosive_Acid, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Devourer);\n      weaponTypeData[Mind_Control.getID()].set(\"Mind Control\", TechTypes::Mind_Control, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Mind_Control, 0, 256, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon);\n      weaponTypeData[Feedback.getID()].set(\"Feedback\", TechTypes::Feedback, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Feedback, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon);\n      weaponTypeData[Optical_Flare.getID()].set(\"Optical Flare\", TechTypes::Optical_Flare, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Optical_Flare, 0, 288, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Medic);\n      weaponTypeData[Maelstrom.getID()].set(\"Maelstrom\", TechTypes::Maelstrom, 0, 1, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Maelstrom, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon);\n      weaponTypeData[Subterranean_Spines.getID()].set(\"Subterranean Spines\", TechTypes::None, 20, 2, 37, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 192, 20, 20, 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Lurker);\n      weaponTypeData[Warp_Blades.getID()].set(\"Warp Blades\", TechTypes::None, 40, 3, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Dark_Templar);\n      weaponTypeData[Warp_Blades_Hero.getID()].set(\"Warp Blades (Hero)\", TechTypes::None, 45, 1, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Dark_Templar);\n      weaponTypeData[Warp_Blades_Zeratul.getID()].set(\"Warp Blades (Zeratul)\", TechTypes::None, 100, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Zeratul);\n      weaponTypeData[None.getID()].set(\"None\", TechTypes::None, 0, 0, 0, 0, UpgradeTypes::None, DamageTypes::None, ExplosionTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::None);\n      weaponTypeData[Unknown.getID()].set(\"Unknown\", TechTypes::None, 0, 0, 0, 0, UpgradeTypes::None, DamageTypes::None, ExplosionTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::None);\n\n      weaponTypeSet.insert(Gauss_Rifle);\n      weaponTypeSet.insert(Gauss_Rifle_Jim_Raynor);\n      weaponTypeSet.insert(C_10_Canister_Rifle);\n      weaponTypeSet.insert(C_10_Canister_Rifle_Sarah_Kerrigan);\n      weaponTypeSet.insert(C_10_Canister_Rifle_Samir_Duran);\n      weaponTypeSet.insert(C_10_Canister_Rifle_Infested_Duran);\n      weaponTypeSet.insert(C_10_Canister_Rifle_Alexei_Stukov);\n      weaponTypeSet.insert(Fragmentation_Grenade);\n      weaponTypeSet.insert(Fragmentation_Grenade_Jim_Raynor);\n      weaponTypeSet.insert(Spider_Mines);\n      weaponTypeSet.insert(Twin_Autocannons);\n      weaponTypeSet.insert(Twin_Autocannons_Alan_Schezar);\n      weaponTypeSet.insert(Hellfire_Missile_Pack);\n      weaponTypeSet.insert(Hellfire_Missile_Pack_Alan_Schezar);\n      weaponTypeSet.insert(Arclite_Cannon);\n      weaponTypeSet.insert(Arclite_Cannon_Edmund_Duke);\n      weaponTypeSet.insert(Fusion_Cutter);\n      weaponTypeSet.insert(Gemini_Missiles);\n      weaponTypeSet.insert(Gemini_Missiles_Tom_Kazansky);\n      weaponTypeSet.insert(Burst_Lasers);\n      weaponTypeSet.insert(Burst_Lasers_Tom_Kazansky);\n      weaponTypeSet.insert(ATS_Laser_Battery);\n      weaponTypeSet.insert(ATS_Laser_Battery_Hero);\n      weaponTypeSet.insert(ATS_Laser_Battery_Hyperion);\n      weaponTypeSet.insert(ATA_Laser_Battery);\n      weaponTypeSet.insert(ATA_Laser_Battery_Hero);\n      weaponTypeSet.insert(ATA_Laser_Battery_Hyperion);\n      weaponTypeSet.insert(Flame_Thrower);\n      weaponTypeSet.insert(Flame_Thrower_Gui_Montag);\n      weaponTypeSet.insert(Arclite_Shock_Cannon);\n      weaponTypeSet.insert(Arclite_Shock_Cannon_Edmund_Duke);\n      weaponTypeSet.insert(Longbolt_Missile);\n      weaponTypeSet.insert(Claws);\n      weaponTypeSet.insert(Claws_Devouring_One);\n      weaponTypeSet.insert(Claws_Infested_Kerrigan);\n      weaponTypeSet.insert(Needle_Spines);\n      weaponTypeSet.insert(Needle_Spines_Hunter_Killer);\n      weaponTypeSet.insert(Kaiser_Blades);\n      weaponTypeSet.insert(Kaiser_Blades_Torrasque);\n      weaponTypeSet.insert(Toxic_Spores);\n      weaponTypeSet.insert(Spines);\n      weaponTypeSet.insert(Acid_Spore);\n      weaponTypeSet.insert(Acid_Spore_Kukulza);\n      weaponTypeSet.insert(Glave_Wurm);\n      weaponTypeSet.insert(Glave_Wurm_Kukulza);\n      weaponTypeSet.insert(Seeker_Spores);\n      weaponTypeSet.insert(Subterranean_Tentacle);\n      weaponTypeSet.insert(Suicide_Infested_Terran);\n      weaponTypeSet.insert(Suicide_Scourge);\n      weaponTypeSet.insert(Particle_Beam);\n      weaponTypeSet.insert(Psi_Blades);\n      weaponTypeSet.insert(Psi_Blades_Fenix);\n      weaponTypeSet.insert(Phase_Disruptor);\n      weaponTypeSet.insert(Phase_Disruptor_Fenix);\n      weaponTypeSet.insert(Psi_Assault);\n      weaponTypeSet.insert(Psionic_Shockwave);\n      weaponTypeSet.insert(Psionic_Shockwave_TZ_Archon);\n      weaponTypeSet.insert(Dual_Photon_Blasters);\n      weaponTypeSet.insert(Dual_Photon_Blasters_Mojo);\n      weaponTypeSet.insert(Dual_Photon_Blasters_Artanis);\n      weaponTypeSet.insert(Anti_Matter_Missiles);\n      weaponTypeSet.insert(Anti_Matter_Missiles_Mojo);\n      weaponTypeSet.insert(Anti_Matter_Missiles_Artanis);\n      weaponTypeSet.insert(Phase_Disruptor_Cannon);\n      weaponTypeSet.insert(Phase_Disruptor_Cannon_Danimoth);\n      weaponTypeSet.insert(Pulse_Cannon);\n      weaponTypeSet.insert(STS_Photon_Cannon);\n      weaponTypeSet.insert(STA_Photon_Cannon);\n      weaponTypeSet.insert(Scarab);\n      weaponTypeSet.insert(Neutron_Flare);\n      weaponTypeSet.insert(Halo_Rockets);\n      weaponTypeSet.insert(Corrosive_Acid);\n      weaponTypeSet.insert(Subterranean_Spines);\n      weaponTypeSet.insert(Warp_Blades);\n      weaponTypeSet.insert(Warp_Blades_Hero);\n      weaponTypeSet.insert(Warp_Blades_Zeratul);\n\n      normalWeaponTypeSet.insert(Gauss_Rifle);\n      normalWeaponTypeSet.insert(Gauss_Rifle_Jim_Raynor);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle_Sarah_Kerrigan);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle_Samir_Duran);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle_Infested_Duran);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle_Alexei_Stukov);\n      normalWeaponTypeSet.insert(Fragmentation_Grenade);\n      normalWeaponTypeSet.insert(Fragmentation_Grenade_Jim_Raynor);\n      normalWeaponTypeSet.insert(Spider_Mines);\n      normalWeaponTypeSet.insert(Twin_Autocannons);\n      normalWeaponTypeSet.insert(Twin_Autocannons_Alan_Schezar);\n      normalWeaponTypeSet.insert(Hellfire_Missile_Pack);\n      normalWeaponTypeSet.insert(Hellfire_Missile_Pack_Alan_Schezar);\n      normalWeaponTypeSet.insert(Arclite_Cannon);\n      normalWeaponTypeSet.insert(Arclite_Cannon_Edmund_Duke);\n      normalWeaponTypeSet.insert(Fusion_Cutter);\n      normalWeaponTypeSet.insert(Gemini_Missiles);\n      normalWeaponTypeSet.insert(Gemini_Missiles_Tom_Kazansky);\n      normalWeaponTypeSet.insert(Burst_Lasers);\n      normalWeaponTypeSet.insert(Burst_Lasers_Tom_Kazansky);\n      normalWeaponTypeSet.insert(ATS_Laser_Battery);\n      normalWeaponTypeSet.insert(ATS_Laser_Battery_Hero);\n      normalWeaponTypeSet.insert(ATS_Laser_Battery_Hyperion);\n      normalWeaponTypeSet.insert(ATA_Laser_Battery);\n      normalWeaponTypeSet.insert(ATA_Laser_Battery_Hero);\n      normalWeaponTypeSet.insert(ATA_Laser_Battery_Hyperion);\n      normalWeaponTypeSet.insert(Flame_Thrower);\n      normalWeaponTypeSet.insert(Flame_Thrower_Gui_Montag);\n      normalWeaponTypeSet.insert(Arclite_Shock_Cannon);\n      normalWeaponTypeSet.insert(Arclite_Shock_Cannon_Edmund_Duke);\n      normalWeaponTypeSet.insert(Longbolt_Missile);\n      normalWeaponTypeSet.insert(Claws);\n      normalWeaponTypeSet.insert(Claws_Devouring_One);\n      normalWeaponTypeSet.insert(Claws_Infested_Kerrigan);\n      normalWeaponTypeSet.insert(Needle_Spines);\n      normalWeaponTypeSet.insert(Needle_Spines_Hunter_Killer);\n      normalWeaponTypeSet.insert(Kaiser_Blades);\n      normalWeaponTypeSet.insert(Kaiser_Blades_Torrasque);\n      normalWeaponTypeSet.insert(Toxic_Spores);\n      normalWeaponTypeSet.insert(Spines);\n      normalWeaponTypeSet.insert(Acid_Spore);\n      normalWeaponTypeSet.insert(Acid_Spore_Kukulza);\n      normalWeaponTypeSet.insert(Glave_Wurm);\n      normalWeaponTypeSet.insert(Glave_Wurm_Kukulza);\n      normalWeaponTypeSet.insert(Seeker_Spores);\n      normalWeaponTypeSet.insert(Subterranean_Tentacle);\n      normalWeaponTypeSet.insert(Suicide_Infested_Terran);\n      normalWeaponTypeSet.insert(Suicide_Scourge);\n      normalWeaponTypeSet.insert(Particle_Beam);\n      normalWeaponTypeSet.insert(Psi_Blades);\n      normalWeaponTypeSet.insert(Psi_Blades_Fenix);\n      normalWeaponTypeSet.insert(Phase_Disruptor);\n      normalWeaponTypeSet.insert(Phase_Disruptor_Fenix);\n      normalWeaponTypeSet.insert(Psi_Assault);\n      normalWeaponTypeSet.insert(Psionic_Shockwave);\n      normalWeaponTypeSet.insert(Psionic_Shockwave_TZ_Archon);\n      normalWeaponTypeSet.insert(Dual_Photon_Blasters);\n      normalWeaponTypeSet.insert(Dual_Photon_Blasters_Mojo);\n      normalWeaponTypeSet.insert(Dual_Photon_Blasters_Artanis);\n      normalWeaponTypeSet.insert(Anti_Matter_Missiles);\n      normalWeaponTypeSet.insert(Anti_Matter_Missiles_Mojo);\n      normalWeaponTypeSet.insert(Anti_Matter_Missiles_Artanis);\n      normalWeaponTypeSet.insert(Phase_Disruptor_Cannon);\n      normalWeaponTypeSet.insert(Phase_Disruptor_Cannon_Danimoth);\n      normalWeaponTypeSet.insert(Pulse_Cannon);\n      normalWeaponTypeSet.insert(STS_Photon_Cannon);\n      normalWeaponTypeSet.insert(STA_Photon_Cannon);\n      normalWeaponTypeSet.insert(Scarab);\n      normalWeaponTypeSet.insert(Neutron_Flare);\n      normalWeaponTypeSet.insert(Halo_Rockets);\n      normalWeaponTypeSet.insert(Corrosive_Acid);\n      normalWeaponTypeSet.insert(Subterranean_Spines);\n      normalWeaponTypeSet.insert(Warp_Blades);\n      normalWeaponTypeSet.insert(Warp_Blades_Hero);\n      normalWeaponTypeSet.insert(Warp_Blades_Zeratul);\n\n      weaponTypeSet.insert(Yamato_Gun);\n      weaponTypeSet.insert(Nuclear_Strike);\n      weaponTypeSet.insert(Lockdown);\n      weaponTypeSet.insert(EMP_Shockwave);\n      weaponTypeSet.insert(Irradiate);\n      weaponTypeSet.insert(Parasite);\n      weaponTypeSet.insert(Spawn_Broodlings);\n      weaponTypeSet.insert(Ensnare);\n      weaponTypeSet.insert(Dark_Swarm);\n      weaponTypeSet.insert(Plague);\n      weaponTypeSet.insert(Consume);\n      weaponTypeSet.insert(Stasis_Field);\n      weaponTypeSet.insert(Psionic_Storm);\n      weaponTypeSet.insert(Disruption_Web);\n      weaponTypeSet.insert(Restoration);\n      weaponTypeSet.insert(Mind_Control);\n      weaponTypeSet.insert(Feedback);\n      weaponTypeSet.insert(Optical_Flare);\n      weaponTypeSet.insert(Maelstrom);\n\n      specialWeaponTypeSet.insert(Yamato_Gun);\n      specialWeaponTypeSet.insert(Nuclear_Strike);\n      specialWeaponTypeSet.insert(Lockdown);\n      specialWeaponTypeSet.insert(EMP_Shockwave);\n      specialWeaponTypeSet.insert(Irradiate);\n      specialWeaponTypeSet.insert(Parasite);\n      specialWeaponTypeSet.insert(Spawn_Broodlings);\n      specialWeaponTypeSet.insert(Ensnare);\n      specialWeaponTypeSet.insert(Dark_Swarm);\n      specialWeaponTypeSet.insert(Plague);\n      specialWeaponTypeSet.insert(Consume);\n      specialWeaponTypeSet.insert(Stasis_Field);\n      specialWeaponTypeSet.insert(Psionic_Storm);\n      specialWeaponTypeSet.insert(Disruption_Web);\n      specialWeaponTypeSet.insert(Restoration);\n      specialWeaponTypeSet.insert(Mind_Control);\n      specialWeaponTypeSet.insert(Feedback);\n      specialWeaponTypeSet.insert(Optical_Flare);\n      specialWeaponTypeSet.insert(Maelstrom);\n\n      weaponTypeSet.insert(None);\n      weaponTypeSet.insert(Unknown);\n\n      foreach(WeaponType i, weaponTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        weaponTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingWeaponType = false;\n    }\n  }\n  WeaponType::WeaponType()\n  {\n    this->id = WeaponTypes::None.id;\n  }\n  WeaponType::WeaponType(int id)\n  {\n    this->id = id;\n    if (!initializingWeaponType && (id < 0 || id >= 132 || !weaponTypeData[id].valid))\n      this->id = WeaponTypes::Unknown.id;\n  }\n  WeaponType::WeaponType(const WeaponType& other)\n  {\n    this->id = other.id;\n  }\n  WeaponType& WeaponType::operator=(const WeaponType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool WeaponType::operator==(const WeaponType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool WeaponType::operator!=(const WeaponType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool WeaponType::operator<(const WeaponType& other) const\n  {\n    return this->id < other.id;\n  }\n  int WeaponType::getID() const\n  {\n    return this->id;\n  }\n  std::string WeaponType::getName() const\n  {\n    return weaponTypeData[this->id].name;\n  }\n  TechType WeaponType::getTech() const\n  {\n    return weaponTypeData[this->id].techType;\n  }\n  UnitType WeaponType::whatUses() const\n  {\n    return weaponTypeData[this->id].whatUses;\n  }\n  int WeaponType::damageAmount() const\n  {\n    return weaponTypeData[this->id].damageAmount;\n  }\n  int WeaponType::damageBonus() const\n  {\n    return weaponTypeData[this->id].damageBonus;\n  }\n  int WeaponType::damageCooldown() const\n  {\n    return weaponTypeData[this->id].damageCooldown;\n  }\n  int WeaponType::damageFactor() const\n  {\n    return weaponTypeData[this->id].damageFactor;\n  }\n  UpgradeType WeaponType::upgradeType() const\n  {\n    return weaponTypeData[this->id].upgradeType;\n  }\n  DamageType WeaponType::damageType() const\n  {\n    return weaponTypeData[this->id].damageType;\n  }\n  ExplosionType WeaponType::explosionType() const\n  {\n    return weaponTypeData[this->id].explosionType;\n  }\n  int WeaponType::minRange() const\n  {\n    return weaponTypeData[this->id].minRange;\n  }\n  int WeaponType::maxRange() const\n  {\n    return weaponTypeData[this->id].maxRange;\n  }\n  int WeaponType::innerSplashRadius() const\n  {\n    return weaponTypeData[this->id].innerSplashRadius;\n  }\n  int WeaponType::medianSplashRadius() const\n  {\n    return weaponTypeData[this->id].medianSplashRadius;\n  }\n  int WeaponType::outerSplashRadius() const\n  {\n    return weaponTypeData[this->id].outerSplashRadius;\n  }\n  bool WeaponType::targetsAir() const\n  {\n    return weaponTypeData[this->id].targetsAir;\n  }\n  bool WeaponType::targetsGround() const\n  {\n    return weaponTypeData[this->id].targetsGround;\n  }\n  bool WeaponType::targetsMechanical() const\n  {\n    return weaponTypeData[this->id].targetsMechanical;\n  }\n  bool WeaponType::targetsOrganic() const\n  {\n    return weaponTypeData[this->id].targetsOrganic;\n  }\n  bool WeaponType::targetsNonBuilding() const\n  {\n    return weaponTypeData[this->id].targetsNonBuilding;\n  }\n  bool WeaponType::targetsNonRobotic() const\n  {\n    return weaponTypeData[this->id].targetsNonRobotic;\n  }\n  bool WeaponType::targetsTerrain() const\n  {\n    return weaponTypeData[this->id].targetsTerrain;\n  }\n  bool WeaponType::targetsOrgOrMech() const\n  {\n    return weaponTypeData[this->id].targetsOrgOrMech;\n  }\n  bool WeaponType::targetsOwn() const\n  {\n    return weaponTypeData[this->id].targetsOwn;\n  }\n  WeaponType WeaponTypes::getWeaponType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, WeaponType>::iterator i = weaponTypeMap.find(name);\n    if (i == weaponTypeMap.end())\n      return WeaponTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<WeaponType>& WeaponTypes::allWeaponTypes()\n  {\n    return weaponTypeSet;\n  }\n  std::set<WeaponType>& WeaponTypes::normalWeaponTypes()\n  {\n    return weaponTypeSet;\n  }\n  std::set<WeaponType>& WeaponTypes::specialWeaponTypes()\n  {\n    return weaponTypeSet;\n  }\n}\n"
  },
  {
    "path": "BOSS/source/rapidjson/document.h",
    "content": "#include \"../Common.h\"\n#ifdef MCDS_FLASH_VERSION\n    #pragma GCC system_header\n#endif\n\n#ifndef RAPIDJSON_DOCUMENT_H_\n#define RAPIDJSON_DOCUMENT_H_\n\n#include \"reader.h\"\n#include \"internal/strfunc.h\"\n#include <new>\t\t// placement new\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4127) // conditional expression is constant\n#endif\n\nnamespace rapidjson {\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericValue\n\n//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.\n/*!\n\tA JSON value can be one of 7 types. This class is a variant type supporting\n\tthese types.\n\n\tUse the Value if UTF8 and default allocator\n\n\t\\tparam Encoding\tEncoding of the value. (Even non-string values need to have the same encoding in a document)\n\t\\tparam Allocator\tAllocator type for allocating memory of object, array and string.\n*/\n#pragma pack (push, 4)\ntemplate <typename Encoding, typename Allocator = MemoryPoolAllocator<> > \nclass GenericValue {\npublic:\n\t//! Name-value pair in an object.\n\tstruct Member { \n\t\tGenericValue<Encoding, Allocator> name;\t\t//!< name of member (must be a string)\n\t\tGenericValue<Encoding, Allocator> value;\t//!< value of member.\n\t};\n\n\ttypedef Encoding EncodingType;\t\t\t\t\t//!< Encoding type from template parameter.\n\ttypedef Allocator AllocatorType;\t\t\t\t//!< Allocator type from template parameter.\n\ttypedef typename Encoding::Ch Ch;\t\t\t\t//!< Character type derived from Encoding.\n\ttypedef Member* MemberIterator;\t\t\t\t\t//!< Member iterator for iterating in object.\n\ttypedef const Member* ConstMemberIterator;\t\t//!< Constant member iterator for iterating in object.\n\ttypedef GenericValue* ValueIterator;\t\t\t//!< Value iterator for iterating in array.\n\ttypedef const GenericValue* ConstValueIterator;\t//!< Constant value iterator for iterating in array.\n\n\t//!@name Constructors and destructor.\n\t//@{\n\n\t//! Default constructor creates a null value.\n\tGenericValue() : flags_(kNullFlag) {}\n\n\t//! Copy constructor is not permitted.\nprivate:\n\tGenericValue(const GenericValue& rhs);\n\npublic:\n\n\t//! Constructor with JSON value type.\n\t/*! This creates a Value of specified type with default content.\n\t\t\\param type\tType of the value.\n\t\t\\note Default content for number is zero.\n\t*/\n\tGenericValue(Type type) {\n\t\tstatic const unsigned defaultFlags[7] = {\n\t\t\tkNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,\n\t\t\tkNumberFlag | kIntFlag | kUintFlag | kInt64Flag | kUint64Flag | kDoubleFlag\n\t\t};\n\t\tRAPIDJSON_ASSERT(type <= kNumberType);\n\t\tflags_ = defaultFlags[type];\n\t\tmemset(&data_, 0, sizeof(data_));\n\t}\n\n\t//! Constructor for boolean value.\n\tGenericValue(bool b) : flags_(b ? kTrueFlag : kFalseFlag) {}\n\n\t//! Constructor for int value.\n\tGenericValue(int i) : flags_(kNumberIntFlag) { \n\t\tdata_.n.i64 = i;\n\t\tif (i >= 0)\n\t\t\tflags_ |= kUintFlag | kUint64Flag;\n\t}\n\n\t//! Constructor for unsigned value.\n\tGenericValue(unsigned u) : flags_(kNumberUintFlag) {\n\t\tdata_.n.u64 = u; \n\t\tif (!(u & 0x80000000))\n\t\t\tflags_ |= kIntFlag | kInt64Flag;\n\t}\n\n\t//! Constructor for int64_t value.\n\tGenericValue(int64_t i64) : flags_(kNumberInt64Flag) {\n\t\tdata_.n.i64 = i64;\n\t\tif (i64 >= 0) {\n\t\t\tflags_ |= kNumberUint64Flag;\n\t\t\tif (!(i64 & 0xFFFFFFFF00000000LL))\n\t\t\t\tflags_ |= kUintFlag;\n\t\t\tif (!(i64 & 0xFFFFFFFF80000000LL))\n\t\t\t\tflags_ |= kIntFlag;\n\t\t}\n\t\telse if (i64 >= -2147483648LL)\n\t\t\tflags_ |= kIntFlag;\n\t}\n\n\t//! Constructor for uint64_t value.\n\tGenericValue(uint64_t u64) : flags_(kNumberUint64Flag) {\n\t\tdata_.n.u64 = u64;\n\t\tif (!(u64 & 0x8000000000000000ULL))\n\t\t\tflags_ |= kInt64Flag;\n\t\tif (!(u64 & 0xFFFFFFFF00000000ULL))\n\t\t\tflags_ |= kUintFlag;\n\t\tif (!(u64 & 0xFFFFFFFF80000000ULL))\n\t\t\tflags_ |= kIntFlag;\n\t}\n\n\t//! Constructor for double value.\n\tGenericValue(double d) : flags_(kNumberDoubleFlag) { data_.n.d = d; }\n\n\t//! Constructor for constant string (i.e. do not make a copy of string)\n\tGenericValue(const Ch* s, SizeType length) { \n\t\tRAPIDJSON_ASSERT(s != NULL);\n\t\tflags_ = kConstStringFlag;\n\t\tdata_.s.str = s;\n\t\tdata_.s.length = length;\n\t}\n\n\t//! Constructor for constant string (i.e. do not make a copy of string)\n\tGenericValue(const Ch* s) { SetStringRaw(s, internal::StrLen(s)); }\n\n\t//! Constructor for copy-string (i.e. do make a copy of string)\n\tGenericValue(const Ch* s, SizeType length, Allocator& allocator) { SetStringRaw(s, length, allocator); }\n\n\t//! Constructor for copy-string (i.e. do make a copy of string)\n\tGenericValue(const Ch*s, Allocator& allocator) { SetStringRaw(s, internal::StrLen(s), allocator); }\n\n\t//! Destructor.\n\t/*! Need to destruct elements of array, members of object, or copy-string.\n\t*/\n\t~GenericValue() {\n\t\tif (Allocator::kNeedFree) {\t// Shortcut by Allocator's trait\n\t\t\tswitch(flags_) {\n\t\t\tcase kArrayFlag:\n\t\t\t\tfor (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)\n\t\t\t\t\tv->~GenericValue();\n\t\t\t\tAllocator::Free(data_.a.elements);\n\t\t\t\tbreak;\n\n\t\t\tcase kObjectFlag:\n\t\t\t\tfor (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {\n\t\t\t\t\tm->name.~GenericValue();\n\t\t\t\t\tm->value.~GenericValue();\n\t\t\t\t}\n\t\t\t\tAllocator::Free(data_.o.members);\n\t\t\t\tbreak;\n\n\t\t\tcase kCopyStringFlag:\n\t\t\t\tAllocator::Free(const_cast<Ch*>(data_.s.str));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t//@}\n\n\t//!@name Assignment operators\n\t//@{\n\n\t//! Assignment with move semantics.\n\t/*! \\param rhs Source of the assignment. It will become a null value after assignment.\n\t*/\n\tGenericValue& operator=(GenericValue& rhs) {\n\t\tRAPIDJSON_ASSERT(this != &rhs);\n\t\tthis->~GenericValue();\n\t\tmemcpy(this, &rhs, sizeof(GenericValue));\n\t\trhs.flags_ = kNullFlag;\n\t\treturn *this;\n\t}\n\n\t//! Assignment with primitive types.\n\t/*! \\tparam T Either Type, int, unsigned, int64_t, uint64_t, const Ch*\n\t\t\\param value The value to be assigned.\n\t*/\n\ttemplate <typename T>\n\tGenericValue& operator=(T value) {\n\t\tthis->~GenericValue();\n\t\tnew (this) GenericValue(value);\n\t\treturn *this;\n\t}\n\t//@}\n\n\t//!@name Type\n\t//@{\n\n\tType GetType()\tconst { return static_cast<Type>(flags_ & kTypeMask); }\n\tbool IsNull()\tconst { return flags_ == kNullFlag; }\n\tbool IsFalse()\tconst { return flags_ == kFalseFlag; }\n\tbool IsTrue()\tconst { return flags_ == kTrueFlag; }\n\tbool IsBool()\tconst { return (flags_ & kBoolFlag) != 0; }\n\tbool IsObject()\tconst { return flags_ == kObjectFlag; }\n\tbool IsArray()\tconst { return flags_ == kArrayFlag; }\n\tbool IsNumber() const { return (flags_ & kNumberFlag) != 0; }\n\tbool IsInt()\tconst { return (flags_ & kIntFlag) != 0; }\n\tbool IsUint()\tconst { return (flags_ & kUintFlag) != 0; }\n\tbool IsInt64()\tconst { return (flags_ & kInt64Flag) != 0; }\n\tbool IsUint64()\tconst { return (flags_ & kUint64Flag) != 0; }\n\tbool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }\n\tbool IsString() const { return (flags_ & kStringFlag) != 0; }\n\n\t//@}\n\n\t//!@name Null\n\t//@{\n\n\tGenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }\n\n\t//@}\n\n\t//!@name Bool\n\t//@{\n\n\tbool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }\n\tGenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }\n\n\t//@}\n\n\t//!@name Object\n\t//@{\n\n\t//! Set this value as an empty object.\n\tGenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }\n\n\t//! Get the value associated with the object's name.\n\tGenericValue& operator[](const Ch* name) {\n\t\tif (Member* member = FindMember(name))\n\t\t\treturn member->value;\n\t\telse {\n\t\t\tstatic GenericValue NullValue;\n\t\t\treturn NullValue;\n\t\t}\n\t}\n\tconst GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; }\n\n\t//! Member iterators.\n\tConstMemberIterator MemberBegin() const\t{ RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }\n\tConstMemberIterator MemberEnd()\tconst\t{ RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }\n\tMemberIterator MemberBegin()\t\t\t{ RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }\n\tMemberIterator MemberEnd()\t\t\t\t{ RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }\n\n\t//! Check whether a member exists in the object.\n\tbool HasMember(const Ch* name) const { return FindMember(name) != 0; }\n\n\t//! Add a member (name-value pair) to the object.\n\t/*! \\param name A string value as name of member.\n\t\t\\param value Value of any type.\n\t    \\param allocator Allocator for reallocating memory.\n\t    \\return The value itself for fluent API.\n\t    \\note The ownership of name and value will be transfered to this object if success.\n\t*/\n\tGenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {\n\t\tRAPIDJSON_ASSERT(IsObject());\n\t\tRAPIDJSON_ASSERT(name.IsString());\n\t\tObject& o = data_.o;\n\t\tif (o.size >= o.capacity) {\n\t\t\tif (o.capacity == 0) {\n\t\t\t\to.capacity = kDefaultObjectCapacity;\n\t\t\t\to.members = (Member*)allocator.Malloc(o.capacity * sizeof(Member));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSizeType oldCapacity = o.capacity;\n\t\t\t\to.capacity *= 2;\n\t\t\t\to.members = (Member*)allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member));\n\t\t\t}\n\t\t}\n\t\to.members[o.size].name.RawAssign(name);\n\t\to.members[o.size].value.RawAssign(value);\n\t\to.size++;\n\t\treturn *this;\n\t}\n\n\tGenericValue& AddMember(const Ch* name, Allocator& nameAllocator, GenericValue& value, Allocator& allocator) {\n\t\tGenericValue n(name, internal::StrLen(name), nameAllocator);\n\t\treturn AddMember(n, value, allocator);\n\t}\n\n\tGenericValue& AddMember(const Ch* name, GenericValue& value, Allocator& allocator) {\n\t\tGenericValue n(name, internal::StrLen(name));\n\t\treturn AddMember(n, value, allocator);\n\t}\n\n\ttemplate <typename T>\n\tGenericValue& AddMember(const Ch* name, T value, Allocator& allocator) {\n\t\tGenericValue n(name, internal::StrLen(name));\n\t\tGenericValue v(value);\n\t\treturn AddMember(n, v, allocator);\n\t}\n\n\t//! Remove a member in object by its name.\n\t/*! \\param name Name of member to be removed.\n\t    \\return Whether the member existed.\n\t    \\note Removing member is implemented by moving the last member. So the ordering of members is changed.\n\t*/\n\tbool RemoveMember(const Ch* name) {\n\t\tRAPIDJSON_ASSERT(IsObject());\n\t\tif (Member* m = FindMember(name)) {\n\t\t\tRAPIDJSON_ASSERT(data_.o.size > 0);\n\t\t\tRAPIDJSON_ASSERT(data_.o.members != 0);\n\n\t\t\tMember* last = data_.o.members + (data_.o.size - 1);\n\t\t\tif (data_.o.size > 1 && m != last) {\n\t\t\t\t// Move the last one to this place\n\t\t\t\tm->name = last->name;\n\t\t\t\tm->value = last->value;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Only one left, just destroy\n\t\t\t\tm->name.~GenericValue();\n\t\t\t\tm->value.~GenericValue();\n\t\t\t}\n\t\t\t--data_.o.size;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t//@}\n\n\t//!@name Array\n\t//@{\n\n\t//! Set this value as an empty array.\n\tGenericValue& SetArray() {\tthis->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }\n\n\t//! Get the number of elements in array.\n\tSizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }\n\n\t//! Get the capacity of array.\n\tSizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }\n\n\t//! Check whether the array is empty.\n\tbool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }\n\n\t//! Remove all elements in the array.\n\t/*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.\n\t*/\n\tvoid Clear() {\n\t\tRAPIDJSON_ASSERT(IsArray()); \n\t\tfor (SizeType i = 0; i < data_.a.size; ++i)\n\t\t\tdata_.a.elements[i].~GenericValue();\n\t\tdata_.a.size = 0;\n\t}\n\n\t//! Get an element from array by index.\n\t/*! \\param index Zero-based index of element.\n\t\t\\note\n\\code\nValue a(kArrayType);\na.PushBack(123);\nint x = a[0].GetInt();\t\t\t\t// Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.\nint y = a[SizeType(0)].GetInt();\t// Cast to SizeType will work.\nint z = a[0u].GetInt();\t\t\t\t// This works too.\n\\endcode\n\t*/\n\tGenericValue& operator[](SizeType index) {\n\t\tRAPIDJSON_ASSERT(IsArray());\n\t\tRAPIDJSON_ASSERT(index < data_.a.size);\n\t\treturn data_.a.elements[index];\n\t}\n\tconst GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }\n\n\t//! Element iterator\n\tValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }\n\tValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }\n\tConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }\n\tConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }\n\n\t//! Request the array to have enough capacity to store elements.\n\t/*! \\param newCapacity\tThe capacity that the array at least need to have.\n\t\t\\param allocator\tThe allocator for allocating memory. It must be the same one use previously.\n\t\t\\return The value itself for fluent API.\n\t*/\n\tGenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {\n\t\tRAPIDJSON_ASSERT(IsArray());\n\t\tif (newCapacity > data_.a.capacity) {\n\t\t\tdata_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));\n\t\t\tdata_.a.capacity = newCapacity;\n\t\t}\n\t\treturn *this;\n\t}\n\n\t//! Append a value at the end of the array.\n\t/*! \\param value\t\tThe value to be appended.\n\t    \\param allocator\tThe allocator for allocating memory. It must be the same one use previously.\n\t    \\return The value itself for fluent API.\n\t    \\note The ownership of the value will be transfered to this object if success.\n\t    \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n\t*/\n\tGenericValue& PushBack(GenericValue& value, Allocator& allocator) {\n\t\tRAPIDJSON_ASSERT(IsArray());\n\t\tif (data_.a.size >= data_.a.capacity)\n\t\t\tReserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator);\n\t\tdata_.a.elements[data_.a.size++].RawAssign(value);\n\t\treturn *this;\n\t}\n\n\ttemplate <typename T>\n\tGenericValue& PushBack(T value, Allocator& allocator) {\n\t\tGenericValue v(value);\n\t\treturn PushBack(v, allocator);\n\t}\n\n\t//! Remove the last element in the array.\n\tGenericValue& PopBack() {\n\t\tRAPIDJSON_ASSERT(IsArray());\n\t\tRAPIDJSON_ASSERT(!Empty());\n\t\tdata_.a.elements[--data_.a.size].~GenericValue();\n\t\treturn *this;\n\t}\n\t//@}\n\n\t//!@name Number\n\t//@{\n\n\tint GetInt() const\t\t\t{ RAPIDJSON_ASSERT(flags_ & kIntFlag);   return data_.n.i.i;   }\n\tunsigned GetUint() const\t{ RAPIDJSON_ASSERT(flags_ & kUintFlag);  return data_.n.u.u;   }\n\tint64_t GetInt64() const\t{ RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }\n\tuint64_t GetUint64() const\t{ RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }\n\n\tdouble GetDouble() const {\n\t\tRAPIDJSON_ASSERT(IsNumber());\n\t\tif ((flags_ & kDoubleFlag) != 0)\t\t\t\treturn data_.n.d;\t// exact type, no conversion.\n\t\tif ((flags_ & kIntFlag) != 0)\t\t\t\t\treturn data_.n.i.i;\t// int -> double\n\t\tif ((flags_ & kUintFlag) != 0)\t\t\t\t\treturn data_.n.u.u;\t// unsigned -> double\n\t\tif ((flags_ & kInt64Flag) != 0)\t\t\t\t\treturn (double)data_.n.i64; // int64_t -> double (may lose precision)\n\t\tRAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0);\treturn (double)data_.n.u64;\t// uint64_t -> double (may lose precision)\n\t}\n\n\tGenericValue& SetInt(int i)\t\t\t\t{ this->~GenericValue(); new (this) GenericValue(i);\treturn *this; }\n\tGenericValue& SetUint(unsigned u)\t\t{ this->~GenericValue(); new (this) GenericValue(u);\treturn *this; }\n\tGenericValue& SetInt64(int64_t i64)\t\t{ this->~GenericValue(); new (this) GenericValue(i64);\treturn *this; }\n\tGenericValue& SetUint64(uint64_t u64)\t{ this->~GenericValue(); new (this) GenericValue(u64);\treturn *this; }\n\tGenericValue& SetDouble(double d)\t\t{ this->~GenericValue(); new (this) GenericValue(d);\treturn *this; }\n\n\t//@}\n\n\t//!@name String\n\t//@{\n\n\tconst Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }\n\n\t//! Get the length of string.\n\t/*! Since rapidjson permits \"\\u0000\" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().\n\t*/\n\tSizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; }\n\n\t//! Set this value as a string without copying source string.\n\t/*! This version has better performance with supplied length, and also support string containing null character.\n\t\t\\param s source string pointer. \n\t\t\\param length The length of source string, excluding the trailing null terminator.\n\t\t\\return The value itself for fluent API.\n\t*/\n\tGenericValue& SetString(const Ch* s, SizeType length) { this->~GenericValue(); SetStringRaw(s, length); return *this; }\n\n\t//! Set this value as a string without copying source string.\n\t/*! \\param s source string pointer. \n\t\t\\return The value itself for fluent API.\n\t*/\n\tGenericValue& SetString(const Ch* s) { return SetString(s, internal::StrLen(s)); }\n\n\t//! Set this value as a string by copying from source string.\n\t/*! This version has better performance with supplied length, and also support string containing null character.\n\t\t\\param s source string. \n\t\t\\param length The length of source string, excluding the trailing null terminator.\n\t\t\\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().\n\t\t\\return The value itself for fluent API.\n\t*/\n\tGenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, length, allocator); return *this; }\n\n\t//! Set this value as a string by copying from source string.\n\t/*!\t\\param s source string. \n\t\t\\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().\n\t\t\\return The value itself for fluent API.\n\t*/\n\tGenericValue& SetString(const Ch* s, Allocator& allocator) {\tSetString(s, internal::StrLen(s), allocator); return *this; }\n\n\t//@}\n\n\t//! Generate events of this value to a Handler.\n\t/*! This function adopts the GoF visitor pattern.\n\t\tTypical usage is to output this JSON value as JSON text via Writer, which is a Handler.\n\t\tIt can also be used to deep clone this value via GenericDocument, which is also a Handler.\n\t\t\\tparam Handler type of handler.\n\t\t\\param handler An object implementing concept Handler.\n\t*/\n\ttemplate <typename Handler>\n\tconst GenericValue& Accept(Handler& handler) const {\n\t\tswitch(GetType()) {\n\t\tcase kNullType:\t\thandler.Null(); break;\n\t\tcase kFalseType:\thandler.Bool(false); break;\n\t\tcase kTrueType:\t\thandler.Bool(true); break;\n\n\t\tcase kObjectType:\n\t\t\thandler.StartObject();\n\t\t\tfor (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {\n\t\t\t\thandler.String(m->name.data_.s.str, m->name.data_.s.length, false);\n\t\t\t\tm->value.Accept(handler);\n\t\t\t}\n\t\t\thandler.EndObject(data_.o.size);\n\t\t\tbreak;\n\n\t\tcase kArrayType:\n\t\t\thandler.StartArray();\n\t\t\tfor (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)\n\t\t\t\tv->Accept(handler);\n\t\t\thandler.EndArray(data_.a.size);\n\t\t\tbreak;\n\n\t\tcase kStringType:\n\t\t\thandler.String(data_.s.str, data_.s.length, false);\n\t\t\tbreak;\n\n\t\tcase kNumberType:\n\t\t\tif (IsInt())\t\t\thandler.Int(data_.n.i.i);\n\t\t\telse if (IsUint())\t\thandler.Uint(data_.n.u.u);\n\t\t\telse if (IsInt64())\t\thandler.Int64(data_.n.i64);\n\t\t\telse if (IsUint64())\thandler.Uint64(data_.n.u64);\n\t\t\telse\t\t\t\t\thandler.Double(data_.n.d);\n\t\t\tbreak;\n\t\t}\n\t\treturn *this;\n\t}\n\nprivate:\n\ttemplate <typename, typename>\n\tfriend class GenericDocument;\n\n\tenum {\n\t\tkBoolFlag = 0x100,\n\t\tkNumberFlag = 0x200,\n\t\tkIntFlag = 0x400,\n\t\tkUintFlag = 0x800,\n\t\tkInt64Flag = 0x1000,\n\t\tkUint64Flag = 0x2000,\n\t\tkDoubleFlag = 0x4000,\n\t\tkStringFlag = 0x100000,\n\t\tkCopyFlag = 0x200000,\n\n\t\t// Initial flags of different types.\n\t\tkNullFlag = kNullType,\n\t\tkTrueFlag = kTrueType | kBoolFlag,\n\t\tkFalseFlag = kFalseType | kBoolFlag,\n\t\tkNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,\n\t\tkNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,\n\t\tkNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,\n\t\tkNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,\n\t\tkNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,\n\t\tkConstStringFlag = kStringType | kStringFlag,\n\t\tkCopyStringFlag = kStringType | kStringFlag | kCopyFlag,\n\t\tkObjectFlag = kObjectType,\n\t\tkArrayFlag = kArrayType,\n\n\t\tkTypeMask = 0xFF\t// bitwise-and with mask of 0xFF can be optimized by compiler\n\t};\n\n\tstatic const SizeType kDefaultArrayCapacity = 16;\n\tstatic const SizeType kDefaultObjectCapacity = 16;\n\n\tstruct String {\n\t\tconst Ch* str;\n\t\tSizeType length;\n\t\tunsigned hashcode;\t//!< reserved\n\t};\t// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n\t// By using proper binary layout, retrieval of different integer types do not need conversions.\n\tunion Number {\n#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN\n\t\tstruct I {\n\t\t\tint i;\n\t\t\tchar padding[4];\n\t\t}i;\n\t\tstruct U {\n\t\t\tunsigned u;\n\t\t\tchar padding2[4];\n\t\t}u;\n#else\n\t\tstruct I {\n\t\t\tchar padding[4];\n\t\t\tint i;\n\t\t}i;\n\t\tstruct U {\n\t\t\tchar padding2[4];\n\t\t\tunsigned u;\n\t\t}u;\n#endif\n\t\tint64_t i64;\n\t\tuint64_t u64;\n\t\tdouble d;\n\t};\t// 8 bytes\n\n\tstruct Object {\n\t\tMember* members;\n\t\tSizeType size;\n\t\tSizeType capacity;\n\t};\t// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n\tstruct Array {\n\t\tGenericValue<Encoding, Allocator>* elements;\n\t\tSizeType size;\n\t\tSizeType capacity;\n\t};\t// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n\tunion Data {\n\t\tString s;\n\t\tNumber n;\n\t\tObject o;\n\t\tArray a;\n\t};\t// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n\t//! Find member by name.\n\tMember* FindMember(const Ch* name) {\n\t\tRAPIDJSON_ASSERT(name);\n\t\tRAPIDJSON_ASSERT(IsObject());\n\n\t\tSizeType length = internal::StrLen(name);\n\n\t\tObject& o = data_.o;\n\t\tfor (Member* member = o.members; member != data_.o.members + data_.o.size; ++member)\n\t\t\tif (length == member->name.data_.s.length && memcmp(member->name.data_.s.str, name, length * sizeof(Ch)) == 0)\n\t\t\t\treturn member;\n\n\t\treturn 0;\n\t}\n\tconst Member* FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }\n\n\t// Initialize this value as array with initial data, without calling destructor.\n\tvoid SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) {\n\t\tflags_ = kArrayFlag;\n\t\tdata_.a.elements = (GenericValue*)alloctaor.Malloc(count * sizeof(GenericValue));\n\t\tmemcpy(data_.a.elements, values, count * sizeof(GenericValue));\n\t\tdata_.a.size = data_.a.capacity = count;\n\t}\n\n\t//! Initialize this value as object with initial data, without calling destructor.\n\tvoid SetObjectRaw(Member* members, SizeType count, Allocator& alloctaor) {\n\t\tflags_ = kObjectFlag;\n\t\tdata_.o.members = (Member*)alloctaor.Malloc(count * sizeof(Member));\n\t\tmemcpy(data_.o.members, members, count * sizeof(Member));\n\t\tdata_.o.size = data_.o.capacity = count;\n\t}\n\n\t//! Initialize this value as constant string, without calling destructor.\n\tvoid SetStringRaw(const Ch* s, SizeType length) {\n\t\tRAPIDJSON_ASSERT(s != NULL);\n\t\tflags_ = kConstStringFlag;\n\t\tdata_.s.str = s;\n\t\tdata_.s.length = length;\n\t}\n\n\t//! Initialize this value as copy string with initial data, without calling destructor.\n\tvoid SetStringRaw(const Ch* s, SizeType length, Allocator& allocator) {\n\t\tRAPIDJSON_ASSERT(s != NULL);\n\t\tflags_ = kCopyStringFlag;\n\t\tdata_.s.str = (Ch *)allocator.Malloc((length + 1) * sizeof(Ch));\n\t\tdata_.s.length = length;\n\t\tmemcpy(const_cast<Ch*>(data_.s.str), s, length * sizeof(Ch));\n\t\tconst_cast<Ch*>(data_.s.str)[length] = '\\0';\n\t}\n\n\t//! Assignment without calling destructor\n\tvoid RawAssign(GenericValue& rhs) {\n\t\tmemcpy(this, &rhs, sizeof(GenericValue));\n\t\trhs.flags_ = kNullFlag;\n\t}\n\n\tData data_;\n\tunsigned flags_;\n};\n#pragma pack (pop)\n\n//! Value with UTF8 encoding.\ntypedef GenericValue<UTF8<> > Value;\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericDocument \n\n//! A document for parsing JSON text as DOM.\n/*!\n\t\\implements Handler\n\t\\tparam Encoding encoding for both parsing and string storage.\n\t\\tparam Alloactor allocator for allocating memory for the DOM, and the stack during parsing.\n*/\ntemplate <typename Encoding, typename Allocator = MemoryPoolAllocator<> >\nclass GenericDocument : public GenericValue<Encoding, Allocator> {\npublic:\n\ttypedef typename Encoding::Ch Ch;\t\t\t\t\t\t//!< Character type derived from Encoding.\n\ttypedef GenericValue<Encoding, Allocator> ValueType;\t//!< Value type of the document.\n\ttypedef Allocator AllocatorType;\t\t\t\t\t\t//!< Allocator type from template parameter.\n\n\t//! Constructor\n\t/*! \\param allocator\t\tOptional allocator for allocating stack memory.\n\t\t\\param stackCapacity\tInitial capacity of stack in bytes.\n\t*/\n\tGenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}\n\n\t//! Parse JSON text from an input stream.\n\t/*! \\tparam parseFlags Combination of ParseFlag.\n\t\t\\param stream Input stream to be parsed.\n\t\t\\return The document itself for fluent API.\n\t*/\n\ttemplate <unsigned parseFlags, typename Stream>\n\tGenericDocument& ParseStream(Stream& stream) {\n\t\tValueType::SetNull(); // Remove existing root if exist\n\t\tGenericReader<Encoding, Allocator> reader;\n\t\tif (reader.template Parse<parseFlags>(stream, *this)) {\n\t\t\tRAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object\n\t\t\tthis->RawAssign(*stack_.template Pop<ValueType>(1));\t// Add this-> to prevent issue 13.\n\t\t\tparseError_ = 0;\n\t\t\terrorOffset_ = 0;\n\t\t}\n\t\telse {\n\t\t\tparseError_ = reader.GetParseError();\n\t\t\terrorOffset_ = reader.GetErrorOffset();\n\t\t\tClearStack();\n\t\t}\n\t\treturn *this;\n\t}\n\n\t//! Parse JSON text from a mutable string.\n\t/*! \\tparam parseFlags Combination of ParseFlag.\n\t\t\\param str Mutable zero-terminated string to be parsed.\n\t\t\\return The document itself for fluent API.\n\t*/\n\ttemplate <unsigned parseFlags>\n\tGenericDocument& ParseInsitu(Ch* str) {\n\t\tGenericInsituStringStream<Encoding> s(str);\n\t\treturn ParseStream<parseFlags | kParseInsituFlag>(s);\n\t}\n\n\t//! Parse JSON text from a read-only string.\n\t/*! \\tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag).\n\t\t\\param str Read-only zero-terminated string to be parsed.\n\t*/\n\ttemplate <unsigned parseFlags>\n\tGenericDocument& Parse(const Ch* str) {\n\t\tRAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));\n\t\tGenericStringStream<Encoding> s(str);\n\t\treturn ParseStream<parseFlags>(s);\n\t}\n\n\t//! Whether a parse error was occured in the last parsing.\n\tbool HasParseError() const { return parseError_ != 0; }\n\n\t//! Get the message of parsing error.\n\tconst char* GetParseError() const { return parseError_; }\n\n\t//! Get the offset in character of the parsing error.\n\tsize_t GetErrorOffset() const { return errorOffset_; }\n\n\t//! Get the allocator of this document.\n\tAllocator& GetAllocator() {\treturn stack_.GetAllocator(); }\n\n\t//! Get the capacity of stack in bytes.\n\tsize_t GetStackCapacity() const { return stack_.GetCapacity(); }\n\nprivate:\n\t// Prohibit assignment\n\tGenericDocument& operator=(const GenericDocument&);\n\n\tfriend class GenericReader<Encoding, Allocator>;\t// for Reader to call the following private handler functions\n\n\t// Implementation of Handler\n\tvoid Null()\t{ new (stack_.template Push<ValueType>()) ValueType(); }\n\tvoid Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); }\n\tvoid Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); }\n\tvoid Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); }\n\tvoid Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }\n\tvoid Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }\n\tvoid Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); }\n\n\tvoid String(const Ch* str, SizeType length, bool copy) { \n\t\tif (copy) \n\t\t\tnew (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());\n\t\telse\n\t\t\tnew (stack_.template Push<ValueType>()) ValueType(str, length);\n\t}\n\n\tvoid StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); }\n\t\n\tvoid EndObject(SizeType memberCount) {\n\t\ttypename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);\n\t\tstack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());\n\t}\n\n\tvoid StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); }\n\t\n\tvoid EndArray(SizeType elementCount) {\n\t\tValueType* elements = stack_.template Pop<ValueType>(elementCount);\n\t\tstack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());\n\t}\n\n\tvoid ClearStack() {\n\t\tif (Allocator::kNeedFree)\n\t\t\twhile (stack_.GetSize() > 0)\t// Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)\n\t\t\t\t(stack_.template Pop<ValueType>(1))->~ValueType();\n\t\telse\n\t\t\tstack_.Clear();\n\t}\n\n\tstatic const size_t kDefaultStackCapacity = 1024;\n\tinternal::Stack<Allocator> stack_;\n\tconst char* parseError_;\n\tsize_t errorOffset_;\n};\n\ntypedef GenericDocument<UTF8<> > Document;\n\n} // namespace rapidjson\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n#endif // RAPIDJSON_DOCUMENT_H_\n"
  },
  {
    "path": "BOSS/source/rapidjson/filestream.h",
    "content": "#ifndef RAPIDJSON_FILESTREAM_H_\n#define RAPIDJSON_FILESTREAM_H_\n\n#include <cstdio>\n\nnamespace rapidjson {\n\n//! Wrapper of C file stream for input or output.\n/*!\n This simple wrapper does not check the validity of the stream.\n \\implements Stream\n*/\nclass FileStream {\npublic:\n typedef char Ch; //!< Character type. Only support char.\n\n FileStream(FILE* fp) : fp_(fp), count_(0) { Read(); }\n char Peek() const { return current_; }\n char Take() { char c = current_; Read(); return c; }\n size_t Tell() const { return count_; }\n void Put(char c) { fputc(c, fp_); }\n\n // Not implemented\n char* PutBegin() { return 0; }\n size_t PutEnd(char*) { return 0; }\n\nprivate:\n void Read() {\n  RAPIDJSON_ASSERT(fp_ != 0);\n  int c = fgetc(fp_);\n  if (c != EOF) {\n   current_ = (char)c;\n   count_++;\n  }\n  else\n   current_ = '\\0';\n }\n\n FILE* fp_;\n char current_;\n size_t count_;\n};\n\n} // namespace rapidjson\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "BOSS/source/rapidjson/internal/pow10.h",
    "content": "#ifndef RAPIDJSON_POW10_\n#define RAPIDJSON_POW10_\n\nnamespace rapidjson {\nnamespace internal {\n\n//! Computes integer powers of 10 in double (10.0^n).\n/*! This function uses lookup table for fast and accurate results.\n\t\\param n positive/negative exponent. Must <= 308.\n\t\\return 10.0^n\n*/\ninline double Pow10(int n) {\n\tstatic const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes\n\t\t1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300,\n\t\t1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280,\n\t\t1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260,\n\t\t1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240,\n\t\t1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220,\n\t\t1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200,\n\t\t1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180,\n\t\t1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160,\n\t\t1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140,\n\t\t1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120,\n\t\t1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100,\n\t\t1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80, \n\t\t1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60, \n\t\t1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, \n\t\t1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, \n\t\t1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9,  1e-8,  1e-7,  1e-6,  1e-5,  1e-4,  1e-3,  1e-2,  1e-1,  1e+0,  \n\t\t1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, \n\t\t1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,\n\t\t1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,\n\t\t1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,\n\t\t1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,\n\t\t1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,\n\t\t1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,\n\t\t1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,\n\t\t1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,\n\t\t1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,\n\t\t1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,\n\t\t1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,\n\t\t1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,\n\t\t1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,\n\t\t1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,\n\t\t1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308\n\t};\n\tRAPIDJSON_ASSERT(n <= 308);\n\treturn n < -308 ? 0.0 : e[n + 308];\n}\n\n} // namespace internal\n} // namespace rapidjson\n\n#endif // RAPIDJSON_POW10_\n"
  },
  {
    "path": "BOSS/source/rapidjson/internal/stack.h",
    "content": "#ifndef RAPIDJSON_INTERNAL_STACK_H_\n#define RAPIDJSON_INTERNAL_STACK_H_\n\nnamespace rapidjson {\nnamespace internal {\n\n///////////////////////////////////////////////////////////////////////////////\n// Stack\n\n//! A type-unsafe stack for storing different types of data.\n/*! \\tparam Allocator Allocator for allocating stack memory.\n*/\ntemplate <typename Allocator>\nclass Stack {\npublic:\n\tStack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {\n\t\tRAPIDJSON_ASSERT(stack_capacity_ > 0);\n\t\tif (!allocator_)\n\t\t\town_allocator_ = allocator_ = new Allocator();\n\t\tstack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);\n\t\tstack_end_ = stack_ + stack_capacity_;\n\t}\n\n\t~Stack() {\n\t\tAllocator::Free(stack_);\n\t\tdelete own_allocator_; // Only delete if it is owned by the stack\n\t}\n\n\tvoid Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }\n\n\ttemplate<typename T>\n\tT* Push(size_t count = 1) {\n\t\t // Expand the stack if needed\n\t\tif (stack_top_ + sizeof(T) * count >= stack_end_) {\n\t\t\tsize_t new_capacity = stack_capacity_ * 2;\n\t\t\tsize_t size = GetSize();\n\t\t\tsize_t new_size = GetSize() + sizeof(T) * count;\n\t\t\tif (new_capacity < new_size)\n\t\t\t\tnew_capacity = new_size;\n\t\t\tstack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity);\n\t\t\tstack_capacity_ = new_capacity;\n\t\t\tstack_top_ = stack_ + size;\n\t\t\tstack_end_ = stack_ + stack_capacity_;\n\t\t}\n\t\tT* ret = (T*)stack_top_;\n\t\tstack_top_ += sizeof(T) * count;\n\t\treturn ret;\n\t}\n\n\ttemplate<typename T>\n\tT* Pop(size_t count) {\n\t\tRAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));\n\t\tstack_top_ -= count * sizeof(T);\n\t\treturn (T*)stack_top_;\n\t}\n\n\ttemplate<typename T>\n\tT* Top() { \n\t\tRAPIDJSON_ASSERT(GetSize() >= sizeof(T));\n\t\treturn (T*)(stack_top_ - sizeof(T));\n\t}\n\n\ttemplate<typename T>\n\tT* Bottom() { return (T*)stack_; }\n\n\tAllocator& GetAllocator() { return *allocator_; }\n\tsize_t GetSize() const { return stack_top_ - stack_; }\n\tsize_t GetCapacity() const { return stack_capacity_; }\n\nprivate:\n\tAllocator* allocator_;\n\tAllocator* own_allocator_;\n\tchar *stack_;\n\tchar *stack_top_;\n\tchar *stack_end_;\n\tsize_t stack_capacity_;\n};\n\n} // namespace internal\n} // namespace rapidjson\n\n#endif // RAPIDJSON_STACK_H_\n"
  },
  {
    "path": "BOSS/source/rapidjson/internal/strfunc.h",
    "content": "#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_\n#define RAPIDJSON_INTERNAL_STRFUNC_H_\n\nnamespace rapidjson {\nnamespace internal {\n\n//! Custom strlen() which works on different character types.\n/*!\t\\tparam Ch Character type (e.g. char, wchar_t, short)\n\t\\param s Null-terminated input string.\n\t\\return Number of characters in the string. \n\t\\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.\n*/\ntemplate <typename Ch>\ninline SizeType StrLen(const Ch* s) {\n\tconst Ch* p = s;\n\twhile (*p != '\\0')\n\t\t++p;\n\treturn SizeType(p - s);\n}\n\n} // namespace internal\n} // namespace rapidjson\n\n#endif // RAPIDJSON_INTERNAL_STRFUNC_H_\n"
  },
  {
    "path": "BOSS/source/rapidjson/prettywriter.h",
    "content": "#ifndef RAPIDJSON_PRETTYWRITER_H_\n#define RAPIDJSON_PRETTYWRITER_H_\n\n#include \"writer.h\"\n\nnamespace rapidjson {\n\n//! Writer with indentation and spacing.\n/*!\n \\tparam Stream Type of ouptut stream.\n \\tparam Encoding Encoding of both source strings and output.\n \\tparam Allocator Type of allocator for allocating memory of stack.\n*/\ntemplate<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >\nclass PrettyWriter : public Writer<Stream, Encoding, Allocator> {\npublic:\n typedef Writer<Stream, Encoding, Allocator> Base;\n typedef typename Base::Ch Ch;\n\n //! Constructor\n /*! \\param stream Output stream.\n  \\param allocator User supplied allocator. If it is null, it will create a private one.\n  \\param levelDepth Initial capacity of \n */\n PrettyWriter(Stream& stream, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : \n  Base(stream, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}\n\n //! Set custom indentation.\n /*! \\param indentChar  Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').\n  \\param indentCharCount Number of indent characters for each indentation level.\n  \\note The default indentation is 4 spaces.\n */\n PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {\n  RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\\t' || indentChar == '\\n' || indentChar == '\\r');\n  indentChar_ = indentChar;\n  indentCharCount_ = indentCharCount;\n  return *this;\n }\n\n //@name Implementation of Handler.\n //@{\n\n PrettyWriter& Null()    { PrettyPrefix(kNullType);   Base::WriteNull();   return *this; }\n PrettyWriter& Bool(bool b)   { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; }\n PrettyWriter& Int(int i)   { PrettyPrefix(kNumberType); Base::WriteInt(i);   return *this; }\n PrettyWriter& Uint(unsigned u)  { PrettyPrefix(kNumberType); Base::WriteUint(u);  return *this; }\n PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64);  return *this; }\n PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; }\n PrettyWriter& Double(double d)  { PrettyPrefix(kNumberType); Base::WriteDouble(d);  return *this; }\n\n PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {\n  (void)copy;\n  PrettyPrefix(kStringType);\n  Base::WriteString(str, length);\n  return *this;\n }\n\n PrettyWriter& StartObject() {\n  PrettyPrefix(kObjectType);\n  new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);\n  Base::WriteStartObject();\n  return *this;\n }\n\n PrettyWriter& EndObject(SizeType memberCount = 0) {\n  (void)memberCount;\n  RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));\n  RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);\n  bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;\n\n  if (!empty) {\n   Base::stream_.Put('\\n');\n   WriteIndent();\n  }\n  Base::WriteEndObject();\n  return *this;\n }\n\n PrettyWriter& StartArray() {\n  PrettyPrefix(kArrayType);\n  new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);\n  Base::WriteStartArray();\n  return *this;\n }\n\n PrettyWriter& EndArray(SizeType memberCount = 0) {\n  (void)memberCount;\n  RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));\n  RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);\n  bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;\n\n  if (!empty) {\n   Base::stream_.Put('\\n');\n   WriteIndent();\n  }\n  Base::WriteEndArray();\n  return *this;\n }\n\n //@}\n\n //! Simpler but slower overload.\n PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); }\n\nprotected:\n void PrettyPrefix(Type type) {\n  (void)type;\n  if (Base::level_stack_.GetSize() != 0) { // this value is not at root\n   typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();\n\n   if (level->inArray) {\n    if (level->valueCount > 0) {\n     Base::stream_.Put(','); // add comma if it is not the first element in array\n     Base::stream_.Put('\\n');\n    }\n    else\n     Base::stream_.Put('\\n');\n    WriteIndent();\n   }\n   else { // in object\n    if (level->valueCount > 0) {\n     if (level->valueCount % 2 == 0) {\n      Base::stream_.Put(',');\n      Base::stream_.Put('\\n');\n     }\n     else {\n      Base::stream_.Put(':');\n      Base::stream_.Put(' ');\n     }\n    }\n    else\n     Base::stream_.Put('\\n');\n\n    if (level->valueCount % 2 == 0)\n     WriteIndent();\n   }\n   if (!level->inArray && level->valueCount % 2 == 0)\n    RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name\n   level->valueCount++;\n  }\n  else\n   RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);\n }\n\n void WriteIndent()  {\n  size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;\n  PutN(Base::stream_, indentChar_, count);\n }\n\n Ch indentChar_;\n unsigned indentCharCount_;\n};\n\n} // namespace rapidjson\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "BOSS/source/rapidjson/rapidjson.h",
    "content": "#include \"../Common.h\"\n#ifdef MCDS_FLASH_VERSION\n    #pragma GCC system_header\n#endif\n\n#ifndef RAPIDJSON_RAPIDJSON_H_\n#define RAPIDJSON_RAPIDJSON_H_\n\n// Copyright (c) 2011-2012 Milo Yip (miloyip@gmail.com)\n// Version 0.11\n\n#include <cstdlib> // malloc(), realloc(), free()\n#include <cstring> // memcpy()\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NO_INT64DEFINE\n\n// Here defines int64_t and uint64_t types in global namespace.\n// If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this.\n#ifndef RAPIDJSON_NO_INT64DEFINE\n#ifdef _MSC_VER\ntypedef __int64 int64_t;\ntypedef unsigned __int64 uint64_t;\n#else\n#include <inttypes.h>\n#endif\n#endif // RAPIDJSON_NO_INT64TYPEDEF\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ENDIAN\n#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine\n#define RAPIDJSON_BIGENDIAN  1 //!< Big endian machine\n\n//! Endianness of the machine.\n/*! GCC provided macro for detecting endianness of the target machine. But other\n compilers may not have this. User can define RAPIDJSON_ENDIAN to either\n RAPIDJSON_LITTLEENDIAN or RAPIDJSON_BIGENDIAN.\n*/\n#ifndef RAPIDJSON_ENDIAN\n#ifdef __BYTE_ORDER__\n#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#else\n#define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#endif // __BYTE_ORDER__\n#else\n#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN // Assumes little endian otherwise.\n#endif\n#endif // RAPIDJSON_ENDIAN\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD\n\n// Enable SSE2 optimization.\n//#define RAPIDJSON_SSE2\n\n// Enable SSE4.2 optimization.\n//#define RAPIDJSON_SSE42\n\n#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)\n#define RAPIDJSON_SIMD\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NO_SIZETYPEDEFINE\n\n#ifndef RAPIDJSON_NO_SIZETYPEDEFINE\nnamespace rapidjson {\n//! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t.\n/*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE.\n*/\ntypedef unsigned SizeType;\n} // namespace rapidjson\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ASSERT\n\n//! Assertion.\n/*! By default, rapidjson uses C assert() for assertion.\n User can override it by defining RAPIDJSON_ASSERT(x) macro.\n*/\n#ifndef RAPIDJSON_ASSERT\n#include <cassert>\n#define RAPIDJSON_ASSERT(x) assert(x)\n#endif // RAPIDJSON_ASSERT\n\n///////////////////////////////////////////////////////////////////////////////\n// Helpers\n\n#define RAPIDJSON_MULTILINEMACRO_BEGIN do {  \n#define RAPIDJSON_MULTILINEMACRO_END \\\n} while((void)0, 0)\n\nnamespace rapidjson {\n\n///////////////////////////////////////////////////////////////////////////////\n// Allocator\n\n/*! \\class rapidjson::Allocator\n \\brief Concept for allocating, resizing and freeing memory block.\n \n Note that Malloc() and Realloc() are non-static but Free() is static.\n \n So if an allocator need to support Free(), it needs to put its pointer in \n the header of memory block.\n\n\\code\nconcept Allocator {\n static const bool kNeedFree; //!< Whether this allocator needs to call Free().\n\n // Allocate a memory block.\n // \\param size of the memory block in bytes.\n // \\returns pointer to the memory block.\n void* Malloc(size_t size);\n\n // Resize a memory block.\n // \\param originalPtr The pointer to current memory block. Null pointer is permitted.\n // \\param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)\n // \\param newSize the new size in bytes.\n void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);\n\n // Free a memory block.\n // \\param pointer to the memory block. Null pointer is permitted.\n static void Free(void *ptr);\n};\n\\endcode\n*/\n\n///////////////////////////////////////////////////////////////////////////////\n// CrtAllocator\n\n//! C-runtime library allocator.\n/*! This class is just wrapper for standard C library memory routines.\n \\implements Allocator\n*/\nclass CrtAllocator {\npublic:\n static const bool kNeedFree = true;\n void* Malloc(size_t size) { return malloc(size); }\n void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); }\n static void Free(void *ptr) { free(ptr); }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// MemoryPoolAllocator\n\n//! Default memory allocator used by the parser and DOM.\n/*! This allocator allocate memory blocks from pre-allocated memory chunks. \n\n    It does not free memory blocks. And Realloc() only allocate new memory.\n\n    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.\n\n    User may also supply a buffer as the first chunk.\n\n    If the user-buffer is full then additional chunks are allocated by BaseAllocator.\n\n    The user-buffer is not deallocated by this allocator.\n\n    \\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.\n \\implements Allocator\n*/\ntemplate <typename BaseAllocator = CrtAllocator>\nclass MemoryPoolAllocator {\npublic:\n static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)\n\n //! Constructor with chunkSize.\n /*! \\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.\n  \\param baseAllocator The allocator for allocating memory chunks.\n */\n MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : \n  chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)\n {\n  if (!baseAllocator_)\n   ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();\n  AddChunk(chunk_capacity_);\n }\n\n //! Constructor with user-supplied buffer.\n /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.\n\n  The user buffer will not be deallocated when this allocator is destructed.\n\n  \\param buffer User supplied buffer.\n  \\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).\n  \\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.\n  \\param baseAllocator The allocator for allocating memory chunks.\n */\n MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :\n  chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)\n {\n  RAPIDJSON_ASSERT(buffer != 0);\n  RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));\n  chunkHead_ = (ChunkHeader*)buffer;\n  chunkHead_->capacity = size - sizeof(ChunkHeader);\n  chunkHead_->size = 0;\n  chunkHead_->next = 0;\n }\n\n //! Destructor.\n /*! This deallocates all memory chunks, excluding the user-supplied buffer.\n */\n ~MemoryPoolAllocator() {\n  Clear();\n  delete ownBaseAllocator_;\n }\n\n //! Deallocates all memory chunks, excluding the user-supplied buffer.\n void Clear() {\n  while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) {\n   ChunkHeader* next = chunkHead_->next;\n   baseAllocator_->Free(chunkHead_);\n   chunkHead_ = next;\n  }\n }\n\n //! Computes the total capacity of allocated memory chunks.\n /*! \\return total capacity in bytes.\n */\n size_t Capacity() {\n  size_t capacity = 0;\n  for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)\n   capacity += c->capacity;\n  return capacity;\n }\n\n //! Computes the memory blocks allocated.\n /*! \\return total used bytes.\n */\n size_t Size() {\n  size_t size = 0;\n  for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)\n   size += c->size;\n  return size;\n }\n\n //! Allocates a memory block. (concept Allocator)\n void* Malloc(size_t size) {\n  size = (size + 3) & ~3; // Force aligning size to 4\n\n  if (chunkHead_->size + size > chunkHead_->capacity)\n   AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);\n\n  char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size;\n  RAPIDJSON_ASSERT(((uintptr_t)buffer & 3) == 0); // returned buffer is aligned to 4\n  chunkHead_->size += size;\n\n  return buffer;\n }\n\n //! Resizes a memory block (concept Allocator)\n void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {\n  if (originalPtr == 0)\n   return Malloc(newSize);\n\n  // Do not shrink if new size is smaller than original\n  if (originalSize >= newSize)\n   return originalPtr;\n\n  // Simply expand it if it is the last allocation and there is sufficient space\n  if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {\n   size_t increment = newSize - originalSize;\n   increment = (increment + 3) & ~3; // Force aligning size to 4\n   if (chunkHead_->size + increment <= chunkHead_->capacity) {\n    chunkHead_->size += increment;\n    RAPIDJSON_ASSERT(((uintptr_t)originalPtr & 3) == 0); // returned buffer is aligned to 4\n    return originalPtr;\n   }\n  }\n\n  // Realloc process: allocate and copy memory, do not free original buffer.\n  void* newBuffer = Malloc(newSize);\n  RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.\n  return memcpy(newBuffer, originalPtr, originalSize);\n }\n\n //! Frees a memory block (concept Allocator)\n static void Free(void *) {} // Do nothing\n\nprivate:\n //! Creates a new chunk.\n /*! \\param capacity Capacity of the chunk in bytes.\n */\n void AddChunk(size_t capacity) {\n  ChunkHeader* chunk = (ChunkHeader*)baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity);\n  chunk->capacity = capacity;\n  chunk->size = 0;\n  chunk->next = chunkHead_;\n  chunkHead_ =  chunk;\n }\n\n static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.\n\n //! Chunk header for perpending to each chunk.\n /*! Chunks are stored as a singly linked list.\n */\n struct ChunkHeader {\n  size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).\n  size_t size;  //!< Current size of allocated memory in bytes.\n  ChunkHeader *next; //!< Next chunk in the linked list.\n };\n\n ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.\n size_t chunk_capacity_;  //!< The minimum capacity of chunk when they are allocated.\n char *userBuffer_;   //!< User supplied buffer.\n BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.\n BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Encoding\n\n/*! \\class rapidjson::Encoding\n \\brief Concept for encoding of Unicode characters.\n\n\\code\nconcept Encoding {\n typename Ch; //! Type of character.\n\n //! \\brief Encode a Unicode codepoint to a buffer.\n //! \\param buffer pointer to destination buffer to store the result. It should have sufficient size of encoding one character.\n //! \\param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.\n //! \\returns the pointer to the next character after the encoded data.\n static Ch* Encode(Ch *buffer, unsigned codepoint);\n};\n\\endcode\n*/\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF8\n\n//! UTF-8 encoding.\n/*! http://en.wikipedia.org/wiki/UTF-8\n \\tparam CharType Type for storing 8-bit UTF-8 data. Default is char.\n \\implements Encoding\n*/\ntemplate<typename CharType = char>\nstruct UTF8 {\n typedef CharType Ch;\n\n static Ch* Encode(Ch *buffer, unsigned codepoint) {\n  if (codepoint <= 0x7F) \n   *buffer++ = codepoint & 0xFF;\n  else if (codepoint <= 0x7FF) {\n   *buffer++ = 0xC0 | ((codepoint >> 6) & 0xFF);\n   *buffer++ = 0x80 | ((codepoint & 0x3F));\n  }\n  else if (codepoint <= 0xFFFF) {\n   *buffer++ = 0xE0 | ((codepoint >> 12) & 0xFF);\n   *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);\n   *buffer++ = 0x80 | (codepoint & 0x3F);\n  }\n  else {\n   RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n   *buffer++ = 0xF0 | ((codepoint >> 18) & 0xFF);\n   *buffer++ = 0x80 | ((codepoint >> 12) & 0x3F);\n   *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);\n   *buffer++ = 0x80 | (codepoint & 0x3F);\n  }\n  return buffer;\n }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF16\n\n//! UTF-16 encoding.\n/*! http://en.wikipedia.org/wiki/UTF-16\n \\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.\n \\implements Encoding\n*/\ntemplate<typename CharType = wchar_t>\nstruct UTF16 {\n typedef CharType Ch;\n\n static Ch* Encode(Ch* buffer, unsigned codepoint) {\n  if (codepoint <= 0xFFFF) {\n   RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair \n   *buffer++ = static_cast<Ch>(codepoint);\n  }\n  else {\n   RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n   unsigned v = codepoint - 0x10000;\n   *buffer++ = static_cast<Ch>((v >> 10) + 0xD800);\n   *buffer++ = (v & 0x3FF) + 0xDC00;\n  }\n  return buffer;\n }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF32\n\n//! UTF-32 encoding. \n/*! http://en.wikipedia.org/wiki/UTF-32\n \\tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.\n \\implements Encoding\n*/\ntemplate<typename CharType = unsigned>\nstruct UTF32 {\n typedef CharType Ch;\n\n static Ch *Encode(Ch* buffer, unsigned codepoint) {\n  RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n  *buffer++ = codepoint;\n  return buffer;\n }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n//  Stream\n\n/*! \\class rapidjson::Stream\n \\brief Concept for reading and writing characters.\n\n For read-only stream, no need to implement PutBegin(), Put() and PutEnd().\n\n For write-only stream, only need to implement Put().\n\n\\code\nconcept Stream {\n typename Ch; //!< Character type of the stream.\n\n //! Read the current character from stream without moving the read cursor.\n Ch Peek() const;\n\n //! Read the current character from stream and moving the read cursor to next character.\n Ch Take();\n\n //! Get the current read cursor.\n //! \\return Number of characters read from start.\n size_t Tell();\n\n //! Begin writing operation at the current read pointer.\n //! \\return The begin writer pointer.\n Ch* PutBegin();\n\n //! Write a character.\n void Put(Ch c);\n\n //! End the writing operation.\n //! \\param begin The begin write pointer returned by PutBegin().\n //! \\return Number of characters written.\n size_t PutEnd(Ch* begin);\n}\n\\endcode\n*/\n\n//! Put N copies of a character to a stream.\ntemplate<typename Stream, typename Ch>\ninline void PutN(Stream& stream, Ch c, size_t n) {\n for (size_t i = 0; i < n; i++)\n  stream.Put(c);\n}\n\n///////////////////////////////////////////////////////////////////////////////\n// StringStream\n\n//! Read-only string stream.\n/*! \\implements Stream\n*/\ntemplate <typename Encoding>\nstruct GenericStringStream {\n typedef typename Encoding::Ch Ch;\n\n GenericStringStream(const Ch *src) : src_(src), head_(src) {}\n\n Ch Peek() const { return *src_; }\n Ch Take() { return *src_++; }\n size_t Tell() const { return src_ - head_; }\n\n Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n void Put(Ch) { RAPIDJSON_ASSERT(false); }\n size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n const Ch* src_;  //!< Current read position.\n const Ch* head_; //!< Original head of the string.\n};\n\ntypedef GenericStringStream<UTF8<> > StringStream;\n\n///////////////////////////////////////////////////////////////////////////////\n// InsituStringStream\n\n//! A read-write string stream.\n/*! This string stream is particularly designed for in-situ parsing.\n \\implements Stream\n*/\ntemplate <typename Encoding>\nstruct GenericInsituStringStream {\n typedef typename Encoding::Ch Ch;\n\n GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}\n\n // Read\n Ch Peek() { return *src_; }\n Ch Take() { return *src_++; }\n size_t Tell() { return src_ - head_; }\n\n // Write\n Ch* PutBegin() { return dst_ = src_; }\n void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }\n size_t PutEnd(Ch* begin) { return dst_ - begin; }\n\n Ch* src_;\n Ch* dst_;\n Ch* head_;\n};\n\ntypedef GenericInsituStringStream<UTF8<> > InsituStringStream;\n\n///////////////////////////////////////////////////////////////////////////////\n// Type\n\n//! Type of JSON value\nenum Type {\n kNullType = 0,  //!< null\n kFalseType = 1,  //!< false\n kTrueType = 2,  //!< true\n kObjectType = 3, //!< object\n kArrayType = 4,  //!< array \n kStringType = 5, //!< string\n kNumberType = 6, //!< number\n};\n\n} // namespace rapidjson\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "BOSS/source/rapidjson/reader.h",
    "content": "#include \"../Common.h\"\n#ifdef MCDS_FLASH_VERSION\n    #pragma GCC system_header\n#endif\n\n#ifndef RAPIDJSON_READER_H_\n#define RAPIDJSON_READER_H_\n\n// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)\n// Version 0.1\n\n#include \"rapidjson.h\"\n#include \"internal/pow10.h\"\n#include \"internal/stack.h\"\n#include <csetjmp>\n\n#ifdef RAPIDJSON_SSE42\n#include <nmmintrin.h>\n#elif defined(RAPIDJSON_SSE2)\n#include <emmintrin.h>\n#endif\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4127) // conditional expression is constant\n#endif\n\n#ifndef RAPIDJSON_PARSE_ERROR\n#define RAPIDJSON_PARSE_ERROR(msg, offset) \\\n\tRAPIDJSON_MULTILINEMACRO_BEGIN \\\n\tparseError_ = msg; \\\n\terrorOffset_ = offset; \\\n\tlongjmp(jmpbuf_, 1); \\\n\tRAPIDJSON_MULTILINEMACRO_END\n#endif\n\nnamespace rapidjson {\n\n///////////////////////////////////////////////////////////////////////////////\n// ParseFlag\n\n//! Combination of parseFlags\nenum ParseFlag {\n\tkParseDefaultFlags = 0,\t\t\t//!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.\n\tkParseInsituFlag = 1\t\t\t//!< In-situ(destructive) parsing.\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Handler\n\n/*!\t\\class rapidjson::Handler\n\t\\brief Concept for receiving events from GenericReader upon parsing.\n\\code\nconcept Handler {\n\ttypename Ch;\n\n\tvoid Null();\n\tvoid Bool(bool b);\n\tvoid Int(int i);\n\tvoid Uint(unsigned i);\n\tvoid Int64(int64_t i);\n\tvoid Uint64(uint64_t i);\n\tvoid Double(double d);\n\tvoid String(const Ch* str, SizeType length, bool copy);\n\tvoid StartObject();\n\tvoid EndObject(SizeType memberCount);\n\tvoid StartArray();\n\tvoid EndArray(SizeType elementCount);\n};\n\\endcode\n*/\n///////////////////////////////////////////////////////////////////////////////\n// BaseReaderHandler\n\n//! Default implementation of Handler.\n/*! This can be used as base class of any reader handler.\n\t\\implements Handler\n*/\ntemplate<typename Encoding = UTF8<> >\nstruct BaseReaderHandler {\n\ttypedef typename Encoding::Ch Ch;\n\n\tvoid Default() {}\n\tvoid Null() { Default(); }\n\tvoid Bool(bool) { Default(); }\n\tvoid Int(int) { Default(); }\n\tvoid Uint(unsigned) { Default(); }\n\tvoid Int64(int64_t) { Default(); }\n\tvoid Uint64(uint64_t) { Default(); }\n\tvoid Double(double) { Default(); }\n\tvoid String(const Ch*, SizeType, bool) { Default(); }\n\tvoid StartObject() { Default(); }\n\tvoid EndObject(SizeType) { Default(); }\n\tvoid StartArray() { Default(); }\n\tvoid EndArray(SizeType) { Default(); }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// SkipWhitespace\n\n//! Skip the JSON white spaces in a stream.\n/*! \\param stream A input stream for skipping white spaces.\n\t\\note This function has SSE2/SSE4.2 specialization.\n*/\ntemplate<typename Stream>\nvoid SkipWhitespace(Stream& stream) {\n\tStream s = stream;\t// Use a local copy for optimization\n\twhile (s.Peek() == ' ' || s.Peek() == '\\n' || s.Peek() == '\\r' || s.Peek() == '\\t')\n\t\ts.Take();\n\tstream = s;\n}\n\n#ifdef RAPIDJSON_SSE42\n//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.\ninline const char *SkipWhitespace_SIMD(const char* p) {\n\tstatic const char whitespace[16] = \" \\n\\r\\t\";\n\t__m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);\n\n\tfor (;;) {\n\t\t__m128i s = _mm_loadu_si128((const __m128i *)p);\n\t\tunsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));\n\t\tif (r == 0)\t// all 16 characters are whitespace\n\t\t\tp += 16;\n\t\telse {\t\t// some of characters may be non-whitespace\n#ifdef _MSC_VER\t\t// Find the index of first non-whitespace\n\t\t\tunsigned long offset;\n\t\t\tif (_BitScanForward(&offset, r))\n\t\t\t\treturn p + offset;\n#else\n\t\t\tif (r != 0)\n\t\t\t\treturn p + __builtin_ffs(r) - 1;\n#endif\n\t\t}\n\t}\n}\n\n#elif defined(RAPIDJSON_SSE2)\n\n//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.\ninline const char *SkipWhitespace_SIMD(const char* p) {\n\tstatic const char whitespaces[4][17] = {\n\t\t\"                \",\n\t\t\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\n\t\t\"\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\",\n\t\t\"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\"};\n\n\t__m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);\n\t__m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);\n\t__m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);\n\t__m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);\n\n\tfor (;;) {\n\t\t__m128i s = _mm_loadu_si128((const __m128i *)p);\n\t\t__m128i x = _mm_cmpeq_epi8(s, w0);\n\t\tx = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));\n\t\tx = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));\n\t\tx = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));\n\t\tunsigned short r = ~_mm_movemask_epi8(x);\n\t\tif (r == 0)\t// all 16 characters are whitespace\n\t\t\tp += 16;\n\t\telse {\t\t// some of characters may be non-whitespace\n#ifdef _MSC_VER\t\t// Find the index of first non-whitespace\n\t\t\tunsigned long offset;\n\t\t\tif (_BitScanForward(&offset, r))\n\t\t\t\treturn p + offset;\n#else\n\t\t\tif (r != 0)\n\t\t\t\treturn p + __builtin_ffs(r) - 1;\n#endif\n\t\t}\n\t}\n}\n\n#endif // RAPIDJSON_SSE2\n\n#ifdef RAPIDJSON_SIMD\n//! Template function specialization for InsituStringStream\ntemplate<> inline void SkipWhitespace(InsituStringStream& stream) { \n\tstream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_));\n}\n\n//! Template function specialization for StringStream\ntemplate<> inline void SkipWhitespace(StringStream& stream) {\n\tstream.src_ = SkipWhitespace_SIMD(stream.src_);\n}\n#endif // RAPIDJSON_SIMD\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericReader\n\n//! SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.\n/*! GenericReader parses JSON text from a stream, and send events synchronously to an \n    object implementing Handler concept.\n\n    It needs to allocate a stack for storing a single decoded string during \n    non-destructive parsing.\n\n    For in-situ parsing, the decoded string is directly written to the source \n    text string, no temporary buffer is required.\n\n    A GenericReader object can be reused for parsing multiple JSON text.\n    \n    \\tparam Encoding Encoding of both the stream and the parse output.\n    \\tparam Allocator Allocator type for stack.\n*/\ntemplate <typename Encoding, typename Allocator = MemoryPoolAllocator<> >\nclass GenericReader {\npublic:\n\ttypedef typename Encoding::Ch Ch;\n\n\t//! Constructor.\n\t/*! \\param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)\n\t\t\\param stackCapacity stack capacity in bytes for storing a single decoded string.  (Only use for non-destructive parsing)\n\t*/\n\tGenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}\n\n\t//! Parse JSON text.\n\t/*! \\tparam parseFlags Combination of ParseFlag. \n\t\t \\tparam Stream Type of input stream.\n\t\t \\tparam Handler Type of handler which must implement Handler concept.\n\t\t \\param stream Input stream to be parsed.\n\t\t \\param handler The handler to receive events.\n\t\t \\return Whether the parsing is successful.\n\t*/\n\ttemplate <unsigned parseFlags, typename Stream, typename Handler>\n\tbool Parse(Stream& stream, Handler& handler) {\n\t\tparseError_ = 0;\n\t\terrorOffset_ = 0;\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable\n#endif\n\t\tif (setjmp(jmpbuf_)) {\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\t\t\tstack_.Clear();\n\t\t\treturn false;\n\t\t}\n\n\t\tSkipWhitespace(stream);\n\n\t\tif (stream.Peek() == '\\0')\n\t\t\tRAPIDJSON_PARSE_ERROR(\"Text only contains white space(s)\", stream.Tell());\n\t\telse {\n\t\t\tswitch (stream.Peek()) {\n\t\t\t\tcase '{': ParseObject<parseFlags>(stream, handler); break;\n\t\t\t\tcase '[': ParseArray<parseFlags>(stream, handler); break;\n\t\t\t\tdefault: RAPIDJSON_PARSE_ERROR(\"Expect either an object or array at root\", stream.Tell());\n\t\t\t}\n\t\t\tSkipWhitespace(stream);\n\n\t\t\tif (stream.Peek() != '\\0')\n\t\t\t\tRAPIDJSON_PARSE_ERROR(\"Nothing should follow the root object or array.\", stream.Tell());\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool HasParseError() const { return parseError_ != 0; }\n\tconst char* GetParseError() const { return parseError_; }\n\tsize_t GetErrorOffset() const { return errorOffset_; }\n\nprivate:\n\t// Parse object: { string : value, ... }\n\ttemplate<unsigned parseFlags, typename Stream, typename Handler>\n\tvoid ParseObject(Stream& stream, Handler& handler) {\n\t\tRAPIDJSON_ASSERT(stream.Peek() == '{');\n\t\tstream.Take();\t// Skip '{'\n\t\thandler.StartObject();\n\t\tSkipWhitespace(stream);\n\n\t\tif (stream.Peek() == '}') {\n\t\t\tstream.Take();\n\t\t\thandler.EndObject(0);\t// empty object\n\t\t\treturn;\n\t\t}\n\n\t\tfor (SizeType memberCount = 0;;) {\n\t\t\tif (stream.Peek() != '\"') {\n\t\t\t\tRAPIDJSON_PARSE_ERROR(\"Name of an object member must be a string\", stream.Tell());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tParseString<parseFlags>(stream, handler);\n\t\t\tSkipWhitespace(stream);\n\n\t\t\tif (stream.Take() != ':') {\n\t\t\t\tRAPIDJSON_PARSE_ERROR(\"There must be a colon after the name of object member\", stream.Tell());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tSkipWhitespace(stream);\n\n\t\t\tParseValue<parseFlags>(stream, handler);\n\t\t\tSkipWhitespace(stream);\n\n\t\t\t++memberCount;\n\n\t\t\tswitch(stream.Take()) {\n\t\t\t\tcase ',': SkipWhitespace(stream); break;\n\t\t\t\tcase '}': handler.EndObject(memberCount); return;\n\t\t\t\tdefault:  RAPIDJSON_PARSE_ERROR(\"Must be a comma or '}' after an object member\", stream.Tell());\n\t\t\t}\n\t\t}\n\t}\n\n\t// Parse array: [ value, ... ]\n\ttemplate<unsigned parseFlags, typename Stream, typename Handler>\n\tvoid ParseArray(Stream& stream, Handler& handler) {\n\t\tRAPIDJSON_ASSERT(stream.Peek() == '[');\n\t\tstream.Take();\t// Skip '['\n\t\thandler.StartArray();\n\t\tSkipWhitespace(stream);\n\n\t\tif (stream.Peek() == ']') {\n\t\t\tstream.Take();\n\t\t\thandler.EndArray(0); // empty array\n\t\t\treturn;\n\t\t}\n\n\t\tfor (SizeType elementCount = 0;;) {\n\t\t\tParseValue<parseFlags>(stream, handler);\n\t\t\t++elementCount;\n\t\t\tSkipWhitespace(stream);\n\n\t\t\tswitch (stream.Take()) {\n\t\t\t\tcase ',': SkipWhitespace(stream); break;\n\t\t\t\tcase ']': handler.EndArray(elementCount); return;\n\t\t\t\tdefault:  RAPIDJSON_PARSE_ERROR(\"Must be a comma or ']' after an array element.\", stream.Tell());\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate<unsigned parseFlags, typename Stream, typename Handler>\n\tvoid ParseNull(Stream& stream, Handler& handler) {\n\t\tRAPIDJSON_ASSERT(stream.Peek() == 'n');\n\t\tstream.Take();\n\n\t\tif (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l')\n\t\t\thandler.Null();\n\t\telse\n\t\t\tRAPIDJSON_PARSE_ERROR(\"Invalid value\", stream.Tell() - 1);\n\t}\n\n\ttemplate<unsigned parseFlags, typename Stream, typename Handler>\n\tvoid ParseTrue(Stream& stream, Handler& handler) {\n\t\tRAPIDJSON_ASSERT(stream.Peek() == 't');\n\t\tstream.Take();\n\n\t\tif (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e')\n\t\t\thandler.Bool(true);\n\t\telse\n\t\t\tRAPIDJSON_PARSE_ERROR(\"Invalid value\", stream.Tell());\n\t}\n\n\ttemplate<unsigned parseFlags, typename Stream, typename Handler>\n\tvoid ParseFalse(Stream& stream, Handler& handler) {\n\t\tRAPIDJSON_ASSERT(stream.Peek() == 'f');\n\t\tstream.Take();\n\n\t\tif (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e')\n\t\t\thandler.Bool(false);\n\t\telse\n\t\t\tRAPIDJSON_PARSE_ERROR(\"Invalid value\", stream.Tell() - 1);\n\t}\n\n\t// Helper function to parse four hexidecimal digits in \\uXXXX in ParseString().\n\ttemplate<typename Stream>\n\tunsigned ParseHex4(Stream& stream) {\n\t\tStream s = stream;\t// Use a local copy for optimization\n\t\tunsigned codepoint = 0;\n\t\tfor (int i = 0; i < 4; i++) {\n\t\t\tCh c = s.Take();\n\t\t\tcodepoint <<= 4;\n\t\t\tcodepoint += c;\n\t\t\tif (c >= '0' && c <= '9')\n\t\t\t\tcodepoint -= '0';\n\t\t\telse if (c >= 'A' && c <= 'F')\n\t\t\t\tcodepoint -= 'A' - 10;\n\t\t\telse if (c >= 'a' && c <= 'f')\n\t\t\t\tcodepoint -= 'a' - 10;\n\t\t\telse \n\t\t\t\tRAPIDJSON_PARSE_ERROR(\"Incorrect hex digit after \\\\u escape\", s.Tell() - 1);\n\t\t}\n\t\tstream = s; // Restore stream\n\t\treturn codepoint;\n\t}\n\n\t// Parse string, handling the prefix and suffix double quotes and escaping.\n\ttemplate<unsigned parseFlags, typename Stream, typename Handler>\n\tvoid ParseString(Stream& stream, Handler& handler) {\n#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n\t\tstatic const Ch escape[256] = {\n\t\t\tZ16, Z16, 0, 0,'\\\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', \n\t\t\tZ16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\\\', 0, 0, 0, \n\t\t\t0, 0,'\\b', 0, 0, 0,'\\f', 0, 0, 0, 0, 0, 0, 0,'\\n', 0, \n\t\t\t0, 0,'\\r', 0,'\\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \n\t\t\tZ16, Z16, Z16, Z16, Z16, Z16, Z16, Z16\n\t\t};\n#undef Z16\n\n\t\tStream s = stream;\t// Use a local copy for optimization\n\t\tRAPIDJSON_ASSERT(s.Peek() == '\\\"');\n\t\ts.Take();\t// Skip '\\\"'\n\t\tCh *head;\n\t\tSizeType len;\n\t\tif (parseFlags & kParseInsituFlag)\n\t\t\thead = s.PutBegin();\n\t\telse\n\t\t\tlen = 0;\n\n#define RAPIDJSON_PUT(x) \\\n\tdo { \\\n\t\tif (parseFlags & kParseInsituFlag) \\\n\t\t\ts.Put(x); \\\n\t\telse { \\\n\t\t\t*stack_.template Push<Ch>() = x; \\\n\t\t\t++len; \\\n\t\t} \\\n\t} while(false)\n\n\t\tfor (;;) {\n\t\t\tCh c = s.Take();\n\t\t\tif (c == '\\\\') {\t// Escape\n\t\t\t\tCh e = s.Take();\n\t\t\t\tif ((sizeof(Ch) == 1 || e < 256) && escape[(unsigned char)e])\n\t\t\t\t\tRAPIDJSON_PUT(escape[(unsigned char)e]);\n\t\t\t\telse if (e == 'u') {\t// Unicode\n\t\t\t\t\tunsigned codepoint = ParseHex4(s);\n\t\t\t\t\tif (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair\n\t\t\t\t\t\tif (s.Take() != '\\\\' || s.Take() != 'u') {\n\t\t\t\t\t\t\tRAPIDJSON_PARSE_ERROR(\"Missing the second \\\\u in surrogate pair\", s.Tell() - 2);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tunsigned codepoint2 = ParseHex4(s);\n\t\t\t\t\t\tif (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) {\n\t\t\t\t\t\t\tRAPIDJSON_PARSE_ERROR(\"The second \\\\u in surrogate pair is invalid\", s.Tell() - 2);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcodepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;\n\t\t\t\t\t}\n\n\t\t\t\t\tCh buffer[4];\n\t\t\t\t\tSizeType count = SizeType(Encoding::Encode(buffer, codepoint) - &buffer[0]);\n\n\t\t\t\t\tif (parseFlags & kParseInsituFlag) \n\t\t\t\t\t\tfor (SizeType i = 0; i < count; i++)\n\t\t\t\t\t\t\ts.Put(buffer[i]);\n\t\t\t\t\telse {\n\t\t\t\t\t\tmemcpy(stack_.template Push<Ch>(count), buffer, count * sizeof(Ch));\n\t\t\t\t\t\tlen += count;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tRAPIDJSON_PARSE_ERROR(\"Unknown escape character\", stream.Tell() - 1);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (c == '\"') {\t// Closing double quote\n\t\t\t\tif (parseFlags & kParseInsituFlag) {\n\t\t\t\t\tsize_t length = s.PutEnd(head);\n\t\t\t\t\tRAPIDJSON_ASSERT(length <= 0xFFFFFFFF);\n\t\t\t\t\tRAPIDJSON_PUT('\\0');\t// null-terminate the string\n\t\t\t\t\thandler.String(head, SizeType(length), false);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tRAPIDJSON_PUT('\\0');\n\t\t\t\t\thandler.String(stack_.template Pop<Ch>(len), len - 1, true);\n\t\t\t\t}\n\t\t\t\tstream = s;\t// restore stream\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (c == '\\0') {\n\t\t\t\tRAPIDJSON_PARSE_ERROR(\"lacks ending quotation before the end of string\", stream.Tell() - 1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if ((unsigned)c < 0x20) {\t// RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF\n\t\t\t\tRAPIDJSON_PARSE_ERROR(\"Incorrect unescaped character in string\", stream.Tell() - 1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t\tRAPIDJSON_PUT(c);\t// Normal character, just copy\n\t\t}\n#undef RAPIDJSON_PUT\n\t}\n\n\ttemplate<unsigned parseFlags, typename Stream, typename Handler>\n\tvoid ParseNumber(Stream& stream, Handler& handler) {\n\t\tStream s = stream; // Local copy for optimization\n\t\t// Parse minus\n\t\tbool minus = false;\n\t\tif (s.Peek() == '-') {\n\t\t\tminus = true;\n\t\t\ts.Take();\n\t\t}\n\n\t\t// Parse int: zero / ( digit1-9 *DIGIT )\n\t\tunsigned i;\n\t\tbool try64bit = false;\n\t\tif (s.Peek() == '0') {\n\t\t\ti = 0;\n\t\t\ts.Take();\n\t\t}\n\t\telse if (s.Peek() >= '1' && s.Peek() <= '9') {\n\t\t\ti = s.Take() - '0';\n\n\t\t\tif (minus)\n\t\t\t\twhile (s.Peek() >= '0' && s.Peek() <= '9') {\n\t\t\t\t\tif (i >= 214748364) { // 2^31 = 2147483648\n\t\t\t\t\t\tif (i != 214748364 || s.Peek() > '8') {\n\t\t\t\t\t\t\ttry64bit = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ti = i * 10 + (s.Take() - '0');\n\t\t\t\t}\n\t\t\telse\n\t\t\t\twhile (s.Peek() >= '0' && s.Peek() <= '9') {\n\t\t\t\t\tif (i >= 429496729) { // 2^32 - 1 = 4294967295\n\t\t\t\t\t\tif (i != 429496729 || s.Peek() > '5') {\n\t\t\t\t\t\t\ttry64bit = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ti = i * 10 + (s.Take() - '0');\n\t\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tRAPIDJSON_PARSE_ERROR(\"Expect a value here.\", stream.Tell());\n\t\t\treturn;\n\t\t}\n\n\t\t// Parse 64bit int\n\t\tuint64_t i64 = 0;\n\t\tbool useDouble = false;\n\t\tif (try64bit) {\n\t\t\ti64 = i;\n\t\t\tif (minus) \n\t\t\t\twhile (s.Peek() >= '0' && s.Peek() <= '9') {\t\t\t\t\t\n\t\t\t\t\tif (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808\n\t\t\t\t\t\tif (i64 != 922337203685477580uLL || s.Peek() > '8') {\n\t\t\t\t\t\t\tuseDouble = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\ti64 = i64 * 10 + (s.Take() - '0');\n\t\t\t\t}\n\t\t\telse\n\t\t\t\twhile (s.Peek() >= '0' && s.Peek() <= '9') {\t\t\t\t\t\n\t\t\t\t\tif (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615\n\t\t\t\t\t\tif (i64 != 1844674407370955161uLL || s.Peek() > '5') {\n\t\t\t\t\t\t\tuseDouble = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\ti64 = i64 * 10 + (s.Take() - '0');\n\t\t\t\t}\n\t\t}\n\n\t\t// Force double for big integer\n\t\tdouble d = 0.0;\n\t\tif (useDouble) {\n\t\t\td = (double)i64;\n\t\t\twhile (s.Peek() >= '0' && s.Peek() <= '9') {\n\t\t\t\tif (d >= 1E307) {\n\t\t\t\t\tRAPIDJSON_PARSE_ERROR(\"Number too big to store in double\", stream.Tell());\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\td = d * 10 + (s.Take() - '0');\n\t\t\t}\n\t\t}\n\n\t\t// Parse frac = decimal-point 1*DIGIT\n\t\tint expFrac = 0;\n\t\tif (s.Peek() == '.') {\n\t\t\tif (!useDouble) {\n\t\t\t\td = try64bit ? (double)i64 : (double)i;\n\t\t\t\tuseDouble = true;\n\t\t\t}\n\t\t\ts.Take();\n\n\t\t\tif (s.Peek() >= '0' && s.Peek() <= '9') {\n\t\t\t\td = d * 10 + (s.Take() - '0');\n\t\t\t\t--expFrac;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tRAPIDJSON_PARSE_ERROR(\"At least one digit in fraction part\", stream.Tell());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twhile (s.Peek() >= '0' && s.Peek() <= '9') {\n\t\t\t\tif (expFrac > -16) {\n\t\t\t\t\td = d * 10 + (s.Peek() - '0');\n\t\t\t\t\t--expFrac;\n\t\t\t\t}\n\t\t\t\ts.Take();\n\t\t\t}\n\t\t}\n\n\t\t// Parse exp = e [ minus / plus ] 1*DIGIT\n\t\tint exp = 0;\n\t\tif (s.Peek() == 'e' || s.Peek() == 'E') {\n\t\t\tif (!useDouble) {\n\t\t\t\td = try64bit ? (double)i64 : (double)i;\n\t\t\t\tuseDouble = true;\n\t\t\t}\n\t\t\ts.Take();\n\n\t\t\tbool expMinus = false;\n\t\t\tif (s.Peek() == '+')\n\t\t\t\ts.Take();\n\t\t\telse if (s.Peek() == '-') {\n\t\t\t\ts.Take();\n\t\t\t\texpMinus = true;\n\t\t\t}\n\n\t\t\tif (s.Peek() >= '0' && s.Peek() <= '9') {\n\t\t\t\texp = s.Take() - '0';\n\t\t\t\twhile (s.Peek() >= '0' && s.Peek() <= '9') {\n\t\t\t\t\texp = exp * 10 + (s.Take() - '0');\n\t\t\t\t\tif (exp > 308) {\n\t\t\t\t\t\tRAPIDJSON_PARSE_ERROR(\"Number too big to store in double\", stream.Tell());\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tRAPIDJSON_PARSE_ERROR(\"At least one digit in exponent\", s.Tell());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (expMinus)\n\t\t\t\texp = -exp;\n\t\t}\n\n\t\t// Finish parsing, call event according to the type of number.\n\t\tif (useDouble) {\n\t\t\td *= internal::Pow10(exp + expFrac);\n\t\t\thandler.Double(minus ? -d : d);\n\t\t}\n\t\telse {\n\t\t\tif (try64bit) {\n\t\t\t\tif (minus)\n\t\t\t\t\thandler.Int64(-(int64_t)i64);\n\t\t\t\telse\n\t\t\t\t\thandler.Uint64(i64);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (minus)\n\t\t\t\t\thandler.Int(-(int)i);\n\t\t\t\telse\n\t\t\t\t\thandler.Uint(i);\n\t\t\t}\n\t\t}\n\n\t\tstream = s; // restore stream\n\t}\n\n\t// Parse any JSON value\n\ttemplate<unsigned parseFlags, typename Stream, typename Handler>\n\tvoid ParseValue(Stream& stream, Handler& handler) {\n\t\tswitch (stream.Peek()) {\n\t\t\tcase 'n': ParseNull  <parseFlags>(stream, handler); break;\n\t\t\tcase 't': ParseTrue  <parseFlags>(stream, handler); break;\n\t\t\tcase 'f': ParseFalse <parseFlags>(stream, handler); break;\n\t\t\tcase '\"': ParseString<parseFlags>(stream, handler); break;\n\t\t\tcase '{': ParseObject<parseFlags>(stream, handler); break;\n\t\t\tcase '[': ParseArray <parseFlags>(stream, handler); break;\n\t\t\tdefault : ParseNumber<parseFlags>(stream, handler);\n\t\t}\n\t}\n\n\tstatic const size_t kDefaultStackCapacity = 256;\t//!< Default stack capacity in bytes for storing a single decoded string. \n\tinternal::Stack<Allocator> stack_;\t//!< A stack for storing decoded string temporarily during non-destructive parsing.\n\tjmp_buf jmpbuf_;\t\t\t\t\t//!< setjmp buffer for fast exit from nested parsing function calls.\n\tconst char* parseError_;\n\tsize_t errorOffset_;\n}; // class GenericReader\n\n//! Reader with UTF8 encoding and default allocator.\ntypedef GenericReader<UTF8<> > Reader;\n\n} // namespace rapidjson\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n#endif // RAPIDJSON_READER_H_\n"
  },
  {
    "path": "BOSS/source/rapidjson/stringbuffer.h",
    "content": "#ifndef RAPIDJSON_STRINGBUFFER_H_\n#define RAPIDJSON_STRINGBUFFER_H_\n\n#include \"rapidjson.h\"\n#include \"internal/stack.h\"\n\nnamespace rapidjson {\n\n//! Represents an in-memory output stream.\n/*!\n \\tparam Encoding Encoding of the stream.\n \\tparam Allocator type for allocating memory buffer.\n \\implements Stream\n*/\ntemplate <typename Encoding, typename Allocator = CrtAllocator>\nstruct GenericStringBuffer {\n typedef typename Encoding::Ch Ch;\n\n GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}\n\n void Put(Ch c) { *stack_.template Push<Ch>() = c; }\n\n void Clear() { stack_.Clear(); }\n\n const char* GetString() const {\n  // Push and pop a null terminator. This is safe.\n  *stack_.template Push<Ch>() = '\\0';\n  stack_.template Pop<Ch>(1);\n\n  return stack_.template Bottom<Ch>();\n }\n\n size_t Size() const { return stack_.GetSize(); }\n\n static const size_t kDefaultCapacity = 256;\n mutable internal::Stack<Allocator> stack_;\n};\n\ntypedef GenericStringBuffer<UTF8<> > StringBuffer;\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {\n memset(stream.stack_.Push<char>(n), c, n * sizeof(c));\n}\n\n} // namespace rapidjson\n\n#endif // RAPIDJSON_STRINGBUFFER_H_\n"
  },
  {
    "path": "BOSS/source/rapidjson/writer.h",
    "content": "#include \"../Common.h\"\n#ifdef MCDS_FLASH_VERSION\n    #pragma GCC system_header\n#endif\n\n#ifndef RAPIDJSON_WRITER_H_\n#define RAPIDJSON_WRITER_H_\n\n#include \"rapidjson.h\"\n#include \"internal/stack.h\"\n#include \"internal/strfunc.h\"\n#include <cstdio> // snprintf() or _sprintf_s()\n#include <new>  // placement new\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4127) // conditional expression is constant\n#endif\n\nnamespace rapidjson {\n\n//! JSON writer\n/*! Writer implements the concept Handler.\n It generates JSON text by events to an output stream.\n\n User may programmatically calls the functions of a writer to generate JSON text.\n\n On the other side, a writer can also be passed to objects that generates events, \n\n for example Reader::Parse() and Document::Accept().\n\n \\tparam Stream Type of ouptut stream.\n \\tparam Encoding Encoding of both source strings and output.\n \\implements Handler\n*/\ntemplate<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >\nclass Writer {\npublic:\n typedef typename Encoding::Ch Ch;\n\n Writer(Stream& stream, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : \n  stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level)) {}\n\n //@name Implementation of Handler\n //@{\n Writer& Null()     { Prefix(kNullType);   WriteNull();   return *this; }\n Writer& Bool(bool b)   { Prefix(b ? kTrueType : kFalseType); WriteBool(b); return *this; }\n Writer& Int(int i)    { Prefix(kNumberType); WriteInt(i);   return *this; }\n Writer& Uint(unsigned u)  { Prefix(kNumberType); WriteUint(u);  return *this; }\n Writer& Int64(int64_t i64)  { Prefix(kNumberType); WriteInt64(i64);  return *this; }\n Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; }\n Writer& Double(double d)  { Prefix(kNumberType); WriteDouble(d);  return *this; }\n\n Writer& String(const Ch* str, SizeType length, bool copy = false) {\n  (void)copy;\n  Prefix(kStringType);\n  WriteString(str, length);\n  return *this;\n }\n\n Writer& StartObject() {\n  Prefix(kObjectType);\n  new (level_stack_.template Push<Level>()) Level(false);\n  WriteStartObject();\n  return *this;\n }\n\n Writer& EndObject(SizeType memberCount = 0) {\n  (void)memberCount;\n  RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));\n  RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);\n  level_stack_.template Pop<Level>(1);\n  WriteEndObject();\n  return *this;\n }\n\n Writer& StartArray() {\n  Prefix(kArrayType);\n  new (level_stack_.template Push<Level>()) Level(true);\n  WriteStartArray();\n  return *this;\n }\n\n Writer& EndArray(SizeType elementCount = 0) {\n  (void)elementCount;\n  RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));\n  RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);\n  level_stack_.template Pop<Level>(1);\n  WriteEndArray();\n  return *this;\n }\n //@}\n\n //! Simpler but slower overload.\n Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); }\n\nprotected:\n //! Information for each nested level\n struct Level {\n  Level(bool inArray_) : inArray(inArray_), valueCount(0) {}\n  bool inArray;  //!< true if in array, otherwise in object\n  size_t valueCount; //!< number of values in this level\n };\n\n static const size_t kDefaultLevelDepth = 32;\n\n void WriteNull()  {\n  stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l');\n }\n\n void WriteBool(bool b)  {\n  if (b) {\n   stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e');\n  }\n  else {\n   stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e');\n  }\n }\n\n void WriteInt(int i) {\n  if (i < 0) {\n   stream_.Put('-');\n   i = -i;\n  }\n  WriteUint((unsigned)i);\n }\n\n void WriteUint(unsigned u) {\n  char buffer[10];\n  char *p = buffer;\n  do {\n   *p++ = (u % 10) + '0';\n   u /= 10;\n  } while (u > 0);\n\n  do {\n   --p;\n   stream_.Put(*p);\n  } while (p != buffer);\n }\n\n void WriteInt64(int64_t i64) {\n  if (i64 < 0) {\n   stream_.Put('-');\n   i64 = -i64;\n  }\n  WriteUint64((uint64_t)i64);\n }\n\n void WriteUint64(uint64_t u64) {\n  char buffer[20];\n  char *p = buffer;\n  do {\n   *p++ = char(u64 % 10) + '0';\n   u64 /= 10;\n  } while (u64 > 0);\n\n  do {\n   --p;\n   stream_.Put(*p);\n  } while (p != buffer);\n }\n\n //! \\todo Optimization with custom double-to-string converter.\n void WriteDouble(double d) {\n  char buffer[100];\n#if _MSC_VER\n  int ret = sprintf_s(buffer, sizeof(buffer), \"%g\", d);\n#else\n  int ret = snprintf(buffer, sizeof(buffer), \"%g\", d);\n#endif\n  RAPIDJSON_ASSERT(ret >= 1);\n  for (int i = 0; i < ret; i++)\n   stream_.Put(buffer[i]);\n }\n\n void WriteString(const Ch* str, SizeType length)  {\n  static const char hexDigits[] = \"0123456789ABCDEF\";\n  static const char escape[256] = {\n#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n   //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F\n   'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00\n   'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10\n     0,   0, '\"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20\n   Z16, Z16,                  // 30~4F\n     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\\\',   0,   0,   0, // 50\n   Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16        // 60~FF\n#undef Z16\n  };\n\n  stream_.Put('\\\"');\n  for (const Ch* p = str; p != str + length; ++p) {\n   if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p])  {\n    stream_.Put('\\\\');\n    stream_.Put(escape[(unsigned char)*p]);\n    if (escape[(unsigned char)*p] == 'u') {\n     stream_.Put('0');\n     stream_.Put('0');\n     stream_.Put(hexDigits[(*p) >> 4]);\n     stream_.Put(hexDigits[(*p) & 0xF]);\n    }\n   }\n   else\n    stream_.Put(*p);\n  }\n  stream_.Put('\\\"');\n }\n\n void WriteStartObject() { stream_.Put('{'); }\n void WriteEndObject() { stream_.Put('}'); }\n void WriteStartArray() { stream_.Put('['); }\n void WriteEndArray() { stream_.Put(']'); }\n\n void Prefix(Type type) {\n  (void)type;\n  if (level_stack_.GetSize() != 0) { // this value is not at root\n   Level* level = level_stack_.template Top<Level>();\n   if (level->valueCount > 0) {\n    if (level->inArray) \n     stream_.Put(','); // add comma if it is not the first element in array\n    else  // in object\n     stream_.Put((level->valueCount % 2 == 0) ? ',' : ':');\n   }\n   if (!level->inArray && level->valueCount % 2 == 0)\n    RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name\n   level->valueCount++;\n  }\n  else\n   RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);\n }\n\n Stream& stream_;\n internal::Stack<Allocator> level_stack_;\n\nprivate:\n // Prohibit assignment for VC C4512 warning\n Writer& operator=(const Writer& w);\n};\n\n} // namespace rapidjson\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "License.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 David Churchill\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "**UAlbertaBot** - StarCraft AI Competition Bot - David Churchill (dave.churchill@gmail.com)\n\n**Update: 2021**\n- UAlbertaBot is not being actively maintained since early 2021\n\n**Update: Feb 28, 2020**\n- UAlbertaBot now uses VS2019\n- UAlbertaBot now uses BWAPI 4.4.0. To get it to compile, you have to compile BWAPI.lib and BWAPIClient.lib with VS2019 and put them in the BWAPI_INSTALL_DIR/lib/ folder\n- UAlbertaBot no longer uses BWTA - it is replaced with the custom BaseLocationManager from CommandCenter\n- UAlbertaBot now uses the Client .exe compilation method instead of module DLL\n- The bot will only work for the first game played after the .exe is run, so AUTO_RESTART won't work well. I'll fix this later\n- You can download StarCraft 1.16.1 here: http://ftp.blizzard.com/pub/broodwar/patches/PC/BW-1161.exe\n\nPlease check out the [Wiki](https://github.com/davechurchill/ualbertabot/wiki) for full instructions and documentation!\n\nNOTE: If you're looking for a StarCraft II bot please check out [CommandCenter](https://github.com/davechurchill/commandcenter/)\n"
  },
  {
    "path": "SparCraft/.gitignore",
    "content": "VisualStudio/Release\nVisualStudio/Debug\nbin/SparCraft\nbin/*.txt\nbin/*.pdb\nbin/*.map\nbin/*.dll\nbin/*.exe\nsource/*.o\n"
  },
  {
    "path": "SparCraft/LINUX_HOW_TO_COMPILE.txt",
    "content": "Compilation Instructions:\n\n1. Install the required libraries\n\nlibsdl2-dev\nlibsdl2-image-dev\n\n2. Clone the BWAPI github repository somewhere on your system\n\ngit clone https://github.com/bwapi/bwapi.git\n\n3. Edit the Makefile to point to the directory that you cloned BWAPI\n\nBWAPI_DIR=/where_you_cloned_to/bwapi/bwapi  (yes, bwapi/bwapi)\n\n4. If your BWAPI_DIR doesn't contain the file svnrev.h, you need to generate it using the vbs script in that dir\n   (note: this may have to be done in windows, but you can just copy the generated .h files to Linux and it will work)\n\n5. Run 'make' in the SparCraft directory, the binary will go to the 'SparCraft/bin' directory\n\n6. cd to 'SparCraft/bin' and run './SparCraft ../sample_experiment/sample_exp.txt'\n\nEnjoy!\n"
  },
  {
    "path": "SparCraft/Makefile",
    "content": "CC=g++\nBWAPI_DIR=/home/dave/facebook/bwapi/bwapi\nSDL_LDFLAGS=`sdl2-config --libs` \nSDL_CFLAGS=`sdl2-config --cflags` \nCFLAGS=-O3 -std=c++11 $(SDL_CFLAGS)\nLDFLAGS=-lGL -lGLU -lSDL2_image $(SDL_LDFLAGS)\nINCLUDES=-I$(BWAPI_DIR)/include -I$(BWAPI_DIR)/include/BWAPI -I$(BWAPI_DIR)\nSOURCES=$(wildcard $(BWAPI_DIR)/BWAPILIB/Source/*.cpp) $(wildcard $(BWAPI_DIR)/BWAPILIB/*.cpp) $(wildcard source/*.cpp) $(wildcard source/main/*.cpp) $(wildcard source/gui/*.cpp)\nOBJECTS=$(SOURCES:.cpp=.o)\n\nall:SparCraft \n\nSparCraft:$(OBJECTS) \n\t$(CC) $(OBJECTS) -o bin/$@  $(LDFLAGS)\n\n.cpp.o:\n\t$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@ \n.cc.o:\n\t$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@\n"
  },
  {
    "path": "SparCraft/README.txt",
    "content": "SparCraft - 2013\nDavid Churchill - dave.churchill@gmail.com\n\n\nFor documentation please visit:\n\nhttps://code.google.com/p/sparcraft/\n\n"
  },
  {
    "path": "SparCraft/VisualStudio/SparCraft.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 2013\nVisualStudioVersion = 12.0.31101.0\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SparCraft\", \"SparCraft.vcxproj\", \"{66236439-5968-4756-B2E7-8A29BEA99078}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SparCraft_main\", \"SparCraft_main.vcxproj\", \"{82E61B13-7AC5-447E-AD88-96D04D881F58}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078} = {66236439-5968-4756-B2E7-8A29BEA99078}\n\tEndProjectSection\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Win32 = Debug|Win32\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|Win32 = Release|Win32\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Debug|x64.Build.0 = Debug|x64\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Release|Win32.Build.0 = Release|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Release|x64.ActiveCfg = Release|x64\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Release|x64.Build.0 = Release|x64\n\t\t{82E61B13-7AC5-447E-AD88-96D04D881F58}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{82E61B13-7AC5-447E-AD88-96D04D881F58}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{82E61B13-7AC5-447E-AD88-96D04D881F58}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{82E61B13-7AC5-447E-AD88-96D04D881F58}.Debug|x64.Build.0 = Debug|x64\n\t\t{82E61B13-7AC5-447E-AD88-96D04D881F58}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{82E61B13-7AC5-447E-AD88-96D04D881F58}.Release|Win32.Build.0 = Release|Win32\n\t\t{82E61B13-7AC5-447E-AD88-96D04D881F58}.Release|x64.ActiveCfg = Release|x64\n\t\t{82E61B13-7AC5-447E-AD88-96D04D881F58}.Release|x64.Build.0 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "SparCraft/VisualStudio/SparCraft.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{66236439-5968-4756-B2E7-8A29BEA99078}</ProjectGuid>\n    <RootNamespace>StarcraftBuildOrderSearch</RootNamespace>\n    <Keyword>Win32Proj</Keyword>\n    <VCTargetsPath Condition=\"'$(VCTargetsPath11)' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''\">$(VCTargetsPath11)</VCTargetsPath>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v142</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v142</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <PlatformToolset>v110</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <PlatformToolset>v110</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</IntDir>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">true</LinkIncremental>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</IntDir>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</LinkIncremental>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <TargetName>$(ProjectName)_d</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>$(BWAPI_DIR)/lib/BWAPId.lib;$(EXTERNAL_LIB_DIR)/SDL.lib;$(EXTERNAL_LIB_DIR)/SDLmain.lib;$(EXTERNAL_LIB_DIR)/opengl32.lib;$(EXTERNAL_LIB_DIR)/SDL_image.lib;$(EXTERNAL_LIB_DIR)/SDL_gfx.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <TargetMachine>MachineX86</TargetMachine>\n      <AdditionalOptions>/NODEFAULTLIB:msvcrt.lib %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <Optimization>Full</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;NOMINMAX;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <OmitFramePointers>true</OmitFramePointers>\n      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>\n      <ExceptionHandling>Sync</ExceptionHandling>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>$(BWAPI_DIR)/lib/BWAPI.lib;$(EXTERNAL_LIB_DIR)/SDL.lib;$(EXTERNAL_LIB_DIR)/SDLmain.lib;$(EXTERNAL_LIB_DIR)/opengl32.lib;$(EXTERNAL_LIB_DIR)/SDL_image.lib;$(EXTERNAL_LIB_DIR)/SDL_gfx.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <TargetMachine>MachineX86</TargetMachine>\n      <Profile>true</Profile>\n      <GenerateMapFile>true</GenerateMapFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\source\\Action.h\" />\n    <ClInclude Include=\"..\\source\\AllPlayers.h\" />\n    <ClInclude Include=\"..\\source\\AlphaBetaMove.h\" />\n    <ClInclude Include=\"..\\source\\AlphaBetaSearch.h\" />\n    <ClInclude Include=\"..\\source\\AlphaBetaSearchParameters.hpp\" />\n    <ClInclude Include=\"..\\source\\AlphaBetaSearchResults.hpp\" />\n    <ClInclude Include=\"..\\source\\AnimationFrameData.h\" />\n    <ClInclude Include=\"..\\source\\BaseTypes.hpp\" />\n    <ClInclude Include=\"..\\source\\EnumData.h\" />\n    <ClInclude Include=\"..\\source\\Game.h\" />\n    <ClInclude Include=\"..\\source\\GameState.h\" />\n    <ClInclude Include=\"..\\source\\GraphViz.hpp\" />\n    <ClInclude Include=\"..\\source\\Hash.h\" />\n    <ClInclude Include=\"..\\source\\Logger.h\" />\n    <ClInclude Include=\"..\\source\\Map.hpp\" />\n    <ClInclude Include=\"..\\source\\MoveArray.h\" />\n    <ClInclude Include=\"..\\source\\Player.h\" />\n    <ClInclude Include=\"..\\source\\PlayerProperties.h\" />\n    <ClInclude Include=\"..\\source\\Player_AlphaBeta.h\" />\n    <ClInclude Include=\"..\\source\\Player_AttackClosest.h\" />\n    <ClInclude Include=\"..\\source\\Player_AttackDPS.h\" />\n    <ClInclude Include=\"..\\source\\Player_AttackWeakest.h\" />\n    <ClInclude Include=\"..\\source\\Player_Cluster.h\" />\n    <ClInclude Include=\"..\\source\\Player_Kiter.h\" />\n    <ClInclude Include=\"..\\source\\Player_KiterDPS.h\" />\n    <ClInclude Include=\"..\\source\\Player_Kiter_NOKDPS.h\" />\n    <ClInclude Include=\"..\\source\\Player_NOKDPS.h\" />\n    <ClInclude Include=\"..\\source\\Player_PortfolioGreedySearch.h\" />\n    <ClInclude Include=\"..\\source\\Player_Random.h\" />\n    <ClInclude Include=\"..\\source\\Player_UCT.h\" />\n    <ClInclude Include=\"..\\source\\PortfolioGreedySearch.h\" />\n    <ClInclude Include=\"..\\source\\Random.hpp\" />\n    <ClInclude Include=\"..\\source\\Common.h\" />\n    <ClInclude Include=\"..\\source\\Position.hpp\" />\n    <ClInclude Include=\"..\\source\\SparCraft.h\" />\n    <ClInclude Include=\"..\\source\\SparCraftAssert.h\" />\n    <ClInclude Include=\"..\\source\\SparCraftException.h\" />\n    <ClInclude Include=\"..\\source\\Timer.h\" />\n    <ClInclude Include=\"..\\source\\TranspositionTable.h\" />\n    <ClInclude Include=\"..\\source\\UCTMemoryPool.hpp\" />\n    <ClInclude Include=\"..\\source\\UCTNode.h\" />\n    <ClInclude Include=\"..\\source\\UCTSearch.h\" />\n    <ClInclude Include=\"..\\source\\UCTSearchParameters.hpp\" />\n    <ClInclude Include=\"..\\source\\UCTSearchResults.hpp\" />\n    <ClInclude Include=\"..\\source\\Unit.h\" />\n    <ClInclude Include=\"..\\source\\Array.hpp\" />\n    <ClInclude Include=\"..\\source\\UnitProperties.h\" />\n    <ClInclude Include=\"..\\source\\UnitScriptData.h\" />\n    <ClInclude Include=\"..\\source\\WeaponProperties.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\source\\Action.cpp\" />\n    <ClCompile Include=\"..\\source\\AllPlayers.cpp\" />\n    <ClCompile Include=\"..\\source\\AlphaBetaMove.cpp\" />\n    <ClCompile Include=\"..\\source\\AlphaBetaSearch.cpp\" />\n    <ClCompile Include=\"..\\source\\AnimationFrameData.cpp\" />\n    <ClCompile Include=\"..\\source\\Common.cpp\" />\n    <ClCompile Include=\"..\\source\\EnumData.cpp\" />\n    <ClCompile Include=\"..\\source\\Game.cpp\" />\n    <ClCompile Include=\"..\\source\\GameState.cpp\" />\n    <ClCompile Include=\"..\\source\\Hash.cpp\" />\n    <ClCompile Include=\"..\\source\\Logger.cpp\" />\n    <ClCompile Include=\"..\\source\\MoveArray.cpp\" />\n    <ClCompile Include=\"..\\source\\Player.cpp\" />\n    <ClCompile Include=\"..\\source\\PlayerProperties.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_AlphaBeta.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_AttackClosest.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_AttackDPS.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_AttackWeakest.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_Cluster.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_Kiter.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_KiterDPS.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_Kiter_NOKDPS.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_NOKDPS.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_PortfolioGreedySearch.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_Random.cpp\" />\n    <ClCompile Include=\"..\\source\\Player_UCT.cpp\" />\n    <ClCompile Include=\"..\\source\\PortfolioGreedySearch.cpp\" />\n    <ClCompile Include=\"..\\source\\SparCraft.cpp\" />\n    <ClCompile Include=\"..\\source\\SparCraftAssert.cpp\" />\n    <ClCompile Include=\"..\\source\\SparCraftException.cpp\" />\n    <ClCompile Include=\"..\\source\\Timer.cpp\" />\n    <ClCompile Include=\"..\\source\\TranspositionTable.cpp\" />\n    <ClCompile Include=\"..\\source\\UCTSearch.cpp\" />\n    <ClCompile Include=\"..\\source\\Unit.cpp\" />\n    <ClCompile Include=\"..\\source\\UnitProperties.cpp\" />\n    <ClCompile Include=\"..\\source\\UnitScriptData.cpp\" />\n    <ClCompile Include=\"..\\source\\WeaponProperties.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "SparCraft/VisualStudio/SparCraft.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\source\\AlphaBetaSearch.cpp\">\n      <Filter>search\\AlphaBeta</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Common.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Game.cpp\">\n      <Filter>simulation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\GameState.cpp\">\n      <Filter>simulation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Hash.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\PortfolioGreedySearch.cpp\">\n      <Filter>search\\Greedy</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Timer.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\TranspositionTable.cpp\">\n      <Filter>search\\AlphaBeta</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\UCTSearch.cpp\">\n      <Filter>search\\UCT</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\UnitScriptData.cpp\">\n      <Filter>search\\Greedy</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player.cpp\">\n      <Filter>simulation\\players</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_AlphaBeta.cpp\">\n      <Filter>simulation\\players\\search</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_AttackDPS.cpp\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_AttackWeakest.cpp\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_Kiter.cpp\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_KiterDPS.cpp\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_NOKDPS.cpp\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_AttackClosest.cpp\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_PortfolioGreedySearch.cpp\">\n      <Filter>simulation\\players\\search</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_Random.cpp\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_UCT.cpp\">\n      <Filter>simulation\\players\\search</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\AllPlayers.cpp\">\n      <Filter>simulation\\players</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\MoveArray.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_Cluster.cpp\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Player_Kiter_NOKDPS.cpp\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Unit.cpp\">\n      <Filter>simulation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\UnitProperties.cpp\">\n      <Filter>simulation\\properties</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\WeaponProperties.cpp\">\n      <Filter>simulation\\properties</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\PlayerProperties.cpp\">\n      <Filter>simulation\\properties</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\SparCraft.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\EnumData.cpp\">\n      <Filter>data</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\AnimationFrameData.cpp\">\n      <Filter>data</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Logger.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\Action.cpp\">\n      <Filter>simulation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\AlphaBetaMove.cpp\">\n      <Filter>search\\AlphaBeta</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\SparCraftAssert.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\SparCraftException.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\source\\AlphaBetaSearch.h\">\n      <Filter>search\\AlphaBeta</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\AlphaBetaSearchResults.hpp\">\n      <Filter>search\\AlphaBeta</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BaseTypes.hpp\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Common.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Array.hpp\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Game.h\">\n      <Filter>simulation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\GameState.h\">\n      <Filter>simulation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Hash.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\PortfolioGreedySearch.h\">\n      <Filter>search\\Greedy</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Position.hpp\">\n      <Filter>simulation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Timer.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\TranspositionTable.h\">\n      <Filter>search\\AlphaBeta</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\UCTNode.h\">\n      <Filter>search\\UCT</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\UCTSearch.h\">\n      <Filter>search\\UCT</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\UnitScriptData.h\">\n      <Filter>search\\Greedy</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\GraphViz.hpp\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player.h\">\n      <Filter>simulation\\players</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_AlphaBeta.h\">\n      <Filter>simulation\\players\\search</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_AttackClosest.h\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_AttackDPS.h\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_AttackWeakest.h\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_Kiter.h\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_KiterDPS.h\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_NOKDPS.h\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_PortfolioGreedySearch.h\">\n      <Filter>simulation\\players\\search</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_Random.h\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_UCT.h\">\n      <Filter>simulation\\players\\search</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\UCTMemoryPool.hpp\">\n      <Filter>search\\UCT</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\UCTSearchResults.hpp\">\n      <Filter>search\\UCT</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\UCTSearchParameters.hpp\">\n      <Filter>search\\UCT</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\AlphaBetaSearchParameters.hpp\">\n      <Filter>search\\AlphaBeta</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\AllPlayers.h\">\n      <Filter>simulation\\players</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\MoveArray.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_Cluster.h\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Player_Kiter_NOKDPS.h\">\n      <Filter>simulation\\players\\script</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Unit.h\">\n      <Filter>simulation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Map.hpp\">\n      <Filter>simulation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\UnitProperties.h\">\n      <Filter>simulation\\properties</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\WeaponProperties.h\">\n      <Filter>simulation\\properties</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\PlayerProperties.h\">\n      <Filter>simulation\\properties</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Random.hpp\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\SparCraft.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\EnumData.h\">\n      <Filter>data</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\AnimationFrameData.h\">\n      <Filter>data</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Logger.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\Action.h\">\n      <Filter>simulation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\AlphaBetaMove.h\">\n      <Filter>search\\AlphaBeta</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\SparCraftAssert.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\SparCraftException.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"util\">\n      <UniqueIdentifier>{6df7ca5f-a32b-4663-841c-e9c0167bef3b}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"search\">\n      <UniqueIdentifier>{448e8c8d-4efd-44ab-9ca4-3da61d3aa047}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"simulation\">\n      <UniqueIdentifier>{d817d60f-8a97-41a1-af70-0d73ee979248}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"search\\AlphaBeta\">\n      <UniqueIdentifier>{39cea388-a0ee-4dab-9c88-fc2c02a0d8c8}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"search\\Greedy\">\n      <UniqueIdentifier>{273d10ab-4a07-439d-9142-aaf654ae5feb}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"search\\UCT\">\n      <UniqueIdentifier>{5d28a734-3947-4ec3-9f52-b1259520d851}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"common\">\n      <UniqueIdentifier>{9aa7fe21-9e2a-421d-b8e6-1b132a0a0c23}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"simulation\\players\">\n      <UniqueIdentifier>{b11ab75e-596d-49f0-b7cd-18835583746c}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"simulation\\players\\script\">\n      <UniqueIdentifier>{4a52919d-1927-49f9-964b-4c447699227a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"simulation\\players\\search\">\n      <UniqueIdentifier>{736c4997-5d98-40e6-a72f-f9075810344b}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"simulation\\properties\">\n      <UniqueIdentifier>{2617c193-9e36-4c48-a76e-4ffcfee4093e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"data\">\n      <UniqueIdentifier>{c8b3aadc-390f-460b-af33-29a0570bb914}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "SparCraft/VisualStudio/SparCraft_main.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{82E61B13-7AC5-447E-AD88-96D04D881F58}</ProjectGuid>\n    <RootNamespace>StarcraftBuildOrderSearch</RootNamespace>\n    <Keyword>Win32Proj</Keyword>\n    <VCTargetsPath Condition=\"'$(VCTargetsPath11)' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''\">$(VCTargetsPath11)</VCTargetsPath>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <PlatformToolset>v110</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <PlatformToolset>v110</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)$(Configuration)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(Configuration)\\</IntDir>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">true</LinkIncremental>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">../bin/</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(Configuration)\\</IntDir>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</LinkIncremental>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <TargetName>SparCraft</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <TargetName>SparCraft</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>$(SDL_IMAGE_DIR)/include;$(SDL_DIR)/include;$(BWAPI_DIR)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>true</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>$(Configuration)/SparCraft/SparCraft_d.lib;$(BWAPI_DIR)/lib/BWAPId.lib;../lib/SDL2.lib;../lib/SDL2_image.lib;../lib/opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <TargetMachine>MachineX86</TargetMachine>\n      <AdditionalOptions>/NODEFAULTLIB:msvcrt.lib %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <Optimization>Full</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)\\include;$(SDL_DIR)\\include;$(SDL_IMAGE_DIR)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;NOMINMAX;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <OmitFramePointers>true</OmitFramePointers>\n      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>\n      <ExceptionHandling>Sync</ExceptionHandling>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>$(Configuration)/SparCraft/SparCraft.lib;$(BWAPI_DIR)/lib/BWAPI.lib;../lib/SDL2.lib;../lib/SDL2_image.lib;../lib/opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <TargetMachine>MachineX86</TargetMachine>\n      <Profile>true</Profile>\n      <GenerateMapFile>true</GenerateMapFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\source\\gui\\GUI.h\" />\n    <ClInclude Include=\"..\\source\\gui\\GUIGame.h\" />\n    <ClInclude Include=\"..\\source\\gui\\GUITools.h\" />\n    <ClInclude Include=\"..\\source\\main\\SearchExperiment.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\source\\gui\\GUI.cpp\" />\n    <ClCompile Include=\"..\\source\\gui\\GUIGame.cpp\" />\n    <ClCompile Include=\"..\\source\\gui\\GUITools.cpp\" />\n    <ClCompile Include=\"..\\source\\main\\main.cpp\" />\n    <ClCompile Include=\"..\\source\\main\\SearchExperiment.cpp\" />\n    <ClCompile Include=\"..\\source\\TutorialCode.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "SparCraft/VisualStudio/SparCraft_main.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\source\\TutorialCode.cpp\" />\n    <ClCompile Include=\"..\\source\\gui\\GUI.cpp\">\n      <Filter>gui</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\gui\\GUIGame.cpp\">\n      <Filter>gui</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\gui\\GUITools.cpp\">\n      <Filter>gui</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\main\\main.cpp\" />\n    <ClCompile Include=\"..\\source\\main\\SearchExperiment.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\source\\gui\\GUI.h\">\n      <Filter>gui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\gui\\GUIGame.h\">\n      <Filter>gui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\gui\\GUITools.h\">\n      <Filter>gui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\main\\SearchExperiment.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"gui\">\n      <UniqueIdentifier>{ceb05fc9-cc5d-4f5b-808d-c844862d2269}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "SparCraft/VisualStudio/bwapidata.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\bwapidata\\include\\AIModule.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Bitmap.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\BulletType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\BWAPI.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Color.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Common.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\DamageType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Error.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Event.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\ExplosionType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\GameType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Order.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\PlayerType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Position.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Race.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\TechType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\TilePosition.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\UnitCommandType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\UnitSizeType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\UnitType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\UpgradeType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\Exceptions.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\FileLogger.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\Logger.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\sha1.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\Strings.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\WeaponType.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\AIModule.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Bitmap.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Bullet.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\BulletType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\BulletData.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\BulletImpl.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\Client.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\Command.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\CommandType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\Event.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\ForceData.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\ForceImpl.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\GameData.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\GameImpl.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\PlayerData.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\PlayerImpl.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\Shape.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\ShapeType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\UnitCommand.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\UnitData.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\UnitImpl.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Color.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Constants.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\CoordinateType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\DamageType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Error.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Event.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\EventType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\ExplosionType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Flag.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Force.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Game.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\GameType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Input.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Latency.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Order.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Player.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\PlayerType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Position.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Race.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\TechType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\TilePosition.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Unit.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UnitCommand.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UnitCommandType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UnitSizeType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UnitType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UpgradeType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\WeaponType.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Common.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Bitmask.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Exceptions.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\FileLogger.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Foreach.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Gnu.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Logger.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\LogLevel.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\RectangleArray.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\RegionQuadTree.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\sha1.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Strings.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Types.h\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{F4605815-8200-4F83-9B2B-AFEA163518F1}</ProjectGuid>\n    <RootNamespace>StarcraftBuildOrderSearch</RootNamespace>\n    <Keyword>Win32Proj</Keyword>\n    <VCTargetsPath Condition=\"'$(VCTargetsPath11)' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''\">$(VCTargetsPath11)</VCTargetsPath>\n    <ProjectName>BWAPIData</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v110</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <PlatformToolset>v110</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <PlatformToolset>v110</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">../bwapidata/lib/</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(Configuration)\\</IntDir>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">true</LinkIncremental>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">../bwapidata/lib/</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(Configuration)\\</IntDir>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</LinkIncremental>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <TargetName>BWAPI</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <TargetName>BWAPId</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>../bwapidata/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>true</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <TargetMachine>MachineX86</TargetMachine>\n      <AdditionalOptions>/NODEFAULTLIB:msvcrt.lib %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <Optimization>Full</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>../bwapidata/include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;NOMINMAX;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <OmitFramePointers>true</OmitFramePointers>\n      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>\n      <ExceptionHandling>Sync</ExceptionHandling>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <TargetMachine>MachineX86</TargetMachine>\n      <Profile>true</Profile>\n      <GenerateMapFile>true</GenerateMapFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "SparCraft/VisualStudio/bwapidata.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Util\">\n      <UniqueIdentifier>{6d542422-cbf6-48e3-a42a-5b613dbfb27b}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"BWAPI\">\n      <UniqueIdentifier>{94969cc2-fa46-48b3-a799-699052395962}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"BWAPI\\Client\">\n      <UniqueIdentifier>{5bf7fa35-3dae-4e58-a8e6-676b0e724c48}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\bwapidata\\include\\AIModule.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Bitmap.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\BulletType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\BWAPI.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Color.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Common.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\DamageType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Error.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Event.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\ExplosionType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\GameType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Order.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\PlayerType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Position.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Race.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\TechType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\TilePosition.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\UnitCommandType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\UnitSizeType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\UnitType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\UpgradeType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\WeaponType.cpp\" />\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\Exceptions.cpp\">\n      <Filter>Util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\FileLogger.cpp\">\n      <Filter>Util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\Logger.cpp\">\n      <Filter>Util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\sha1.cpp\">\n      <Filter>Util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\bwapidata\\include\\Util\\Strings.cpp\">\n      <Filter>Util</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Common.h\" />\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Bitmask.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Exceptions.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\FileLogger.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Foreach.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Gnu.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Logger.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\LogLevel.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\RectangleArray.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\RegionQuadTree.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\sha1.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Strings.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\Util\\Types.h\">\n      <Filter>Util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\BulletData.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\BulletImpl.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\Client.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\Command.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\CommandType.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\Event.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\ForceData.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\ForceImpl.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\GameData.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\GameImpl.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\PlayerData.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\PlayerImpl.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\Shape.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\ShapeType.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\UnitCommand.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\UnitData.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client\\UnitImpl.h\">\n      <Filter>BWAPI\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\AIModule.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Bitmap.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Bullet.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\BulletType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Client.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Color.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Constants.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\CoordinateType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\DamageType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Error.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Event.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\EventType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\ExplosionType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Flag.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Force.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Game.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\GameType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Input.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Latency.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Order.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Player.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\PlayerType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Position.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Race.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\TechType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\TilePosition.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\Unit.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UnitCommand.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UnitCommandType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UnitSizeType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UnitType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\UpgradeType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\bwapidata\\include\\BWAPI\\WeaponType.h\">\n      <Filter>BWAPI</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "SparCraft/VisualStudio/set_environment_variables.bat",
    "content": "@echo off\necho Set SparCraft Windows Environment Variables\necho Please edit this file before running for the first time\n\npause\n\nsetx BWAPI_DIR %CD%\\bwapidata\nsetx BOOST_DIR C:\\libraries\\boost_1_53_0\nsetx EXTERNAL_LIB_DIR c:\\libraries\\external_lib_dir\nsetx SDL_DIR C:\\libraries\\SDL-1.2.15\nsetx SDL_IMAGE_DIR C:\\libraries\\SDL_image-1.2.12\nsetx SDL_GFX_DIR c:\\libraries\\SDL_gfx-2.0.23\n\npause"
  },
  {
    "path": "SparCraft/asset/images/command_icons/fix.bat",
    "content": "for %%f in (*.png) DO ( convert \"%%f\" -strip -resize 32x32! \"%%f\" )\n"
  },
  {
    "path": "SparCraft/asset/images/units/fix.bat",
    "content": "for %%f in (*.png) DO ( convert \"%%f\" -strip \"%%f\" )\n"
  },
  {
    "path": "SparCraft/bin/.gitkeep",
    "content": ""
  },
  {
    "path": "SparCraft/bwapidata/README.txt",
    "content": "bwapidata\n----------------\n\nThis is used to compile SparCraft in a linux environment without having to worry about reconfiguring BWAPI\n\nThis is a stripped-down version of BWAPI which contains only headers and .cpp files, without BWTA\n\nUsed with permission from Adam Heinermann of the BWAPI project:\n\nhttps://code.google.com/p/bwapi/"
  },
  {
    "path": "SparCraft/bwapidata/include/AIModule.cpp",
    "content": "#include <BWAPI/AIModule.h>\nnamespace BWAPI\n{\n  AIModule::AIModule()\n  { }\n  AIModule::~AIModule()\n  { }\n  void AIModule::onStart()\n  { }\n  void AIModule::onEnd(bool isWinner)\n  { }\n  void AIModule::onFrame()\n  { }\n  void AIModule::onSendText(std::string text)\n  { }\n  void AIModule::onReceiveText(Player* player, std::string text)\n  { }\n  void AIModule::onPlayerLeft(Player *player)\n  { }\n  void AIModule::onNukeDetect(Position target)\n  { }\n  void AIModule::onUnitDiscover(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitEvade(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitShow(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitHide(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitCreate(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitDestroy(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitMorph(BWAPI::Unit* unit)\n  { }\n  void AIModule::onUnitRenegade(BWAPI::Unit* unit)\n  { }\n  void AIModule::onSaveGame(std::string gameName)\n  { }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/AIModule.h",
    "content": "#pragma once\n#include <string>\n#include <BWAPI/Position.h>\nnamespace BWAPI\n{\n  class Unit;\n  class Player;\n\n  /** AIModule is a virtual class that is intended to be implemented or inherited by a custom AI class.\n   *\n   * \\note\n   * Using BWAPI in a different thread than the default one will produce unexpected results and possibly crash\n   * the program. Multi-threaded AIs are possible so long as all BWAPI interaction is limited to the default\n   * thread (during one of the call-backs). */\n  class AIModule\n  {\n    public:\n      AIModule();\n      virtual ~AIModule();\n\n      /** BWAPI calls this at the start of a match. Typically an AI will execute set up code in this method\n       * (initialize data structures, load build orders, etc). */\n      virtual void onStart();\n\n      /** BWAPI calls this at the end of the match. isWinner will be true if the AIModule won the game. If the\n       * game is a replay, isWinner will always be false. */\n      virtual void onEnd(bool isWinner);\n\n      /** BWAPI calls this on every logical frame in the game. */\n      virtual void onFrame();\n\n      /** If Flag::UserInput is enabled, BWAPI will call this each time a user enters a message into the chat.\n       * */\n      virtual void onSendText(std::string text);\n\n      /** BWAPI calls this when another player sends a message. */\n      virtual void onReceiveText(Player* player, std::string text);\n\n      /** BWAPI calls this when a player leaves the game. */\n      virtual void onPlayerLeft(Player* player);\n\n      /** BWAPI calls this when a nuclear launch has been detected. If the target position is visible, or if\n       * Complete Map Information is enabled, the target position will also be provided. If Complete Map\n       * Information is disabled and the target position is not visible, target will be set to\n       * Positions::Unknown. */\n      virtual void onNukeDetect(Position target);\n\n      /** BWAPI calls this when a unit becomes accessible. */\n      virtual void onUnitDiscover(Unit* unit);\n\n      /** BWAPI calls this when a unit becomes inaccessible. */\n      virtual void onUnitEvade(Unit* unit);\n\n      /** BWAPI calls this the instant a previously invisible unit becomes visible. The complete map\n       * information flag has no effect on this callback. */\n      virtual void onUnitShow(Unit* unit);\n\n      /** BWAPI calls this right before a unit becomes invisible, so if you want your non-cheating AI to\n       * remember where it last saw a unit, this callback would be a good place to implement it. The complete\n       * map information flag has no effect on this callback. */\n      virtual void onUnitHide(Unit* unit);\n\n      /** BWAPI calls this when a unit is created. Note that this is NOT called when a unit changes type\n       * (such as larva into egg or egg into drone). Building a refinery/assimilator/extractor will not\n       * produce an onUnitCreate call since the vespene geyser changes to the unit type of the\n       * refinery/assimilator/extractor. If Complete Map Information is enabled, this will also be called for\n       * new units that are hidden by the fog of war. If the unit is visible upon creation, onUnitShow will be\n       * called shortly after onUnitCreate is called. */\n      virtual void onUnitCreate(Unit* unit);\n\n      /** BWAPI calls this when a unit dies or otherwise removed from the game (i.e. a mined out mineral\n       * patch). When a zerg drone becomes an extractor, the Vespene geyser changes to the Zerg Extractor type\n       * and the drone is removed. If Complete Map Information is enabled, this will also be called for units\n       * that are hidden by the fog of war. If a unit that was visible gets destroyed, onUnitHide will be\n       * called right before onUnitDestroy is called. */\n      virtual void onUnitDestroy(Unit* unit);\n\n      /** BWAPI calls this when a unit changes type, such as from a Zerg Drone to a Zerg Hatchery, or from a\n       * Terran Siege Tank Tank Mode to Terran Siege Tank Siege Mode. This is not called when the type changes\n       * to or from UnitTypes::Unknown (which happens when a unit becomes visible or invisible). */\n      virtual void onUnitMorph(Unit* unit);\n\n      /** BWAPI calls this when an accessible unit changes ownership. */\n      virtual void onUnitRenegade(Unit* unit);\n\n      // TODO: Add Doxygen documentation\n      virtual void onSaveGame(std::string gameName);\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Bitmap.h",
    "content": "#include <BWAPI/Color.h>\n#pragma once\n\nnamespace BWAPI\n{\n  class BitmapProxy\n  {\n  public:\n    BitmapProxy(unsigned char *data, unsigned short width, unsigned short height, int x);\n    Color operator[](int y);\n  private:\n    unsigned char *data;\n    unsigned short width;\n    unsigned short height;\n    int x;\n  };\n\n  class Bitmap\n  {\n    public:\n      BitmapProxy operator[](int x);\n      unsigned short getWidth();\n      unsigned short getHeight();\n\n    private:\n      unsigned short wid;\n      unsigned short ht;\n      unsigned char  *data;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Bullet.h",
    "content": "#pragma once\n\n#include <BWAPI/BulletType.h>\n#include <BWAPI/Position.h>\n\nnamespace BWAPI\n{\n  class Player;\n  class Unit;\n  class Bullet\n  {\n    public:\n      virtual int getID() const = 0;\n      virtual Player* getPlayer() const = 0;\n      virtual BulletType getType() const = 0;\n      virtual Unit* getSource() const = 0;\n      virtual Position getPosition() const = 0;\n      virtual double getAngle() const = 0;\n      virtual double getVelocityX() const = 0;\n      virtual double getVelocityY() const = 0;\n      virtual Unit* getTarget() const = 0;\n      virtual Position getTargetPosition() const = 0;\n      virtual int getRemoveTimer() const = 0;\n      virtual bool exists() const = 0;\n      virtual bool isVisible() const = 0;\n      virtual bool isVisible(Player* player) const = 0;\n  };\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/BulletType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\n\nnamespace BWAPI\n{\n  class BulletType\n  {\n    public:\n      BulletType();\n      BulletType(int id);\n      BulletType(const BulletType& other);\n      BulletType& operator=(const BulletType& other);\n      bool operator==(const BulletType& other) const;\n      bool operator!=(const BulletType& other) const;\n      bool operator<(const BulletType& other) const;\n\n      /** Returns the unique ID for this bullet type. */\n      int getID() const;\n\n      /** Returns the name of this bullet type. */\n      std::string getName() const;\n    private:\n      int id;\n  };\n\n  namespace BulletTypes\n  {\n    /** Given the name of an bullet type, getBulletType() will return the corresponding BulletType object. */\n    BulletType getBulletType(std::string name);\n\n    /** Returns the set of all the BulletTypes. */\n    std::set<BulletType>& allBulletTypes();\n    void init();\n    extern const BulletType Melee;\n    extern const BulletType Fusion_Cutter_Hit;\n    extern const BulletType Gauss_Rifle_Hit;\n    extern const BulletType C_10_Canister_Rifle_Hit;\n    extern const BulletType Gemini_Missiles;\n    extern const BulletType Fragmentation_Grenade;\n    extern const BulletType Longbolt_Missile;\n    extern const BulletType ATS_ATA_Laser_Battery;\n    extern const BulletType Burst_Lasers;\n    extern const BulletType Arclite_Shock_Cannon_Hit;\n    extern const BulletType EMP_Missile;\n    extern const BulletType Dual_Photon_Blasters_Hit;\n    extern const BulletType Particle_Beam_Hit;\n    extern const BulletType Anti_Matter_Missile;\n    extern const BulletType Pulse_Cannon;\n    extern const BulletType Psionic_Shockwave_Hit;\n    extern const BulletType Psionic_Storm;\n    extern const BulletType Yamato_Gun;\n    extern const BulletType Phase_Disruptor;\n    extern const BulletType STA_STS_Cannon_Overlay;\n    extern const BulletType Sunken_Colony_Tentacle;\n    extern const BulletType Acid_Spore;\n    extern const BulletType Glave_Wurm;\n    extern const BulletType Seeker_Spores;\n    extern const BulletType Queen_Spell_Carrier;\n    extern const BulletType Plague_Cloud;\n    extern const BulletType Consume;\n    extern const BulletType Needle_Spine_Hit;\n    extern const BulletType Invisible;\n    extern const BulletType Optical_Flare_Grenade;\n    extern const BulletType Halo_Rockets;\n    extern const BulletType Subterranean_Spines;\n    extern const BulletType Corrosive_Acid_Shot;\n    extern const BulletType Neutron_Flare;\n    extern const BulletType None;\n    extern const BulletType Unknown;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/BulletData.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  struct BulletData\n  {\n    int id;\n    int player;\n    int type;\n    int source;\n    int positionX;\n    int positionY;\n    double angle;\n    double velocityX;\n    double velocityY;\n    int target;\n    int targetPositionX;\n    int targetPositionY;\n    int removeTimer;\n    bool exists;\n    bool isVisible[9];\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/BulletImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"BulletData.h\"\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Player;\n  class Unit;\n  class BulletImpl : public Bullet\n  {\n    private:\n      const BulletData* self;\n      int index;\n    public:\n\n      BulletImpl(int index);\n      virtual int getID() const;\n      virtual Player* getPlayer() const;\n      virtual BulletType getType() const;\n      virtual Unit* getSource() const;\n      virtual Position getPosition() const;\n      virtual double getAngle() const;\n      virtual double getVelocityX() const;\n      virtual double getVelocityY() const;\n      virtual Unit* getTarget() const;\n      virtual Position getTargetPosition() const;\n      virtual int getRemoveTimer() const;\n      virtual bool exists() const;\n      virtual bool isVisible() const;\n      virtual bool isVisible(Player* player) const;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/Client.h",
    "content": "#pragma once\n#include <windows.h>\n#include \"GameData.h\"\n#include \"GameImpl.h\"\n#include \"ForceImpl.h\"\n#include \"PlayerImpl.h\"\n#include \"UnitImpl.h\"\n\n\nnamespace BWAPI\n{\n  class Client\n  {\n    public:\n    Client();\n    ~Client();\n    GameData* data;\n    bool isConnected();\n    bool connect();\n    void disconnect();\n    void update();\n\n  private:\n    HANDLE pipeObjectHandle;\n    HANDLE mapFileHandle;\n    bool connected;\n  };\n  extern Client BWAPIClient;\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/Command.h",
    "content": "#pragma once\n#include \"CommandType.h\"\n\nnamespace BWAPIC\n{\n  struct Command\n  {\n    Command(CommandType::Enum _commandType, int _value1=0, int _value2=0)\n    {\n      type=_commandType;\n      value1=_value1;\n      value2=_value2;\n    }\n    CommandType::Enum type;\n    int value1;\n    int value2;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/CommandType.h",
    "content": "#pragma once\n/**\n *  Used in UnitCommand\n */\n\nnamespace BWAPIC\n{\n  namespace CommandType\n  {\n    enum Enum\n    {\n      None,\n      SetScreenPosition,\n      PingMinimap,\n      EnableFlag,\n      Printf,\n      SendText,\n      ChangeRace,\n      StartGame,\n      PauseGame,\n      ResumeGame,\n      LeaveGame,\n      RestartGame,\n      SetLocalSpeed,\n      SetTextSize,\n      SetLatCom,\n      SetGui\n    };\n  }\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/Event.h",
    "content": "#pragma once\n\n#include <BWAPI\\Event.h>\n#include <BWAPI\\EventType.h>\n\nnamespace BWAPIC\n{ \n  struct Event\n  {\n    BWAPI::EventType::Enum type;\n    int v1;\n    int v2;\n  };\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/ForceData.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  struct ForceData\n  {\n    char name[32];\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/ForceImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"ForceData.h\"\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Game;\n  class Player;\n  class Unit;\n  class ForceImpl : public Force\n  {\n    private:\n      const ForceData* self;\n      int id;\n    public:\n      ForceImpl(int id);\n      virtual int getID() const;\n      virtual std::string getName() const;\n      virtual std::set<Player*> getPlayers() const;\n  };\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/GameData.h",
    "content": "#pragma once\n\n#include \"UnitCommand.h\"\n#include \"ForceData.h\"\n#include \"PlayerData.h\"\n#include \"UnitData.h\"\n#include \"BulletData.h\"\n#include \"Event.h\"\n#include \"Command.h\"\n#include \"Shape.h\"\n\nnamespace BWAPI\n{\n  struct GameData\n  {\n    GameData();\n    int instanceID;\n\n    //forces\n    int forceCount;\n    ForceData forces[5];\n\n    //players\n    int playerCount;\n    PlayerData players[12];\n\n    //units\n    int initialUnitCount;\n    UnitData units[10000];\n\n    //unit table\n    int unitArray[1700];\n\n    //bullets\n    BulletData bullets[100];\n\n    int gameType;\n    int latency;\n    int latencyFrames;\n    int latencyTime;\n    int remainingLatencyFrames;\n    int remainingLatencyTime;\n    int revision;\n    bool isDebug;\n    bool hasLatCom;\n    int replayFrameCount;\n    int frameCount;\n    int fps;\n    double averageFPS;\n\n    // user input\n    int mouseX;\n    int mouseY;\n    bool mouseState[3];\n    bool keyState[256];\n    int screenX;\n    int screenY;\n\n    bool flags[2];\n\n    // map\n    int mapWidth;\n    int mapHeight;\n    char mapFileName[261];  //size based on broodwar memory\n    char mapPathName[261];  //size based on broodwar memory\n    char mapName[33];      //size based on broodwar memory\n    char mapHash[41];\n\n    //tile data\n    int getGroundHeight[256][256];\n    bool isWalkable[1024][1024]; \n    bool isBuildable[256][256];\n    bool isVisible[256][256];\n    bool isExplored[256][256];\n    bool hasCreep[256][256];\n\n    unsigned short mapTileRegionId[256][256];\n    unsigned short mapSplitTilesMiniTileMask[5000];\n    unsigned short mapSplitTilesRegion1[5000];\n    unsigned short mapSplitTilesRegion2[5000];\n    unsigned short regionGroupIndex[5000];\n\n\n    // start locations\n    int startLocationCount;\n    int startLocationsX[8];\n    int startLocationsY[8];\n\n    // match mode\n    bool isInGame;\n    bool isMultiplayer;\n    bool isBattleNet;\n    bool isPaused;\n    bool isReplay;\n\n    //selected units\n    int selectedUnitCount;\n    int selectedUnits[12];\n\n    // players\n    int self;\n\n    //events from server to client\n    int eventCount;\n    BWAPIC::Event events[10000];\n\n    //strings (used in events, shapes, and commands)\n    int stringCount;\n    char strings[20000][256];\n\n    //shapes, commands, unitCommands, from client to server\n    int shapeCount;\n    BWAPIC::Shape shapes[20000];\n\n    int commandCount;\n    BWAPIC::Command commands[20000];\n\n    int unitCommandCount;\n    BWAPIC::UnitCommand unitCommands[20000];\n\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/GameImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"GameData.h\"\n#include \"Client.h\"\n#include \"Shape.h\"\n#include \"Command.h\"\n#include \"UnitCommand.h\"\n#include \"ForceImpl.h\"\n#include \"PlayerImpl.h\"\n#include \"UnitImpl.h\"\n#include \"BulletImpl.h\"\n#include <list>\n#include <map>\n#include <set>\n#include <vector>\n\nnamespace BWAPI\n{\n  class Force;\n  class Player;\n  class Unit;\n  class GameImpl : public Game\n  {\n    private :\n      int addShape(BWAPIC::Shape &s);\n      int addString(const char* text);\n      int addText(BWAPIC::Shape &s, const char* text);\n      int addCommand(BWAPIC::Command &c);\n      void clearAll();\n\n      GameData* data;\n      std::vector<ForceImpl> forceVector;\n      std::vector<PlayerImpl> playerVector;\n      std::vector<UnitImpl> unitVector;\n      std::vector<BulletImpl> bulletVector;\n\n      std::set<Force*> forces;\n      std::set<Player*> players;\n      std::set<Unit*> accessibleUnits;//all units that are accessible (and definitely alive)\n      //notDestroyedUnits - accessibleUnits = all units that may or may not be alive (status unknown)\n      std::set<Unit*> minerals;\n      std::set<Unit*> geysers;\n      std::set<Unit*> neutralUnits;\n      std::set<Unit*> staticMinerals;\n      std::set<Unit*> staticGeysers;\n      std::set<Unit*> staticNeutralUnits;\n      std::set<Bullet*> bullets;\n      std::set<Unit*> selectedUnits;\n      std::set<Unit*> pylons;\n      std::set<Unit*> unitsOnTileData[256][256];\n\n      std::set< TilePosition > startLocations;\n      std::list< Event > events;\n      bool flagEnabled[2];\n      Player* thePlayer;\n      Player* theEnemy;\n      Error lastError;\n\n    public :\n      Event makeEvent(BWAPIC::Event e);\n      int addUnitCommand(BWAPIC::UnitCommand& c);\n      bool inGame;\n      GameImpl(GameData* data);\n      void onMatchStart();\n      void onMatchEnd();\n      void onMatchFrame();\n      const GameData* getGameData() const;\n      std::set<Unit*>& getPlayerUnits(const Player* player);\n\n      virtual std::set< Force* >& getForces();\n      virtual std::set< Player* >& getPlayers();\n      virtual std::set< Unit* >& getAllUnits();\n      virtual std::set< Unit* >& getMinerals();\n      virtual std::set< Unit* >& getGeysers();\n      virtual std::set< Unit* >& getNeutralUnits();\n\n      virtual std::set< Unit* >& getStaticMinerals();\n      virtual std::set< Unit* >& getStaticGeysers();\n      virtual std::set< Unit* >& getStaticNeutralUnits();\n\n      virtual std::set< Bullet* >& getBullets();\n      virtual std::list< Event>& getEvents();\n\n      virtual Force* getForce(int forceID);\n      virtual Player* getPlayer(int playerID);\n      virtual Unit* getUnit(int unitID);\n      virtual Unit* indexToUnit(int unitIndex);\n\n      virtual GameType getGameType();\n      virtual int getLatency();\n      virtual int getFrameCount();\n      virtual int getFPS();\n      virtual double getAverageFPS();\n      virtual BWAPI::Position getMousePosition();\n      virtual bool getMouseState(MouseButton button);\n      virtual bool getMouseState(int button);\n      virtual bool getKeyState(Key key);\n      virtual bool getKeyState(int key);\n      virtual BWAPI::Position getScreenPosition();\n      virtual void setScreenPosition(int x, int y);\n      virtual void setScreenPosition(BWAPI::Position p);\n      virtual void pingMinimap(int x, int y);\n      virtual void pingMinimap(BWAPI::Position p);\n\n      virtual bool  isFlagEnabled(int flag);\n      virtual void  enableFlag(int flag);\n      virtual std::set<Unit*>& unitsOnTile(int x, int y);\n      virtual Error getLastError() const;\n      virtual bool  setLastError(BWAPI::Error e);\n\n      virtual int         mapWidth();\n      virtual int         mapHeight();\n      virtual std::string mapFileName();\n      virtual std::string mapPathName();\n      virtual std::string mapName();\n      virtual std::string mapHash();\n\n      virtual bool isWalkable(int x, int y);\n      virtual int  getGroundHeight(int x, int y);\n      virtual int  getGroundHeight(TilePosition position);\n      virtual bool isBuildable(int x, int y);\n      virtual bool isBuildable(TilePosition position);\n      virtual bool isVisible(int x, int y);\n      virtual bool isVisible(TilePosition position);\n      virtual bool isExplored(int x, int y);\n      virtual bool isExplored(TilePosition position);\n      virtual bool hasCreep(int x, int y);\n      virtual bool hasCreep(TilePosition position);\n      virtual bool hasPower(int x, int y, int tileWidth, int tileHeight);\n      virtual bool hasPower(TilePosition position, int tileWidth, int tileHeight);\n\n      virtual bool canBuildHere(Unit* builder, TilePosition position, UnitType type, bool checkExplored = false);\n      virtual bool canMake(Unit* builder, UnitType type);\n      virtual bool canResearch(Unit* unit, TechType type);\n      virtual bool canUpgrade(Unit* unit, UpgradeType type);\n      virtual std::set< TilePosition >& getStartLocations();\n\n      virtual void printf(const char* text, ...);\n      virtual void sendText(const char* text, ...);\n      virtual void sendTextEx(bool toAllies, const char *format, ...);\n\n      virtual void changeRace(BWAPI::Race race);\n      virtual bool isInGame();\n      virtual bool isMultiplayer();\n      virtual bool isBattleNet();\n      virtual bool isPaused();\n      virtual bool isReplay();\n\n      virtual void  startGame();\n      virtual void  pauseGame();\n      virtual void  resumeGame();\n      virtual void  leaveGame();\n      virtual void  restartGame();\n      virtual void  setLocalSpeed(int speed = -1);\n      virtual std::set<BWAPI::Unit*>& getSelectedUnits();\n      virtual Player*  self();\n      virtual Player*  enemy();\n\n      virtual void setTextSize(int size = 1);\n      virtual void drawText(int ctype, int x, int y, const char* text, ...);\n      virtual void drawTextMap(int x, int y, const char* text, ...);\n      virtual void drawTextMouse(int x, int y, const char* text, ...);\n      virtual void drawTextScreen(int x, int y, const char* text, ...);\n\n      virtual void drawBox(int ctype, int left, int top, int right, int bottom, Color color, bool isSolid = false);\n      virtual void drawBoxMap(int left, int top, int right, int bottom, Color color, bool isSolid = false);\n      virtual void drawBoxMouse(int left, int top, int right, int bottom, Color color, bool isSolid = false);\n      virtual void drawBoxScreen(int left, int top, int right, int bottom, Color color, bool isSolid = false);\n\n      virtual void drawTriangle(int ctype, int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false);\n      virtual void drawTriangleMap(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false);\n      virtual void drawTriangleMouse(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false);\n      virtual void drawTriangleScreen(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false);\n\n      virtual void drawCircle(int ctype, int x, int y, int radius, Color color, bool isSolid = false);\n      virtual void drawCircleMap(int x, int y, int radius, Color color, bool isSolid = false);\n      virtual void drawCircleMouse(int x, int y, int radius, Color color, bool isSolid = false);\n      virtual void drawCircleScreen(int x, int y, int radius, Color color, bool isSolid = false);\n\n      virtual void drawEllipse(int ctype, int x, int y, int xrad, int yrad, Color color, bool isSolid = false);\n      virtual void drawEllipseMap(int x, int y, int xrad, int yrad, Color color, bool isSolid = false);\n      virtual void drawEllipseMouse(int x, int y, int xrad, int yrad, Color color, bool isSolid = false);\n      virtual void drawEllipseScreen(int x, int y, int xrad, int yrad, Color color, bool isSolid = false);\n\n      virtual void drawDot(int ctype, int x, int y, Color color);\n      virtual void drawDotMap(int x, int y, Color color);\n      virtual void drawDotMouse(int x, int y, Color color);\n      virtual void drawDotScreen(int x, int y, Color color);\n\n      virtual void drawLine(int ctype, int x1, int y1, int x2, int y2, Color color);\n      virtual void drawLineMap(int x1, int y1, int x2, int y2, Color color);\n      virtual void drawLineMouse(int x1, int y1, int x2, int y2, Color color);\n      virtual void drawLineScreen(int x1, int y1, int x2, int y2, Color color);\n\n      virtual void *getScreenBuffer();\n      virtual int  getLatencyFrames();\n      virtual int  getLatencyTime();\n      virtual int  getRemainingLatencyFrames();\n      virtual int  getRemainingLatencyTime();\n      virtual int  getRevision();\n      virtual bool isDebug();\n      virtual bool isLatComEnabled();\n      virtual void setLatCom(bool isEnabled);\n      virtual int  getReplayFrameCount();\n      virtual void setGUI(bool enabled = true);\n      virtual int  getInstanceNumber();\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/PlayerData.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  struct PlayerData\n  {\n    char name[25];\n    int  race;\n    int  type;\n    int  force;\n    bool isAlly[12];\n    bool isEnemy[12];\n    bool isNeutral;\n    int  startLocationX;\n    int  startLocationY;\n    bool isVictorious;\n    bool isDefeated;\n    bool leftGame;\n\n    int minerals;\n    int gas;\n    int cumulativeMinerals;\n    int cumulativeGas;\n    int supplyTotal[3];\n    int supplyUsed[3];\n\n    int allUnitCount[230];\n    int completedUnitCount[230];\n    int deadUnitCount[230];\n    int killedUnitCount[230];\n\n    int  upgradeLevel[63];\n    bool hasResearched[47];\n    bool isResearching[47];\n    bool isUpgrading[63];\n\n    int colorByte;\n    int color;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/PlayerImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"PlayerData.h\"\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Unit;\n  class Force;\n  class PlayerImpl : public Player\n  {\n    private:\n      int id;\n    public:\n      PlayerData* self;\n      std::set<Unit*> units;\n      void clear();\n      PlayerImpl(int id);\n      virtual int getID() const;\n      virtual std::string getName() const;\n      virtual const std::set<Unit*>& getUnits() const;\n      virtual Race getRace() const;\n      virtual PlayerType getType() const;\n      virtual Force* getForce() const;\n      virtual bool isAlly(Player* player) const;\n      virtual bool isEnemy(Player* player) const;\n      virtual bool isNeutral() const;\n      virtual TilePosition getStartLocation() const;\n      virtual bool isVictorious() const;\n      virtual bool isDefeated() const;\n      virtual bool leftGame() const;\n\n      virtual int minerals() const;\n      virtual int gas() const;\n      virtual int cumulativeMinerals() const;\n      virtual int cumulativeGas() const;\n\n      virtual int supplyTotal() const;\n      virtual int supplyUsed() const;\n      virtual int supplyTotal(Race race) const;\n      virtual int supplyUsed(Race race) const;\n\n      virtual int allUnitCount(UnitType unit) const;\n      virtual int completedUnitCount(UnitType unit) const;\n      virtual int incompleteUnitCount(UnitType unit) const;\n      virtual int deadUnitCount(UnitType unit) const;\n      virtual int killedUnitCount(UnitType unit) const;\n\n      virtual int  getUpgradeLevel(UpgradeType upgrade) const;\n      virtual bool hasResearched(TechType tech) const;\n      virtual bool isResearching(TechType tech) const;\n      virtual bool isUpgrading(UpgradeType upgrade) const;\n\n      virtual int maxEnergy(UnitType unit) const;\n\n      virtual BWAPI::Color getColor() const;\n      virtual int getTextColor() const;\n  };\n};\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/Shape.h",
    "content": "#pragma once\n#include \"ShapeType.h\"\n\nnamespace BWAPIC\n{\n  struct Shape\n  {\n    Shape(ShapeType::Enum _shapeType, int _ctype, int _x1, int _y1, int _x2, int _y2, int _extra1, int _extra2, int _color, bool _isSolid)\n    {\n      type=_shapeType;\n      ctype=_ctype;\n      x1=_x1;\n      y1=_y1;\n      x2=_x2;\n      y2=_y2;\n      extra1=_extra1;\n      extra2=_extra2;\n      color=_color;\n      isSolid=_isSolid;\n    }\n    ShapeType::Enum type;\n    int ctype;\n    int x1;\n    int y1;\n    int x2;\n    int y2;\n    int extra1;\n    int extra2;\n    int color;\n    bool isSolid;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/ShapeType.h",
    "content": "#pragma once\n/**\n *  Used in UnitCommand\n */\n\nnamespace BWAPIC\n{\n  namespace ShapeType\n  {\n    enum Enum\n    {\n      None,\n      Text,\n      Box,\n      Triangle,\n      Circle,\n      Ellipse,\n      Dot,\n      Line\n    };\n  }\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/UnitCommand.h",
    "content": "#pragma once\n\n#include <BWAPI.h>\n\n/**\n * UnitOrder contains a single whole order\n */\n\nnamespace BWAPIC\n{\n  struct UnitCommand\n  {\n    BWAPI::UnitCommandType type;\n    int unitIndex;\n    int targetIndex;\n    int x;\n    int y;\n    int extra;\n  };\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/UnitData.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  struct UnitData\n  {\n    int clearanceLevel;\n    int id;\n    int player;\n    int type;\n    int positionX;\n    int positionY;\n    double angle;\n    double velocityX;\n    double velocityY;\n    int hitPoints;\n    int lastHitPoints;\n    int shields;\n    int energy;\n    int resources;\n    int resourceGroup;\n\n    int killCount;\n    int scarabCount;\n    int spiderMineCount;\n    int groundWeaponCooldown;\n    int airWeaponCooldown;\n    int spellCooldown;\n    int defenseMatrixPoints;\n\n    int defenseMatrixTimer;\n    int ensnareTimer;\n    int irradiateTimer;\n    int lockdownTimer;\n    int maelstromTimer;\n    int orderTimer;\n    int plagueTimer;\n    int removeTimer;\n    int stasisTimer;\n    int stimTimer;\n\n    int buildType;\n    int trainingQueueCount;\n    int trainingQueue[5];\n    int tech;\n    int upgrade;\n    int remainingBuildTime;\n    int remainingTrainTime;\n    int remainingResearchTime;\n    int remainingUpgradeTime;\n    int buildUnit;\n\n    int target;\n    int targetPositionX;\n    int targetPositionY;\n    int order;\n    int orderTarget;\n    int secondaryOrder;\n    int rallyPositionX;\n    int rallyPositionY;\n    int rallyUnit;\n    int addon;\n    int nydusExit;\n    int powerUp;\n\n    int transport;\n    int carrier;\n    int hatchery;\n    \n    bool exists;\n    bool hasNuke;\n    bool isAccelerating;\n    bool isAttacking;\n    bool isBeingGathered;\n    bool isBlind;\n    bool isBraking;\n    bool isBurrowed;\n    int carryResourceType;\n    bool isCloaked;\n    bool isCompleted;\n    bool isConstructing;\n    bool isDetected;\n    bool isGathering;\n    bool isHallucination;\n    bool isIdle;\n    bool isInterruptible;\n    bool isLifted;\n    bool isMorphing;\n    bool isMoving;\n    bool isParasited;\n    bool isSelected;\n    bool isStartingAttack;\n    bool isStuck;\n    bool isTraining;\n    bool isUnderStorm;\n    bool isUnpowered;\n    bool isVisible[9];\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client/UnitImpl.h",
    "content": "#pragma once\n#include <BWAPI.h>\n#include \"UnitData.h\"\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Player;\n  class UnitImpl : public Unit\n  {\n    private:\n      int id;\n      UnitType initialType;\n      int initialResources;\n      int initialHitPoints;\n      Position initialPosition;\n      int lastOrderFrame;\n      void* clientInfo;\n    public:\n      UnitData* self;\n      std::set<Unit*> connectedUnits;\n      std::set<Unit*> loadedUnits;\n      void clear();\n      void saveInitialState();\n\n      UnitImpl(int id);\n      virtual int          getID() const;\n      virtual Player*      getPlayer() const;\n      virtual UnitType     getType() const;\n      virtual Position     getPosition() const;\n      virtual TilePosition getTilePosition() const;\n      virtual double       getAngle() const;\n      virtual double       getVelocityX() const;\n      virtual double       getVelocityY() const;\n      virtual int          getHitPoints() const;\n      virtual int          getShields() const;\n      virtual int          getEnergy() const;\n      virtual int          getResources() const;\n      virtual int          getResourceGroup() const;\n\n      virtual double getDistance(Unit* target) const;\n      virtual double getDistance(Position target) const;\n      virtual bool   hasPath(Unit* target) const;\n      virtual bool   hasPath(Position target) const;\n      virtual int    getLastOrderFrame() const;\n      virtual int    getUpgradeLevel(UpgradeType upgrade) const;\n\n      virtual UnitType     getInitialType() const;\n      virtual Position     getInitialPosition() const;\n      virtual TilePosition getInitialTilePosition() const;\n      virtual int          getInitialHitPoints() const;\n      virtual int          getInitialResources() const;\n\n      virtual int getKillCount() const;\n      virtual int getInterceptorCount() const;\n      virtual int getScarabCount() const;\n      virtual int getSpiderMineCount() const;\n      virtual int getGroundWeaponCooldown() const;\n      virtual int getAirWeaponCooldown() const;\n      virtual int getSpellCooldown() const;\n      virtual int getDefenseMatrixPoints() const;\n\n      virtual int getDefenseMatrixTimer() const;\n      virtual int getEnsnareTimer() const;\n      virtual int getIrradiateTimer() const;\n      virtual int getLockdownTimer() const;\n      virtual int getMaelstromTimer() const;\n      virtual int getOrderTimer() const;\n      virtual int getPlagueTimer() const;\n      virtual int getRemoveTimer() const;\n      virtual int getStasisTimer() const;\n      virtual int getStimTimer() const;\n\n      virtual UnitType            getBuildType() const;\n      virtual std::list<UnitType> getTrainingQueue() const;\n      virtual TechType            getTech() const;\n      virtual UpgradeType         getUpgrade() const;\n      virtual int                 getRemainingBuildTime() const;\n      virtual int                 getRemainingTrainTime() const;\n      virtual int                 getRemainingResearchTime() const;\n      virtual int                 getRemainingUpgradeTime() const;\n      virtual Unit*               getBuildUnit() const;\n\n      virtual Unit*    getTarget() const;\n      virtual Position getTargetPosition() const;\n      virtual Order    getOrder() const;\n      virtual Unit*    getOrderTarget() const;\n      virtual Order    getSecondaryOrder() const;\n      virtual Position getRallyPosition() const;\n      virtual Unit*    getRallyUnit() const;\n      virtual Unit*    getAddon() const;\n      virtual Unit*    getNydusExit() const;\n      virtual Unit*    getPowerUp() const;\n\n      virtual Unit*           getTransport() const;\n      virtual std::set<Unit*> getLoadedUnits() const;\n      virtual Unit*           getCarrier() const;\n      virtual std::set<Unit*> getInterceptors() const;\n      virtual Unit*           getHatchery() const;\n      virtual std::set<Unit*> getLarva() const;\n\n      virtual bool exists() const;\n      virtual bool hasNuke() const;\n      virtual bool isAccelerating() const;\n      virtual bool isAttacking() const;\n      virtual bool isBeingConstructed() const;\n      virtual bool isBeingGathered() const;\n      virtual bool isBeingHealed() const;\n      virtual bool isBlind() const;\n      virtual bool isBraking() const;\n      virtual bool isBurrowed() const;\n      virtual bool isCarryingGas() const;\n      virtual bool isCarryingMinerals() const;\n      virtual bool isCloaked() const;\n      virtual bool isCompleted() const;\n      virtual bool isConstructing() const;\n      virtual bool isDefenseMatrixed() const;\n      virtual bool isDetected() const;\n      virtual bool isEnsnared() const;\n      virtual bool isFollowing() const;\n      virtual bool isGatheringGas() const;\n      virtual bool isGatheringMinerals() const;\n      virtual bool isHallucination() const;\n      virtual bool isHoldingPosition() const;\n      virtual bool isIdle() const;\n      virtual bool isInterruptible() const;\n      virtual bool isIrradiated() const;\n      virtual bool isLifted() const;\n      virtual bool isLoaded() const;\n      virtual bool isLockedDown() const;\n      virtual bool isMaelstrommed() const;\n      virtual bool isMorphing() const;\n      virtual bool isMoving() const;\n      virtual bool isParasited() const;\n      virtual bool isPatrolling() const;\n      virtual bool isPlagued() const;\n      virtual bool isRepairing() const;\n      virtual bool isResearching() const;\n      virtual bool isSelected() const;\n      virtual bool isSieged() const;\n      virtual bool isStartingAttack() const;\n      virtual bool isStasised() const;\n      virtual bool isStimmed() const;\n      virtual bool isStuck() const;\n      virtual bool isTraining() const;\n      virtual bool isUnderStorm() const;\n      virtual bool isUnpowered() const;\n      virtual bool isUpgrading() const;\n      virtual bool isVisible() const;\n      virtual bool isVisible(Player* player) const;\n\n      virtual bool issueCommand(UnitCommand command);\n\n      virtual bool attackMove(Position target);\n      virtual bool attackUnit(Unit* target);\n      virtual bool build(TilePosition target, UnitType type);\n      virtual bool buildAddon(UnitType type);\n      virtual bool train(UnitType type);\n      virtual bool morph(UnitType type);\n      virtual bool research(TechType tech);\n      virtual bool upgrade(UpgradeType upgrade);\n      virtual bool setRallyPoint(Position target);\n      virtual bool setRallyPoint(Unit* target);\n      virtual bool move(Position target);\n      virtual bool patrol(Position target);\n      virtual bool holdPosition();\n      virtual bool stop();\n      virtual bool follow(Unit* target);\n      virtual bool gather(Unit* target);\n      virtual bool returnCargo();\n      virtual bool repair(Unit* target);\n      virtual bool burrow();\n      virtual bool unburrow();\n      virtual bool cloak();\n      virtual bool decloak();\n      virtual bool siege();\n      virtual bool unsiege();\n      virtual bool lift();\n      virtual bool land(TilePosition target);\n      virtual bool load(Unit* target);\n      virtual bool unload(Unit* target);\n      virtual bool unloadAll();\n      virtual bool unloadAll(Position target);\n      virtual bool rightClick(Position target);\n      virtual bool rightClick(Unit* target);\n      virtual bool haltConstruction();\n      virtual bool cancelConstruction();\n      virtual bool cancelAddon();\n      virtual bool cancelTrain(int slot = -2);\n      virtual bool cancelMorph();\n      virtual bool cancelResearch();\n      virtual bool cancelUpgrade();\n      virtual bool useTech(TechType tech);\n      virtual bool useTech(TechType tech, Position target);\n      virtual bool useTech(TechType tech, Unit* target);\n\n      virtual void setClientInfo(void* clientinfo);\n      virtual void* getClientInfo() const;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Client.h",
    "content": "#pragma once\n#include <BWAPI/Client/Client.h>\n#include <BWAPI/Client/Command.h>\n#include <BWAPI/Client/CommandType.h>\n#include <BWAPI/Client/Event.h>\n#include <BWAPI/Client/ForceData.h>\n#include <BWAPI/Client/ForceImpl.h>\n#include <BWAPI/Client/GameData.h>\n#include <BWAPI/Client/GameImpl.h>\n#include <BWAPI/Client/PlayerData.h>\n#include <BWAPI/Client/PlayerImpl.h>\n#include <BWAPI/Client/Shape.h>\n#include <BWAPI/Client/ShapeType.h>\n#include <BWAPI/Client/UnitCommand.h>\n#include <BWAPI/Client/UnitData.h>\n#include <BWAPI/Client/UnitImpl.h>"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Color.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  // TODO: Add color palette image and info about text color\n  /** StarCraft uses a 256 color palette to render everything, so the colors we can use to draw shapes using\n   * BWAPI is limited to the colors available in the Palette. */\n  class Color\n  {\n    public:\n      Color();\n\n      /** Create a color using the specified index from the Broodwar color palette. */\n      Color(int id);\n      Color(const Color& other);\n\n      /** Create a color using the color in the palette that is closest to the RGB color specified. */\n      Color(int red, int green, int blue);\n\n      /** Return the index of the color in the color palette. */\n      int getID() const;\n\n      /** Return the red component of the color. */\n      int red() const;\n\n      /** Return the green component of the color. */\n      int green() const;\n\n      /** Return the blue component of the color. */\n      int blue() const;\n\n      Color& operator=(const Color& other);\n      bool operator==(const Color& other) const;\n      bool operator!=(const Color& other) const;\n      bool operator<(const Color& other) const;\n    private:\n      int id;\n  };\n\n  /** While any color from the palette can be used, the following colors are available as short cuts. */\n  namespace Colors\n  {\n    void init();\n    extern const Color Red;\n    extern const Color Blue;\n    extern const Color Teal;\n    extern const Color Purple;\n    extern const Color Orange;\n    extern const Color Brown;\n    extern const Color White;\n    extern const Color Yellow;\n    extern const Color Green;\n    extern const Color Cyan;\n    extern const Color Black;\n    extern const Color Grey;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Constants.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  /** Used for converting between TilePosition coordinates and Position coordinates. */\n  #define TILE_SIZE      32\n  #define PYLON_X_RADIUS  8\n  #define PYLON_Y_RADIUS  5\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/CoordinateType.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  namespace CoordinateType\n  {\n    enum Enum\n    {\n      Screen    = 1, /**< (0,0) corresponds to the top left corner of the screen. */\n      Map       = 2, /**< (0,0) corresponds to the top left corner of the map. */\n      Mouse     = 3, /**< (0,0) corresponds to the tip of the mouse . */\n    };\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/DamageType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class DamageType\n  {\n    public:\n      DamageType();\n      DamageType(int id);\n      DamageType(const DamageType& other);\n      DamageType& operator=(const DamageType& other);\n      bool operator==(const DamageType& other) const;\n      bool operator!=(const DamageType& other) const;\n      bool operator<(const DamageType& other) const;\n\n      /** Returns a unique ID for this damage type. */\n      int getID() const;\n\n      /** Returns the name of this damage type. For example DamageTypes::Explosive.getName() will return\n       * std::string(\"Explosive\"). */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace DamageTypes\n  {\n    /** Given the name of a damage type, this will return a corresponding DamageType object. For example,\n     * DamageTypes::getDamageType(\"Concussive\") will return DamageTypes::Concussive. */\n    DamageType getDamageType(std::string name);\n\n    /** Returns the set of all the DamageTypes. */\n    std::set<DamageType>& allDamageTypes();\n\n    void init();\n    extern const DamageType Independent;\n    extern const DamageType Explosive;\n    extern const DamageType Concussive;\n    extern const DamageType Normal;\n    extern const DamageType Ignore_Armor;\n    extern const DamageType None;\n    extern const DamageType Unknown;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Error.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class UnitType;\n\n  /** Functions in BWAPI may set an error code. To retrieve the error code, call Game::getLastError. */\n  class Error\n  {\n    public:\n      Error();\n      Error(int id);\n      Error(const Error& other);\n      Error& operator=(const Error& other);\n      bool operator==(const Error& other) const;\n      bool operator!=(const Error& other) const;\n      bool operator<(const Error& other) const;\n\n      /** Returns a unique ID for this error. */\n      int getID() const;\n\n      /** Returns the name of the error. For example Errors::Insufficient_Minerals?.toString() will return a\n       * std::string object containing \"Insufficient Minerals\". */\n      std::string toString() const;\n    private:\n      int id;\n  };\n  namespace Errors\n  {\n    /** Given the name of an error, this function will return the error code. For example:\n     * Errors::getError(\"Unbuildable Location\") will return Errors::Unbuildable_Location?. */\n    Error getError(std::string name);\n\n    /** The set of all the error codes. */\n    std::set<Error>& allErrors();\n\n    void init();\n\n    /** Returned if you try to order a unit or get information from a unit that no longer exists. */\n    extern const Error Unit_Does_Not_Exist;\n\n    /** Returned if you try to retrieve information about a unit that is not currently visible or is dead. */\n    extern const Error Unit_Not_Visible;\n\n    /** Returned when attempting to order a unit that BWAPI does not own (i.e. can't order enemy army to go\n     *  away) */\n    extern const Error Unit_Not_Owned;\n\n    /** Returned when trying to order a unit to do something when it is performing another order or is in a\n     * state which prevents it from performing the desired order. For example, ordering a Terran Engineering\n     * Bay to upgrade something while it is already upgrading something else will return this error.\n     * Similarly, trying to train units from a factory that is lifted will return this error. */\n    extern const Error Unit_Busy;\n\n    /** Returned if you do something weird like try to build a Pylon with an SCV, or train Vultures in a\n     * Barracks, or order a Hydralisk to lay a spider mine. */\n    extern const Error Incompatible_UnitType;\n\n    /** Returned when trying to use a tech type with the wrong Unit::useTech method. */\n    extern const Error Incompatible_TechType;\n\n    /** Returned if you to do something like try to cancel an upgrade when the unit isn't upgrading. */\n    extern const Error Incompatible_State;\n\n    /** Returned if you try to research something that is already researched. */\n    extern const Error Already_Researched;\n\n    /** Returned if you try to upgrade something that is already fully upgraded. */\n    extern const Error Fully_Upgraded;\n\n    /** Returned if you try to research something that is already being researched. */\n    extern const Error Currently_Researching;\n\n    /** Returned if you try to upgrade something that is already being upgraded. */\n    extern const Error Currently_Upgrading;\n\n    /** Returned if you try to train or build something without enough minerals. */\n    extern const Error Insufficient_Minerals;\n\n    /** Returned if you try to train or build something without enough vespene gas. */\n    extern const Error Insufficient_Gas;\n\n    /** Returned if you try to train something without enough supply. */\n    extern const Error Insufficient_Supply;\n\n    /** Returned if you to do something like try to order a Defiler to cast a Dark Swarm without enough\n     * energy. */\n    extern const Error Insufficient_Energy;\n\n    /** Returned if you do something like try to train Medics when you don't have an Academy, or try to lay\n     * Spider Mines before spider mines have been researched. */\n    extern const Error Insufficient_Tech;\n\n    /** Returned if you do something like try to lay Spider Mines when your Vulture is out of Spider Mines.\n     * Same thing with Reavers and Scarabs. */\n    extern const Error Insufficient_Ammo;\n\n    /** Returned if you try to build something on unbuildable terrain (either from the buildability map data\n     * or if a unit is in the way). For build tiles that are not visible, we could just use the buildability\n     * map data and assume that no units are blocking it (to prevent cheating). */\n    extern const Error Insufficient_Space;\n\n    /** Returned if you order an immovable unit, like a Protoss Photon Cannon, to attack a unit that is out\n     * of range. */\n    extern const Error Unbuildable_Location;\n\n    /** Returned if you try to construct a building where the worker cannot reach based on static map data. */\n    extern const Error Unreachable_Location;\n\n    /** Returned if you order an immovable unit, like a Protoss Photon Cannon, to attack a unit that is out of\n     * range.*/\n    extern const Error Out_Of_Range;\n\n    /** Returned if you do something like order a Vulture to attack a flying unit. */\n    extern const Error Unable_To_Hit;\n\n    /** Returned if you try to get information that is not allowed with the given flag settings. For example,\n     * trying to read the enemy's resource counts while the CompleteMapInformation?  flag is not enabled will\n     * return this error. Similarly, trying to read the coordinates of the screen or mouse while the UserInput\n     *  flag is not enabled will also return this error. */\n    extern const Error Access_Denied;\n\n    /** Used when no error has been encountered. */\n    extern const Error None;\n\n    /** Used when the error code is not recognized or can not be determined. */\n    extern const Error Unknown;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Event.h",
    "content": "#pragma once\n#include <BWAPI/EventType.h>\n#include <BWAPI/Player.h>\n#include <BWAPI/Unit.h>\n#include <BWAPI/Position.h>\n#include <string>\n\nnamespace BWAPI\n{\n  class Event\n  {\n    public:\n      Event();\n      bool operator==(const Event& other);\n      static Event MatchStart();\n      static Event MatchEnd(bool isWinner);\n      static Event MatchFrame();\n      static Event MenuFrame();\n      static Event SendText(std::string text);\n      static Event ReceiveText(Player* player, std::string text);\n      static Event PlayerLeft(Player* player);\n      static Event NukeDetect(Position target);\n      static Event UnitDiscover(Unit* unit);\n      static Event UnitEvade(Unit* unit);\n      static Event UnitShow(Unit* unit);\n      static Event UnitHide(Unit* unit);\n      static Event UnitCreate(Unit* unit);\n      static Event UnitDestroy(Unit* unit);\n      static Event UnitMorph(Unit* unit);\n      static Event UnitRenegade(Unit* unit);\n      static Event SaveGame(std::string gameName);\n      EventType::Enum type;\n      Position position;\n      std::string text;\n      Unit* unit;\n      Player* player;\n      bool isWinner;\n  };\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/EventType.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  namespace EventType\n  {\n    enum Enum\n    {\n      MatchStart,\n      MatchEnd,\n      MatchFrame,\n      MenuFrame,\n      SendText,\n      ReceiveText,\n      PlayerLeft,\n      NukeDetect,\n      UnitDiscover,\n      UnitEvade,\n      UnitShow,\n      UnitHide,\n      UnitCreate,\n      UnitDestroy,\n      UnitMorph,\n      UnitRenegade,\n      SaveGame,\n      None\n    };\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/ExplosionType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class ExplosionType\n  {\n    public:\n      ExplosionType();\n      ExplosionType(int id);\n      ExplosionType(const ExplosionType& other);\n      ExplosionType& operator=(const ExplosionType& other);\n      bool operator==(const ExplosionType& other) const;\n      bool operator!=(const ExplosionType& other) const;\n      bool operator<(const ExplosionType& other) const;\n\n      /** Returns a unique ID for this explosion type. */\n      int getID() const;\n\n      /** Returns the name of this explosion type. */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace ExplosionTypes\n  {\n    /** Given a name of an explosion type, this will return the corresponding ExplosionType  object. */\n    ExplosionType getExplosionType(std::string name);\n\n    /** Returns the set of all ExplosionTypes. */\n    std::set<ExplosionType>& allExplosionTypes();\n\n    void init();\n    extern const ExplosionType None;\n    extern const ExplosionType Normal;\n    extern const ExplosionType Radial_Splash;\n    extern const ExplosionType Enemy_Splash;\n    extern const ExplosionType Lockdown;\n    extern const ExplosionType Nuclear_Missile;\n    extern const ExplosionType Parasite;\n    extern const ExplosionType Broodlings;\n    extern const ExplosionType EMP_Shockwave;\n    extern const ExplosionType Irradiate;\n    extern const ExplosionType Ensnare;\n    extern const ExplosionType Plague;\n    extern const ExplosionType Stasis_Field;\n    extern const ExplosionType Dark_Swarm;\n    extern const ExplosionType Consume;\n    extern const ExplosionType Yamato_Gun;\n    extern const ExplosionType Restoration;\n    extern const ExplosionType Disruption_Web;\n    extern const ExplosionType Corrosive_Acid;\n    extern const ExplosionType Mind_Control;\n    extern const ExplosionType Feedback;\n    extern const ExplosionType Optical_Flare;\n    extern const ExplosionType Maelstrom;\n    extern const ExplosionType Air_Splash;\n    extern const ExplosionType Unknown;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Flag.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  namespace Flag\n  {\n    enum Enum\n    {\n      /** Enable to get information about all units on the map, not just the visible units. */\n      CompleteMapInformation = 0,\n\n      /** Enable to get information from the user (what units are selected, chat messages the user enters,\n       * etc) */\n      UserInput              = 1,\n\n      Max\n    };\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Force.h",
    "content": "#pragma once\n#include <set>\n#include <string>\n\nnamespace BWAPI\n{\n  class Player;\n\n  /** The Force class is used to get information about each force in the match, such as the name of the force\n   * and the set of players in the force. */\n  class Force\n  {\n    public :\n      /** Returns a unique ID for the force. */\n      virtual int getID() const = 0;\n\n      /** Returns the name of the force. */\n      virtual std::string getName() const = 0;\n\n      /** Returns the set of players in the force. */\n      virtual std::set<Player*> getPlayers() const = 0;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Game.h",
    "content": "#pragma once\n\n#include <list>\n#include <map>\n#include <set>\n#include <vector>\n\n#include <BWAPI/Color.h>\n#include <BWAPI/CoordinateType.h>\n#include <BWAPI/Error.h>\n#include <BWAPI/Event.h>\n#include <BWAPI/Flag.h>\n#include <BWAPI/GameType.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/Order.h>\n#include <BWAPI/Latency.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/Input.h>\nnamespace BWAPI\n{\n  class Force;\n  class Player;\n  class Unit;\n  class Bullet;\n\n  /** The abstract Game class is implemented by BWAPI and offers many methods for retrieving information\n   * about the current Broodwar game, including the set of players, units, map information, as well as\n   * information about the user, such as mouse position, screen position, and the current selection of\n   * units. */\n  class Game\n  {\n    public :\n      /** Returns the set of all forces in the match. */\n      virtual std::set< Force* >& getForces() = 0;\n\n      /** Returns the set of all players in the match. Note that this includes the Neutral player, which owns\n       * all the neutral units such as minerals, critters, etc. */\n      virtual std::set< Player* >& getPlayers() = 0;\n\n      /** Returns all the visible units. If Flag::CompleteMapInformation is enabled, the set of all units\n       * is returned, not just visible ones. Note that units inside refineries are not included in this set\n       * yet. */\n      virtual std::set< Unit* >& getAllUnits() = 0;\n\n      /** Returns the set of all accessible mineral patches. */\n      virtual std::set< Unit* >& getMinerals() = 0;\n\n      /** Returns the set of all accessible vespene geysers. */\n      virtual std::set< Unit* >& getGeysers() = 0;\n\n      /** Returns the set of all accessible neutral units. */\n      virtual std::set< Unit* >& getNeutralUnits() = 0;\n\n      /** Returns the set of all mineral patches (including mined out and other inaccessible ones). */\n      virtual std::set< Unit* >& getStaticMinerals() = 0;\n\n      /** Returns the set of all vespene geysers (including mined out and other inaccessible ones). */\n      virtual std::set< Unit* >& getStaticGeysers() = 0;\n\n      /** Returns the set of all neutral units (including mined out and other inaccessible ones). */\n      virtual std::set< Unit* >& getStaticNeutralUnits() = 0;\n\n      /** Returns all visible bullets. If Flag::CompleteMapInformation is enabled, the set of all bullets is\n       * returned, not just visible ones. */\n\n      virtual std::set< Bullet* >& getBullets() = 0;\n\n      /** Returns the list of events */\n      virtual std::list< Event >& getEvents() = 0;\n\n      /** Returns the force with the given ID, or NULL if no force has the given ID */\n      virtual Force* getForce(int forceID) = 0;\n\n      /** Returns the player with the given ID, or NULL if no player has the given ID */\n      virtual Player* getPlayer(int playerID) = 0;\n\n      /** Returns the unit with the given ID, or NULL if no unit has the given ID */\n      virtual Unit* getUnit(int unitID) = 0;\n\n      /** Returns a pointer to a Unit given an index. */\n      virtual Unit* indexToUnit(int unitIndex) = 0;\n\n      /** Returns the game type */\n      virtual GameType getGameType() = 0;\n\n      /** Returns the amount of latency the current game has. Currently only returns Latency::SinglePlayer,\n       * Latency::LanLow, Latency::LanMedium, or Latency::LanHigh. */\n      virtual int getLatency() = 0;\n\n      /** Returns the number of logical frames since the match started. If the game is paused,\n       * Game::getFrameCount will not increase however AIModule::onFrame will still be called while paused.\n       * On Fastest, there are about 23.8 - 24 frames per second. */\n      virtual int getFrameCount() = 0;\n\n      /** Returns the Frames Per Second (FPS) that the game is currently running at */\n      virtual int getFPS() = 0;\n      virtual double getAverageFPS() = 0;\n\n      /** Returns the position of the mouse on the screen. Returns Positions::Unknown if Flag::UserInput is\n       * disabled. */\n      virtual BWAPI::Position getMousePosition() = 0;\n\n      /** Returns true if the specified mouse button is pressed. Returns false if Flag::UserInput is\n       * disabled. */\n      virtual bool getMouseState(MouseButton button) = 0;\n\n      /** \\copydoc getMouseState(MouseButton) */\n      virtual bool getMouseState(int button) = 0;\n\n      /** Returns true if the specified key is pressed. Returns false if Flag::UserInput is disabled.\n       * Unfortunately this does not read the raw keyboard input yet - when you hold down a key, the\n       * getKeyState function is true for a frame, then false for a few frames, and then alternates between\n       * true and false (as if you were holding down the key in a text box). Hopefully this will be fixed in\n       * a later version. */\n      virtual bool getKeyState(Key key) = 0;\n\n      /** \\copydoc getKeyState(Key) */\n      virtual bool getKeyState(int key) = 0;\n\n      /** Returns the position of the top left corner of the screen on the map. Returns Positions::Unknown if\n       * Flag::UserInput is disabled. */\n      virtual BWAPI::Position getScreenPosition() = 0;\n\n      /** Moves the screen to the given position on the map. The position specified where the top left corner\n       * of the screen will be. */\n      virtual void setScreenPosition(int x, int y) = 0;\n\n      /** \\copydoc setScreenPosition(int, int) */\n      virtual void setScreenPosition(BWAPI::Position p) = 0;\n\n      /** Pings the given position on the minimap. */\n      virtual void pingMinimap(int x, int y) = 0;\n\n      /** \\copydoc pingMinimap(int, int) */\n      virtual void pingMinimap(BWAPI::Position p) = 0;\n\n      /** Returns true if the given flag has been enabled. Note that flags can only be enabled at the\n       * beginning of a match, during the AIModule::onStart callback. */\n      virtual bool isFlagEnabled(int flag) = 0;\n\n      /** Enables the specified flag. Note that flags can only be enabled at the beginning of a match, during\n       * the AIModule::onStart callback. */\n      virtual void enableFlag(int flag) = 0;\n\n      /** Returns the set of units that are on the given build tile. Only returns accessible units on\n       * accessible tiles. */\n      virtual std::set<Unit*>& unitsOnTile(int tileX, int tileY) = 0;\n\n      /** Returns the last error that was set. If you try to order enemy units around, or morph bunkers into\n       * lurkers, BWAPI will set error codes, which can be retrieved using this function. */\n      virtual Error getLastError() const = 0;\n\n      /** Sets the last error code. */\n      virtual bool setLastError(BWAPI::Error e) = 0;\n\n      /** Returns the width of the current map, in build tile units. To get the width of the current map in\n       * walk tile units, multiply by 4. To get the width of the current map in Position units, multiply by\n       * TILE_SIZE (which is 32). */\n      virtual int mapWidth() = 0;\n\n      /** Returns the height of the current map, in build tile units. To get the height of the current map in\n       * walk tile units, multiply by 4. To get the height of the current map in Position units, multiply by\n       * TILE_SIZE (which is 32). */\n      virtual int mapHeight() = 0;\n\n      /** Returns the file name of the current map. */\n      virtual std::string mapFileName() = 0;\n\n      /** Returns the full path name of the current map. */\n      virtual std::string mapPathName() = 0;\n\n      /** Returns the name/title of the current map. */\n      virtual std::string mapName() = 0;\n\n      /** Returns the SHA-1 hash of the map file. */\n      virtual std::string mapHash() = 0;\n\n      /** Returns true if the specified walk tile is walkable. The values of x and y are in walk tile\n       * coordinates (different from build tile coordinates). Note that this just uses the static map data.\n       * You will also need to make sure no ground units are on the coresponding build tile to see if its\n       * currently walkable. To do this, see unitsOnTile. */\n      virtual bool isWalkable(int walkX, int walkY) = 0;\n\n      /** Returns the ground height of the given build tile. 0 = normal, 1 = high ground.  2 = very high ground. */\n      virtual int  getGroundHeight(int tileX, int tileY) = 0;\n      /** Returns the ground height of the given build tile. 0 = normal, 1 = high ground. 2 = very high ground. */\n      virtual int  getGroundHeight(TilePosition position) = 0;\n\n      /** Returns true if the specified build tile is buildable. Note that this just uses the static map data.\n       * You will also need to make sure no ground units on the tile to see if its currently buildable. To do\n       * this, see unitsOnTile. */\n      virtual bool isBuildable(int tileX, int tileY) = 0;\n      /** \\copydoc isBuildable(int, int) */\n      virtual bool isBuildable(TilePosition position) = 0;\n\n      /** Returns true if the specified build tile is visible. If the tile is concealed by fog of war, the\n       * function will return false. */\n      virtual bool isVisible(int tileX, int tileY) = 0;\n      /** \\copydoc isVisible(int, int) */\n      virtual bool isVisible(TilePosition position) = 0;\n\n      /** Returns true if the specified build tile has been explored (i.e. was visible at some point in the\n       * match). */\n      virtual bool isExplored(int tileX, int tileY) = 0;\n      /** \\copydoc isExplored(int, int) */\n      virtual bool isExplored(TilePosition position) = 0;\n\n      /** Returns true if the specified build tile has zerg creep on it. If the tile is concealed by fog of\n       * war, the function will return false. */\n      virtual bool hasCreep(int tileX, int tileY) = 0;\n      /** \\copydoc hasCreep(int, int) */\n      virtual bool hasCreep(TilePosition position) = 0;\n\n      /** Returns true if the given build location is powered by a nearby friendly pylon. */\n      virtual bool hasPower(int tileX, int tileY, int tileWidth, int tileHeight) = 0;\n      /** \\copydoc hasPower(int, int, int, int) */\n      virtual bool hasPower(TilePosition position, int tileWidth, int tileHeight) = 0;\n\n      /** Returns true if the given unit type can be built at the given build tile position. Note the tile\n       * position specifies the top left tile of the building. If builder is not null, the unit will be\n       * discarded when determining whether or not any ground units are blocking the build location. */\n      virtual bool canBuildHere(Unit *builder, TilePosition position, UnitType type, bool checkExplored = false) = 0;\n\n      /** Returns true if the AI player has enough resources, supply, tech, and required units in order to\n       * make the given unit type. If builder is not null, canMake will return true only if the builder unit\n       * can build the given unit type. */\n      virtual bool canMake(Unit *builder, UnitType type) = 0;\n\n      /** Returns true if the AI player has enough resources required to research the given tech type. If unit\n       * is not null, canResearch will return true only if the given unit can research the given tech type. */\n      virtual bool canResearch(Unit *unit, TechType type) = 0;\n\n      /** Returns true if the AI player has enough resources required to upgrade the given upgrade type. If\n       * unit is not null, canUpgrade will return true only if the given unit can upgrade the given upgrade\n       * type. */\n      virtual bool canUpgrade(Unit *unit, UpgradeType type) = 0;\n\n      /** Returns the set of starting locations for the given map. To determine the starting location for the\n       * players in the current match, see Player::getStartLocation. */\n      virtual std::set< TilePosition >& getStartLocations() = 0;\n\n      /** Prints text on the screen. Text is not sent to other players in multiplayer games. */\n      virtual void printf(const char *format, ...) = 0;\n\n      /** Sends text to other players - as if it were entered in chat. In single player games and replays,\n       * this will just print the text on the screen. If the game is a single player match and not a replay,\n       * then this function can be used to execute cheat codes, i.e. Broodwar->sendText(\"show me the money\"). */\n      virtual void sendText(const char *format, ...) = 0;\n      virtual void sendTextEx(bool toAllies, const char *format, ...) = 0;\n\n      /** Used to change the race while in a lobby. Note that there is no onLobbyEnter callback yet, so this\n       * function cannot be used at this time. */\n      virtual void changeRace(Race race) = 0;\n\n      /** Returns true if Broodwar is in a game. Returns false for lobby and menu screens */\n      virtual bool isInGame() = 0;\n\n      /** Returns true if Broodwar is in a multiplayer game. Returns false for single player games and\n       * replays. */\n      virtual bool isMultiplayer() = 0;\n\n      /** Returns true if Broodwar is in a BNet multiplayer game.\n      */\n      virtual bool isBattleNet() = 0;\n\n      /** Returns true if Broodwar is paused. If the game is paused, Game::getFrameCount will continue to\n       * increase and AIModule::onFrame will still be called while paused. */\n      virtual bool isPaused() = 0;\n\n      /** Returns true if Broodwar is in a replay. */\n      virtual bool isReplay() = 0;\n\n      /** Used to start the game while in a lobby. Note that there is no onLobbyEnter callback yet, so this\n       * function cannot be used at this time. */\n      virtual void startGame() = 0;\n\n      /** Pauses the game. If the game is paused, Game::getFrameCount will not increase however\n       * AIModule::onFrame will still be called while paused. */\n      virtual void pauseGame() = 0;\n\n      /** Resumes the game. */\n      virtual void resumeGame() = 0;\n\n      /** Leaves the current match and goes to the after-game stats screen. */\n      virtual void leaveGame() = 0;\n\n      /** Restarts the match. Works the same way as if you restarted the match from the menu screen. Only\n       * available in single player mode. */\n      virtual void restartGame() = 0;\n\n      /** Sets the speed of the game to the given number. Lower numbers are faster. 0 is the fastest speed\n       * StarCraft can handle (which is about as fast as the fastest speed you can view a replay at). Any\n       * negative value will reset the speed to the StarCraft default. */\n      virtual void setLocalSpeed(int speed = -1) = 0;\n\n      /** Returns the set of units currently selected by the user in the GUI. If Flag?::UserInput? was not\n       * enabled during the AIModule::onStart callback, this function will always return an empty set. */\n      virtual std::set<Unit*>& getSelectedUnits() = 0;\n\n      /** Returns a pointer to the player that BWAPI controls. In replays this will return null. */\n      virtual Player* self() = 0;\n\n      /** Returns a pointer to the enemy player. If there is more than one enemy, this returns a pointer to\n       * just one enemy (see getPlayers  and Player::isEnemy to get the other enemies). In replays this will\n       * return NULL. */\n      virtual Player* enemy() = 0;\n\n      virtual void setTextSize(int size = 1) = 0;\n      /** Draws text on the screen at the given position. Text can be drawn in different colors by using the\n       * following control characters: TODO: add image from wiki.*/\n      virtual void drawText(int ctype, int x, int y, const char* text, ...) = 0;\n      virtual void drawTextMap(int x, int y, const char* text, ...) = 0;\n      virtual void drawTextMouse(int x, int y, const char* text, ...) = 0;\n      virtual void drawTextScreen(int x, int y, const char* text, ...) = 0;\n\n      /** Draws a box on the screen, with the given color. If isSolid is true, the entire box will be\n       * rendered, otherwise just the outline will be drawn. */\n      virtual void drawBox(int ctype, int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0;\n      virtual void drawBoxMap(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0;\n      virtual void drawBoxMouse(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0;\n      virtual void drawBoxScreen(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0;\n\n      /** Draws a triangle on the screen. If isSolid is true, a solid triangle is drawn, otherwise just the\n       * outline of the triangle will be drawn. */\n      virtual void drawTriangle(int ctype, int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0;\n      virtual void drawTriangleMap(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0;\n      virtual void drawTriangleMouse(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0;\n      virtual void drawTriangleScreen(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0;\n\n      /** Draws a circle on the screen, with the given color. If isSolid is true, a solid circle is drawn,\n       * otherwise just the outline of a circle will be drawn. */\n      virtual void drawCircle(int ctype, int x, int y, int radius, Color color, bool isSolid = false) = 0;\n      virtual void drawCircleMap(int x, int y, int radius, Color color, bool isSolid = false) = 0;\n      virtual void drawCircleMouse(int x, int y, int radius, Color color, bool isSolid = false) = 0;\n      virtual void drawCircleScreen(int x, int y, int radius, Color color, bool isSolid = false) = 0;\n\n      /** Draws an ellipse on the screen, with the given color. If isSolid is true, a solid ellipse is drawn,\n       * otherwise just the outline of an ellipse will be drawn. */\n      virtual void drawEllipse(int ctype, int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0;\n      virtual void drawEllipseMap(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0;\n      virtual void drawEllipseMouse(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0;\n      virtual void drawEllipseScreen(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0;\n\n      /** Draws a dot on the screen at the given position with the given color. */\n      virtual void drawDot(int ctype, int x, int y, Color color) = 0;\n      virtual void drawDotMap(int x, int y, Color color) = 0;\n      virtual void drawDotMouse(int x, int y, Color color) = 0;\n      virtual void drawDotScreen(int x, int y, Color color) = 0;\n\n      /** Draws a line on the screen from (x1,y1) to (x2,y2) with the given color. */\n      virtual void drawLine(int ctype, int x1, int y1, int x2, int y2, Color color) = 0;\n      virtual void drawLineMap(int x1, int y1, int x2, int y2, Color color) = 0;\n      virtual void drawLineMouse(int x1, int y1, int x2, int y2, Color color) = 0;\n      virtual void drawLineScreen(int x1, int y1, int x2, int y2, Color color) = 0;\n\n      /** Retrieves the screen buffer for the game (excluding the HUD) */\n      virtual void *getScreenBuffer() = 0;\n\n      /** Retrieves latency values for the game. Includes latency, speed, and mode */\n      virtual int getLatencyFrames() = 0;\n      virtual int getLatencyTime() = 0;\n      virtual int getRemainingLatencyFrames() = 0;\n      virtual int getRemainingLatencyTime() = 0;\n\n      /** Retrieves the current revision of BWAPI. */\n      virtual int getRevision() = 0;\n\n      /** Retrieves the debug state of the BWAPI build. */\n      virtual bool isDebug() = 0;\n\n      /** Returns true if latency compensation is enabled */\n      virtual bool isLatComEnabled() = 0;\n\n      /** Use to enable or disable latency compensation. Default: Enabled */\n      virtual void setLatCom(bool isEnabled) = 0;\n\n      /** Retrieves the number of frames in the replay */\n      virtual int getReplayFrameCount() = 0;\n\n      /** Sets the rendering state of the Starcraft GUI */\n      virtual void setGUI(bool enabled = true) = 0;\n\n      /** Retrieves the instance number recorded by BWAPI to identify which instance an AI module belongs to */\n      virtual int  getInstanceNumber() = 0;\n  };\n  extern Game* Broodwar;\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/GameType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class GameType\n  {\n    public:\n      GameType();\n      GameType(int id);\n      GameType(const GameType& other);\n      GameType& operator=(const GameType& other);\n      bool operator==(const GameType& other) const;\n      bool operator!=(const GameType& other) const;\n      bool operator<(const GameType& other) const;\n\n      /** Returns the unique ID for this game type. */\n      int getID() const;\n\n      /** Returns the name of the game type. For example GameTypes::Melee.getName() will return an\n       * std::string object containing \"Melee\". */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace GameTypes\n  {\n    /** Given the name of a game type, this function will return the GameType. For example:\n     *  GameTypes::getGameType(\"Free For All\") will return GameTypes::Free_For_All. */\n    GameType getGameType(std::string name);\n\n    /** Returns the set of all the GameTypes. */\n    std::set<GameType>& allGameTypes();\n    void init();\n    extern const GameType Melee;\n    extern const GameType Free_For_All;\n    extern const GameType One_on_One;\n    extern const GameType Capture_The_Flag;\n    extern const GameType Greed;\n    extern const GameType Slaughter;\n    extern const GameType Sudden_Death;\n    extern const GameType Ladder;\n    extern const GameType Use_Map_Settings;\n    extern const GameType Team_Melee;\n    extern const GameType Team_Free_For_All;\n    extern const GameType Team_Capture_The_Flag;\n    extern const GameType Top_vs_Bottom;\n    extern const GameType Pro_Gamer_League;\n    extern const GameType None;\n    extern const GameType Unknown;\n  }\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Input.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  enum MouseButton\n  {\n    M_LEFT   = 0,\n    M_RIGHT  = 1,\n    M_MIDDLE = 2,\n  };\n\n  enum Key\n  {\n    K_LBUTTON             = 0x01,\n    K_RBUTTON             = 0x02,\n    K_CANCEL              = 0x03,\n    K_MBUTTON             = 0x04,\n    K_XBUTTON1            = 0x05,\n    K_XBUTTON2            = 0x06,\n    K_BACK                = 0x08,\n    K_TAB                 = 0x09,\n    K_CLEAR               = 0x0C,\n    K_RETURN              = 0x0D,\n    K_SHIFT               = 0x10,\n    K_CONTROL             = 0x11,\n    K_MENU                = 0x12,\n    K_PAUSE               = 0x13,\n    K_CAPITAL             = 0x14,\n    K_KANA                = 0x15,\n    K_HANGEUL             = 0x15,\n    K_HANGUL              = 0x15,\n    K_JUNJA               = 0x17,\n    K_FINAL               = 0x18,\n    K_HANJA               = 0x19,\n    K_KANJI               = 0x19,\n    K_ESCAPE              = 0x1B,\n    K_CONVERT             = 0x1C,\n    K_NONCONVERT          = 0x1D,\n    K_ACCEPT              = 0x1E,\n    K_MODECHANGE          = 0x1F,\n    K_SPACE               = 0x20,\n    K_PRIOR               = 0x21,\n    K_NEXT                = 0x22,\n    K_END                 = 0x23,\n    K_HOME                = 0x24,\n    K_LEFT                = 0x25,\n    K_UP                  = 0x26,\n    K_RIGHT               = 0x27,\n    K_DOWN                = 0x28,\n    K_SELECT              = 0x29,\n    K_PRINT               = 0x2A,\n    K_EXECUTE             = 0x2B,\n    K_SNAPSHOT            = 0x2C,\n    K_INSERT              = 0x2D,\n    K_DELETE              = 0x2E,\n    K_HELP                = 0x2F,\n    K_0                   = 0x30,\n    K_1                   = 0x31,\n    K_2                   = 0x32,\n    K_3                   = 0x33,\n    K_4                   = 0x34,\n    K_5                   = 0x35,\n    K_6                   = 0x36,\n    K_7                   = 0x37,\n    K_8                   = 0x38,\n    K_9                   = 0x39,\n    K_A                   = 0x41,\n    K_B                   = 0x42,\n    K_C                   = 0x43,\n    K_D                   = 0x44,\n    K_E                   = 0x45,\n    K_F                   = 0x46,\n    K_G                   = 0x47,\n    K_H                   = 0x48,\n    K_I                   = 0x49,\n    K_J                   = 0x4A,\n    K_K                   = 0x4B,\n    K_L                   = 0x4C,\n    K_M                   = 0x4D,\n    K_N                   = 0x4E,\n    K_O                   = 0x4F,\n    K_P                   = 0x50,\n    K_Q                   = 0x51,\n    K_R                   = 0x52,\n    K_S                   = 0x53,\n    K_T                   = 0x54,\n    K_U                   = 0x55,\n    K_V                   = 0x56,\n    K_W                   = 0x57,\n    K_X                   = 0x58,\n    K_Y                   = 0x59,\n    K_Z                   = 0x5A,\n    K_LWIN                = 0x5B,\n    K_RWIN                = 0x5C,\n    K_APPS                = 0x5D,\n    K_SLEEP               = 0x5F,\n    K_NUMPAD0             = 0x60,\n    K_NUMPAD1             = 0x61,\n    K_NUMPAD2             = 0x62,\n    K_NUMPAD3             = 0x63,\n    K_NUMPAD4             = 0x64,\n    K_NUMPAD5             = 0x65,\n    K_NUMPAD6             = 0x66,\n    K_NUMPAD7             = 0x67,\n    K_NUMPAD8             = 0x68,\n    K_NUMPAD9             = 0x69,\n    K_MULTIPLY            = 0x6A,\n    K_ADD                 = 0x6B,\n    K_SEPARATOR           = 0x6C,\n    K_SUBTRACT            = 0x6D,\n    K_DECIMAL             = 0x6E,\n    K_DIVIDE              = 0x6F,\n    K_F1                  = 0x70,\n    K_F2                  = 0x71,\n    K_F3                  = 0x72,\n    K_F4                  = 0x73,\n    K_F5                  = 0x74,\n    K_F6                  = 0x75,\n    K_F7                  = 0x76,\n    K_F8                  = 0x77,\n    K_F9                  = 0x78,\n    K_F10                 = 0x79,\n    K_F11                 = 0x7A,\n    K_F12                 = 0x7B,\n    K_F13                 = 0x7C,\n    K_F14                 = 0x7D,\n    K_F15                 = 0x7E,\n    K_F16                 = 0x7F,\n    K_F17                 = 0x80,\n    K_F18                 = 0x81,\n    K_F19                 = 0x82,\n    K_F20                 = 0x83,\n    K_F21                 = 0x84,\n    K_F22                 = 0x85,\n    K_F23                 = 0x86,\n    K_F24                 = 0x87,\n    K_NUMLOCK             = 0x90,\n    K_SCROLL              = 0x91,\n    K_OEM_NEC_EQUAL       = 0x92,\n    K_OEM_FJ_JISHO        = 0x92,\n    K_OEM_FJ_MASSHOU      = 0x93,\n    K_OEM_FJ_TOUROKU      = 0x94,\n    K_OEM_FJ_LOYA         = 0x95,\n    K_OEM_FJ_ROYA         = 0x96,\n    K_LSHIFT              = 0xA0,\n    K_RSHIFT              = 0xA1,\n    K_LCONTROL            = 0xA2,\n    K_RCONTROL            = 0xA3,\n    K_LMENU               = 0xA4,\n    K_RMENU               = 0xA5,\n    K_BROWSER_BACK        = 0xA6,\n    K_BROWSER_FORWARD     = 0xA7,\n    K_BROWSER_REFRESH     = 0xA8,\n    K_BROWSER_STOP        = 0xA9,\n    K_BROWSER_SEARCH      = 0xAA,\n    K_BROWSER_FAVORITES   = 0xAB,\n    K_BROWSER_HOME        = 0xAC,\n    K_VOLUME_MUTE         = 0xAD,\n    K_VOLUME_DOWN         = 0xAE,\n    K_VOLUME_UP           = 0xAF,\n    K_MEDIA_NEXT_TRACK    = 0xB0,\n    K_MEDIA_PREV_TRACK    = 0xB1,\n    K_MEDIA_STOP          = 0xB2,\n    K_MEDIA_PLAY_PAUSE    = 0xB3,\n    K_LAUNCH_MAIL         = 0xB4,\n    K_LAUNCH_MEDIA_SELECT = 0xB5,\n    K_LAUNCH_APP1         = 0xB6,\n    K_LAUNCH_APP2         = 0xB7,\n    K_OEM_1               = 0xBA,\n    K_OEM_PLUS            = 0xBB,\n    K_OEM_COMMA           = 0xBC,\n    K_OEM_MINUS           = 0xBD,\n    K_OEM_PERIOD          = 0xBE,\n    K_OEM_2               = 0xBF,\n    K_OEM_3               = 0xC0,\n    K_OEM_4               = 0xDB,\n    K_OEM_5               = 0xDC,\n    K_OEM_6               = 0xDD,\n    K_OEM_7               = 0xDE,\n    K_OEM_8               = 0xDF,\n    K_OEM_AX              = 0xE1,\n    K_OEM_102             = 0xE2,\n    K_ICO_HELP            = 0xE3,\n    K_ICO_00              = 0xE4,\n    K_PROCESSKEY          = 0xE5,\n    K_ICO_CLEAR           = 0xE6,\n    K_PACKET              = 0xE7,\n    K_OEM_RESET           = 0xE9,\n    K_OEM_JUMP            = 0xEA,\n    K_OEM_PA1             = 0xEB,\n    K_OEM_PA2             = 0xEC,\n    K_OEM_PA3             = 0xED,\n    K_OEM_WSCTRL          = 0xEE,\n    K_OEM_CUSEL           = 0xEF,\n    K_OEM_ATTN            = 0xF0,\n    K_OEM_FINISH          = 0xF1,\n    K_OEM_COPY            = 0xF2,\n    K_OEM_AUTO            = 0xF3,\n    K_OEM_ENLW            = 0xF4,\n    K_OEM_BACKTAB         = 0xF5,\n    K_ATTN                = 0xF6,\n    K_CRSEL               = 0xF7,\n    K_EXSEL               = 0xF8,\n    K_EREOF               = 0xF9,\n    K_PLAY                = 0xFA,\n    K_ZOOM                = 0xFB,\n    K_NONAME              = 0xFC,\n    K_PA1                 = 0xFD,\n    K_OEM_CLEAR           = 0xFE\n  };\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Latency.h",
    "content": "#pragma once\nnamespace BWAPI\n{\n  namespace Latency\n  {\n    enum Enum\n    {\n      SinglePlayer    = 2,\n      LanLow          = 5,\n      LanMedium       = 7,\n      LanHigh         = 9,\n      BattlenetLow    = 14,\n      BattlenetMedium = 19,\n      BattlenetHigh   = 24\n    };\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Order.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  /** To get detailed information about what a unit is doing, you can use the Unit::getOrder method, which\n   * will return an Order object. Note that a single command, like gather minerals, can consist of several\n   * orders ( MoveToMinerals, HarvestMinerals2, MiningMinerals, ReturnMinerals, etc) which will indicate what\n   * state the unit is in while executing the command. For information about how to issue commands to units,\n   * go to Unit. */\n  class Order\n  {\n    public:\n      Order();\n      Order(int id);\n      Order(const Order& other);\n      Order& operator=(const Order& other);\n      bool operator==(const Order& other) const;\n      bool operator!=(const Order& other) const;\n      bool operator<(const Order& other) const;\n\n      /** Returns the unique ID for this order. */\n      int getID() const;\n\n      /** Returns the name of this order. */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace Orders\n  {\n    /** Given the name of an order, getOrder() will return the corresponding order object. */\n    Order getOrder(std::string name);\n\n    /** Returns the set of all the Orders. */\n    std::set<Order>& allOrders();\n\n    void init();\n    extern const Order Die;\n    extern const Order Stop;\n    extern const Order Guard;\n    extern const Order PlayerGuard;\n    extern const Order TurretGuard;\n    extern const Order BunkerGuard;\n    extern const Order Move;\n    extern const Order AttackUnit;\n    extern const Order AttackTile;\n    extern const Order Hover;\n    extern const Order AttackMove;\n    extern const Order InfestedCommandCenter;\n    extern const Order UnusedNothing;\n    extern const Order UnusedPowerup;\n    extern const Order TowerGuard;\n    extern const Order VultureMine;\n    extern const Order Nothing;\n    extern const Order Nothing3;\n    extern const Order CastInfestation;\n    extern const Order InfestingCommandCenter;\n    extern const Order PlaceBuilding;\n    extern const Order BuildProtoss2;\n    extern const Order ConstructingBuilding;\n    extern const Order Repair;\n    extern const Order PlaceAddon;\n    extern const Order BuildAddon;\n    extern const Order Train;\n    extern const Order RallyPointUnit;\n    extern const Order RallyPointTile;\n    extern const Order ZergBirth;\n    extern const Order ZergUnitMorph;\n    extern const Order ZergBuildingMorph;\n    extern const Order IncompleteBuilding;\n    extern const Order BuildNydusExit;\n    extern const Order EnterNydusCanal;\n    extern const Order Follow;\n    extern const Order Carrier;\n    extern const Order ReaverCarrierMove;\n    extern const Order CarrierIgnore2;\n    extern const Order Reaver;\n    extern const Order TrainFighter;\n    extern const Order InterceptorAttack;\n    extern const Order ScarabAttack;\n    extern const Order RechargeShieldsUnit;\n    extern const Order RechargeShieldsBattery;\n    extern const Order ShieldBattery;\n    extern const Order InterceptorReturn;\n    extern const Order BuildingLand;\n    extern const Order BuildingLiftOff;\n    extern const Order DroneLiftOff;\n    extern const Order LiftingOff;\n    extern const Order ResearchTech;\n    extern const Order Upgrade;\n    extern const Order Larva;\n    extern const Order SpawningLarva;\n    extern const Order Harvest1;\n    extern const Order Harvest2;\n    extern const Order MoveToGas;\n    extern const Order WaitForGas;\n    extern const Order HarvestGas;\n    extern const Order ReturnGas;\n    extern const Order MoveToMinerals;\n    extern const Order WaitForMinerals;\n    extern const Order MiningMinerals;\n    extern const Order Harvest3;\n    extern const Order Harvest4;\n    extern const Order ReturnMinerals;\n    extern const Order Interrupted;\n    extern const Order EnterTransport;\n    extern const Order PickupIdle;\n    extern const Order PickupTransport;\n    extern const Order PickupBunker;\n    extern const Order Pickup4;\n    extern const Order PowerupIdle;\n    extern const Order Sieging;\n    extern const Order Unsieging;\n    extern const Order InitCreepGrowth;\n    extern const Order SpreadCreep;\n    extern const Order StoppingCreepGrowth;\n    extern const Order GuardianAspect;\n    extern const Order ArchonWarp;\n    extern const Order CompletingArchonsummon;\n    extern const Order HoldPosition;\n    extern const Order Cloak;\n    extern const Order Decloak;\n    extern const Order Unload;\n    extern const Order MoveUnload;\n    extern const Order FireYamatoGun;\n    extern const Order CastLockdown;\n    extern const Order Burrowing;\n    extern const Order Burrowed;\n    extern const Order Unburrowing;\n    extern const Order CastDarkSwarm;\n    extern const Order CastParasite;\n    extern const Order CastSpawnBroodlings;\n    extern const Order CastEMPShockwave;\n    extern const Order NukeWait;\n    extern const Order NukeTrain;\n    extern const Order NukeLaunch;\n    extern const Order NukeUnit;\n    extern const Order CastNuclearStrike;\n    extern const Order NukeTrack;\n    extern const Order CloakNearbyUnits;\n    extern const Order PlaceMine;\n    extern const Order RightClickAction;\n    extern const Order CastRecall;\n    extern const Order TeleporttoLocation;\n    extern const Order CastScannerSweep;\n    extern const Order Scanner;\n    extern const Order CastDefensiveMatrix;\n    extern const Order CastPsionicStorm;\n    extern const Order CastIrradiate;\n    extern const Order CastPlague;\n    extern const Order CastConsume;\n    extern const Order CastEnsnare;\n    extern const Order CastStasisField;\n    extern const Order CastHallucination;\n    extern const Order Hallucination2;\n    extern const Order ResetCollision;\n    extern const Order Patrol;\n    extern const Order CTFCOPInit;\n    extern const Order CTFCOP1;\n    extern const Order CTFCOP2;\n    extern const Order ComputerAI;\n    extern const Order AtkMoveEP;\n    extern const Order HarassMove;\n    extern const Order AIPatrol;\n    extern const Order GuardPost;\n    extern const Order RescuePassive;\n    extern const Order Neutral;\n    extern const Order ComputerReturn;\n    extern const Order SelfDestrucing;\n    extern const Order Critter;\n    extern const Order HiddenGun;\n    extern const Order OpenDoor;\n    extern const Order CloseDoor;\n    extern const Order HideTrap;\n    extern const Order RevealTrap;\n    extern const Order Enabledoodad;\n    extern const Order Disabledoodad;\n    extern const Order Warpin;\n    extern const Order Medic;\n    extern const Order MedicHeal1;\n    extern const Order HealMove;\n    extern const Order MedicHeal2;\n    extern const Order CastRestoration;\n    extern const Order CastDisruptionWeb;\n    extern const Order CastMindControl;\n    extern const Order DarkArchonMeld;\n    extern const Order CastFeedback;\n    extern const Order CastOpticalFlare;\n    extern const Order CastMaelstrom;\n    extern const Order JunkYardDog;\n    extern const Order Fatal;\n    extern const Order None;\n    extern const Order Unknown;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Player.h",
    "content": "#pragma once\n#include <set>\n#include <string>\n\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/PlayerType.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/Client/PlayerData.h>\n#include <BWAPI/Color.h>\nnamespace BWAPI\n{\n  class Unit;\n  class Force;\n\n  /** Each player in a match will have his or her own player instance. There is also a neutral player which\n   * owns all the neutral units. */\n  class Player\n  {\n    public :\n      /** Returns a unique ID for the player. */\n      virtual int getID() const = 0;\n\n      /** Returns the name of the player. */\n      virtual std::string getName() const = 0;\n\n      /** Returns the set of units the player own. Note that units loaded into Terran dropships, Terran\n       * bunkers, Terran refineries, Protoss assimilators, and Zerg extractors are not yet included in the\n       * set. */\n      virtual const std::set<Unit*>& getUnits() const = 0;\n\n      /** Returns the race of the player. */\n      virtual Race getRace() const = 0;\n\n      /** Returns the type of the player. */\n      virtual PlayerType getType() const = 0;\n\n      /** Returns the force the player is on. */\n      virtual Force* getForce() const = 0;\n\n      /** Returns true if other player is an ally of this player. */\n      virtual bool isAlly(Player* player) const = 0;\n\n      /** Returns true if other player is an enemy of this player. */\n      virtual bool isEnemy(Player* player) const = 0;\n\n      /** Returns true if the player is the neutral player. */\n      virtual bool isNeutral() const = 0;\n\n      /** Returns the starting location of the player. If complete map information is disabled, this function\n       * will return TilePositions::Unknown for enemy players. For the complete set of starting locations for\n       * the current map, see Game::getStartLocations. */\n      virtual TilePosition getStartLocation() const = 0;\n\n      /** Returns true if the player has achieved victory. */\n      virtual bool isVictorious() const = 0;\n\n      /** Returns true if the player has been defeated. */\n      virtual bool isDefeated() const = 0;\n\n      /** Returns true if the player left the game. */\n      virtual bool leftGame() const = 0;\n\n      /** Returns the amount of minerals the player has. */\n      virtual int minerals() const = 0;\n\n      /** Returns the amount of vespene gas the player has. */\n      virtual int gas() const = 0;\n\n      /** Returns the cumulative amount of minerals the player has mined up to this point (including the 50\n       * minerals at the start of the game). */\n      virtual int cumulativeMinerals() const = 0;\n\n      /** Returns the cumulative amount of gas the player has harvested up to this point. */\n      virtual int cumulativeGas() const = 0;\n\n      // TODO: ground methods\n      /** Returns the total amount of supply the player has. If a race is provided, the total supply for the\n       * given race will be returned, otherwise the player's initial race will be used. Supply counts returned\n       * by BWAPI are double what you would expect to see from playing the game. This is because zerglings\n       * take up 0.5 in-game supply. */\n      virtual int supplyTotal() const = 0;\n      virtual int supplyTotal(Race race) const = 0;\n\n      /** Returns how much of the supply is actually being used by units. If a race is provided, the used\n       * supply for the given race will be returned, otherwise the player's initial race will be used. Supply\n       * counts returned by BWAPI are double what you would expect to see from playing the game. This is\n       * because zerglings take up 0.5 in-game supply. */\n      virtual int supplyUsed() const = 0;\n      virtual int supplyUsed(Race race) const = 0;\n\n      /** Returns the number of all units of the given type. */\n      virtual int allUnitCount(UnitType unit) const = 0;\n\n      /** Returns the number of completed units of the given type. */\n      virtual int completedUnitCount(UnitType unit) const = 0;\n\n      /** Returns the number of incomplete units of the given type. */\n      virtual int incompleteUnitCount(UnitType unit) const = 0;\n\n      /** Returns the number of dead units of the given type. */\n      virtual int deadUnitCount(UnitType unit) const = 0;\n\n      /** Returns the number of killed units of the given type. */\n      virtual int killedUnitCount(UnitType unit) const = 0;\n\n      /** Returns the player's current upgrade level of the given upgrade. To order a unit to upgrade a given\n       * upgrade type, see Unit::upgrade. */\n      virtual int  getUpgradeLevel(UpgradeType upgrade) const = 0;\n\n      /** Returns true if the player has finished researching the given tech. To order a unit to research a\n       * given tech type, see Unit::research. */\n      virtual bool hasResearched(TechType tech) const = 0;\n\n      /** Returns true if the player is researching the given tech. To order a unit to research a given tech\n       * type, see Unit::reseach. */\n      virtual bool isResearching(TechType tech) const = 0;\n\n      /** Returns true if the player is upgrading the given upgrade. To order a unit to upgrade a given\n       * upgrade type, see Unit::upgrade. */\n      virtual bool isUpgrading(UpgradeType upgrade) const = 0;\n\n      /** Returns the max energy of the given unit type, taking into account upgrades */\n      virtual int maxEnergy(UnitType unit) const = 0;\n\n      /** Returns the color of the player for drawing */\n      virtual BWAPI::Color getColor() const = 0;\n\n      /** Returns the color of the player for text messages */\n      virtual int getTextColor() const = 0;\n  };\n};\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/PlayerType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class PlayerType\n  {\n    public:\n      PlayerType();\n      PlayerType(int id);\n      PlayerType(const PlayerType& other);\n      PlayerType& operator=(const PlayerType& other);\n      bool operator==(const PlayerType& other) const;\n      bool operator!=(const PlayerType& other) const;\n      bool operator<(const PlayerType& other) const;\n\n      /** Returns the unique ID for this player type. */\n      int getID() const;\n\n      /** Returns the name of the player type. For example PlayerTypes::Computer.getName() will return an\n       * std::string object containing \"Computer\". */\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace PlayerTypes\n  {\n    /** Given the name of a player type, this function will return the playertype. For example:\n     *  PlayerTypes::getPlayerType(\"Human\") will return PlayerTypes::Human. */\n    PlayerType getPlayerType(std::string name);\n\n    /** Returns the set of all the PlayerTypes. */\n    std::set<PlayerType>& allPlayerTypes();\n    void init();\n    extern const PlayerType None;\n    extern const PlayerType Computer;\n    extern const PlayerType Player;\n    extern const PlayerType RescuePassive;\n    extern const PlayerType EitherPreferComputer;\n    extern const PlayerType EitherPreferHuman;\n    extern const PlayerType Neutral;\n    extern const PlayerType Closed;\n    extern const PlayerType PlayerLeft;\n    extern const PlayerType ComputerLeft;\n    extern const PlayerType Unknown;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Position.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  class TilePosition;\n\n  // TODO: Add doxygen documentation\n  class Position\n  {\n    public :\n      Position();\n      explicit Position(const TilePosition& position);\n      Position(int x, int y);\n      bool operator == (const Position& position) const;\n      bool operator != (const Position& position) const;\n      bool operator  < (const Position& position) const;\n      bool isValid() const;\n      Position operator+(const Position& position) const;\n      Position operator-(const Position& position) const;\n      Position& makeValid();\n      Position& operator+=(const Position& position);\n      Position& operator-=(const Position& position);\n      double getDistance(const Position& position) const;\n      double getApproxDistance(const Position& position) const;\n      double getLength() const;\n      int& x();\n      int& y();\n      int x() const;\n      int y() const;\n    private :\n      int _x;\n      int _y;\n  };\n  namespace Positions\n  {\n    extern const Position Invalid;\n    extern const Position None;\n    extern const Position Unknown;\n  }\n};\n\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Race.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class UnitType;\n  class Race\n  {\n    public:\n      Race();\n      Race(int id);\n      Race(const Race& other);\n      Race& operator=(const Race& other);\n      bool operator==(const Race& other) const;\n      bool operator!=(const Race& other) const;\n      bool operator<(const Race& other) const;\n\n      /** Returns a unique ID for this race. */\n      int getID() const;\n\n      /** Returns the name of the race. For example Races::Terran.getName() will return a std::string object\n       * containing \"Terran\". */\n      std::string getName() const;\n\n      /** Returns the worker unit type for the given race. For example Races::Protoss.getWorker() will return\n       * a pointer to UnitTypes::Protoss_Probe. */\n      UnitType getWorker() const;\n\n      /** Returns the center unit type for the given race. For example Races::Terran.getCenter() will return a\n       * pointer to UnitTypes::Terran_Command_Center. While there are three center types for Zerg\n       * (Hatchery, Lair, and Hive), Races::Zerg.getCenter() will only return a pointer to\n       * UnitTypes::Zerg_Hatchery, since it is the unit type needed to make a new center. */\n      UnitType getCenter() const;\n\n      /** Returns the refinery unit type for the given race. For example: Races::Zerg.getRefinery() will\n       * return a pointer to UnitTypes::Zerg_Extractor?. */\n      UnitType getRefinery() const;\n\n      /** Returns the transport unit type for the given race. For example: Races::Protoss.getTransport() will\n       * return a pointer to UnitTypes::Protoss_Shuttle. */\n      UnitType getTransport() const;\n\n      /** Returns the main supply provider unit type for the given race. For example:\n       * Races::Terran.getSupplyProvider() will return a pointer to UnitTypes::Terran_Supply_Depot?. */\n      UnitType getSupplyProvider() const;\n    private:\n      int id;\n  };\n  namespace Races\n  {\n    /** Given the name of a race, this function will return the race type. For example:\n     * Races::getRace(\"Zerg\") will return Races::Zerg. */\n    Race getRace(std::string name);\n\n    /** Returns the set of all the races, which are listed below. */\n    std::set<Race>& allRaces();\n    void init();\n    extern const Race Zerg;\n    extern const Race Terran;\n    extern const Race Protoss;\n    extern const Race Random;\n    extern const Race Other;\n    extern const Race None;\n    extern const Race Unknown;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/TechType.h",
    "content": "#pragma once\n\n#include <string>\n#include <set>\n#include <BWAPI/Race.h>\nnamespace BWAPI\n{\n  class UnitType;\n  class WeaponType;\n  class TechType\n  {\n    public:\n      TechType();\n      TechType(int id);\n      TechType(const TechType& other);\n      TechType& operator=(const TechType& other);\n      bool operator==(const TechType& other) const;\n      bool operator!=(const TechType& other) const;\n      bool operator<(const TechType& other) const;\n      /** Returns the unique ID for this tech type. */\n      int getID() const;\n\n      /** Returns the name of the tech type. */\n      std::string getName() const;\n\n      /** Returns the race that uses the TechType. For example, TechTypes::Scanner_Sweep?.getRace() will\n       * return Races::Terran. */\n      Race getRace() const;\n\n      /** Returns the mineral cost of the tech type. */\n      int mineralPrice() const;\n\n      /** Returns the vespene gas price of the tech type. */\n      int gasPrice() const;\n\n      /** Returns the number of frames needed to research the tech type. */\n      int researchTime() const;\n\n      /** Returns the amount of energy used each time this tech type is used. */\n      int energyUsed() const;\n\n      /** Returns the type of unit that researches this tech type. If this tech type is available for free\n       * (does not need to be researched), then this method will return UnitTypes::None. */\n      UnitType whatResearches() const;\n\n      /** Returns the corresponding weapon for this tech type, or TechTypes::None if no corresponding weapon\n       * exists. For example, TechTypes::Dark_Swarm.getWeapon() will return a pointer to\n       * WeaponTypes::Dark_Swarm. */\n      WeaponType getWeapon() const;\n\n      /** Returns the set of units that can use this tech type. Usually this will just be a set of one unit\n       * type, however in some cases, such as TechTypes::Burrowing, several unit types will be returned. */\n      const std::set<UnitType>& whatUses() const;\n    private:\n      int id;\n  };\n  namespace TechTypes\n  {\n    /** Given a string, this will return the tech type. */\n    TechType getTechType(std::string name);\n\n    /** Returns the set of all the TechTypes. */\n    std::set<TechType>& allTechTypes();\n    void init();\n    extern const TechType Stim_Packs;\n    extern const TechType Lockdown;\n    extern const TechType EMP_Shockwave;\n    extern const TechType Spider_Mines;\n    extern const TechType Scanner_Sweep;\n    extern const TechType Tank_Siege_Mode;\n    extern const TechType Defensive_Matrix;\n    extern const TechType Irradiate;\n    extern const TechType Yamato_Gun;\n    extern const TechType Cloaking_Field;\n    extern const TechType Personnel_Cloaking;\n    extern const TechType Burrowing;\n    extern const TechType Infestation;\n    extern const TechType Spawn_Broodlings;\n    extern const TechType Dark_Swarm;\n    extern const TechType Plague;\n    extern const TechType Consume;\n    extern const TechType Ensnare;\n    extern const TechType Parasite;\n    extern const TechType Psionic_Storm;\n    extern const TechType Hallucination;\n    extern const TechType Recall;\n    extern const TechType Stasis_Field;\n    extern const TechType Archon_Warp;\n    extern const TechType Restoration;\n    extern const TechType Disruption_Web;\n    extern const TechType Mind_Control;\n    extern const TechType Dark_Archon_Meld;\n    extern const TechType Feedback;\n    extern const TechType Optical_Flare;\n    extern const TechType Maelstrom;\n    extern const TechType Lurker_Aspect;\n    extern const TechType Healing;\n    extern const TechType None;\n    extern const TechType Unknown;\n    extern const TechType Nuclear_Strike;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/TilePosition.h",
    "content": "#pragma once\n\nnamespace BWAPI\n{\n  class Position;\n\n  // TODO: Add doxygen documentation\n  class TilePosition\n  {\n    public :\n      TilePosition();\n      explicit TilePosition(const Position& position);\n      TilePosition(int x, int y);\n      bool operator == (const TilePosition& TilePosition) const;\n      bool operator != (const TilePosition& TilePosition) const;\n      bool operator  < (const TilePosition& TilePosition) const;\n      bool isValid() const;\n      TilePosition operator+(const TilePosition& position) const;\n      TilePosition operator-(const TilePosition& position) const;\n      TilePosition& makeValid();\n      TilePosition& operator+=(const TilePosition& position);\n      TilePosition& operator-=(const TilePosition& position);\n      double getDistance(const TilePosition& position) const;\n      double getLength() const;\n      int& x();\n      int& y();\n      int x() const;\n      int y() const;\n    private :\n      int _x;\n      int _y;\n  };\n  namespace TilePositions\n  {\n    extern const TilePosition Invalid;\n    extern const TilePosition None;\n    extern const TilePosition Unknown;\n  }\n};\n\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/Unit.h",
    "content": "#pragma once\n\n#include <list>\n\n#include <BWAPI/Order.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/UnitCommand.h>\n#include <BWAPI/Client/UnitData.h>\nnamespace BWAPI\n{\n  class Player;\n\n  /** The Unit class is used to get information about individual units as well as issue orders to units. Each\n   * unit in the game has a unique Unit object, and Unit objects are not deleted until the end of the match\n   * (so you don't need to worry about unit pointers becoming invalid).\n   *\n   * Every Unit in the game is either accessible or inaccessible. To determine if an AI can access a\n   * particular unit, BWAPI checks to see if Flag::CompleteMapInformation? is enabled. So there are two cases\n   * to consider - either the flag is enabled, or it is disabled:\n   *\n   * If Flag::CompleteMapInformation? is disabled, then a unit is accessible if and only if it is visible.\n   * Note also that some properties of visible enemy units will not be made available to the AI (such as the\n   * contents of visible enemy dropships). If a unit is not visible, Unit::exists will return false,\n   * regardless of whether or not the unit exists. This is because absolutely no state information on\n   * invisible enemy units is made available to the AI. To determine if an enemy unit has been destroyed, the\n   * AI must watch for AIModule::onUnitDestroy messages from BWAPI, which is only called for visible units\n   * which get destroyed.\n   *\n   * If Flag::CompleteMapInformation? is enabled, then all units that exist in the game are accessible, and\n   * Unit::exists is accurate for all units. Similarly AIModule::onUnitDestroy messages are generated for all\n   * units that get destroyed, not just visible ones.\n   *\n   * If a Unit is not accessible, in general the only the getInitial__ functions will be available to the AI.\n   * However for units that were owned by the player, getPlayer and getType will continue to work for units\n   * that have been destroyed. */\n  class Unit\n  {\n    public:\n      /** Returns a unique ID for this unit. It simply casts the unit's address as an integer, since each unit\n       * has a unique address. */\n      virtual int getID() const = 0;\n\n      /** Returns a pointer to the player that owns this unit. */\n      virtual Player* getPlayer() const = 0;\n\n      /** Returns the current type of the unit. */\n      virtual UnitType getType() const = 0;\n\n      /** Returns the position of the unit on the map. */\n      virtual Position getPosition() const = 0;\n\n      /** Returns the build tile position of the unit on the map. Useful if the unit is a building. The tile\n       * position is of the top left corner of the building. */\n      virtual TilePosition getTilePosition() const = 0;\n\n      /** Returns the direction the unit is facing, measured in radians. An angle of 0 means the unit is\n       * facing east. */\n      virtual double getAngle() const = 0;\n\n      /** Returns the x component of the unit's velocity, measured in pixels per frame. */\n      virtual double getVelocityX() const = 0;\n\n      /** Returns the y component of the unit's velocity, measured in pixels per frame. */\n      virtual double getVelocityY() const = 0;\n\n      /** Returns the unit's current amount of hit points. */\n      virtual int getHitPoints() const = 0;\n\n      /** Returns the unit's current amount of shields. */\n      virtual int getShields() const = 0;\n\n      /** Returns the unit's current amount of energy. */\n      virtual int getEnergy() const = 0;\n\n      /** Returns the unit's current amount of containing resources. Useful for determining how much minerals\n       * are left in a mineral patch, or how much gas is left in a geyser\n       * (can also be called on a refinery/assimilator/extractor). */\n      virtual int getResources() const = 0;\n\n      /** Retrieves the group ID of a resource. Can be used to identify which resources belong to an expansion. */\n      virtual int getResourceGroup() const = 0;\n\n      /** Returns the edge-to-edge distance between the current unit and the target unit. */\n      virtual double getDistance(Unit* target) const = 0;\n\n      /** Returns the distance from the edge of the current unit to the target position. */\n      virtual double getDistance(Position target) const = 0;\n\n      /** Returns true if the unit is able to move to the target unit */\n      virtual bool hasPath(Unit* target) const = 0;\n\n      /** Returns true if the unit is able to move to the target position */\n      virtual bool hasPath(Position target) const = 0;\n\n      /** Retrieves the frame of the last successful order. Frame is comparable to Game::getFrameCount(). */\n      virtual int getLastOrderFrame() const = 0;\n\n      /** Returns the player's current upgrade level for the given upgrade, if the unit is affected by this\n       * upgrade.*/\n      virtual int getUpgradeLevel(UpgradeType upgrade) const = 0;\n\n      /** Returns the initial type of the unit or Unknown if it wasn't a neutral unit at the beginning of the\n       * game. */\n      virtual UnitType getInitialType() const = 0;\n\n      /** Returns the initial position of the unit on the map, or Positions::Unknown if the unit wasn't a\n       * neutral unit at the beginning of the game. */\n      virtual Position getInitialPosition() const = 0;\n\n      /** Returns the initial build tile position of the unit on the map, or TilePositions::Unknown if the\n       * unit wasn't a neutral unit at the beginning of the game. The tile position is of the top left corner\n       * of the building. */\n      virtual TilePosition getInitialTilePosition() const = 0;\n\n      /** Returns the unit's initial amount of hit points, or 0 if it wasn't a neutral unit at the beginning\n       * of the game. */\n      virtual int getInitialHitPoints() const = 0;\n\n      /** Returns the unit's initial amount of containing resources, or 0 if the unit wasn't a neutral unit\n       * at the beginning of the game. */\n      virtual int getInitialResources() const = 0;\n\n      /** Returns the unit's current kill count. */\n      virtual int getKillCount() const = 0;\n\n      /** Returns the number of interceptors the Protoss Carrier has. */\n      virtual int getInterceptorCount() const = 0;\n\n      /** Returns the number of scarabs in the Protoss Reaver. */\n      virtual int getScarabCount() const = 0;\n\n      /** Returns the number of spider mines in the Terran Vulture. */\n      virtual int getSpiderMineCount() const = 0;\n\n      /** Returns unit's ground weapon cooldown. It is 0 if the unit is ready to attack. */\n      virtual int getGroundWeaponCooldown() const = 0;\n\n      /** Returns unit's air weapon cooldown. It is 0 if the unit is ready to attack. */\n      virtual int getAirWeaponCooldown() const = 0;\n\n      /** Returns unit's ground weapon cooldown. It is 0 if the unit is ready cast a spell. */\n      virtual int getSpellCooldown() const = 0;\n\n      /** Returns the remaining hit points of the defense matrix. Initially a defense Matrix has 250 points.\n       * \\see Unit::getDefenseMatrixTimer, Unit::isDefenseMatrixed. */\n      virtual int getDefenseMatrixPoints() const = 0;\n\n      /** Returns the time until the defense matrix wears off. 0 -> No defense Matrix present. */\n      virtual int getDefenseMatrixTimer() const = 0;\n\n      /** Returns the time until the ensnare effect wears off. 0 -> No ensnare effect present. */\n      virtual int getEnsnareTimer() const = 0;\n\n      /** Returns the time until the radiation wears off. 0 -> No radiation present. */\n      virtual int getIrradiateTimer() const = 0;\n\n      /** Returns the time until the lockdown wears off. 0 -> No lockdown present. */\n      virtual int getLockdownTimer() const = 0;\n\n      /** Returns the time until the maelstrom wears off. 0 -> No maelstrom present. */\n      virtual int getMaelstromTimer() const = 0;\n\n      // TODO: add doc\n      virtual int getOrderTimer() const = 0;\n\n      /** Returns the time until the plague wears off. 0 -> No plague present. */\n      virtual int getPlagueTimer() const = 0;\n\n      /** Returns the amount of time until the unit is removed, or 0 if the unit does not have a remove timer.\n       * Used to determine how much time remains before hallucinated units, dark swarm, etc have until they\n       * are removed. */\n      virtual int getRemoveTimer() const = 0;\n\n      /** Returns the time until the stasis field wears off. 0 -> No stasis field present. */\n      virtual int getStasisTimer() const = 0;\n\n      /** Returns the time until the stimpack wears off. 0 -> No stimpack boost present. */\n      virtual int getStimTimer() const = 0;\n\n      /** Returns the building type a worker is about to construct. If the unit is a morphing Zerg unit or an\n       * incomplete building, this returns the UnitType the unit is about to become upon completion.*/\n      virtual UnitType getBuildType() const = 0;\n\n     /** Returns the list of units queued up to be trained.\n       * \\see Unit::train, Unit::cancelTrain, Unit::isTraining. */\n      virtual std::list<UnitType > getTrainingQueue() const = 0;\n\n      /** Returns the tech that the unit is currently researching. If the unit is not researching anything,\n       * TechTypes::None is returned.\n       * \\see Unit::research, Unit::cancelResearch, Unit::isResearching, Unit::getRemainingResearchTime. */\n      virtual TechType getTech() const = 0;\n\n      /** Returns the upgrade that the unit is currently upgrading. If the unit is not upgrading anything,\n       * UpgradeTypes::None is returned.\n       * \\see Unit::upgrade, Unit::cancelUpgrade, Unit::isUpgrading, Unit::getRemainingUpgradeTime. */\n      virtual UpgradeType getUpgrade() const = 0;\n\n      /** Returns the remaining build time of a unit/building that is being constructed. */\n      virtual int getRemainingBuildTime() const = 0;\n\n      /** Returns the remaining time of the unit that is currently being trained. If the unit is a Hatchery,\n       * Lair, or Hive, this returns the amount of time until the next larva spawns, or 0 if the unit already\n       * has 3 larva. */\n      virtual int getRemainingTrainTime() const = 0;\n\n      /** Returns the amount of time until the unit is done researching its current tech. If the unit is not\n       * researching anything, 0 is returned.\n       * \\see Unit::research, Unit::cancelResearch, Unit::isResearching, Unit::getTech. */\n      virtual int getRemainingResearchTime() const = 0;\n\n      /** Returns the amount of time until the unit is done upgrading its current upgrade. If the unit is not\n       * upgrading anything, 0 is returned.\n       * \\see Unit::upgrade, Unit::cancelUpgrade, Unit::isUpgrading, Unit::getUpgrade. */\n      virtual int getRemainingUpgradeTime() const = 0;\n\n      /** If the unit is an SCV that is constructing a building, this will return the building it is\n       * constructing. If the unit is a Terran building that is being constructed, this will return the SCV\n       * that is constructing it. */\n      virtual Unit* getBuildUnit() const = 0;\n\n      /** Generally returns the appropriate target unit after issuing an order that accepts a target unit\n       * (i.e. attack, repair, gather, follow, etc.). To check for a target that has been acquired\n       * automatically (without issuing an order) see getOrderTarget. */\n      virtual Unit* getTarget() const = 0;\n\n      /** Returns the target position the unit is moving to (provided a valid path to the target position\n       * exists). */\n      virtual Position getTargetPosition() const = 0;\n\n      // TODO: add doc\n      virtual Order getOrder() const = 0;\n\n      /** This is usually set when the low level unit AI acquires a new target automatically. For example if\n       * an enemy probe comes in range of your marine, the marine will start attacking it, and getOrderTarget\n       * will be set in this case, but not getTarget. */\n      virtual Unit* getOrderTarget() const = 0;\n      virtual Order getSecondaryOrder() const = 0;\n\n      /** Returns the position the building is rallied to. If the building does not produce units,\n       * Positions::None is returned.\n       * \\see Unit::setRallyPoint, Unit::getRallyUnit. */\n      virtual Position getRallyPosition() const = 0;\n\n      /** Returns the unit the building is rallied to. If the building is not rallied to any unit, NULL is\n       * returned.\n       * \\see Unit::setRallyPoint, Unit::getRallyPosition. */\n      virtual Unit* getRallyUnit() const = 0;\n\n      /** Returns the add-on of this unit, or NULL if the unit doesn't have an add-on. */\n      virtual Unit* getAddon() const = 0;\n\n      /** Returns the corresponding connected nydus canal of this unit, or NULL if the unit does not have a\n       * connected nydus canal. */\n      virtual Unit* getNydusExit() const = 0;\n\n      /** Returns the power up the unit is holding, or NULL if the unit is not holding a power up */\n      virtual Unit* getPowerUp() const = 0;\n\n      /** Returns the dropship, shuttle, overlord, or bunker that is this unit is loaded in to. */\n      virtual Unit* getTransport() const = 0;\n\n      /** Returns a list of the units loaded into a Terran Bunker, Terran Dropship, Protoss Shuttle, or Zerg\n       * Overlord. */\n      virtual std::set<Unit*> getLoadedUnits() const = 0;\n\n      /** For Protoss Interceptors, this returns the Carrier unit this Interceptor is controlled by. For all\n       * other unit types this function returns NULL. */\n      virtual Unit* getCarrier() const = 0;\n\n      /** Returns the set of interceptors controlled by this unit. If the unit has no interceptors, or is not\n       * a Carrier, this function returns an empty set. */\n      virtual std::set<Unit*> getInterceptors() const = 0;\n\n      /** For Zerg Larva, this returns the Hatchery, Lair, or Hive unit this Larva was spawned from. For all\n       * other unit types this function returns NULL. */\n      virtual Unit* getHatchery() const = 0;\n\n      /** Returns the set of larva spawned by this unit. If the unit has no larva, or is not a Hatchery, Lair,\n       * or Hive, this function returns an empty set. Equivalent to clicking \"Select Larva\" from the Starcraft\n       * GUI. */\n      virtual std::set<Unit*> getLarva() const = 0;\n\n      /**\n       * 3 cases to consider:\n       *\n       * - If exists() returns true, the unit exists.\n       * - If exists() returns false and the unit is owned by self(), then the unit does not exist.\n       * - If exists() returns false and the unit is not owned by self(), then the unit may or may not exist.\n       *\n       * \\see Unit::isVisible.\n       * */\n      virtual bool exists() const = 0;\n\n      /* Returns true if the Nuclear Missile Silo has a nuke */\n      virtual bool hasNuke() const = 0;\n\n      /** Returns true if the unit is currently accelerating. */\n      virtual bool isAccelerating() const = 0;\n\n      // TODO: add doc\n      virtual bool isAttacking() const = 0;\n\n      /** Returns true if the unit is being constructed. Always true for incomplete Protoss and Zerg\n       * buildings, and true for incomplete Terran buildings that have an SCV constructing them. If the SCV\n       * halts construction, isBeingConstructed will return false.\n       *\n       * \\see Unit::build, Unit::cancelConstruction, Unit::haltConstruction, Unit::isConstructing. */\n      virtual bool isBeingConstructed() const = 0;\n\n      /** Returns true if the unit is a mineral patch or refinery that is being gathered. */\n      virtual bool isBeingGathered() const = 0;\n\n      /** Returns true if the unit is currently being healed by a Terran Medic, or repaired by a Terran SCV. */\n      virtual bool isBeingHealed() const = 0;\n\n      /** Returns true if the unit is currently blind from a Medic's Optical Flare. */\n      virtual bool isBlind() const = 0;\n\n      /** Returns true if the unit is currently braking/slowing down. */\n      virtual bool isBraking() const = 0;\n\n      /** Returns true if the unit is a Zerg unit that is current burrowed.\n       * \\see Unit::burrow, Unit::unburrow. */\n      virtual bool isBurrowed() const = 0;\n\n      /** Returns true if the unit is a worker that is carrying gas.\n       * \\see Unit::returnCargo, Unit::isGatheringGas. */\n      virtual bool isCarryingGas() const = 0;\n\n      /** Returns true if the unit is a worker that is carrying minerals.\n       * \\see Unit::returnCargo, Unit::isGatheringMinerals. */\n      virtual bool isCarryingMinerals() const = 0;\n\n      /** Returns true if the unit is cloaked.\n       * \\see Unit::cloak, Unit::decloak. */\n      virtual bool isCloaked() const = 0;\n\n      /** Returns true if the unit has been completed. */\n      virtual bool isCompleted() const = 0;\n\n      /** Returns true when a unit has been issued an order to build a structure and is moving to the build\n       * location. Also returns true for Terran SCVs while they construct a building.\n       * \\see Unit::build, Unit::cancelConstruction, Unit::haltConstruction, Unit::isBeingConstructed. */\n      virtual bool isConstructing() const = 0;\n\n      /** Returns true if the unit has a defense matrix from a Terran Science Vessel. */\n      virtual bool isDefenseMatrixed() const = 0;\n\n      /** Returns true if the unit is detected. */\n      virtual bool isDetected() const = 0;\n\n      /** Returns true if the unit has been ensnared by a Zerg Queen. */\n      virtual bool isEnsnared() const = 0;\n\n      /** Returns true if the unit is following another unit.\n       * \\see Unit::follow, Unit::getTarget. */\n      virtual bool isFollowing() const = 0;\n\n      /** Returns true if the unit is in one of the four states for gathering gas (MoveToGas, WaitForGas,\n       * HarvestGas, ReturnGas).\n       * \\see Unit::isCarryingGas. */\n      virtual bool isGatheringGas() const = 0;\n\n      /** Returns true if the unit is in one of the four states for gathering minerals (MoveToMinerals,\n       * WaitForMinerals, MiningMinerals, ReturnMinerals).\n       * \\see Unit::isCarryingMinerals. */\n      virtual bool isGatheringMinerals() const = 0;\n\n      /** Returns true for hallucinated units, false for normal units. Returns true for hallucinated enemy\n       * units only if Complete Map Information is enabled.\n       * \\see Unit::getRemoveTimer. */\n      virtual bool isHallucination() const = 0;\n\n      /** Returns true if the unit is holding position\n       * \\see Unit::holdPosition. */\n      virtual bool isHoldingPosition() const = 0;\n\n      /** Returns true if the unit is not doing anything.\n       * \\see Unit::stop. */\n      virtual bool isIdle() const = 0;\n\n      /** Returns true if the unit can be interrupted. */\n      virtual bool isInterruptible() const = 0;\n\n      /** Returns true if the unit is being irradiated by a Terran Science Vessel.\n       * \\see Unit::getIrradiateTimer. */\n      virtual bool isIrradiated() const = 0;\n\n      /** Returns true if the unit is a Terran building that is currently lifted off the ground.\n       * \\see Unit::lift,Unit::land. */\n      virtual bool isLifted() const = 0;\n\n      /** Return true if the unit is loaded into a Terran Bunker, Terran Dropship, Protoss Shuttle, or Zerg\n       * Overlord.\n       * \\see Unit::load, Unit::unload, Unit::unloadAll. */\n      virtual bool isLoaded() const = 0;\n\n      /** Returns true if the unit is locked down by a Terran Ghost.\n       *  \\see Unit::getLockdownTimer. */\n      virtual bool isLockedDown() const = 0;\n\n      /** Returns true if the unit is being maelstrommed.\n       * \\see Unit::getMaelstromTimer. */\n      virtual bool isMaelstrommed() const = 0;\n\n      /** Returns true if the unit is a zerg unit that is morphing.\n       * \\see Unit::morph, Unit::cancelMorph, Unit::getBuildType, Unit::getRemainingBuildTime. */\n      virtual bool isMorphing() const = 0;\n\n      /** Returns true if the unit is moving.\n       * \\see Unit::attackMove, Unit::stop. */\n      virtual bool isMoving() const = 0;\n\n      /** Returns true if the unit has been parasited by some other player. */\n      virtual bool isParasited() const = 0;\n\n      /** Returns true if the unit is patrolling between two positions.\n       * \\see Unit::patrol. */\n      virtual bool isPatrolling() const = 0;\n\n      /** Returns true if the unit has been plagued by a Zerg Defiler.\n       * \\see Unit::getPlagueTimer. */\n      virtual bool isPlagued() const = 0;\n\n      /** Returns true if the unit is a Terran SCV that is repairing or moving to repair another unit. */\n      virtual bool isRepairing() const = 0;\n\n      /** Returns true if the unit is a building that is researching tech. See TechTypes for the complete list\n       * of available techs in Broodwar.\n       * \\see Unit::research, Unit::cancelResearch, Unit::getTech, Unit::getRemainingResearchTime. */\n      virtual bool isResearching() const = 0;\n\n      /** Returns true if the unit has been selected by the user via the starcraft GUI. Only available if you\n       * enable Flag::UserInput during AIModule::onStart.\n       * \\see Game::getSelectedUnits. */\n      virtual bool isSelected() const = 0;\n\n      /** Returns true if the unit is a Terran Siege Tank that is currently in Siege mode.\n       * \\see Unit::siege, Unit::unsiege. */\n      virtual bool isSieged() const = 0;\n\n      /** Returns true if the unit is starting to attack.\n       * \\see Unit::attackUnit, Unit::getGroundWeaponCooldown, Unit::getAirWeaponCooldown. */\n      virtual bool isStartingAttack() const = 0;\n\n      /** Returns true if the unit has been stasised by a Protoss Arbiter.\n       * \\see Unit::getStasisTimer. */\n      virtual bool isStasised() const = 0;\n\n      /** Returns true if the unit is currently stimmed.\n       * \\see Unit::getStimTimer. */\n      virtual bool isStimmed() const = 0;\n\n      /** Returns true if the unit is being pushed off of another unit */\n      virtual bool isStuck() const = 0;\n\n      /** Returns true if the unit is training units (i.e. a Barracks training Marines).\n       * \\see Unit::train, Unit::getTrainingQueue, Unit::cancelTrain, Unit::getRemainingTrainTime. */\n      virtual bool isTraining() const = 0;\n\n      /** Returns true if the unit is under a Protoss Psionic Storm. */\n      virtual bool isUnderStorm() const = 0;\n\n      /** Returns true if the unit is a Protoss building that is unpowered because no pylons are in range. */\n      virtual bool isUnpowered() const = 0;\n\n      /** Returns true if the unit is a building that is upgrading. See UpgradeTypes for the complete list\n       * of available upgrades in Broodwar.\n       * \\see Unit::upgrade, Unit::cancelUpgrade, Unit::getUpgrade, Unit::getRemainingUpgradeTime. */\n      virtual bool isUpgrading() const = 0;\n\n      /** Returns true if the unit is visible. If the CompleteMapInformation?  cheat flag is enabled, existing\n       * units hidden by the fog of war will be accessible, but isVisible will still return false.\n       * \\see Unit::exists. */\n      virtual bool isVisible() const = 0;\n      virtual bool isVisible(Player* player) const = 0;\n\n      /** Takes any unit command and calls the corresponding order that will execute it */\n      virtual bool issueCommand(UnitCommand command) = 0;\n\n      /** Orders the unit to attack move to the specified location. */\n      virtual bool attackMove(Position target) = 0;\n\n      /** Orders the unit to attack the specified unit. */\n      virtual bool attackUnit(Unit* target) = 0;\n\n      /** Orders the unit to build the given unit type at the given position. Note that if the player does not\n       * have enough resources when the unit attempts to place the building down, the order will fail. The\n       * tile position specifies where the top left corner of the building will be placed. */\n      virtual bool build(TilePosition target, UnitType type) = 0;\n\n      /** Orders the unit to build the given addon. The unit must be a Terran building that can have an addon\n       * and the specified unit type must be an addon unit type. */\n      virtual bool buildAddon(UnitType type) = 0;\n\n      /** Orders this unit to add the specified unit type to the training queue. Note that the player must\n       * have sufficient resources to train. If you wish to make units from a hatchery, use getLarva to get\n       * the larva associated with the hatchery and then call morph on the larva you want to morph. This\n       * command can also be used to make interceptors and scarabs. */\n      virtual bool train(UnitType type) = 0;\n\n      /** Orders the unit to morph into the specified unit type. Returns false if given a wrong type.\n       * \\see Unit::cancelMorph, Unit::isMorphing. */\n      virtual bool morph(UnitType type) = 0;\n\n      /** Orders the unit to research the given tech type.\n       * \\see Unit::cancelResearch, Unit::Unit#isResearching, Unit::getRemainingResearchTime, Unit::getTech. */\n      virtual bool research(TechType tech) = 0;\n\n      /** Orders the unit to upgrade the given upgrade type.\n       * \\see Unit::cancelUpgrade, Unit::Unit#isUpgrading, Unit::getRemainingUpgradeTime, Unit::getUpgrade. */\n      virtual bool upgrade(UpgradeType upgrade) = 0;\n\n      /** Orders the unit to set its rally position to the specified position.\n       * \\see Unit::getRallyPosition, Unit::getRallyUnit. */\n      virtual bool setRallyPoint(Position target) = 0;\n\n      /** Orders the unit to set its rally unit to the specified unit.\n       * \\see Unit::setRallyPosition, Unit::getRallyPosition, Unit::getRallyUnit. */\n      virtual bool setRallyPoint(Unit* target) = 0;\n\n      /** Orders the unit to move from its current position to the specified position.\n       * \\see Unit::isMoving.  */\n      virtual bool move(Position target) = 0;\n\n      /** Orders the unit to patrol between its current position and the specified position.\n       * \\see Unit::isPatrolling.  */\n      virtual bool patrol(Position target) = 0;\n\n      /** Orders the unit to hold its position.*/\n      virtual bool holdPosition() = 0;\n\n      /** Orders the unit to stop. */\n      virtual bool stop() = 0;\n\n      /** Orders the unit to follow the specified unit.\n       * \\see Unit::isFollowing. */\n      virtual bool follow(Unit* target) = 0;\n\n      /** Orders the unit to gather the specified unit (must be mineral or refinery type).\n       * \\see Unit::isGatheringGas, Unit::isGatheringMinerals. */\n      virtual bool gather(Unit* target) = 0;\n\n      /** Orders the unit to return its cargo to a nearby resource depot such as a Command Center. Only\n       * workers that are carrying minerals or gas can be ordered to return cargo.\n       * \\see Unit::isCarryingGas, Unit::isCarryingMinerals. */\n      virtual bool returnCargo() = 0;\n\n      /** Orders the unit to repair the specified unit. Only Terran SCVs can be ordered to repair, and the\n       * target must be a mechanical Terran unit or building.\n       * \\see Unit::isRepairing. */\n      virtual bool repair(Unit* target) = 0;\n\n      /** Orders the unit to burrow. Either the unit must be a Zerg Lurker, or the unit must be a Zerg ground\n       * unit and burrow tech must be researched.\n       * \\see: Unit::unburrow, Unit::isBurrowed. */\n      virtual bool burrow() = 0;\n\n      /** Orders the burrowed unit to unburrow.\n       * \\see: Unit::burrow, Unit::isBurrowed.\n       * */\n      virtual bool unburrow() = 0;\n\n      /** Orders the unit to cloak.\n       * \\see: Unit::decloak, Unit::isCloaked. */\n      virtual bool cloak() = 0;\n\n      /** Orders the unit to decloak.\n       * \\see: Unit::cloak, Unit::isCloaked. */\n      virtual bool decloak() = 0;\n\n      /** Orders the unit to siege. Note: unit must be a Terran siege tank.\n       * \\see Unit::unsiege, Unit::isSieged. */\n      virtual bool siege() = 0;\n\n      /** Orders the unit to unsiege. Note: unit must be a Terran siege tank.\n       * \\see: Unit::unsiege, Unit::isSieged. */\n      virtual bool unsiege() = 0;\n\n      /** Orders the unit to lift. Note: unit must be a Terran building that can be lifted.\n       * \\see Unit::land, Unit::isLifted.  */\n      virtual bool lift() = 0;\n\n      /** Orders the unit to land. Note: unit must be a Terran building that is currently lifted.\n       * \\see Unit::lift, Unit::isLifted. */\n      virtual bool land(TilePosition target) = 0;\n\n      /** Orders the unit to load the target unit.\n       * \\see Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */\n      virtual bool load(Unit* target) = 0;\n\n      /** Orders the unit to unload the target unit.\n       * \\see Unit::load, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */\n      virtual bool unload(Unit* target) = 0;\n\n      /** Orders the unit to unload all loaded units at the unit's current position.\n       * \\see Unit::load, Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */\n      virtual bool unloadAll() = 0;\n\n      /** Orders the unit to unload all loaded units at the specified location. Unit should be a Terran\n       * Dropship, Protoss Shuttle, or Zerg Overlord. If the unit is a Terran Bunker, the units will be\n       * unloaded right outside the bunker, like in the first version of unloadAll.\n       * \\see Unit::load, Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */\n      virtual bool unloadAll(Position target) = 0;\n\n      /** Works like the right click in the GUI. */\n      virtual bool rightClick(Position target) = 0;\n\n      /** Works like the right click in the GUI. Right click on a mineral patch to order a worker to mine,\n       * right click on an enemy to attack it. */\n      virtual bool rightClick(Unit* target) = 0;\n\n      /** Orders the SCV to stop constructing the building, and the building is left in a partially complete\n       * state until it is canceled, destroyed, or completed.\n       * \\see Unit::isConstructing. */\n      virtual bool haltConstruction() = 0;\n\n      /** Orders the building to stop being constructed.\n       * \\see Unit::beingConstructed. */\n      virtual bool cancelConstruction() = 0;\n\n      /** Orders the unit to stop making the addon. */\n      virtual bool cancelAddon() = 0;\n\n      /** Orders the unit to remove the specified unit from its training queue.\n       * \\see Unit::train, Unit::cancelTrain, Unit::isTraining, Unit::getTrainingQueue. */\n      virtual bool cancelTrain(int slot = -2) = 0;\n\n      /** Orders the unit to stop morphing.\n       * \\see Unit::morph, Unit::isMorphing. */\n      virtual bool cancelMorph() = 0;\n\n      /** Orders the unit to cancel a research in progress.\n       * \\see Unit::research, Unit::isResearching, Unit::getTech. */\n      virtual bool cancelResearch() = 0;\n\n      /** Orders the unit to cancel an upgrade in progress.\n       * \\see Unit::upgrade, Unit::isUpgrading, Unit::getUpgrade. */\n      virtual bool cancelUpgrade() = 0;\n\n      /** Orders the unit to use a tech not requiring a target (ie Stim Pack). Returns true if it is a valid\n       * tech. */\n      virtual bool useTech(TechType tech) = 0;\n\n      /** Orders the unit to use a tech requiring a position target (ie Dark Swarm). Returns true if it is a\n       * valid tech.*/\n      virtual bool useTech(TechType tech, Position target) = 0;\n\n      /** Orders the unit to use a tech requiring a unit target (ie Irradiate). Returns true if it is a valid\n       * tech.*/\n      virtual bool useTech(TechType tech, Unit* target) = 0;\n\n      /** Sets the unit's custom client info. The client is responsible for deallocation. */\n      virtual void setClientInfo(void* clientinfo) = 0;\n\n      /** Returns the unit's custom client info. The client is responsible for deallocation. */\n      virtual void* getClientInfo() const = 0;\n  };\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/UnitCommand.h",
    "content": "#pragma once\n\n#include <BWAPI/UnitCommandType.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/UnitType.h>\n\nnamespace BWAPI\n{\n  class Unit;\n  class UnitCommand\n  {\n    public:\n      UnitCommand() : target(NULL), x(0), y(0), extra(0) { type = UnitCommandTypes::None; }\n      UnitCommand(Unit* source, UnitCommandType _type, Unit* _target, int _x, int _y, int _extra) : unit(source), type(_type), target(_target), x(_x), y(_y), extra(_extra) {}\n\n      static UnitCommand attackMove(Unit* unit, Position target);\n      static UnitCommand attackUnit(Unit* unit, Unit* target);\n      static UnitCommand build(Unit* unit, TilePosition target, UnitType type);\n      static UnitCommand buildAddon(Unit* unit, UnitType type);\n      static UnitCommand train(Unit* unit, UnitType type);\n      static UnitCommand morph(Unit* unit, UnitType type);\n      static UnitCommand research(Unit* unit, TechType tech);\n      static UnitCommand upgrade(Unit* unit, UpgradeType upgrade);\n      static UnitCommand setRallyPosition(Unit* unit, Position target);\n      static UnitCommand setRallyUnit(Unit* unit, Unit* target);\n      static UnitCommand move(Unit* unit, Position target);\n      static UnitCommand patrol(Unit* unit, Position target);\n      static UnitCommand holdPosition(Unit* unit);\n      static UnitCommand stop(Unit* unit);\n      static UnitCommand follow(Unit* unit, Unit* target);\n      static UnitCommand gather(Unit* unit, Unit* target);\n      static UnitCommand returnCargo(Unit* unit);\n      static UnitCommand repair(Unit* unit, Unit* target);\n      static UnitCommand burrow(Unit* unit);\n      static UnitCommand unburrow(Unit* unit);\n      static UnitCommand cloak(Unit* unit);\n      static UnitCommand decloak(Unit* unit);\n      static UnitCommand siege(Unit* unit);\n      static UnitCommand unsiege(Unit* unit);\n      static UnitCommand lift(Unit* unit);\n      static UnitCommand land(Unit* unit, TilePosition target);\n      static UnitCommand load(Unit* unit, Unit* target);\n      static UnitCommand unload(Unit* unit, Unit* target);\n      static UnitCommand unloadAll(Unit* unit);\n      static UnitCommand unloadAll(Unit* unit, Position target);\n      static UnitCommand rightClick(Unit* unit, Position target);\n      static UnitCommand rightClick(Unit* unit, Unit* target);\n      static UnitCommand haltConstruction(Unit* unit);\n      static UnitCommand cancelConstruction(Unit* unit);\n      static UnitCommand cancelAddon(Unit* unit);\n      static UnitCommand cancelTrain(Unit* unit, int slot = -2);\n      static UnitCommand cancelMorph(Unit* unit);\n      static UnitCommand cancelResearch(Unit* unit);\n      static UnitCommand cancelUpgrade(Unit* unit);\n      static UnitCommand useTech(Unit* unit,TechType tech);\n      static UnitCommand useTech(Unit* unit,TechType tech, Position target);\n      static UnitCommand useTech(Unit* unit,TechType tech, Unit* target);\n      Unit* unit;\n      UnitCommandType type;\n      Unit* target;\n      int x;\n      int y;\n      int extra;\n  };\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/UnitCommandType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class UnitCommandType\n  {\n    public:\n      UnitCommandType();\n      UnitCommandType(int id);\n      UnitCommandType(const UnitCommandType& other);\n      UnitCommandType& operator=(const UnitCommandType& other);\n      bool operator==(const UnitCommandType& other) const;\n      bool operator!=(const UnitCommandType& other) const;\n      bool operator<(const UnitCommandType& other) const;\n\n      /** Returns a unique ID for this UnitCommandType. */\n      int getID() const;\n\n      /** Returns the string corresponding to the UnitCommandType object. For example,\n       * UnitCommandTypes::Set_Rally_Position.getName() returns std::string(\"Set Rally Position\")*/\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace UnitCommandTypes\n  {\n    /** Given a string, this function returns the command type it refers to. For example,\n     * UnitCommandTypes::getUnitCommandType(\"Attack Position\") returns UnitCommandTypes::Attack_Position. */\n    UnitCommandType getUnitCommandType(std::string name);\n\n    /** Returns the set of all the sizes, which are listed below: */\n    std::set<UnitCommandType>& allUnitCommandTypes();\n    void init();\n    extern const UnitCommandType Attack_Move;\n    extern const UnitCommandType Attack_Unit;\n    extern const UnitCommandType Build;\n    extern const UnitCommandType Build_Addon;\n    extern const UnitCommandType Train;\n    extern const UnitCommandType Morph;\n    extern const UnitCommandType Research;\n    extern const UnitCommandType Upgrade;\n    extern const UnitCommandType Set_Rally_Position;\n    extern const UnitCommandType Set_Rally_Unit;\n    extern const UnitCommandType Move;\n    extern const UnitCommandType Patrol;\n    extern const UnitCommandType Hold_Position;\n    extern const UnitCommandType Stop;\n    extern const UnitCommandType Follow;\n    extern const UnitCommandType Gather;\n    extern const UnitCommandType Return_Cargo;\n    extern const UnitCommandType Repair;\n    extern const UnitCommandType Burrow;\n    extern const UnitCommandType Unburrow;\n    extern const UnitCommandType Cloak;\n    extern const UnitCommandType Decloak;\n    extern const UnitCommandType Siege;\n    extern const UnitCommandType Unsiege;\n    extern const UnitCommandType Lift;\n    extern const UnitCommandType Land;\n    extern const UnitCommandType Load;\n    extern const UnitCommandType Unload;\n    extern const UnitCommandType Unload_All;\n    extern const UnitCommandType Unload_All_Position;\n    extern const UnitCommandType Right_Click_Position;\n    extern const UnitCommandType Right_Click_Unit;\n    extern const UnitCommandType Halt_Construction;\n    extern const UnitCommandType Cancel_Construction;\n    extern const UnitCommandType Cancel_Addon;\n    extern const UnitCommandType Cancel_Train;\n    extern const UnitCommandType Cancel_Train_Slot;\n    extern const UnitCommandType Cancel_Morph;\n    extern const UnitCommandType Cancel_Research;\n    extern const UnitCommandType Cancel_Upgrade;\n    extern const UnitCommandType Use_Tech;\n    extern const UnitCommandType Use_Tech_Position;\n    extern const UnitCommandType Use_Tech_Unit;\n    extern const UnitCommandType None;\n    extern const UnitCommandType Unknown;\n  }\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/UnitSizeType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class UnitSizeType\n  {\n    public:\n      UnitSizeType();\n      UnitSizeType(int id);\n      UnitSizeType(const UnitSizeType& other);\n      UnitSizeType& operator=(const UnitSizeType& other);\n      bool operator==(const UnitSizeType& other) const;\n      bool operator!=(const UnitSizeType& other) const;\n      bool operator<(const UnitSizeType& other) const;\n\n      /** Returns a unique ID for this UnitSizeType. */\n      int getID() const;\n\n      /** Returns the string corresponding to the UnitSizeType object. For example,\n       * UnitSizeTypes::Medium.getName() returns std::string(\"Medium\")*/\n      std::string getName() const;\n    private:\n      int id;\n  };\n  namespace UnitSizeTypes\n  {\n    /** Given a string, this function returns the size type it refers to. For example,\n     * UnitSizeTypes::getUnitSizeType(\"Small\") returns UnitSizeTypes::Small. */\n    UnitSizeType getUnitSizeType(std::string name);\n\n    /** Returns the set of all the sizes, which are listed below: */\n    std::set<UnitSizeType>& allUnitSizeTypes();\n    void init();\n    extern const UnitSizeType Independent;\n    extern const UnitSizeType Small;\n    extern const UnitSizeType Medium;\n    extern const UnitSizeType Large;\n    extern const UnitSizeType None;\n    extern const UnitSizeType Unknown;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/UnitType.h",
    "content": "#pragma once\n#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/Race.h>\n#include <BWAPI/UnitSizeType.h>\n\nnamespace BWAPI\n{\n  class TechType;\n  class UpgradeType;\n  class WeaponType;\n\n  /** The UnitType class is used to get information about a particular type of unit, such as the build time\n   * of a Lurker, or the mineral price of an Ultralisk. TODO Add the unittype table from the wiki*/\n  class UnitType\n  {\n    public:\n      UnitType();\n      UnitType(int id);\n      UnitType(const UnitType& other);\n      UnitType& operator=(const UnitType& other);\n      bool operator==(const UnitType& other) const;\n      bool operator!=(const UnitType& other) const;\n      bool operator<(const UnitType& other) const;\n\n      /** Returns a unique ID for this unit type. */\n      int getID() const;\n\n      /** Returns the name of the unit. */\n      std::string getName() const;\n\n      /** Returns the race that the unit belongs to. For example UnitTypes::Terran_SCV.getRace() will return\n       * Races::Terran. */\n      Race getRace() const;\n\n      /** Returns what builds this unit type. The second number will usually be 1 unless the unit type is\n       * Protoss_Archon or Protoss_Dark_Archon. Units that cannot be created, such as critters and mineral\n       * fields, will return a pair where the unit type is UnitTypes::None, and the second component is 0.\n       *\n       * Example: UnitTypes::Terran_Marine.whatBuilds() will return an std::pair, where the first component\n       * is UnitTypes::Terran_Barracks. */\n      const std::pair< UnitType, int > whatBuilds() const;\n\n      /** Returns the units the player is required to have before it can train or build the given unit type.\n       *\n       * Example: UnitTypes::Terran_Battlecruiser.requiredUnits() will return a map of three keys:\n       * UnitTypes::Terran_Starport, UnitTypes::Terran_Control_Tower, and UnitTypes::Terran_Physics_Lab. */\n      const std::map< UnitType, int >& requiredUnits() const;\n\n      /** Included in the API for completeness, since the only units that actually needs tech to be trained\n       * are the Zerg_Lurker and Zerg_Lurker_Egg. The tech type needed is TechTypes::Lurker_Aspect. */\n      TechType requiredTech() const;\n\n      /** Returns the tech used to cloak the unit, or TechTypes::None if the unit cannot cloak or is\n          permanently cloaked */\n      TechType cloakingTech() const;\n\n      /** Returns the set of tech types this unit can use, provided the tech types have been researched and\n       * the unit has enough energy. */\n      const std::set< TechType >& abilities() const;\n\n      /** Returns the set of upgrade types that can affect this unit. */\n      const std::set< UpgradeType >& upgrades() const;\n\n      /** Returns the upgrade that increase's the unit's armor, or UpgradeTypes::None if no upgrade\n       * increase's this unit's armor. For example UnitTypes::Terran_Marine.armorUpgrade() will return a\n       * pointer to UpgradeTypes::Terran_Infantry_Armor. */\n      UpgradeType armorUpgrade() const;\n\n      /** Returns the maximum amount of hit points the unit type can have. */\n      int maxHitPoints() const;\n\n      /** Returns the maximum amount of shields the unit type can have. */\n      int maxShields() const;\n\n      /** Returns the maximum amount of energy the unit type can have. */\n      int maxEnergy() const;\n\n      /** Returns the amount of armor the non-upgraded unit type has. */\n      int armor() const;\n\n      /** Returns the mineral price of the unit.\n       *\n       * Example: UnitTypes::Siege_Tank_Tank_Mode.mineralPrice() returns 150. */\n      int mineralPrice() const;\n\n      /** UnitTypes::Siege_Tank_Tank_Mode.gasPrice() returns 100. */\n      int gasPrice() const;\n\n      /** Returns the number of frames needed to make this unit type. */\n      int buildTime() const;\n\n      /** Returns the amount of supply used by this unit. Supply counts returned by BWAPI are double what you\n       *  would expect to see from playing the game. This is because zerglings take up 0.5 in-game supply. */\n      int supplyRequired() const;\n\n      /** Returns the amount of supply produced by this unit (i.e. for a Protoss_Pylon). Supply counts\n       * returned by BWAPI are double what you would expect to see from playing the game. This is because\n       * zerglings take up 0.5 in-game supply. */\n      int supplyProvided() const;\n\n      /** Returns the amount of space this unit type takes up inside a bunker or transport unit. */\n      int spaceRequired() const;\n\n      /** Returns the amount of space this unit type provides. */\n      int spaceProvided() const;\n\n      /** Returns the score which is used to determine the total scores in the after-game stats screen. */\n      int buildScore() const;\n\n      /** Returns the score which is used to determine the total scores in the after-game stats screen. */\n      int destroyScore() const;\n\n      /** Returns the size of the unit - either Small, Medium, Large, or Independent. */\n      UnitSizeType size() const;\n\n      /** Returns the tile width of the unit. Useful for determining the size of buildings. For example\n       * UnitTypes::Terran_Supply_Depot.tileWidth() will return 3. */\n      int tileWidth() const;\n\n      /** Returns the tile height of the unit. Useful for determining the size of buildings. For example\n       * UnitTypes::Terran_Supply_Depot.tileHeight() will return 2. */\n      int tileHeight() const;\n\n      /** Distance from the center of the unit to the left edge of the unit, measured in pixels. */\n      int dimensionLeft() const;\n\n      /** Distance from the center of the unit to the top edge of the unit, measured in pixels. */\n      int dimensionUp() const;\n\n      /** Distance from the center of the unit to the right edge of the unit, measured in pixels. */\n      int dimensionRight() const;\n\n      /** Distance from the center of the unit to the bottom edge of the unit, measured in pixels. */\n      int dimensionDown() const;\n\n      /** Returns the range at which the unit will start targeting enemy units, measured in pixels. */\n      int seekRange() const;\n\n      /** Returns how far the un-upgraded unit type can see into the fog of war, measured in pixels. */\n      int sightRange() const;\n\n      /** Returns the unit's ground weapon. */\n      WeaponType groundWeapon() const;\n\n      // TODO: add doc\n      int maxGroundHits() const;\n\n      /** Returns the unit's air weapon. */\n      WeaponType airWeapon() const;\n\n      // TODO: add doc\n      int maxAirHits() const;\n\n      /** Returns the unit's non-upgraded top speed in pixels per frame. For Terran buildings that can lift\n       * off and the Zerg Infested Command Center, this returns how fast the building moves when it is\n       * lifted. */\n      double topSpeed() const;\n\n      /** Returns how fast the unit can accelerate to its top speed. What units this quantity is measured in\n       * is currently unknown. */\n      int acceleration() const;\n\n      /** Related to how fast the unit can halt. What units this quantity is measured in is currently\n       * unknown. */\n      int haltDistance() const;\n\n      /** Related to how fast the unit can turn. What units this quantity is measured in is currently\n       * unknown. */\n      int turnRadius() const;\n\n      /** Returns true if the unit can train other units. For example, UnitTypes::Terran_Barracks.canProduce()\n       * will return true, while UnitTypes::Terran_Marine?.canProduce() will return false. This is also true\n       * for two non-building units: Protoss Carrier (can produce interceptors) and Protoss Reaver\n       * (can produce scarabs). */\n      bool canProduce() const;\n\n      /** Returns true if the unit can attack (either ground or air). Returns false for units that can only\n       * inflict damage via special abilities (such as Protoss High Templar). */\n      bool canAttack() const;\n\n      /** Returns true if the unit can move. Note that buildings will return false, even Terran buildings\n       * which can move once lifted. */\n      bool canMove() const;\n\n      /** Returns true for flying/air units. */\n      bool isFlyer() const;\n\n      /** Returns true for units that regenerate health (i.e. zerg units). */\n      bool regeneratesHP() const;\n\n      /** Returns true if the unit type is capable of casting spells / using technology. */\n      bool isSpellcaster() const;\n\n      /** Returns true for the two units that are permanently cloaked - Protoss Observer and Protoss Dark\n       * Templar. */\n      bool hasPermanentCloak() const;\n\n      /** Returns true for units that cannot be destroyed (i.e. Terran Nuclear Missile, Mineral Field,\n       * Vespene Geyser, etc) */\n      bool isInvincible() const;\n\n      /** Returns true if the unit is organic, such as a Terran Marine. */\n      bool isOrganic() const;\n\n      /** Returns true if the unit is mechanical such as a Terran Vulture. */\n      bool isMechanical() const;\n\n      /** Returns true for the four robotic Protoss units - Probe, Shuttle, Reaver, and Observer. */\n      bool isRobotic() const;\n\n      /** Returns true for the seven units that can detect cloaked units - Terran Science Vessel, Spell\n       * Scanner Sweep, Zerg Overlord, Protoss Observer, Terran Missile Turret, Zerg Spore Colony, and Protoss\n       * Photon Cannon. */\n      bool isDetector() const;\n\n      /** Returns true for the five units that hold resources - Mineral Field, Vespene Geyser,\n       * Terran Refinery, Zerg Extractor, and Protoss Assimilator. */\n      bool isResourceContainer() const;\n\n      /** Returns true for the five units that can accept resources - Terran Command Center, Protoss Nexus,\n       * Zerg Hatchery, Zerg Lair, and Zerg Hive. */\n      bool isResourceDepot() const;\n\n      /** Returns true for Terran Refinery, Zerg Extractor, and Protoss Assimilator. */\n      bool isRefinery() const;\n\n      /** Returns true for Protoss Probe, Terran SCV, and Zerg Drone. */\n      bool isWorker() const;\n\n      /** Returns true for buildings that must be near a pylon to be constructed. */\n      bool requiresPsi() const;\n\n      /** Returns true for buildings that can only be built on zerg creep. */\n      bool requiresCreep() const;\n\n      /** Returns true for Zergling and Scourge. */\n      bool isTwoUnitsInOneEgg() const;\n\n      /** Returns true for Zerg Lurker and units that can burrow when burrow tech is researched. */\n      bool isBurrowable() const;\n\n      /** Returns true for units that can be cloaked - Terran Ghost and Terran Wraith. Does not include units\n       * which have permanent cloak (Protoss Observer and Protoss Dark Templar). */\n      bool isCloakable() const;\n\n      /** Returns true if the unit is a building (also true for mineral field and vespene geyser). */\n      bool isBuilding() const;\n\n      /** Returns true if the unit is an add-on, such as a Terran Comsat Station. */\n      bool isAddon() const;\n\n      /** Returns true for Terran buildings that can lift off (i.e. Barracks). */\n      bool isFlyingBuilding() const;\n\n      /** Returns true if the unit is neutral, such as a critter or mineral field. */\n      bool isNeutral() const;\n\n      /** Returns true if the unit is a Hero unit. */\n      bool isHero() const;\n\n      /** Returns true if the unit is a Powerup unit. */\n      bool isPowerup() const;\n\n      /** Returns true if the unit is a regular Beacon. */\n      bool isBeacon() const;\n\n      /** Returns true if the unit is a flag Beacon. */\n      bool isFlagBeacon() const;\n\n      /** Returns true if the unit is a special building. */\n      bool isSpecialBuilding() const;\n\n      /** Returns true if the unit is a spell unit. */\n      bool isSpell() const;\n\n      /** Returns true if the unit produces larva. */\n      bool producesLarva() const;\n\n    private:\n      int id;\n  };\n  namespace UnitTypes\n  {\n\n    /** Given the name of a unit type, this function will return the unit type.\n     * For example, UnitTypes::getUnitType(\"Terran Marine\") will return UnitTypes::Terran_Marine. */\n    UnitType getUnitType(std::string name);\n\n    /** Returns the set of all the UnitTypes. */\n    std::set<UnitType>& allUnitTypes();\n    void init();\n    extern const UnitType Terran_Marine;\n    extern const UnitType Hero_Jim_Raynor_Marine;\n    extern const UnitType Terran_Ghost;\n    extern const UnitType Hero_Sarah_Kerrigan;\n    extern const UnitType Hero_Samir_Duran;\n    extern const UnitType Hero_Infested_Duran;\n    extern const UnitType Hero_Alexei_Stukov;\n    extern const UnitType Terran_Vulture;\n    extern const UnitType Hero_Jim_Raynor_Vulture;\n    extern const UnitType Terran_Goliath;\n    extern const UnitType Hero_Alan_Schezar;\n    extern const UnitType Terran_Siege_Tank_Tank_Mode;\n    extern const UnitType Hero_Edmund_Duke_Tank_Mode;\n    extern const UnitType Terran_SCV;\n    extern const UnitType Terran_Wraith;\n    extern const UnitType Hero_Tom_Kazansky;\n    extern const UnitType Terran_Science_Vessel;\n    extern const UnitType Hero_Magellan;\n    extern const UnitType Terran_Dropship;\n    extern const UnitType Terran_Battlecruiser;\n    extern const UnitType Hero_Arcturus_Mengsk;\n    extern const UnitType Hero_Hyperion;\n    extern const UnitType Hero_Norad_II;\n    extern const UnitType Hero_Gerard_DuGalle;\n    extern const UnitType Terran_Vulture_Spider_Mine;\n    extern const UnitType Terran_Nuclear_Missile;\n    extern const UnitType Terran_Siege_Tank_Siege_Mode;\n    extern const UnitType Hero_Edmund_Duke_Siege_Mode;\n    extern const UnitType Terran_Firebat;\n    extern const UnitType Hero_Gui_Montag;\n    extern const UnitType Spell_Scanner_Sweep;\n    extern const UnitType Terran_Medic;\n    extern const UnitType Terran_Civilian;\n    extern const UnitType Zerg_Larva;\n    extern const UnitType Zerg_Egg;\n    extern const UnitType Zerg_Zergling;\n    extern const UnitType Hero_Devouring_One;\n    extern const UnitType Hero_Infested_Kerrigan;\n    extern const UnitType Zerg_Hydralisk;\n    extern const UnitType Hero_Hunter_Killer;\n    extern const UnitType Zerg_Ultralisk;\n    extern const UnitType Hero_Torrasque;\n    extern const UnitType Zerg_Broodling;\n    extern const UnitType Zerg_Drone;\n    extern const UnitType Zerg_Overlord;\n    extern const UnitType Hero_Yggdrasill;\n    extern const UnitType Zerg_Mutalisk;\n    extern const UnitType Hero_Kukulza_Mutalisk;\n    extern const UnitType Zerg_Guardian;\n    extern const UnitType Hero_Kukulza_Guardian;\n    extern const UnitType Zerg_Queen;\n    extern const UnitType Hero_Matriarch;\n    extern const UnitType Zerg_Defiler;\n    extern const UnitType Hero_Unclean_One;\n    extern const UnitType Zerg_Scourge;\n    extern const UnitType Zerg_Infested_Terran;\n    extern const UnitType Terran_Valkyrie;\n    extern const UnitType Zerg_Cocoon;\n    extern const UnitType Protoss_Corsair;\n    extern const UnitType Hero_Raszagal;\n    extern const UnitType Protoss_Dark_Templar;\n    extern const UnitType Hero_Dark_Templar;\n    extern const UnitType Hero_Zeratul;\n    extern const UnitType Zerg_Devourer;\n    extern const UnitType Protoss_Dark_Archon;\n    extern const UnitType Protoss_Probe;\n    extern const UnitType Protoss_Zealot;\n    extern const UnitType Hero_Fenix_Zealot;\n    extern const UnitType Protoss_Dragoon;\n    extern const UnitType Hero_Fenix_Dragoon;\n    extern const UnitType Protoss_High_Templar;\n    extern const UnitType Hero_Tassadar;\n    extern const UnitType Hero_Aldaris;\n    extern const UnitType Protoss_Archon;\n    extern const UnitType Hero_Tassadar_Zeratul_Archon;\n    extern const UnitType Protoss_Shuttle;\n    extern const UnitType Protoss_Scout;\n    extern const UnitType Hero_Mojo;\n    extern const UnitType Hero_Artanis;\n    extern const UnitType Protoss_Arbiter;\n    extern const UnitType Hero_Danimoth;\n    extern const UnitType Protoss_Carrier;\n    extern const UnitType Hero_Gantrithor;\n    extern const UnitType Protoss_Interceptor;\n    extern const UnitType Protoss_Reaver;\n    extern const UnitType Hero_Warbringer;\n    extern const UnitType Protoss_Observer;\n    extern const UnitType Protoss_Scarab;\n    extern const UnitType Critter_Rhynadon;\n    extern const UnitType Critter_Bengalaas;\n    extern const UnitType Critter_Scantid;\n    extern const UnitType Critter_Kakaru;\n    extern const UnitType Critter_Ragnasaur;\n    extern const UnitType Critter_Ursadon;\n    extern const UnitType Zerg_Lurker_Egg;\n    extern const UnitType Zerg_Lurker;\n    extern const UnitType Spell_Disruption_Web;\n    extern const UnitType Terran_Command_Center;\n    extern const UnitType Terran_Comsat_Station;\n    extern const UnitType Terran_Nuclear_Silo;\n    extern const UnitType Terran_Supply_Depot;\n    extern const UnitType Terran_Refinery;\n    extern const UnitType Terran_Barracks;\n    extern const UnitType Terran_Academy;\n    extern const UnitType Terran_Factory;\n    extern const UnitType Terran_Starport;\n    extern const UnitType Terran_Control_Tower;\n    extern const UnitType Terran_Science_Facility;\n    extern const UnitType Terran_Covert_Ops;\n    extern const UnitType Terran_Physics_Lab;\n    extern const UnitType Terran_Machine_Shop;\n    extern const UnitType Terran_Engineering_Bay;\n    extern const UnitType Terran_Armory;\n    extern const UnitType Terran_Missile_Turret;\n    extern const UnitType Terran_Bunker;\n    extern const UnitType Special_Crashed_Norad_II;\n    extern const UnitType Special_Ion_Cannon;\n    extern const UnitType Zerg_Infested_Command_Center;\n    extern const UnitType Zerg_Hatchery;\n    extern const UnitType Zerg_Lair;\n    extern const UnitType Zerg_Hive;\n    extern const UnitType Zerg_Nydus_Canal;\n    extern const UnitType Zerg_Hydralisk_Den;\n    extern const UnitType Zerg_Defiler_Mound;\n    extern const UnitType Zerg_Greater_Spire;\n    extern const UnitType Zerg_Queens_Nest;\n    extern const UnitType Zerg_Evolution_Chamber;\n    extern const UnitType Zerg_Ultralisk_Cavern;\n    extern const UnitType Zerg_Spire;\n    extern const UnitType Zerg_Spawning_Pool;\n    extern const UnitType Zerg_Creep_Colony;\n    extern const UnitType Zerg_Spore_Colony;\n    extern const UnitType Zerg_Sunken_Colony;\n    extern const UnitType Special_Overmind_With_Shell;\n    extern const UnitType Special_Overmind;\n    extern const UnitType Zerg_Extractor;\n    extern const UnitType Special_Mature_Chrysalis;\n    extern const UnitType Special_Cerebrate;\n    extern const UnitType Special_Cerebrate_Daggoth;\n    extern const UnitType Protoss_Nexus;\n    extern const UnitType Protoss_Robotics_Facility;\n    extern const UnitType Protoss_Pylon;\n    extern const UnitType Protoss_Assimilator;\n    extern const UnitType Protoss_Observatory;\n    extern const UnitType Protoss_Gateway;\n    extern const UnitType Protoss_Photon_Cannon;\n    extern const UnitType Protoss_Citadel_of_Adun;\n    extern const UnitType Protoss_Cybernetics_Core;\n    extern const UnitType Protoss_Templar_Archives;\n    extern const UnitType Protoss_Forge;\n    extern const UnitType Protoss_Stargate;\n    extern const UnitType Special_Stasis_Cell_Prison;\n    extern const UnitType Protoss_Fleet_Beacon;\n    extern const UnitType Protoss_Arbiter_Tribunal;\n    extern const UnitType Protoss_Robotics_Support_Bay;\n    extern const UnitType Protoss_Shield_Battery;\n    extern const UnitType Special_Khaydarin_Crystal_Form;\n    extern const UnitType Special_Protoss_Temple;\n    extern const UnitType Special_XelNaga_Temple;\n    extern const UnitType Resource_Mineral_Field;\n    extern const UnitType Resource_Vespene_Geyser;\n    extern const UnitType Special_Warp_Gate;\n    extern const UnitType Special_Psi_Disrupter;\n    extern const UnitType Special_Power_Generator;\n    extern const UnitType Special_Overmind_Cocoon;\n    extern const UnitType Special_Zerg_Beacon;\n    extern const UnitType Special_Terran_Beacon;\n    extern const UnitType Special_Protoss_Beacon;\n    extern const UnitType Special_Zerg_Flag_Beacon;\n    extern const UnitType Special_Terran_Flag_Beacon;\n    extern const UnitType Special_Protoss_Flag_Beacon;\n    extern const UnitType Spell_Dark_Swarm;\n    extern const UnitType Powerup_Uraj_Crystal;\n    extern const UnitType Powerup_Khalis_Crystal;\n    extern const UnitType Powerup_Flag;\n    extern const UnitType Powerup_Young_Chrysalis;\n    extern const UnitType Powerup_Psi_Emitter;\n    extern const UnitType Powerup_Data_Disk;\n    extern const UnitType Powerup_Khaydarin_Crystal;\n    extern const UnitType None;\n    extern const UnitType Unknown;\n\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/UpgradeType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\n#include <BWAPI/Race.h>\nnamespace BWAPI\n{\n  class UnitType;\n  class UpgradeType\n  {\n    public:\n      UpgradeType();\n      UpgradeType(int id);\n      UpgradeType(const UpgradeType& other);\n      UpgradeType& operator=(const UpgradeType& other);\n      bool operator==(const UpgradeType& other) const;\n      bool operator!=(const UpgradeType& other) const;\n      bool operator<(const UpgradeType& other) const;\n\n      /** Returns the unique ID for this upgrade type. */\n      int getID() const;\n\n      /** Returns the name for the upgrade type. */\n      std::string getName() const;\n\n      /** Returns the race the upgrade is for. For example, UpgradeTypes::Terran_Infantry_Armor.getRace()\n       * will return Races::Terran. */\n      Race getRace() const;\n\n      /** Returns the mineral price for the first upgrade. */\n      int mineralPrice() const;\n\n      /** Returns the amount that the mineral price increases for each additional upgrade. */\n      int mineralPriceFactor() const;\n\n      /** Returns the vespene gas price for the first upgrade. */\n      int gasPrice() const;\n\n      /** Returns the amount that the vespene gas price increases for each additional upgrade. */\n      int gasPriceFactor() const;\n\n      /** Returns the number of frames needed to research the first upgrade. */\n      int upgradeTime() const;\n\n      /** Returns the number of frames that the upgrade time increases for each additional upgrade. */\n      int upgradeTimeFactor() const;\n\n      /** Returns the maximum number of times the upgrade can be researched. */\n      int maxRepeats() const;\n\n      /** Returns the type of unit that researches the upgrade. */\n      UnitType whatUpgrades() const;\n\n      /** Returns the set of units that are affected by this upgrade. */\n      const std::set<UnitType>& whatUses() const;\n    private:\n      int id;\n  };\n  namespace UpgradeTypes\n  {\n    /** Given a string, this will return the upgrade type. */\n    UpgradeType getUpgradeType(std::string name);\n\n    /** Returns the set of all the UpgradeTypes. */\n    std::set<UpgradeType>& allUpgradeTypes();\n    void init();\n    extern const UpgradeType Terran_Infantry_Armor;\n    extern const UpgradeType Terran_Vehicle_Plating;\n    extern const UpgradeType Terran_Ship_Plating;\n    extern const UpgradeType Zerg_Carapace;\n    extern const UpgradeType Zerg_Flyer_Carapace;\n    extern const UpgradeType Protoss_Ground_Armor;\n    extern const UpgradeType Protoss_Air_Armor;\n    extern const UpgradeType Terran_Infantry_Weapons;\n    extern const UpgradeType Terran_Vehicle_Weapons;\n    extern const UpgradeType Terran_Ship_Weapons;\n    extern const UpgradeType Zerg_Melee_Attacks;\n    extern const UpgradeType Zerg_Missile_Attacks;\n    extern const UpgradeType Zerg_Flyer_Attacks;\n    extern const UpgradeType Protoss_Ground_Weapons;\n    extern const UpgradeType Protoss_Air_Weapons;\n    extern const UpgradeType Protoss_Plasma_Shields;\n    extern const UpgradeType U_238_Shells;\n    extern const UpgradeType Ion_Thrusters;\n    extern const UpgradeType Titan_Reactor;\n    extern const UpgradeType Ocular_Implants;\n    extern const UpgradeType Moebius_Reactor;\n    extern const UpgradeType Apollo_Reactor;\n    extern const UpgradeType Colossus_Reactor;\n    extern const UpgradeType Ventral_Sacs;\n    extern const UpgradeType Antennae;\n    extern const UpgradeType Pneumatized_Carapace;\n    extern const UpgradeType Metabolic_Boost;\n    extern const UpgradeType Adrenal_Glands;\n    extern const UpgradeType Muscular_Augments;\n    extern const UpgradeType Grooved_Spines;\n    extern const UpgradeType Gamete_Meiosis;\n    extern const UpgradeType Metasynaptic_Node;\n    extern const UpgradeType Singularity_Charge;\n    extern const UpgradeType Leg_Enhancements;\n    extern const UpgradeType Scarab_Damage;\n    extern const UpgradeType Reaver_Capacity;\n    extern const UpgradeType Gravitic_Drive;\n    extern const UpgradeType Sensor_Array;\n    extern const UpgradeType Gravitic_Boosters;\n    extern const UpgradeType Khaydarin_Amulet;\n    extern const UpgradeType Apial_Sensors;\n    extern const UpgradeType Gravitic_Thrusters;\n    extern const UpgradeType Carrier_Capacity;\n    extern const UpgradeType Khaydarin_Core;\n    extern const UpgradeType Argus_Jewel;\n    extern const UpgradeType Argus_Talisman;\n    extern const UpgradeType Caduceus_Reactor;\n    extern const UpgradeType Chitinous_Plating;\n    extern const UpgradeType Anabolic_Synthesis;\n    extern const UpgradeType Charon_Boosters;\n    extern const UpgradeType None;\n    extern const UpgradeType Unknown;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI/WeaponType.h",
    "content": "#pragma once\n#include <string>\n#include <set>\nnamespace BWAPI\n{\n  class TechType;\n  class UpgradeType;\n  class DamageType;\n  class ExplosionType;\n  class WeaponType\n  {\n    public:\n      WeaponType();\n      WeaponType(int id);\n      WeaponType(const WeaponType& other);\n      WeaponType& operator=(const WeaponType& other);\n      bool operator==(const WeaponType& other) const;\n      bool operator!=(const WeaponType& other) const;\n      bool operator<(const WeaponType& other) const;\n\n      /** Returns a unique ID for this weapon type. */\n      int getID() const;\n\n      /** Returns the name of the weapon. */\n      std::string getName() const;\n\n      /** Returns the tech type that must be researched before this weapon can be used, or TechTypes::None if\n       * no tech type is required. */\n      TechType getTech() const;\n\n      /** Returns the unit that can use this weapon. */\n      UnitType whatUses() const;\n\n      /** Returns the amount of damage that this weapon deals per attack. */\n      int damageAmount() const;\n\n      // TODO: add doc\n      int damageBonus() const;\n\n      /** Returns the amount of cooldown time between attacks. */\n      int damageCooldown() const;\n\n      /** Returns the amount that the damage increases per upgrade.\n       * \\see WeaponType::upgradeType. */\n      int damageFactor() const;\n\n      /** Returns the upgrade type that can be upgraded to increase the attack damage. */\n      UpgradeType upgradeType() const;\n\n      /** Returns the type of damage that this weapon uses (i.e. concussive, normal, explosive, etc). */\n      DamageType damageType() const;\n\n      /** Returns the type of explosion that this weapon uses. */\n      ExplosionType explosionType() const;\n\n      /** Returns the minimum attack range of the weapon, measured in pixels, 0 for most things except\n       * WeaponTypes::Arclite_Shock_Cannon (the weapon of the Terran Siege Tank in Siege Mode). */\n      int minRange() const;\n\n      /** Returns the maximum attack range of the weapon, measured in pixels. */\n      int maxRange() const;\n\n      /** Inner radius used in splash damage calculations. */\n      int innerSplashRadius() const;\n\n      /** Median radius used in splash damage calculations. */\n      int medianSplashRadius() const;\n\n      /** Outer radius used in splash damage calculations. */\n      int outerSplashRadius() const;\n\n      /** Returns true if this weapon can attack air units. */\n      bool targetsAir() const;\n\n      // TODO: group these methods\n      /** Returns true if this weapon can attack ground units. */\n      bool targetsGround() const;\n      bool targetsMechanical() const;\n      bool targetsOrganic() const;\n      bool targetsNonBuilding() const;\n      bool targetsNonRobotic() const;\n      bool targetsTerrain() const;\n      bool targetsOrgOrMech() const;\n      bool targetsOwn() const;\n    private:\n      int id;\n  };\n  namespace WeaponTypes\n  {\n    /** Given the name of a weapon, this will return the corresponding weapon type object. */\n    WeaponType getWeaponType(std::string name);\n\n    /** Returns the set of all the WeaponTypes. */\n    std::set<WeaponType>& allWeaponTypes();\n\n    /** Returns the set of all normal weapons in WeaponTypes. */\n    std::set<WeaponType>& normalWeaponTypes();\n\n    /** Returns the set of all special weapons in WeaponTypes. */\n    std::set<WeaponType>& specialWeaponTypes();\n    void init();\n    extern const WeaponType Gauss_Rifle;\n    extern const WeaponType Gauss_Rifle_Jim_Raynor;\n    extern const WeaponType C_10_Canister_Rifle;\n    extern const WeaponType C_10_Canister_Rifle_Sarah_Kerrigan;\n    extern const WeaponType C_10_Canister_Rifle_Samir_Duran;\n    extern const WeaponType C_10_Canister_Rifle_Infested_Duran;\n    extern const WeaponType C_10_Canister_Rifle_Alexei_Stukov;\n    extern const WeaponType Fragmentation_Grenade;\n    extern const WeaponType Fragmentation_Grenade_Jim_Raynor;\n    extern const WeaponType Spider_Mines;\n    extern const WeaponType Twin_Autocannons;\n    extern const WeaponType Twin_Autocannons_Alan_Schezar;\n    extern const WeaponType Hellfire_Missile_Pack;\n    extern const WeaponType Hellfire_Missile_Pack_Alan_Schezar;\n    extern const WeaponType Arclite_Cannon;\n    extern const WeaponType Arclite_Cannon_Edmund_Duke;\n    extern const WeaponType Fusion_Cutter;\n    extern const WeaponType Gemini_Missiles;\n    extern const WeaponType Gemini_Missiles_Tom_Kazansky;\n    extern const WeaponType Burst_Lasers;\n    extern const WeaponType Burst_Lasers_Tom_Kazansky;\n    extern const WeaponType ATS_Laser_Battery;\n    extern const WeaponType ATS_Laser_Battery_Hero;\n    extern const WeaponType ATS_Laser_Battery_Hyperion;\n    extern const WeaponType ATA_Laser_Battery;\n    extern const WeaponType ATA_Laser_Battery_Hero;\n    extern const WeaponType ATA_Laser_Battery_Hyperion;\n    extern const WeaponType Flame_Thrower;\n    extern const WeaponType Flame_Thrower_Gui_Montag;\n    extern const WeaponType Arclite_Shock_Cannon;\n    extern const WeaponType Arclite_Shock_Cannon_Edmund_Duke;\n    extern const WeaponType Longbolt_Missile;\n    extern const WeaponType Claws;\n    extern const WeaponType Claws_Devouring_One;\n    extern const WeaponType Claws_Infested_Kerrigan;\n    extern const WeaponType Needle_Spines;\n    extern const WeaponType Needle_Spines_Hunter_Killer;\n    extern const WeaponType Kaiser_Blades;\n    extern const WeaponType Kaiser_Blades_Torrasque;\n    extern const WeaponType Toxic_Spores;\n    extern const WeaponType Spines;\n    extern const WeaponType Acid_Spore;\n    extern const WeaponType Acid_Spore_Kukulza;\n    extern const WeaponType Glave_Wurm;\n    extern const WeaponType Glave_Wurm_Kukulza;\n    extern const WeaponType Seeker_Spores;\n    extern const WeaponType Subterranean_Tentacle;\n    extern const WeaponType Suicide_Infested_Terran;\n    extern const WeaponType Suicide_Scourge;\n    extern const WeaponType Particle_Beam;\n    extern const WeaponType Psi_Blades;\n    extern const WeaponType Psi_Blades_Fenix;\n    extern const WeaponType Phase_Disruptor;\n    extern const WeaponType Phase_Disruptor_Fenix;\n    extern const WeaponType Psi_Assault;\n    extern const WeaponType Psionic_Shockwave;\n    extern const WeaponType Psionic_Shockwave_TZ_Archon;\n    extern const WeaponType Dual_Photon_Blasters;\n    extern const WeaponType Dual_Photon_Blasters_Mojo;\n    extern const WeaponType Dual_Photon_Blasters_Artanis;\n    extern const WeaponType Anti_Matter_Missiles;\n    extern const WeaponType Anti_Matter_Missiles_Mojo;\n    extern const WeaponType Anti_Matter_Missiles_Artanis;\n    extern const WeaponType Phase_Disruptor_Cannon;\n    extern const WeaponType Phase_Disruptor_Cannon_Danimoth;\n    extern const WeaponType Pulse_Cannon;\n    extern const WeaponType STS_Photon_Cannon;\n    extern const WeaponType STA_Photon_Cannon;\n    extern const WeaponType Scarab;\n    extern const WeaponType Neutron_Flare;\n    extern const WeaponType Halo_Rockets;\n    extern const WeaponType Corrosive_Acid;\n    extern const WeaponType Subterranean_Spines;\n    extern const WeaponType Warp_Blades;\n    extern const WeaponType Warp_Blades_Hero;\n    extern const WeaponType Warp_Blades_Zeratul;\n\n    extern const WeaponType Yamato_Gun;\n    extern const WeaponType Nuclear_Strike;\n    extern const WeaponType Lockdown;\n    extern const WeaponType EMP_Shockwave;\n    extern const WeaponType Irradiate;\n    extern const WeaponType Parasite;\n    extern const WeaponType Spawn_Broodlings;\n    extern const WeaponType Ensnare;\n    extern const WeaponType Dark_Swarm;\n    extern const WeaponType Plague;\n    extern const WeaponType Consume;\n    extern const WeaponType Stasis_Field;\n    extern const WeaponType Psionic_Storm;\n    extern const WeaponType Disruption_Web;\n    extern const WeaponType Restoration;\n    extern const WeaponType Mind_Control;\n    extern const WeaponType Feedback;\n    extern const WeaponType Optical_Flare;\n    extern const WeaponType Maelstrom;\n\n    extern const WeaponType None;\n    extern const WeaponType Unknown;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI.cpp",
    "content": "#include <BWAPI.h>\n\nnamespace BWAPI\n{\n    Game * Broodwar;\n}\n\nvoid BWAPI::BWAPI_init()\n{\n  BWAPI::Races::init();\n  BWAPI::DamageTypes::init();\n  BWAPI::ExplosionTypes::init();\n  BWAPI::Orders::init();\n  BWAPI::TechTypes::init();\n  BWAPI::PlayerTypes::init();\n  BWAPI::UpgradeTypes::init();\n  BWAPI::WeaponTypes::init();\n  BWAPI::UnitSizeTypes::init();\n  BWAPI::UnitCommandTypes::init();\n  BWAPI::UnitTypes::init();\n  BWAPI::BulletTypes::init();\n  BWAPI::Errors::init();\n  BWAPI::Colors::init();\n  BWAPI::GameTypes::init();\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BWAPI.h",
    "content": "#include <BWAPI/AIModule.h>\n#include <BWAPI/Bullet.h>\n#include <BWAPI/BulletType.h>\n#include <BWAPI/Color.h>\n#include <BWAPI/Constants.h>\n#include <BWAPI/CoordinateType.h>\n#include <BWAPI/DamageType.h>\n#include <BWAPI/Error.h>\n#include <BWAPI/Event.h>\n#include <BWAPI/EventType.h>\n#include <BWAPI/ExplosionType.h>\n#include <BWAPI/Flag.h>\n#include <BWAPI/Force.h>\n#include <BWAPI/Game.h>\n#include <BWAPI/GameType.h>\n#include <BWAPI/Input.h>\n#include <BWAPI/Latency.h>\n#include <BWAPI/Order.h>\n#include <BWAPI/Player.h>\n#include <BWAPI/PlayerType.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/Unit.h>\n#include <BWAPI/UnitCommand.h>\n#include <BWAPI/UnitCommandType.h>\n#include <BWAPI/UnitSizeType.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/WeaponType.h>\n\nnamespace BWAPI\n{\n  /** You have to call this from your AIModule Dllmain function.\n   *\n   * \\code\n   * BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)\n   * {\n   *   switch (ul_reason_for_call)\n   *   {\n   *     case DLL_PROCESS_ATTACH:\n   *       BWAPI::BWAPI_init();\n   *       break;\n   *     case DLL_PROCESS_DETACH:\n   *       break;\n   *   }\n   *\n   *   return TRUE;\n   * }\n   * \\endcode */\n  void BWAPI_init();\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Bitmap.cpp",
    "content": "#include <BWAPI/Bitmap.h>\n\nnamespace BWAPI\n{\n  BitmapProxy::BitmapProxy(unsigned char *data, unsigned short width, unsigned short height, int x)\n  :data(data)\n  ,width(width)\n  ,height(height)\n  ,x(x)\n  {}\n\n  Color BitmapProxy::operator[](int y)\n  {\n    unsigned int offs = y * this->width + this->x;\n    if ( offs < (unsigned int)(this->width * this->height) )\n      return Color(this->data[offs]);\n    return Color(0);\n  }\n\n  BitmapProxy Bitmap::operator[](int x)\n  {\n    return BitmapProxy(this->data, this->wid, this->ht, x);\n  }\n\n  unsigned short Bitmap::getWidth()\n  {\n    return this->wid;\n  }\n\n  unsigned short Bitmap::getHeight()\n  {\n    return this->ht;\n  }\n}\n\n"
  },
  {
    "path": "SparCraft/bwapidata/include/BulletType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/BulletType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingBulletType = true;\n  std::string bulletTypeName[211];\n  std::map<std::string, BulletType> bulletTypeMap;\n  std::set< BulletType > bulletTypeSet;\n  namespace BulletTypes\n  {\n    const BulletType Melee(0);\n    const BulletType Fusion_Cutter_Hit(141);\n    const BulletType Gauss_Rifle_Hit(142);\n    const BulletType C_10_Canister_Rifle_Hit(143);\n    const BulletType Gemini_Missiles(144);\n    const BulletType Fragmentation_Grenade(145);\n    const BulletType Longbolt_Missile(146);\n    const BulletType ATS_ATA_Laser_Battery(148);\n    const BulletType Burst_Lasers(149);\n    const BulletType Arclite_Shock_Cannon_Hit(150);\n    const BulletType EMP_Missile(151);\n    const BulletType Dual_Photon_Blasters_Hit(152);\n    const BulletType Particle_Beam_Hit(153);\n    const BulletType Anti_Matter_Missile(154);\n    const BulletType Pulse_Cannon(155);\n    const BulletType Psionic_Shockwave_Hit(156);\n    const BulletType Psionic_Storm(157);\n    const BulletType Yamato_Gun(158);\n    const BulletType Phase_Disruptor(159);\n    const BulletType STA_STS_Cannon_Overlay(160);\n    const BulletType Sunken_Colony_Tentacle(161);\n    const BulletType Acid_Spore(163);\n    const BulletType Glave_Wurm(165);\n    const BulletType Seeker_Spores(166);\n    const BulletType Queen_Spell_Carrier(167);\n    const BulletType Plague_Cloud(168);\n    const BulletType Consume(169);\n    const BulletType Needle_Spine_Hit(171);\n    const BulletType Invisible(172);\n    const BulletType Optical_Flare_Grenade(201);\n    const BulletType Halo_Rockets(202);\n    const BulletType Subterranean_Spines(203);\n    const BulletType Corrosive_Acid_Shot(204);\n    const BulletType Neutron_Flare(206);\n    const BulletType None(209);\n    const BulletType Unknown(210);\n\n    void init()\n    {\n      bulletTypeName[Melee.getID()]                    = \"Melee\";\n      bulletTypeName[Fusion_Cutter_Hit.getID()]        = \"Fusion Cutter Hit\";\n      bulletTypeName[Gauss_Rifle_Hit.getID()]          = \"Gauss Rifle Hit\";\n      bulletTypeName[C_10_Canister_Rifle_Hit.getID()]  = \"C-10 Canister Rifle Hit\";\n      bulletTypeName[Gemini_Missiles.getID()]          = \"Gemini Missiles\";\n      bulletTypeName[Fragmentation_Grenade.getID()]    = \"Fragmentation Grenade\";\n      bulletTypeName[Longbolt_Missile.getID()]         = \"Longbolt Missile\";\n      bulletTypeName[ATS_ATA_Laser_Battery.getID()]    = \"ATS ATA Laser Battery\";\n      bulletTypeName[Burst_Lasers.getID()]             = \"Burst Lasers\";\n      bulletTypeName[Arclite_Shock_Cannon_Hit.getID()] = \"Arclite Shock Cannon Hit\";\n      bulletTypeName[EMP_Missile.getID()]              = \"EMP Missile\";\n      bulletTypeName[Dual_Photon_Blasters_Hit.getID()] = \"Dual Photon Blasters Hit\";\n      bulletTypeName[Particle_Beam_Hit.getID()]        = \"Particle Beam Hit\";\n      bulletTypeName[Anti_Matter_Missile.getID()]      = \"Anti-Matter Missile\";\n      bulletTypeName[Pulse_Cannon.getID()]             = \"Pulse Cannon\";\n      bulletTypeName[Psionic_Shockwave_Hit.getID()]    = \"Psionic Shockwave Hit\";\n      bulletTypeName[Psionic_Storm.getID()]            = \"Psionic Storm\";\n      bulletTypeName[Yamato_Gun.getID()]               = \"Yamato Gun\";\n      bulletTypeName[Phase_Disruptor.getID()]          = \"Phase Disruptor\";\n      bulletTypeName[STA_STS_Cannon_Overlay.getID()]   = \"STA STS Cannon Overlay\";\n      bulletTypeName[Sunken_Colony_Tentacle.getID()]   = \"Sunken Colony Tentacle\";\n      bulletTypeName[Acid_Spore.getID()]               = \"Acid Spore\";\n      bulletTypeName[Glave_Wurm.getID()]               = \"Glave Wurm\";\n      bulletTypeName[Seeker_Spores.getID()]            = \"Seeker Spores\";\n      bulletTypeName[Queen_Spell_Carrier.getID()]      = \"Queen Spell Carrier\";\n      bulletTypeName[Plague_Cloud.getID()]             = \"Plague Cloud\";\n      bulletTypeName[Consume.getID()]                  = \"Consume\";\n      bulletTypeName[Needle_Spine_Hit.getID()]         = \"Needle Spine Hit\";\n      bulletTypeName[Invisible.getID()]                = \"Invisible\";\n      bulletTypeName[Optical_Flare_Grenade.getID()]    = \"Optical Flare Grenade\";\n      bulletTypeName[Halo_Rockets.getID()]             = \"Halo Rockets\";\n      bulletTypeName[Subterranean_Spines.getID()]      = \"Subterranean Spines\";\n      bulletTypeName[Corrosive_Acid_Shot.getID()]      = \"Corrosive Acid Shot\";\n      bulletTypeName[Neutron_Flare.getID()]            = \"Neutron Flare\";\n      bulletTypeName[None.getID()]                     = \"None\";\n      bulletTypeName[Unknown.getID()]                  = \"Unknown\";\n\n      bulletTypeSet.insert(Melee);\n      bulletTypeSet.insert(Fusion_Cutter_Hit);\n      bulletTypeSet.insert(Gauss_Rifle_Hit);\n      bulletTypeSet.insert(C_10_Canister_Rifle_Hit);\n      bulletTypeSet.insert(Gemini_Missiles);\n      bulletTypeSet.insert(Fragmentation_Grenade);\n      bulletTypeSet.insert(Longbolt_Missile);\n      bulletTypeSet.insert(ATS_ATA_Laser_Battery);\n      bulletTypeSet.insert(Burst_Lasers);\n      bulletTypeSet.insert(Arclite_Shock_Cannon_Hit);\n      bulletTypeSet.insert(EMP_Missile);\n      bulletTypeSet.insert(Dual_Photon_Blasters_Hit);\n      bulletTypeSet.insert(Particle_Beam_Hit);\n      bulletTypeSet.insert(Anti_Matter_Missile);\n      bulletTypeSet.insert(Pulse_Cannon);\n      bulletTypeSet.insert(Psionic_Shockwave_Hit);\n      bulletTypeSet.insert(Psionic_Storm);\n      bulletTypeSet.insert(Yamato_Gun);\n      bulletTypeSet.insert(Phase_Disruptor);\n      bulletTypeSet.insert(STA_STS_Cannon_Overlay);\n      bulletTypeSet.insert(Sunken_Colony_Tentacle);\n      bulletTypeSet.insert(Acid_Spore);\n      bulletTypeSet.insert(Glave_Wurm);\n      bulletTypeSet.insert(Seeker_Spores);\n      bulletTypeSet.insert(Queen_Spell_Carrier);\n      bulletTypeSet.insert(Plague_Cloud);\n      bulletTypeSet.insert(Consume);\n      bulletTypeSet.insert(Needle_Spine_Hit);\n      bulletTypeSet.insert(Invisible);\n      bulletTypeSet.insert(Optical_Flare_Grenade);\n      bulletTypeSet.insert(Halo_Rockets);\n      bulletTypeSet.insert(Subterranean_Spines);\n      bulletTypeSet.insert(Corrosive_Acid_Shot);\n      bulletTypeSet.insert(Neutron_Flare);\n      bulletTypeSet.insert(None);\n      bulletTypeSet.insert(Unknown);\n\n      foreach(BulletType i, bulletTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        bulletTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingBulletType = false;\n    }\n  }\n\n  BulletType::BulletType()\n  {\n    this->id = BulletTypes::None.id;\n  }\n  BulletType::BulletType(int id)\n  {\n    this->id = id;\n    if (!initializingBulletType && (id < 0 || id >= 211 || bulletTypeName[id].length() == 0))\n      this->id = BulletTypes::Unknown.id;\n  }\n  BulletType::BulletType(const BulletType& other)\n  {\n    this->id = other.id;\n  }\n  BulletType& BulletType::operator=(const BulletType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool BulletType::operator==(const BulletType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool BulletType::operator!=(const BulletType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool BulletType::operator<(const BulletType& other) const\n  {\n    return this->id < other.id;\n  }\n  int BulletType::getID() const\n  {\n    return this->id;\n  }\n  std::string BulletType::getName() const\n  {\n    return bulletTypeName[this->id];\n  }\n  BulletType BulletTypes::getBulletType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, BulletType>::iterator i = bulletTypeMap.find(name);\n    if (i == bulletTypeMap.end())\n      return BulletTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<BulletType>& BulletTypes::allBulletTypes()\n  {\n    return bulletTypeSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Color.cpp",
    "content": "#include <BWAPI/Color.h>\n#include <list>\n#include <Util/Foreach.h>\nnamespace BWAPI\n{\n  int palette[256] = {0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,\n                      0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x3a003a, 0x190019,\n                      0x2c2418, 0x482414, 0x5c2c14, 0x703014, 0x683c24, 0x7c4018, 0x784c2c, 0xa80808,\n                      0x8c5430, 0x846044, 0xa0541c, 0xc44c18, 0xbc6824, 0xb4703c, 0xd06420, 0xdc9434,\n                      0xe09454, 0xecc454, 0x344428, 0x406c3c, 0x486c50, 0x4c8050, 0x508c5c, 0x5ca078,\n                      0x000018, 0x001034, 0x000850, 0x243448, 0x304054, 0x14347c, 0x344c6c, 0x405874,\n                      0x48688c, 0x00709c, 0x5880a4, 0x4068d4, 0x18acb8, 0x2424fc, 0x6494bc, 0x70a8cc,\n                      0x8cc0d8, 0x94dcf4, 0xacdce8, 0xacfcfc, 0xccf8f8, 0xfcfc00, 0xf4e490, 0xfcfcc0,\n                      0x0c0c0c, 0x181410, 0x1c1c20, 0x282830, 0x383024, 0x383c44, 0x4c4030, 0x4c4c4c,\n                      0x5c5040, 0x585858, 0x686868, 0x78846c, 0x68946c, 0x74a47c, 0x98948c, 0x90b894,\n                      0x98c4a8, 0xb0b0b0, 0xacccb0, 0xc4c0bc, 0xcce0d0, 0xf0f0f0, 0x1c1008, 0x28180c,\n                      0x341008, 0x34200c, 0x381020, 0x342820, 0x443408, 0x483018, 0x600000, 0x542820,\n                      0x504014, 0x5c5414, 0x840404, 0x684c34, 0x7c3830, 0x706420, 0x7c5050, 0xa4341c,\n                      0x946c00, 0x985c40, 0x8c8034, 0x987454, 0xb85444, 0xb09018, 0xb0745c, 0xf40404,\n                      0xc87854, 0xfc6854, 0xe0a484, 0xfc9468, 0xfccc2c, 0x10fc18, 0x0c0020, 0x1c1c2c,\n                      0x24244c, 0x282c68, 0x2c3084, 0x2018b8, 0x343cac, 0x686894, 0x6490fc, 0x7cacfc,\n                      0x00e4fc, 0x9c9040, 0xa89454, 0xbca45c, 0xccb860, 0xe8d880, 0xecc4b0, 0xfcfc38,\n                      0xfcfc7c, 0xfcfca4, 0x080808, 0x101010, 0x181818, 0x282828, 0x343434, 0x4c3c38,\n                      0x444444, 0x484858, 0x585868, 0x746838, 0x78645c, 0x60607c, 0x847474, 0x84849c,\n                      0xac8c7c, 0xac9894, 0x9090b8, 0xb8b8e8, 0xf88c14, 0x10543c, 0x209070, 0x2cb494,\n                      0x042064, 0x481c50, 0x083498, 0x683078, 0x88409c, 0x0c48cc, 0xbcb834, 0xdcdc3c,\n                      0x100000, 0x240000, 0x340000, 0x480000, 0x601804, 0x8c2808, 0xc81818, 0xe02c2c,\n                      0xe82020, 0xe85014, 0xfc2020, 0xe87824, 0xf8ac3c, 0x001400, 0x002800, 0x004400,\n                      0x006400, 0x088008, 0x249824, 0x3c9c3c, 0x58b058, 0x68b868, 0x80c480, 0x94d494,\n                      0x0c1424, 0x243c64, 0x305084, 0x385c94, 0x4874b4, 0x5484c4, 0x6094d4, 0x78b4ec,\n                      0x141008, 0x18140c, 0x242c0c, 0x101018, 0x141420, 0x2c2c40, 0x444c68, 0x040404,\n                      0x1c1810, 0x201c14, 0x24201c, 0x30281c, 0x40382c, 0x544838, 0x685c4c, 0x907c64,\n                      0x282014, 0x302814, 0x342c18, 0x382c1c, 0x3c301c, 0x443824, 0x544430, 0x0c1004,\n                      0x141804, 0x181c08, 0x1c2008, 0x20240c, 0x2c3410, 0x343c10, 0x404810, 0x202030,\n                      0x28283c, 0x303448, 0x141414, 0x20181c, 0x282018, 0x241c24, 0x282424, 0x302c2c,\n                      0x3c2c34, 0x3c383c, 0x483c30, 0x443440, 0x503c48, 0x5c5034, 0x2323ff, 0x2323ff,\n                      0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff\n                     };\n  namespace Colors\n  {\n    const Color Red(111);\n    const Color Blue(165);\n    const Color Teal(159);\n    const Color Purple(156);\n    const Color Orange(179);\n    const Color Brown(19);\n    const Color White(255);\n    const Color Yellow(135);\n    const Color Green(117);\n    const Color Cyan(128);\n    \n    const Color Black(0);\n    const Color Grey(74);\n\n    std::list<int> cell[8][8][8];\n    void init()\n    {\n      for(int i = 0; i < 256; ++i)\n      {\n        int redCell   = (palette[i] >> 21) & 0x07;\n        int greenCell = (palette[i] >> 13) & 0x07;\n        int blueCell  = (palette[i] >> 5)  & 0x07;\n        cell[redCell][greenCell][blueCell].push_back(i);\n      }\n    }\n  }\n  int min(int a, int b)\n  {\n    return a < b ? a : b;\n  }\n  int max(int a, int b)\n  {\n    return a > b ? a : b;\n  }\n  Color::Color()\n  {\n    this->id = 0;\n  }\n  Color::Color(int id)\n  {\n    this->id = id;\n  }\n  Color::Color(const Color& other)\n  {\n    this->id = other.id;\n  }\n  Color::Color(int red, int green, int blue)\n  {\n    int redCell    = red   >> 5;\n    int greenCell  = green >> 5;\n    int blueCell   = blue  >> 5;\n    int redCellS   = max(redCell   - 1, 0);\n    int redCellF   = min(redCell   + 1, 7);\n    int greenCellS = max(greenCell - 1, 0);\n    int greenCellF = min(greenCell + 1, 7);\n    int blueCellS  = max(blueCell  - 1, 0);\n    int blueCellF  = min(blueCell  + 1, 7);\n    int min_dist   = 3 * 256 * 256;\n    int best_id    = -1;\n    for(int rc = redCellS; rc <= redCellF; ++rc)\n    {\n      for(int gc = greenCellS; gc <= greenCellF; ++gc)\n      {\n        for(int bc = blueCellS; bc <= blueCellF; ++bc)\n        {\n          foreach(int id, Colors::cell[rc][gc][bc])\n          {\n            int ired   = (palette[id] >> 16) & 0xFF;\n            int igreen = (palette[id] >> 8)  & 0xFF;\n            int iblue  = (palette[id] >> 0)  & 0xFF;\n            int distance = (red - ired) * (red - ired) + (green - igreen) * (green - igreen) + (blue - iblue) * (blue - iblue);\n            if (distance < min_dist)\n            {\n              min_dist = distance;\n              best_id  = id;\n            }\n          }\n        }\n      }\n    }\n    if (best_id == -1)\n    {\n      int min_dist = 3 * 256 * 256;\n      int best_id = -1;\n      for(int id = 0; id < 255; ++id)\n      {\n        int ired   = (palette[id] >> 16) & 0xFF;\n        int igreen = (palette[id] >> 8)  & 0xFF;\n        int iblue  = (palette[id] >> 0)  & 0xFF;\n        int distance = (red - ired) * (red - ired) + (green - igreen) * (green - igreen) + (blue - iblue) * (blue - iblue);\n        if (distance < min_dist)\n        {\n          min_dist = distance;\n          best_id = id;\n        }\n      }\n    }\n    this->id = best_id;\n  }\n  Color& Color::operator=(const Color& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool Color::operator==(const Color& other) const\n  {\n    return palette[this->id] == palette[other.id];\n  }\n  bool Color::operator!=(const Color& other) const\n  {\n    return palette[this->id] != palette[other.id];\n  }\n  bool Color::operator<(const Color& other) const\n  {\n    return this->id < other.id;\n  }\n  int Color::getID() const\n  {\n    return this->id;\n  }\n  int Color::red() const\n  {\n    return (palette[this->id] >> 16) & 0xFF;\n  }\n  int Color::green() const\n  {\n    return (palette[this->id] >> 8) & 0xFF;\n  }\n  int Color::blue() const\n  {\n    return palette[this->id] & 0xFF;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Common.cpp",
    "content": "#include \"Common.h\"\n\nnamespace BWAPI\n{\n  void fixName(std::string *name)\n  {\n    for(unsigned int j = 0; j < name->length(); ++j)\n    {\n      if ( (*name)[j] == ' ')\n        (*name)[j] = '_';\n      if ( (*name)[j] >= 'a' && (*name)[j] <= 'z')\n        (*name)[j] += 'A'-'a';\n    }\n  }\n\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/Common.h",
    "content": "#pragma once\n#include <string>\n\nnamespace BWAPI\n{\n  void fixName(std::string *name);\n\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/DamageType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/DamageType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingDamageType = true;\n  std::string damageTypeName[7];\n  std::map<std::string, DamageType> damageTypeMap;\n  std::set< DamageType > damageTypeSet;\n  namespace DamageTypes\n  {\n    const DamageType Independent(0);\n    const DamageType Explosive(1);\n    const DamageType Concussive(2);\n    const DamageType Normal(3);\n    const DamageType Ignore_Armor(4);\n    const DamageType None(5);\n    const DamageType Unknown(6);\n\n    void init()\n    {\n      damageTypeName[Independent.getID()]  = \"Independent\";\n      damageTypeName[Explosive.getID()]    = \"Explosive\";\n      damageTypeName[Concussive.getID()]   = \"Concussive\";\n      damageTypeName[Normal.getID()]       = \"Normal\";\n      damageTypeName[Ignore_Armor.getID()] = \"Ignore Armor\";\n      damageTypeName[None.getID()]         = \"None\";\n      damageTypeName[Unknown.getID()]      = \"Unknown\";\n\n      damageTypeSet.insert(Independent);\n      damageTypeSet.insert(Explosive);\n      damageTypeSet.insert(Concussive);\n      damageTypeSet.insert(Normal);\n      damageTypeSet.insert(Ignore_Armor);\n      damageTypeSet.insert(None);\n      damageTypeSet.insert(Unknown);\n\n      foreach(DamageType i, damageTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        damageTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingDamageType = false;\n    }\n  }\n  DamageType::DamageType()\n  {\n    this->id = DamageTypes::None.id;\n  }\n  DamageType::DamageType(int id)\n  {\n    this->id = id;\n    if (!initializingDamageType && (id < 0 || id >= 7))\n      this->id = DamageTypes::Unknown.id;\n  }\n  DamageType::DamageType(const DamageType& other)\n  {\n    this->id = other.id;\n  }\n  DamageType& DamageType::operator=(const DamageType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool DamageType::operator==(const DamageType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool DamageType::operator!=(const DamageType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool DamageType::operator<(const DamageType& other) const\n  {\n    return this->id < other.id;\n  }\n  int DamageType::getID() const\n  {\n    return this->id;\n  }\n  std::string DamageType::getName() const\n  {\n    return damageTypeName[this->id];\n  }\n\n  DamageType DamageTypes::getDamageType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, DamageType>::iterator i = damageTypeMap.find(name);\n    if (i == damageTypeMap.end())\n      return DamageTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<DamageType>& DamageTypes::allDamageTypes()\n  {\n    return damageTypeSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Error.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/Error.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingError = true;\n  std::string errorName[25];\n  std::map<std::string, Error> errorMap;\n  std::set< Error > errorSet;\n  namespace Errors\n  {\n    const Error Unit_Does_Not_Exist(0);\n    const Error Unit_Not_Visible(1);\n    const Error Unit_Not_Owned(2);\n    const Error Unit_Busy(3);\n    const Error Incompatible_UnitType(4);\n    const Error Incompatible_TechType(5);\n    const Error Incompatible_State(6);\n    const Error Already_Researched(7);\n    const Error Fully_Upgraded(8);\n    const Error Currently_Researching(9);\n    const Error Currently_Upgrading(10);\n    const Error Insufficient_Minerals(11);\n    const Error Insufficient_Gas(12);\n    const Error Insufficient_Supply(13);\n    const Error Insufficient_Energy(14);\n    const Error Insufficient_Tech(15);\n    const Error Insufficient_Ammo(16);\n    const Error Insufficient_Space(17);\n    const Error Unbuildable_Location(18);\n    const Error Unreachable_Location(19);\n    const Error Out_Of_Range(20);\n    const Error Unable_To_Hit(21);\n    const Error Access_Denied(22);\n    const Error None(23);\n    const Error Unknown(24);\n\n    void init()\n    {\n      errorName[Unit_Does_Not_Exist.getID()]   = \"Unit Does Not Exist\";\n      errorName[Unit_Not_Visible.getID()]      = \"Unit Not Visible\";\n      errorName[Unit_Not_Owned.getID()]        = \"Unit Not Owned\";\n      errorName[Unit_Busy.getID()]             = \"Unit Busy\";\n      errorName[Incompatible_UnitType.getID()] = \"Incompatible UnitType\";\n      errorName[Incompatible_TechType.getID()] = \"Incompatible TechType\";\n      errorName[Incompatible_State.getID()]    = \"Incompatible State\";\n      errorName[Already_Researched.getID()]    = \"Already Researched\";\n      errorName[Fully_Upgraded.getID()]        = \"Fully Upgraded\";\n      errorName[Currently_Researching.getID()] = \"Currently Researching\";\n      errorName[Currently_Upgrading.getID()]   = \"Currently Upgrading\";\n      errorName[Insufficient_Minerals.getID()] = \"Insufficient Minerals\";\n      errorName[Insufficient_Gas.getID()]      = \"Insufficient Gas\";\n      errorName[Insufficient_Supply.getID()]   = \"Insufficient Supply\";\n      errorName[Insufficient_Energy.getID()]   = \"Insufficient Energy\";\n      errorName[Insufficient_Tech.getID()]     = \"Insufficient Tech\";\n      errorName[Insufficient_Ammo.getID()]     = \"Insufficient Ammo\";\n      errorName[Insufficient_Space.getID()]    = \"Insufficient Space\";\n      errorName[Unbuildable_Location.getID()]  = \"Unbuildable Location\";\n      errorName[Unreachable_Location.getID()]  = \"Unreachable Location\";\n      errorName[Out_Of_Range.getID()]          = \"Out Of Range\";\n      errorName[Unable_To_Hit.getID()]         = \"Unable To Hit\";\n      errorName[Access_Denied.getID()]         = \"Access Denied\";\n      errorName[None.getID()]                  = \"None\";\n      errorName[Unknown.getID()]               = \"Unknown\";\n\n      errorSet.insert(Unit_Does_Not_Exist);\n      errorSet.insert(Unit_Not_Visible);\n      errorSet.insert(Unit_Not_Owned);\n      errorSet.insert(Unit_Busy);\n      errorSet.insert(Incompatible_UnitType);\n      errorSet.insert(Incompatible_TechType);\n      errorSet.insert(Incompatible_State);\n      errorSet.insert(Already_Researched);\n      errorSet.insert(Fully_Upgraded);\n      errorSet.insert(Currently_Researching);\n      errorSet.insert(Currently_Upgrading);\n      errorSet.insert(Insufficient_Minerals);\n      errorSet.insert(Insufficient_Gas);\n      errorSet.insert(Insufficient_Supply);\n      errorSet.insert(Insufficient_Energy);\n      errorSet.insert(Insufficient_Tech);\n      errorSet.insert(Insufficient_Ammo);\n      errorSet.insert(Insufficient_Space);\n      errorSet.insert(Unbuildable_Location);\n      errorSet.insert(Unreachable_Location);\n      errorSet.insert(Out_Of_Range);\n      errorSet.insert(Unable_To_Hit);\n      errorSet.insert(Access_Denied);\n      errorSet.insert(None);\n      errorSet.insert(Unknown);\n\n      foreach(Error i, errorSet)\n      {\n        std::string name = i.toString();\n        fixName(&name);\n        errorMap.insert(std::make_pair(name, i));\n      }\n      initializingError = false;\n    }\n  }\n\n  Error::Error()\n  {\n    this->id = Errors::None.id;\n  }\n  Error::Error(int id)\n  {\n    this->id = id;\n    if (!initializingError && (id < 0 || id >= 25))\n      this->id = Errors::Unknown.id;\n  }\n  Error::Error(const Error& other)\n  {\n    this->id = other.id;\n  }\n  Error& Error::operator=(const Error& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool Error::operator==(const Error& other) const\n  {\n    return this->id == other.id;\n  }\n  bool Error::operator!=(const Error& other) const\n  {\n    return this->id != other.id;\n  }\n  bool Error::operator<(const Error& other) const\n  {\n    return this->id < other.id;\n  }\n  int Error::getID() const\n  {\n    return this->id;\n  }\n  std::string Error::toString() const\n  {\n    return errorName[this->id];\n  }\n  Error Errors::getError(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, Error>::iterator i = errorMap.find(name);\n    if (i == errorMap.end())\n      return Errors::Unknown;\n    return (*i).second;\n  }\n  std::set<Error>& Errors::allErrors()\n  {\n    return errorSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Event.cpp",
    "content": "#include <BWAPI/Event.h>\nnamespace BWAPI\n{\n  Event::Event() : type(EventType::None), position(Positions::None), text(\"\"), unit(NULL), player(NULL), isWinner(false)\n  {\n  }\n  bool Event::operator==(const Event& other)\n  {\n    return (type     == other.type &&\n            position == other.position &&\n            text     == other.text &&\n            unit     == other.unit &&\n            player   == other.player &&\n            isWinner == other.isWinner);\n  }\n  Event Event::MatchStart()\n  {\n    Event e;\n    e.type = EventType::MatchStart;\n    return e;\n  }\n  Event Event::MatchEnd(bool isWinner)\n  {\n    Event e;\n    e.type     = EventType::MatchEnd;\n    e.isWinner = isWinner;\n    return e;\n  }\n  Event Event::MatchFrame()\n  {\n    Event e;\n    e.type = EventType::MatchFrame;\n    return e;\n  }\n  Event Event::MenuFrame()\n  {\n    Event e;\n    e.type = EventType::MenuFrame;\n    return e;\n  }\n  Event Event::SendText(std::string text)\n  {\n    Event e;\n    e.type = EventType::SendText;\n    e.text = text;\n    return e;\n  }\n  Event Event::ReceiveText(Player* player, std::string text)\n  {\n    Event e;\n    e.type   = EventType::ReceiveText;\n    e.player = player;\n    e.text   = text;\n    return e;\n  }\n  Event Event::PlayerLeft(Player* player)\n  {\n    Event e;\n    e.type   = EventType::PlayerLeft;\n    e.player = player;\n    return e;\n  }\n  Event Event::NukeDetect(Position target)\n  {\n    Event e;\n    e.type     = EventType::NukeDetect;\n    e.position = target;\n    return e;\n  }\n  Event Event::UnitDiscover(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitDiscover;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitEvade(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitEvade;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitShow(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitShow;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitHide(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitHide;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitCreate(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitCreate;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitDestroy(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitDestroy;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitMorph(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitMorph;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::UnitRenegade(Unit* unit)\n  {\n    Event e;\n    e.type = EventType::UnitRenegade;\n    e.unit = unit;\n    return e;\n  }\n  Event Event::SaveGame(std::string gameName)\n  {\n    Event e;\n    e.type = EventType::SaveGame;\n    e.text = gameName;\n    return e;\n  }\n}"
  },
  {
    "path": "SparCraft/bwapidata/include/ExplosionType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/ExplosionType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingExplosionType = true;\n  std::string explosionTypeName[26];\n  std::map<std::string, ExplosionType> explosionTypeMap;\n  std::set< ExplosionType > explosionTypeSet;\n  namespace ExplosionTypes\n  {\n    const ExplosionType None(0);\n    const ExplosionType Normal(1);\n    const ExplosionType Radial_Splash(2);\n    const ExplosionType Enemy_Splash(3);\n    const ExplosionType Lockdown(4);\n    const ExplosionType Nuclear_Missile(5);\n    const ExplosionType Parasite(6);\n    const ExplosionType Broodlings(7);\n    const ExplosionType EMP_Shockwave(8);\n    const ExplosionType Irradiate(9);\n    const ExplosionType Ensnare(10);\n    const ExplosionType Plague(11);\n    const ExplosionType Stasis_Field(12);\n    const ExplosionType Dark_Swarm(13);\n    const ExplosionType Consume(14);\n    const ExplosionType Yamato_Gun(15);\n    const ExplosionType Restoration(16);\n    const ExplosionType Disruption_Web(17);\n    const ExplosionType Corrosive_Acid(18);\n    const ExplosionType Mind_Control(19);\n    const ExplosionType Feedback(20);\n    const ExplosionType Optical_Flare(21);\n    const ExplosionType Maelstrom(22);\n    const ExplosionType Air_Splash(24);\n    const ExplosionType Unknown(25);\n\n    void init()\n    {\n      explosionTypeName[None.getID()]            = \"None\";\n      explosionTypeName[Normal.getID()]          = \"Normal\";\n      explosionTypeName[Radial_Splash.getID()]   = \"Radial Splash\";\n      explosionTypeName[Enemy_Splash.getID()]    = \"Enemy Splash\";\n      explosionTypeName[Lockdown.getID()]        = \"Lockdown\";\n      explosionTypeName[Nuclear_Missile.getID()] = \"Nuclear Missile\";\n      explosionTypeName[Parasite.getID()]        = \"Parasite\";\n      explosionTypeName[Broodlings.getID()]      = \"Broodlings\";\n      explosionTypeName[EMP_Shockwave.getID()]   = \"EMP Shockwave\";\n      explosionTypeName[Irradiate.getID()]       = \"Irradiate\";\n      explosionTypeName[Ensnare.getID()]         = \"Ensnare\";\n      explosionTypeName[Plague.getID()]          = \"Plague\";\n      explosionTypeName[Stasis_Field.getID()]    = \"Stasis Field\";\n      explosionTypeName[Dark_Swarm.getID()]      = \"Dark Swarm\";\n      explosionTypeName[Consume.getID()]         = \"Consume\";\n      explosionTypeName[Yamato_Gun.getID()]      = \"Yamato Gun\";\n      explosionTypeName[Restoration.getID()]     = \"Restoration\";\n      explosionTypeName[Disruption_Web.getID()]  = \"Disruption Web\";\n      explosionTypeName[Corrosive_Acid.getID()]  = \"Corrosive Acid\";\n      explosionTypeName[Mind_Control.getID()]    = \"Mind Control\";\n      explosionTypeName[Feedback.getID()]        = \"Feedback\";\n      explosionTypeName[Optical_Flare.getID()]   = \"Optical Flare\";\n      explosionTypeName[Maelstrom.getID()]       = \"Maelstrom\";\n      explosionTypeName[Air_Splash.getID()]      = \"Air Splash\";\n      explosionTypeName[Unknown.getID()]         = \"Unknown\";\n\n      explosionTypeSet.insert(None);\n      explosionTypeSet.insert(Normal);\n      explosionTypeSet.insert(Radial_Splash);\n      explosionTypeSet.insert(Enemy_Splash);\n      explosionTypeSet.insert(Lockdown);\n      explosionTypeSet.insert(Nuclear_Missile);\n      explosionTypeSet.insert(Parasite);\n      explosionTypeSet.insert(Broodlings);\n      explosionTypeSet.insert(EMP_Shockwave);\n      explosionTypeSet.insert(Irradiate);\n      explosionTypeSet.insert(Ensnare);\n      explosionTypeSet.insert(Plague);\n      explosionTypeSet.insert(Stasis_Field);\n      explosionTypeSet.insert(Dark_Swarm);\n      explosionTypeSet.insert(Consume);\n      explosionTypeSet.insert(Yamato_Gun);\n      explosionTypeSet.insert(Restoration);\n      explosionTypeSet.insert(Disruption_Web);\n      explosionTypeSet.insert(Corrosive_Acid);\n      explosionTypeSet.insert(Mind_Control);\n      explosionTypeSet.insert(Feedback);\n      explosionTypeSet.insert(Optical_Flare);\n      explosionTypeSet.insert(Maelstrom);\n      explosionTypeSet.insert(Air_Splash);\n      explosionTypeSet.insert(Unknown);\n\n      foreach(ExplosionType i, explosionTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        explosionTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingExplosionType = false;\n    }\n  }\n  ExplosionType::ExplosionType()\n  {\n    this->id = ExplosionTypes::None.id;\n  }\n  ExplosionType::ExplosionType(int id)\n  {\n    this->id = id;\n    if (!initializingExplosionType && (id < 0 || id >= 26))\n      this->id = ExplosionTypes::Unknown.id;\n  }\n  ExplosionType::ExplosionType(const ExplosionType& other)\n  {\n    this->id = other.id;\n  }\n  ExplosionType& ExplosionType::operator=(const ExplosionType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool ExplosionType::operator==(const ExplosionType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool ExplosionType::operator!=(const ExplosionType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool ExplosionType::operator<(const ExplosionType& other) const\n  {\n    return this->id < other.id;\n  }\n  int ExplosionType::getID() const\n  {\n    return this->id;\n  }\n  std::string ExplosionType::getName() const\n  {\n    return explosionTypeName[this->id];\n  }\n\n  ExplosionType ExplosionTypes::getExplosionType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, ExplosionType>::iterator i = explosionTypeMap.find(name);\n    if (i == explosionTypeMap.end())\n      return ExplosionTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<ExplosionType>& ExplosionTypes::allExplosionTypes()\n  {\n    return explosionTypeSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/GameType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/GameType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingGameType = true;\n  std::string gameTypeName[35];\n  std::map<std::string, GameType> gameTypeMap;\n  std::set< GameType > gameTypeSet;\n  namespace GameTypes\n  {\n    const GameType Melee(2);\n    const GameType Free_For_All(3);\n    const GameType One_on_One(4);\n    const GameType Capture_The_Flag(5);\n    const GameType Greed(6);\n    const GameType Slaughter(7);\n    const GameType Sudden_Death(8);\n    const GameType Ladder(9);\n    const GameType Use_Map_Settings(10);\n    const GameType Team_Melee(11);\n    const GameType Team_Free_For_All(12);\n    const GameType Team_Capture_The_Flag(13);\n    const GameType Top_vs_Bottom(15);\n    const GameType Pro_Gamer_League(32);\n    const GameType None(33);\n    const GameType Unknown(34);\n\n    void init()\n    {\n      gameTypeName[Melee.getID()]                 = \"Melee\";\n      gameTypeName[Free_For_All.getID()]          = \"Free For All\";\n      gameTypeName[One_on_One.getID()]            = \"One on One\";\n      gameTypeName[Capture_The_Flag.getID()]      = \"Capture The Flag\";\n      gameTypeName[Greed.getID()]                 = \"Greed\";\n      gameTypeName[Slaughter.getID()]             = \"Slaughter\";\n      gameTypeName[Sudden_Death.getID()]          = \"Sudden Death\";\n      gameTypeName[Ladder.getID()]                = \"Ladder\";\n      gameTypeName[Use_Map_Settings.getID()]      = \"Use Map Settings\";\n      gameTypeName[Team_Melee.getID()]            = \"Team Melee\";\n      gameTypeName[Team_Free_For_All.getID()]     = \"Team Free For All\";\n      gameTypeName[Team_Capture_The_Flag.getID()] = \"Team Capture The Flag\";\n      gameTypeName[Top_vs_Bottom.getID()]         = \"Top vs Bottom\";\n      gameTypeName[Pro_Gamer_League.getID()]      = \"Pro Gamer League\";\n      gameTypeName[None.getID()]                  = \"None\";\n      gameTypeName[Unknown.getID()]               = \"Unknown\";\n\n      gameTypeSet.insert(Melee);\n      gameTypeSet.insert(Free_For_All);\n      gameTypeSet.insert(One_on_One);\n      gameTypeSet.insert(Capture_The_Flag);\n      gameTypeSet.insert(Greed);\n      gameTypeSet.insert(Slaughter);\n      gameTypeSet.insert(Sudden_Death);\n      gameTypeSet.insert(Ladder);\n      gameTypeSet.insert(Use_Map_Settings);\n      gameTypeSet.insert(Team_Melee);\n      gameTypeSet.insert(Team_Free_For_All);\n      gameTypeSet.insert(Team_Capture_The_Flag);\n      gameTypeSet.insert(Top_vs_Bottom);\n      gameTypeSet.insert(Pro_Gamer_League);\n      gameTypeSet.insert(None);\n      gameTypeSet.insert(Unknown);\n\n      foreach(GameType i, gameTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        gameTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingGameType = false;\n    }\n  }\n  GameType::GameType()\n  {\n    this->id = GameTypes::None.id;\n  }\n  GameType::GameType(int id)\n  {\n    this->id = id;\n    if (!initializingGameType && (id < 0 || id >= 35 || gameTypeName[id].length() == 0))\n      this->id = GameTypes::Unknown.id;\n  }\n  GameType::GameType(const GameType& other)\n  {\n    this->id = other.id;\n  }\n  GameType& GameType::operator=(const GameType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool GameType::operator==(const GameType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool GameType::operator!=(const GameType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool GameType::operator<(const GameType& other) const\n  {\n    return this->id < other.id;\n  }\n  int GameType::getID() const\n  {\n    return this->id;\n  }\n  std::string GameType::getName() const\n  {\n    return gameTypeName[this->id];\n  }\n  GameType GameTypes::getGameType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, GameType>::iterator i = gameTypeMap.find(name);\n    if (i == gameTypeMap.end()) return GameTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<GameType>& GameTypes::allGameTypes()\n  {\n    return gameTypeSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Order.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/Order.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingOrder = true;\n  std::string orderName[191];\n  std::map<std::string, Order> orderMap;\n  std::set< Order > orderSet;\n  namespace Orders\n  {\n    const Order Die(0);\n    const Order Stop(1);\n    const Order Guard(2);\n    const Order PlayerGuard(3);\n    const Order TurretGuard(4);\n    const Order BunkerGuard(5);\n    const Order Move(6);\n    const Order AttackUnit(10);\n    const Order AttackTile(12);\n    const Order Hover(13);\n    const Order AttackMove(14);\n    const Order InfestedCommandCenter(15);\n    const Order UnusedNothing(16);\n    const Order UnusedPowerup(17);\n    const Order TowerGuard(18);\n    const Order VultureMine(20);\n    const Order Nothing(23);\n    const Order Nothing3(24);\n    const Order CastInfestation(27);\n    const Order InfestingCommandCenter(29);\n    const Order PlaceBuilding(30);\n    const Order BuildProtoss2(32);\n    const Order ConstructingBuilding(33);\n    const Order Repair(34);\n    const Order PlaceAddon(36);\n    const Order BuildAddon(37);\n    const Order Train(38);\n    const Order RallyPointUnit(39);\n    const Order RallyPointTile(40);\n    const Order ZergBirth(41);\n    const Order ZergUnitMorph(42);\n    const Order ZergBuildingMorph(43);\n    const Order IncompleteBuilding(44);\n    const Order BuildNydusExit(46);\n    const Order EnterNydusCanal(47);\n    const Order Follow(49);\n    const Order Carrier(50);\n    const Order ReaverCarrierMove(51);\n    const Order CarrierIgnore2(55);\n    const Order Reaver(58);\n    const Order TrainFighter(63);\n    const Order InterceptorAttack(64);\n    const Order ScarabAttack(65);\n    const Order RechargeShieldsUnit(66);\n    const Order RechargeShieldsBattery(67);\n    const Order ShieldBattery(68);\n    const Order InterceptorReturn(69);\n    const Order BuildingLand(71);\n    const Order BuildingLiftOff(72);\n    const Order DroneLiftOff(73);\n    const Order LiftingOff(74);\n    const Order ResearchTech(75);\n    const Order Upgrade(76);\n    const Order Larva(77);\n    const Order SpawningLarva(78);\n    const Order Harvest1(79);\n    const Order Harvest2(80);\n    const Order MoveToGas(81);\n    const Order WaitForGas(82);\n    const Order HarvestGas(83);\n    const Order ReturnGas(84);\n    const Order MoveToMinerals(85);\n    const Order WaitForMinerals(86);\n    const Order MiningMinerals(87);\n    const Order Harvest3(88);\n    const Order Harvest4(89);\n    const Order ReturnMinerals(90);\n    const Order Interrupted(91);\n    const Order EnterTransport(92);\n    const Order PickupIdle(93);\n    const Order PickupTransport(94);\n    const Order PickupBunker(95);\n    const Order Pickup4(96);\n    const Order PowerupIdle(97);\n    const Order Sieging(98);\n    const Order Unsieging(99);\n    const Order InitCreepGrowth(101);\n    const Order SpreadCreep(102);\n    const Order StoppingCreepGrowth(103);\n    const Order GuardianAspect(104);\n    const Order ArchonWarp(105);\n    const Order CompletingArchonsummon(106);\n    const Order HoldPosition(107);\n    const Order Cloak(109);\n    const Order Decloak(110);\n    const Order Unload(111);\n    const Order MoveUnload(112);\n    const Order FireYamatoGun(113);\n    const Order CastLockdown(115);\n    const Order Burrowing(116);\n    const Order Burrowed(117);\n    const Order Unburrowing(118);\n    const Order CastDarkSwarm(119);\n    const Order CastParasite(120);\n    const Order CastSpawnBroodlings(121);\n    const Order CastEMPShockwave(122);\n    const Order NukeWait(123);\n    const Order NukeTrain(124);\n    const Order NukeLaunch(125);\n    const Order NukeUnit(127);\n    const Order CastNuclearStrike(128);\n    const Order NukeTrack(129);\n    const Order CloakNearbyUnits(131);\n    const Order PlaceMine(132);\n    const Order RightClickAction(133);\n    const Order CastRecall(137);\n    const Order TeleporttoLocation(138);\n    const Order CastScannerSweep(139);\n    const Order Scanner(140);\n    const Order CastDefensiveMatrix(141);\n    const Order CastPsionicStorm(142);\n    const Order CastIrradiate(143);\n    const Order CastPlague(144);\n    const Order CastConsume(145);\n    const Order CastEnsnare(146);\n    const Order CastStasisField(147);\n    const Order CastHallucination(148);\n    const Order Hallucination2(149);\n    const Order ResetCollision(150);\n    const Order Patrol(152);\n    const Order CTFCOPInit(153);\n    const Order CTFCOP1(154);\n    const Order CTFCOP2(155);\n    const Order ComputerAI(156);\n    const Order AtkMoveEP(157);\n    const Order HarassMove(158);\n    const Order AIPatrol(159);\n    const Order GuardPost(160);\n    const Order RescuePassive(161);\n    const Order Neutral(162);\n    const Order ComputerReturn(163);\n    const Order SelfDestrucing(165);\n    const Order Critter(166);\n    const Order HiddenGun(167);\n    const Order OpenDoor(168);\n    const Order CloseDoor(169);\n    const Order HideTrap(170);\n    const Order RevealTrap(171);\n    const Order Enabledoodad(172);\n    const Order Disabledoodad(173);\n    const Order Warpin(174);\n    const Order Medic(175);\n    const Order MedicHeal1(176);\n    const Order HealMove(177);\n    const Order MedicHeal2(179);\n    const Order CastRestoration(180);\n    const Order CastDisruptionWeb(181);\n    const Order CastMindControl(182);\n    const Order DarkArchonMeld(183);\n    const Order CastFeedback(184);\n    const Order CastOpticalFlare(185);\n    const Order CastMaelstrom(186);\n    const Order JunkYardDog(187);\n    const Order Fatal(188);\n    const Order None(189);\n    const Order Unknown(190);\n\n    void init()\n    {\n      orderName[Die.getID()]                    = \"Die\";\n      orderName[Stop.getID()]                   = \"Stop\";\n      orderName[Guard.getID()]                  = \"Guard\";\n      orderName[PlayerGuard.getID()]            = \"PlayerGuard\";\n      orderName[TurretGuard.getID()]            = \"TurretGuard\";\n      orderName[BunkerGuard.getID()]            = \"BunkerGuard\";\n      orderName[Move.getID()]                   = \"Move\";\n      orderName[AttackUnit.getID()]             = \"AttackUnit\";\n      orderName[AttackTile.getID()]             = \"AttackTile\";\n      orderName[Hover.getID()]                  = \"Hover\";\n      orderName[AttackMove.getID()]             = \"AttackMove\";\n      orderName[InfestedCommandCenter.getID()]  = \"InfestedCommandCenter\";\n      orderName[UnusedNothing.getID()]          = \"UnusedNothing\";\n      orderName[UnusedPowerup.getID()]          = \"UnusedPowerup\";\n      orderName[TowerGuard.getID()]             = \"TowerGuard\";\n      orderName[VultureMine.getID()]            = \"VultureMine\";\n      orderName[Nothing.getID()]                = \"Nothing\";\n      orderName[Nothing3.getID()]               = \"Nothing3\";\n      orderName[CastInfestation.getID()]        = \"CastInfestation\";\n      orderName[InfestingCommandCenter.getID()] = \"InfestingCommandCenter\";\n      orderName[PlaceBuilding.getID()]          = \"PlaceBuilding\";\n      orderName[BuildProtoss2.getID()]          = \"BuildProtoss2\";\n      orderName[ConstructingBuilding.getID()]   = \"ConstructingBuilding\";\n      orderName[Repair.getID()]                 = \"Repair\";\n      orderName[PlaceAddon.getID()]             = \"PlaceAddon\";\n      orderName[BuildAddon.getID()]             = \"BuildAddon\";\n      orderName[Train.getID()]                  = \"Train\";\n      orderName[RallyPointUnit.getID()]         = \"RallyPointUnit\";\n      orderName[RallyPointTile.getID()]         = \"RallyPointTile\";\n      orderName[ZergBirth.getID()]              = \"ZergBirth\";\n      orderName[ZergUnitMorph.getID()]          = \"ZergUnitMorph\";\n      orderName[ZergBuildingMorph.getID()]      = \"ZergBuildingMorph\";\n      orderName[IncompleteBuilding.getID()]     = \"IncompleteBuilding\";\n      orderName[BuildNydusExit.getID()]         = \"BuildNydusExit\";\n      orderName[EnterNydusCanal.getID()]        = \"EnterNydusCanal\";\n      orderName[Follow.getID()]                 = \"Follow\";\n      orderName[Carrier.getID()]                = \"Carrier\";\n      orderName[ReaverCarrierMove.getID()]      = \"ReaverCarrierMove\";\n      orderName[CarrierIgnore2.getID()]         = \"CarrierIgnore2\";\n      orderName[Reaver.getID()]                 = \"Reaver\";\n      orderName[TrainFighter.getID()]           = \"TrainFighter\";\n      orderName[InterceptorAttack.getID()]      = \"InterceptorAttack\";\n      orderName[ScarabAttack.getID()]           = \"ScarabAttack\";\n      orderName[RechargeShieldsUnit.getID()]    = \"RechargeShieldsUnit\";\n      orderName[RechargeShieldsBattery.getID()] = \"RechargeShieldsBattery\";\n      orderName[ShieldBattery.getID()]          = \"ShieldBattery\";\n      orderName[InterceptorReturn.getID()]      = \"InterceptorReturn\";\n      orderName[BuildingLand.getID()]           = \"BuildingLand\";\n      orderName[BuildingLiftOff.getID()]        = \"BuildingLiftOff\";\n      orderName[DroneLiftOff.getID()]           = \"DroneLiftOff\";\n      orderName[LiftingOff.getID()]             = \"LiftingOff\";\n      orderName[ResearchTech.getID()]           = \"ResearchTech\";\n      orderName[Upgrade.getID()]                = \"Upgrade\";\n      orderName[Larva.getID()]                  = \"Larva\";\n      orderName[SpawningLarva.getID()]          = \"SpawningLarva\";\n      orderName[Harvest1.getID()]               = \"Harvest1\";\n      orderName[Harvest2.getID()]               = \"Harvest2\";\n      orderName[MoveToGas.getID()]              = \"MoveToGas\";\n      orderName[WaitForGas.getID()]             = \"WaitForGas\";\n      orderName[HarvestGas.getID()]             = \"HarvestGas\";\n      orderName[ReturnGas.getID()]              = \"ReturnGas\";\n      orderName[MoveToMinerals.getID()]         = \"MoveToMinerals\";\n      orderName[WaitForMinerals.getID()]        = \"WaitForMinerals\";\n      orderName[MiningMinerals.getID()]         = \"MiningMinerals\";\n      orderName[Harvest3.getID()]               = \"Harvest3\";\n      orderName[Harvest4.getID()]               = \"Harvest4\";\n      orderName[ReturnMinerals.getID()]         = \"ReturnMinerals\";\n      orderName[Interrupted.getID()]            = \"Interrupted\";\n      orderName[EnterTransport.getID()]         = \"EnterTransport\";\n      orderName[PickupIdle.getID()]             = \"PickupIdle\";\n      orderName[PickupTransport.getID()]        = \"PickupTransport\";\n      orderName[PickupBunker.getID()]           = \"PickupBunker\";\n      orderName[Pickup4.getID()]                = \"Pickup4\";\n      orderName[PowerupIdle.getID()]            = \"PowerupIdle\";\n      orderName[Sieging.getID()]                = \"Sieging\";\n      orderName[Unsieging.getID()]              = \"Unsieging\";\n      orderName[InitCreepGrowth.getID()]        = \"InitCreepGrowth\";\n      orderName[SpreadCreep.getID()]            = \"SpreadCreep\";\n      orderName[StoppingCreepGrowth.getID()]    = \"StoppingCreepGrowth\";\n      orderName[GuardianAspect.getID()]         = \"GuardianAspect\";\n      orderName[ArchonWarp.getID()]             = \"ArchonWarp\";\n      orderName[CompletingArchonsummon.getID()] = \"CompletingArchonsummon\";\n      orderName[HoldPosition.getID()]           = \"HoldPosition\";\n      orderName[Cloak.getID()]                  = \"Cloak\";\n      orderName[Decloak.getID()]                = \"Decloak\";\n      orderName[Unload.getID()]                 = \"Unload\";\n      orderName[MoveUnload.getID()]             = \"MoveUnload\";\n      orderName[FireYamatoGun.getID()]          = \"FireYamatoGun\";\n      orderName[CastLockdown.getID()]           = \"CastLockdown\";\n      orderName[Burrowing.getID()]              = \"Burrowing\";\n      orderName[Burrowed.getID()]               = \"Burrowed\";\n      orderName[Unburrowing.getID()]            = \"Unburrowing\";\n      orderName[CastDarkSwarm.getID()]          = \"CastDarkSwarm\";\n      orderName[CastParasite.getID()]           = \"CastParasite\";\n      orderName[CastSpawnBroodlings.getID()]    = \"CastSpawnBroodlings\";\n      orderName[CastEMPShockwave.getID()]       = \"CastEMPShockwave\";\n      orderName[NukeWait.getID()]               = \"NukeWait\";\n      orderName[NukeTrain.getID()]              = \"NukeTrain\";\n      orderName[NukeLaunch.getID()]             = \"NukeLaunch\";\n      orderName[NukeUnit.getID()]               = \"NukeUnit\";\n      orderName[CastNuclearStrike.getID()]      = \"CastNuclearStrike\";\n      orderName[NukeTrack.getID()]              = \"NukeTrack\";\n      orderName[CloakNearbyUnits.getID()]       = \"CloakNearbyUnits\";\n      orderName[PlaceMine.getID()]              = \"PlaceMine\";\n      orderName[RightClickAction.getID()]       = \"RightClickAction\";\n      orderName[CastRecall.getID()]             = \"CastRecall\";\n      orderName[TeleporttoLocation.getID()]     = \"TeleporttoLocation\";\n      orderName[CastScannerSweep.getID()]       = \"CastScannerSweep\";\n      orderName[Scanner.getID()]                = \"Scanner\";\n      orderName[CastDefensiveMatrix.getID()]    = \"CastDefensiveMatrix\";\n      orderName[CastPsionicStorm.getID()]       = \"CastPsionicStorm\";\n      orderName[CastIrradiate.getID()]          = \"CastIrradiate\";\n      orderName[CastPlague.getID()]             = \"CastPlague\";\n      orderName[CastConsume.getID()]            = \"CastConsume\";\n      orderName[CastEnsnare.getID()]            = \"CastEnsnare\";\n      orderName[CastStasisField.getID()]        = \"CastStasisField\";\n      orderName[CastHallucination.getID()]      = \"CastHallucination\";\n      orderName[Hallucination2.getID()]         = \"Hallucination2\";\n      orderName[ResetCollision.getID()]         = \"ResetCollision\";\n      orderName[Patrol.getID()]                 = \"Patrol\";\n      orderName[CTFCOPInit.getID()]             = \"CTFCOPInit\";\n      orderName[CTFCOP1.getID()]                = \"CTFCOP1\";\n      orderName[CTFCOP2.getID()]                = \"CTFCOP2\";\n      orderName[ComputerAI.getID()]             = \"ComputerAI\";\n      orderName[AtkMoveEP.getID()]              = \"AtkMoveEP\";\n      orderName[HarassMove.getID()]             = \"HarassMove\";\n      orderName[AIPatrol.getID()]               = \"AIPatrol\";\n      orderName[GuardPost.getID()]              = \"GuardPost\";\n      orderName[RescuePassive.getID()]          = \"RescuePassive\";\n      orderName[Neutral.getID()]                = \"Neutral\";\n      orderName[ComputerReturn.getID()]         = \"ComputerReturn\";\n      orderName[SelfDestrucing.getID()]         = \"SelfDestrucing\";\n      orderName[Critter.getID()]                = \"Critter\";\n      orderName[HiddenGun.getID()]              = \"HiddenGun\";\n      orderName[OpenDoor.getID()]               = \"OpenDoor\";\n      orderName[CloseDoor.getID()]              = \"CloseDoor\";\n      orderName[HideTrap.getID()]               = \"HideTrap\";\n      orderName[RevealTrap.getID()]             = \"RevealTrap\";\n      orderName[Enabledoodad.getID()]           = \"Enabledoodad\";\n      orderName[Disabledoodad.getID()]          = \"Disabledoodad\";\n      orderName[Warpin.getID()]                 = \"Warpin\";\n      orderName[Medic.getID()]                  = \"Medic\";\n      orderName[MedicHeal1.getID()]             = \"MedicHeal1\";\n      orderName[HealMove.getID()]               = \"HealMove\";\n      orderName[MedicHeal2.getID()]             = \"MedicHeal2\";\n      orderName[CastRestoration.getID()]        = \"CastRestoration\";\n      orderName[CastDisruptionWeb.getID()]      = \"CastDisruptionWeb\";\n      orderName[CastMindControl.getID()]        = \"CastMindControl\";\n      orderName[DarkArchonMeld.getID()]         = \"DarkArchonMeld\";\n      orderName[CastFeedback.getID()]           = \"CastFeedback\";\n      orderName[CastOpticalFlare.getID()]       = \"CastOpticalFlare\";\n      orderName[CastMaelstrom.getID()]          = \"CastMaelstrom\";\n      orderName[JunkYardDog.getID()]            = \"JunkYardDog\";\n      orderName[Fatal.getID()]                  = \"Fatal\";\n      orderName[None.getID()]                   = \"None\";\n      orderName[Unknown.getID()]                = \"Unknown\";\n\n      orderSet.insert(Die);\n      orderSet.insert(Stop);\n      orderSet.insert(Guard);\n      orderSet.insert(PlayerGuard);\n      orderSet.insert(TurretGuard);\n      orderSet.insert(BunkerGuard);\n      orderSet.insert(Move);\n      orderSet.insert(AttackUnit);\n      orderSet.insert(AttackTile);\n      orderSet.insert(Hover);\n      orderSet.insert(AttackMove);\n      orderSet.insert(InfestedCommandCenter);\n      orderSet.insert(UnusedNothing);\n      orderSet.insert(UnusedPowerup);\n      orderSet.insert(TowerGuard);\n      orderSet.insert(VultureMine);\n      orderSet.insert(Nothing);\n      orderSet.insert(Nothing3);\n      orderSet.insert(CastInfestation);\n      orderSet.insert(InfestingCommandCenter);\n      orderSet.insert(PlaceBuilding);\n      orderSet.insert(BuildProtoss2);\n      orderSet.insert(ConstructingBuilding);\n      orderSet.insert(Repair);\n      orderSet.insert(PlaceAddon);\n      orderSet.insert(BuildAddon);\n      orderSet.insert(Train);\n      orderSet.insert(RallyPointUnit);\n      orderSet.insert(RallyPointTile);\n      orderSet.insert(ZergBirth);\n      orderSet.insert(ZergUnitMorph);\n      orderSet.insert(ZergBuildingMorph);\n      orderSet.insert(IncompleteBuilding);\n      orderSet.insert(BuildNydusExit);\n      orderSet.insert(EnterNydusCanal);\n      orderSet.insert(Follow);\n      orderSet.insert(Carrier);\n      orderSet.insert(ReaverCarrierMove);\n      orderSet.insert(CarrierIgnore2);\n      orderSet.insert(Reaver);\n      orderSet.insert(TrainFighter);\n      orderSet.insert(InterceptorAttack);\n      orderSet.insert(ScarabAttack);\n      orderSet.insert(RechargeShieldsUnit);\n      orderSet.insert(RechargeShieldsBattery);\n      orderSet.insert(ShieldBattery);\n      orderSet.insert(InterceptorReturn);\n      orderSet.insert(BuildingLand);\n      orderSet.insert(BuildingLiftOff);\n      orderSet.insert(DroneLiftOff);\n      orderSet.insert(LiftingOff);\n      orderSet.insert(ResearchTech);\n      orderSet.insert(Upgrade);\n      orderSet.insert(Larva);\n      orderSet.insert(SpawningLarva);\n      orderSet.insert(Harvest1);\n      orderSet.insert(Harvest2);\n      orderSet.insert(MoveToGas);\n      orderSet.insert(WaitForGas);\n      orderSet.insert(HarvestGas);\n      orderSet.insert(ReturnGas);\n      orderSet.insert(MoveToMinerals);\n      orderSet.insert(WaitForMinerals);\n      orderSet.insert(MiningMinerals);\n      orderSet.insert(Harvest3);\n      orderSet.insert(Harvest4);\n      orderSet.insert(ReturnMinerals);\n      orderSet.insert(Interrupted);\n      orderSet.insert(EnterTransport);\n      orderSet.insert(PickupIdle);\n      orderSet.insert(PickupTransport);\n      orderSet.insert(PickupBunker);\n      orderSet.insert(Pickup4);\n      orderSet.insert(PowerupIdle);\n      orderSet.insert(Sieging);\n      orderSet.insert(Unsieging);\n      orderSet.insert(InitCreepGrowth);\n      orderSet.insert(SpreadCreep);\n      orderSet.insert(StoppingCreepGrowth);\n      orderSet.insert(GuardianAspect);\n      orderSet.insert(ArchonWarp);\n      orderSet.insert(CompletingArchonsummon);\n      orderSet.insert(HoldPosition);\n      orderSet.insert(Cloak);\n      orderSet.insert(Decloak);\n      orderSet.insert(Unload);\n      orderSet.insert(MoveUnload);\n      orderSet.insert(FireYamatoGun);\n      orderSet.insert(CastLockdown);\n      orderSet.insert(Burrowing);\n      orderSet.insert(Burrowed);\n      orderSet.insert(Unburrowing);\n      orderSet.insert(CastDarkSwarm);\n      orderSet.insert(CastParasite);\n      orderSet.insert(CastSpawnBroodlings);\n      orderSet.insert(CastEMPShockwave);\n      orderSet.insert(NukeWait);\n      orderSet.insert(NukeTrain);\n      orderSet.insert(NukeLaunch);\n      orderSet.insert(NukeUnit);\n      orderSet.insert(CastNuclearStrike);\n      orderSet.insert(NukeTrack);\n      orderSet.insert(CloakNearbyUnits);\n      orderSet.insert(PlaceMine);\n      orderSet.insert(RightClickAction);\n      orderSet.insert(CastRecall);\n      orderSet.insert(TeleporttoLocation);\n      orderSet.insert(CastScannerSweep);\n      orderSet.insert(Scanner);\n      orderSet.insert(CastDefensiveMatrix);\n      orderSet.insert(CastPsionicStorm);\n      orderSet.insert(CastIrradiate);\n      orderSet.insert(CastPlague);\n      orderSet.insert(CastConsume);\n      orderSet.insert(CastEnsnare);\n      orderSet.insert(CastStasisField);\n      orderSet.insert(CastHallucination);\n      orderSet.insert(Hallucination2);\n      orderSet.insert(ResetCollision);\n      orderSet.insert(Patrol);\n      orderSet.insert(CTFCOPInit);\n      orderSet.insert(CTFCOP1);\n      orderSet.insert(CTFCOP2);\n      orderSet.insert(ComputerAI);\n      orderSet.insert(AtkMoveEP);\n      orderSet.insert(HarassMove);\n      orderSet.insert(AIPatrol);\n      orderSet.insert(GuardPost);\n      orderSet.insert(RescuePassive);\n      orderSet.insert(Neutral);\n      orderSet.insert(ComputerReturn);\n      orderSet.insert(SelfDestrucing);\n      orderSet.insert(Critter);\n      orderSet.insert(HiddenGun);\n      orderSet.insert(OpenDoor);\n      orderSet.insert(CloseDoor);\n      orderSet.insert(HideTrap);\n      orderSet.insert(RevealTrap);\n      orderSet.insert(Enabledoodad);\n      orderSet.insert(Disabledoodad);\n      orderSet.insert(Warpin);\n      orderSet.insert(Medic);\n      orderSet.insert(MedicHeal1);\n      orderSet.insert(HealMove);\n      orderSet.insert(MedicHeal2);\n      orderSet.insert(CastRestoration);\n      orderSet.insert(CastDisruptionWeb);\n      orderSet.insert(CastMindControl);\n      orderSet.insert(DarkArchonMeld);\n      orderSet.insert(CastFeedback);\n      orderSet.insert(CastOpticalFlare);\n      orderSet.insert(CastMaelstrom);\n      orderSet.insert(JunkYardDog);\n      orderSet.insert(Fatal);\n      orderSet.insert(None);\n      orderSet.insert(Unknown);\n\n      foreach(Order i, orderSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        orderMap.insert(std::make_pair(name, i));\n      }\n      initializingOrder = false;\n    }\n  }\n\n  Order::Order()\n  {\n    this->id = Orders::None.id;\n  }\n  Order::Order(int id)\n  {\n    this->id = id;\n    if (!initializingOrder && (id < 0 || id >= 191 || orderName[id].length() == 0))\n      this->id = Orders::Unknown.id;\n  }\n  Order::Order(const Order& other)\n  {\n    this->id = other.id;\n  }\n  Order& Order::operator=(const Order& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool Order::operator==(const Order& other) const\n  {\n    return this->id == other.id;\n  }\n  bool Order::operator!=(const Order& other) const\n  {\n    return this->id != other.id;\n  }\n  bool Order::operator<(const Order& other) const\n  {\n    return this->id < other.id;\n  }\n  int Order::getID() const\n  {\n    return this->id;\n  }\n  std::string Order::getName() const\n  {\n    return orderName[this->id];\n  }\n  Order Orders::getOrder(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, Order>::iterator i = orderMap.find(name);\n    if (i == orderMap.end())\n      return Orders::Unknown;\n    return (*i).second;\n  }\n  std::set<Order>& Orders::allOrders()\n  {\n    return orderSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/PlayerType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/PlayerType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingPlayerType = true;\n  std::string playerTypeName[13];\n  std::map<std::string, PlayerType> playerTypeMap;\n  std::set< PlayerType > playerTypeSet;\n  namespace PlayerTypes\n  {\n    const PlayerType None(0);\n    const PlayerType Computer(1);\n    const PlayerType Player(2);\n    const PlayerType RescuePassive(3);\n    const PlayerType EitherPreferComputer(5);\n    const PlayerType EitherPreferHuman(6);\n    const PlayerType Neutral(7);\n    const PlayerType Closed(8);\n    const PlayerType PlayerLeft(10);\n    const PlayerType ComputerLeft(11);\n    const PlayerType Unknown(12);\n\n    void init()\n    {\n      playerTypeName[None.getID()]                 = \"None\";\n      playerTypeName[Computer.getID()]             = \"Computer\";\n      playerTypeName[Player.getID()]               = \"Player\";\n      playerTypeName[RescuePassive.getID()]        = \"RescuePassive\";\n      playerTypeName[EitherPreferComputer.getID()] = \"EitherPreferComputer\";\n      playerTypeName[EitherPreferHuman.getID()]    = \"EitherPreferHuman\";\n      playerTypeName[Neutral.getID()]              = \"Neutral\";\n      playerTypeName[Closed.getID()]               = \"Closed\";\n      playerTypeName[PlayerLeft.getID()]           = \"PlayerLeft\";\n      playerTypeName[ComputerLeft.getID()]         = \"ComputerLeft\";\n      playerTypeName[Unknown.getID()]              = \"Unknown\";\n\n      playerTypeSet.insert(None);\n      playerTypeSet.insert(Computer);\n      playerTypeSet.insert(Player);\n      playerTypeSet.insert(RescuePassive);\n      playerTypeSet.insert(EitherPreferComputer);\n      playerTypeSet.insert(EitherPreferHuman);\n      playerTypeSet.insert(Neutral);\n      playerTypeSet.insert(Closed);\n      playerTypeSet.insert(PlayerLeft);\n      playerTypeSet.insert(ComputerLeft);\n      playerTypeSet.insert(Unknown);\n\n      foreach(PlayerType i, playerTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        playerTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingPlayerType = false;\n    }\n  }\n  PlayerType::PlayerType()\n  {\n    this->id = PlayerTypes::None.id;\n  }\n  PlayerType::PlayerType(int id)\n  {\n    this->id = id;\n    if (!initializingPlayerType && (id < 0 || id >= 13 || playerTypeName[id].length() == 0) )\n      this->id = PlayerTypes::Unknown.id;\n  }\n  PlayerType::PlayerType(const PlayerType& other)\n  {\n    this->id = other.id;\n  }\n  PlayerType& PlayerType::operator=(const PlayerType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool PlayerType::operator==(const PlayerType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool PlayerType::operator!=(const PlayerType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool PlayerType::operator<(const PlayerType& other) const\n  {\n    return this->id < other.id;\n  }\n  int PlayerType::getID() const\n  {\n    return this->id;\n  }\n  std::string PlayerType::getName() const\n  {\n    return playerTypeName[this->id];\n  }\n  PlayerType PlayerTypes::getPlayerType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, PlayerType>::iterator i = playerTypeMap.find(name);\n    if (i == playerTypeMap.end())\n      return PlayerTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<PlayerType>& PlayerTypes::allPlayerTypes()\n  {\n    return playerTypeSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Position.cpp",
    "content": "#include <BWAPI/Constants.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/Game.h>\n\n#include <math.h>\n#include <stdlib.h>\n\nnamespace BWAPI\n{\n  namespace Positions\n  {\n    const Position Invalid(32000, 32000);\n    const Position None(32000, 32032);\n    const Position Unknown(32000, 32064);\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  Position::Position()\n      : _x(0)\n      , _y(0)\n  {\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  Position::Position(const TilePosition& position)\n      : _x(position.x()*TILE_SIZE)\n      , _y(position.y()*TILE_SIZE)\n  {\n  }\n  //----------------------------------------------- DESTRUCTOR -----------------------------------------------\n  Position::Position(int x, int y)\n      : _x(x)\n      , _y(y)\n  {\n  }\n  //---------------------------------------------- OPERATOR == -----------------------------------------------\n  bool Position::operator == (const Position& position) const\n  {\n    return this->x() == position.x() &&\n           this->y() == position.y();\n  }\n  //---------------------------------------------- OPERATOR != -----------------------------------------------\n  bool Position::operator != (const Position& position) const\n  {\n    return this->x() != position.x() ||\n           this->y() != position.y();\n  }\n  //---------------------------------------------- OPERATOR < ------------------------------------------------\n  bool Position::operator  < (const Position& position) const\n  {\n    return this->x() < position.x() ||\n           (this->x() == position.x() && this->y() < position.y());\n  }\n  //---------------------------------------------- IS VALID --------------------------------------------------\n  bool Position::isValid() const\n  {\n    return (_x >= 0 && _y >= 0 && _x < Broodwar->mapWidth()*32 && _y < Broodwar->mapHeight()*32);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  Position Position::operator+(const Position& position) const\n  {\n    return Position(this->x() + position.x(), this->y() + position.y());\n  }\n  //----------------------------------------------------------------------------------------------------------\n  Position Position::operator-(const Position& position) const\n  {\n    return Position(this->x() - position.x(), this->y() - position.y());\n  }\n  //-------------------------------------------- MAKE VALID --------------------------------------------------\n  Position& Position::makeValid()\n  {\n    if (_x > Broodwar->mapWidth()*32 - 1)\n      _x = Broodwar->mapWidth()*32 - 1;\n    if (_y > Broodwar->mapHeight()*32 - 1)\n      _y = Broodwar->mapHeight()*32 - 1;\n    if (_x < 0)\n      _x = 0;\n    if (_y < 0)\n      _y = 0;\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  Position& Position::operator+=(const Position& position)\n  {\n    this->x() += position.x();\n    this->y() += position.y();\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  Position& Position::operator-=(const Position& position)\n  {\n    this->x() -= position.x();\n    this->y() -= position.y();\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double Position::getDistance(const Position& position) const\n  {\n    return ((*this) - position).getLength();\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double Position::getApproxDistance(const Position& position) const\n  {\n    double min = abs(this->x() - position.x());\n    double max = abs(this->y() - position.y());\n    if (max < min)\n    {\n      double temp = min;\n      min = max;\n      max = temp;\n    }\n    if (min < max*0.25)\n      return max;\n    return min*0.4 + max*0.9;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double Position::getLength() const\n  {\n    double x = this->x();\n    double y = this->y();\n    return sqrt(x * x + y * y);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int& Position::x()\n  {\n    return this->_x;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int& Position::y()\n  {\n    return this->_y;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int Position::x() const\n  {\n    return this->_x;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int Position::y() const\n  {\n    return this->_y;\n  }\n  //----------------------------------------------------------------------------------------------------------\n};\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Race.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/Race.h>\n#include <BWAPI/UnitType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingRace = true;\n  class RaceInternal\n  {\n    public:\n      void set(const char* name, UnitType worker, UnitType center, UnitType refinery, UnitType transport, UnitType supplyProvider)\n      {\n        if (initializingRace)\n        {\n          this->name           = name;\n          this->worker         = worker;\n          this->center         = center;\n          this->refinery       = refinery;\n          this->transport      = transport;\n          this->supplyProvider = supplyProvider;\n        }\n      }\n      std::string name;\n      UnitType worker;\n      UnitType center;\n      UnitType refinery;\n      UnitType transport;\n      UnitType supplyProvider;\n  };\n  RaceInternal raceData[7];\n  std::map<std::string, Race> raceMap;\n  std::set< Race > raceSet;\n  namespace Races\n  {\n    const Race Zerg(0);\n    const Race Terran(1);\n    const Race Protoss(2);\n    const Race Random(3);\n    const Race Other(4);\n    const Race None(5);\n    const Race Unknown(6);\n\n    void init()\n    {\n      raceData[Zerg.getID()].set(   \"Zerg\",    UnitTypes::Zerg_Drone,    UnitTypes::Zerg_Hatchery,         UnitTypes::Zerg_Extractor,      UnitTypes::Zerg_Overlord,   UnitTypes::Zerg_Overlord);\n      raceData[Terran.getID()].set( \"Terran\",  UnitTypes::Terran_SCV,    UnitTypes::Terran_Command_Center, UnitTypes::Terran_Refinery,     UnitTypes::Terran_Dropship, UnitTypes::Terran_Supply_Depot);\n      raceData[Protoss.getID()].set(\"Protoss\", UnitTypes::Protoss_Probe, UnitTypes::Protoss_Nexus,         UnitTypes::Protoss_Assimilator, UnitTypes::Protoss_Shuttle, UnitTypes::Protoss_Pylon);\n      raceData[Random.getID()].set( \"Random\",  UnitTypes::Unknown,       UnitTypes::Unknown,               UnitTypes::Unknown,             UnitTypes::Unknown,         UnitTypes::Unknown);\n      raceData[Other.getID()].set(  \"Other\",   UnitTypes::Unknown,       UnitTypes::Unknown,               UnitTypes::Unknown,             UnitTypes::Unknown,         UnitTypes::Unknown);\n      raceData[None.getID()].set(   \"None\",    UnitTypes::None,          UnitTypes::None,                  UnitTypes::None,                UnitTypes::None,            UnitTypes::None);\n      raceData[Unknown.getID()].set(\"Unknown\", UnitTypes::Unknown,       UnitTypes::Unknown,               UnitTypes::Unknown,             UnitTypes::Unknown,         UnitTypes::Unknown);\n\n      raceSet.insert(Zerg);\n      raceSet.insert(Terran);\n      raceSet.insert(Protoss);\n      raceSet.insert(Other);\n      raceSet.insert(None);\n      raceSet.insert(Unknown);\n\n      foreach(Race i, raceSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        raceMap.insert(std::make_pair(name, i));\n      }\n      initializingRace = false;\n    }\n  }\n  Race::Race()\n  {\n    this->id = Races::None.id;\n  }\n  Race::Race(int id)\n  {\n    this->id = id;\n    if (!initializingRace && (id < 0 || id >= 7) )\n      this->id = Races::Unknown.id;\n  }\n  Race::Race(const Race& other)\n  {\n    this->id = other.id;\n  }\n  Race& Race::operator=(const Race& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool Race::operator==(const Race& other) const\n  {\n    return this->id == other.id;\n  }\n  bool Race::operator!=(const Race& other) const\n  {\n    return this->id != other.id;\n  }\n  bool Race::operator<(const Race& other) const\n  {\n    return this->id < other.id;\n  }\n  int Race::getID() const\n  {\n    return this->id;\n  }\n  std::string Race::getName() const\n  {\n    return raceData[this->id].name;\n  }\n  UnitType Race::getWorker() const\n  {\n    return raceData[this->id].worker;\n  }\n  UnitType Race::getCenter() const\n  {\n    return raceData[this->id].center;\n  }\n  UnitType Race::getRefinery() const\n  {\n    return raceData[this->id].refinery;\n  }\n  UnitType Race::getTransport() const\n  {\n    return raceData[this->id].transport;\n  }\n  UnitType Race::getSupplyProvider() const\n  {\n    return raceData[this->id].supplyProvider;\n  }\n  Race Races::getRace(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, Race>::iterator i = raceMap.find(name);\n    if (i == raceMap.end())\n      return Races::Unknown;\n    return (*i).second;\n  }\n  std::set<Race>& Races::allRaces()\n  {\n    return raceSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/TechType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/TechType.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/WeaponType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingTechType = true;\n  class TechTypeInternal\n  {\n    public:\n      TechTypeInternal() {valid = false;}\n      void set(const char* name, int mineralPrice, int gasPrice, int researchTime, int energyUsed, UnitType whatResearches, Race race, WeaponType weapon, UnitType whatUses1, UnitType whatUses2=UnitTypes::None, UnitType whatUses3=UnitTypes::None, UnitType whatUses4=UnitTypes::None, UnitType whatUses5=UnitTypes::None, UnitType whatUses6=UnitTypes::None)\n      {\n        this->name           = name;\n        this->mineralPrice   = mineralPrice;\n        this->gasPrice       = gasPrice;\n        this->researchTime   = researchTime;\n        this->energyUsed     = energyUsed;\n        this->whatResearches = whatResearches;\n        this->race           = race;\n        this->weapon         = weapon;\n        if (whatUses1 != UnitTypes::None)\n          this->whatUses.insert(whatUses1);\n\n        if (whatUses2 != UnitTypes::None)\n          this->whatUses.insert(whatUses2);\n\n        if (whatUses3 != UnitTypes::None)\n          this->whatUses.insert(whatUses3);\n\n        if (whatUses4 != UnitTypes::None)\n          this->whatUses.insert(whatUses4);\n\n        if (whatUses5 != UnitTypes::None)\n          this->whatUses.insert(whatUses5);\n\n        if (whatUses6 != UnitTypes::None)\n          this->whatUses.insert(whatUses6);\n\n        this->valid = true;\n      }\n      std::string name;\n      int mineralPrice;\n      int gasPrice;\n      int researchTime;\n      int energyUsed;\n      UnitType whatResearches;\n      Race race;\n      WeaponType weapon;\n      std::set<UnitType> whatUses;\n\n      bool valid;\n  };\n  TechTypeInternal techTypeData[47];\n  std::map<std::string, TechType> techTypeMap;\n  std::set< TechType > techTypeSet;\n  namespace TechTypes\n  {\n    const TechType Stim_Packs(0);\n    const TechType Lockdown(1);\n    const TechType EMP_Shockwave(2);\n    const TechType Spider_Mines(3);\n    const TechType Scanner_Sweep(4);\n    const TechType Tank_Siege_Mode(5);\n    const TechType Defensive_Matrix(6);\n    const TechType Irradiate(7);\n    const TechType Yamato_Gun(8);\n    const TechType Cloaking_Field(9);\n    const TechType Personnel_Cloaking(10);\n    const TechType Burrowing(11);\n    const TechType Infestation(12);\n    const TechType Spawn_Broodlings(13);\n    const TechType Dark_Swarm(14);\n    const TechType Plague(15);\n    const TechType Consume(16);\n    const TechType Ensnare(17);\n    const TechType Parasite(18);\n    const TechType Psionic_Storm(19);\n    const TechType Hallucination(20);\n    const TechType Recall(21);\n    const TechType Stasis_Field(22);\n    const TechType Archon_Warp(23);\n    const TechType Restoration(24);\n    const TechType Disruption_Web(25);\n    const TechType Mind_Control(27);\n    const TechType Dark_Archon_Meld(28);\n    const TechType Feedback(29);\n    const TechType Optical_Flare(30);\n    const TechType Maelstrom(31);\n    const TechType Lurker_Aspect(32);\n    const TechType Healing(34);\n    const TechType None(44);\n    const TechType Unknown(45);\n    const TechType Nuclear_Strike(46);\n\n    void init()\n    {\n      techTypeData[Stim_Packs.getID()].set(\"Stim Packs\"                ,100,100,1200,0  ,UnitTypes::Terran_Academy          ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Marine, UnitTypes::Terran_Firebat, UnitTypes::Hero_Jim_Raynor_Marine, UnitTypes::Hero_Gui_Montag);\n      techTypeData[Lockdown.getID()].set(\"Lockdown\"                    ,200,200,1500,100,UnitTypes::Terran_Covert_Ops       ,Races::Terran ,WeaponTypes::Lockdown        ,UnitTypes::Terran_Ghost, UnitTypes::Hero_Alexei_Stukov, UnitTypes::Hero_Infested_Duran, UnitTypes::Hero_Samir_Duran, UnitTypes::Hero_Sarah_Kerrigan);\n      techTypeData[EMP_Shockwave.getID()].set(\"EMP Shockwave\"          ,200,200,1800,100,UnitTypes::Terran_Science_Facility ,Races::Terran ,WeaponTypes::EMP_Shockwave   ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan);\n      techTypeData[Spider_Mines.getID()].set(\"Spider Mines\"            ,100,100,1200,0  ,UnitTypes::Terran_Machine_Shop     ,Races::Terran ,WeaponTypes::Spider_Mines    ,UnitTypes::Terran_Vulture, UnitTypes::Hero_Jim_Raynor_Vulture);\n      techTypeData[Scanner_Sweep.getID()].set(\"Scanner Sweep\"          ,0  ,0  ,0   ,50 ,UnitTypes::None                    ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Comsat_Station);\n      techTypeData[Tank_Siege_Mode.getID()].set(\"Tank Siege Mode\"      ,150,150,1200,0  ,UnitTypes::Terran_Machine_Shop     ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Siege_Tank_Tank_Mode, UnitTypes::Terran_Siege_Tank_Siege_Mode, UnitTypes::Hero_Edmund_Duke_Tank_Mode, UnitTypes::Hero_Edmund_Duke_Siege_Mode);\n      techTypeData[Defensive_Matrix.getID()].set(\"Defensive Matrix\"    ,0  ,0  ,0   ,100,UnitTypes::None                    ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan);\n      techTypeData[Irradiate.getID()].set(\"Irradiate\"                  ,200,200,1200,75 ,UnitTypes::Terran_Science_Facility ,Races::Terran ,WeaponTypes::Irradiate       ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan);\n      techTypeData[Yamato_Gun.getID()].set(\"Yamato Gun\"                ,100,100,1800,150,UnitTypes::Terran_Physics_Lab      ,Races::Terran ,WeaponTypes::Yamato_Gun      ,UnitTypes::Terran_Battlecruiser, UnitTypes::Hero_Gerard_DuGalle, UnitTypes::Hero_Hyperion, UnitTypes::Hero_Norad_II);\n      techTypeData[Cloaking_Field.getID()].set(\"Cloaking Field\"        ,150,150,1500,25 ,UnitTypes::Terran_Control_Tower    ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Wraith, UnitTypes::Hero_Tom_Kazansky);\n      techTypeData[Personnel_Cloaking.getID()].set(\"Personnel Cloaking\",100,100,1200,25 ,UnitTypes::Terran_Covert_Ops       ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Ghost, UnitTypes::Hero_Alexei_Stukov, UnitTypes::Hero_Infested_Duran, UnitTypes::Hero_Samir_Duran, UnitTypes::Hero_Sarah_Kerrigan, UnitTypes::Hero_Infested_Kerrigan);\n      techTypeData[Burrowing.getID()].set(\"Burrowing\"                  ,100,100,1200,0  ,UnitTypes::Zerg_Hatchery           ,Races::Zerg   ,WeaponTypes::None            ,UnitTypes::Zerg_Drone, UnitTypes::Zerg_Zergling, UnitTypes::Zerg_Hydralisk, UnitTypes::Zerg_Defiler, UnitTypes::Zerg_Infested_Terran, UnitTypes::Zerg_Lurker);\n      techTypeData[Infestation.getID()].set(\"Infestation\"              ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Zerg   ,WeaponTypes::None            ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch);\n      techTypeData[Spawn_Broodlings.getID()].set(\"Spawn Broodlings\"    ,100,100,1200,150,UnitTypes::Zerg_Queens_Nest        ,Races::Zerg   ,WeaponTypes::Spawn_Broodlings,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch);\n      techTypeData[Dark_Swarm.getID()].set(\"Dark Swarm\"                ,0  ,0  ,0   ,100,UnitTypes::None                    ,Races::Zerg   ,WeaponTypes::Dark_Swarm      ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One);\n      techTypeData[Plague.getID()].set(\"Plague\"                        ,200,200,1500,150,UnitTypes::Zerg_Defiler_Mound      ,Races::Zerg   ,WeaponTypes::Plague          ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One);\n      techTypeData[Consume.getID()].set(\"Consume\"                      ,100,100,1500,0  ,UnitTypes::Zerg_Defiler_Mound      ,Races::Zerg   ,WeaponTypes::Consume         ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One);\n      techTypeData[Ensnare.getID()].set(\"Ensnare\"                      ,100,100,1200,75 ,UnitTypes::Zerg_Queens_Nest        ,Races::Zerg   ,WeaponTypes::Ensnare         ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch);\n      techTypeData[Parasite.getID()].set(\"Parasite\"                    ,0  ,0  ,0   ,75 ,UnitTypes::None                    ,Races::Zerg   ,WeaponTypes::Parasite        ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch);\n      techTypeData[Psionic_Storm.getID()].set(\"Psionic Storm\"          ,200,200,1800,75 ,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Psionic_Storm   ,UnitTypes::Protoss_High_Templar, UnitTypes::Hero_Tassadar);\n      techTypeData[Hallucination.getID()].set(\"Hallucination\"          ,150,150,1200,100,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::None            ,UnitTypes::Protoss_High_Templar, UnitTypes::Hero_Tassadar);\n      techTypeData[Recall.getID()].set(\"Recall\"                        ,150,150,1800,150,UnitTypes::Protoss_Arbiter_Tribunal,Races::Protoss,WeaponTypes::None            ,UnitTypes::Protoss_Arbiter, UnitTypes::Hero_Danimoth);\n      techTypeData[Stasis_Field.getID()].set(\"Stasis Field\"            ,150,150,1500,100,UnitTypes::Protoss_Arbiter_Tribunal,Races::Protoss,WeaponTypes::Stasis_Field    ,UnitTypes::Protoss_Arbiter, UnitTypes::Hero_Danimoth);\n      techTypeData[Archon_Warp.getID()].set(\"Archon Warp\"              ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Protoss,WeaponTypes::None            ,UnitTypes::Protoss_High_Templar);\n      techTypeData[Restoration.getID()].set(\"Restoration\"              ,100,100,1200,50 ,UnitTypes::Terran_Academy          ,Races::Terran ,WeaponTypes::Restoration     ,UnitTypes::Terran_Medic);\n      techTypeData[Disruption_Web.getID()].set(\"Disruption Web\"        ,200,200,1200,125,UnitTypes::Protoss_Fleet_Beacon    ,Races::Protoss,WeaponTypes::Disruption_Web  ,UnitTypes::Protoss_Corsair, UnitTypes::Hero_Raszagal);\n      techTypeData[Mind_Control.getID()].set(\"Mind Control\"            ,200,200,1800,150,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Mind_Control    ,UnitTypes::Protoss_Dark_Archon);\n      techTypeData[Dark_Archon_Meld.getID()].set(\"Dark Archon Meld\"    ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Protoss,WeaponTypes::None            ,UnitTypes::Protoss_Dark_Templar);\n      techTypeData[Feedback.getID()].set(\"Feedback\"                    ,0  ,0  ,0   ,50 ,UnitTypes::None                    ,Races::Protoss,WeaponTypes::Feedback        ,UnitTypes::Protoss_Dark_Archon);\n      techTypeData[Optical_Flare.getID()].set(\"Optical Flare\"          ,100,100,1800,75 ,UnitTypes::Terran_Academy          ,Races::Terran ,WeaponTypes::Optical_Flare   ,UnitTypes::Terran_Medic);\n      techTypeData[Maelstrom.getID()].set(\"Maelstrom\"                  ,100,100,1500,100,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Maelstrom       ,UnitTypes::Protoss_Dark_Archon);\n      techTypeData[Lurker_Aspect.getID()].set(\"Lurker Aspect\"          ,200,200,1800,0  ,UnitTypes::Zerg_Hydralisk_Den      ,Races::Zerg   ,WeaponTypes::None            ,UnitTypes::Zerg_Lurker);\n      techTypeData[Healing.getID()].set(\"Healing\"                      ,0  ,0  ,0   ,1  ,UnitTypes::None                    ,Races::Terran ,WeaponTypes::None            ,UnitTypes::Terran_Medic);\n      techTypeData[None.getID()].set(\"None\"                            ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::None   ,WeaponTypes::None            ,UnitTypes::None);\n      techTypeData[Unknown.getID()].set(\"Unknown\"                      ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Unknown,WeaponTypes::None            ,UnitTypes::None);\n      techTypeData[Nuclear_Strike.getID()].set(\"Nuclear Strike\"        ,0  ,0  ,0   ,0  ,UnitTypes::None                    ,Races::Terran ,WeaponTypes::Nuclear_Strike  ,UnitTypes::Terran_Ghost);\n\n      techTypeSet.insert(Stim_Packs);\n      techTypeSet.insert(Lockdown);\n      techTypeSet.insert(EMP_Shockwave);\n      techTypeSet.insert(Spider_Mines);\n      techTypeSet.insert(Scanner_Sweep);\n      techTypeSet.insert(Tank_Siege_Mode);\n      techTypeSet.insert(Defensive_Matrix);\n      techTypeSet.insert(Irradiate);\n      techTypeSet.insert(Yamato_Gun);\n      techTypeSet.insert(Cloaking_Field);\n      techTypeSet.insert(Personnel_Cloaking);\n      techTypeSet.insert(Burrowing);\n      techTypeSet.insert(Infestation);\n      techTypeSet.insert(Spawn_Broodlings);\n      techTypeSet.insert(Dark_Swarm);\n      techTypeSet.insert(Plague);\n      techTypeSet.insert(Consume);\n      techTypeSet.insert(Ensnare);\n      techTypeSet.insert(Parasite);\n      techTypeSet.insert(Psionic_Storm);\n      techTypeSet.insert(Hallucination);\n      techTypeSet.insert(Recall);\n      techTypeSet.insert(Stasis_Field);\n      techTypeSet.insert(Archon_Warp);\n      techTypeSet.insert(Restoration);\n      techTypeSet.insert(Disruption_Web);\n      techTypeSet.insert(Mind_Control);\n      techTypeSet.insert(Dark_Archon_Meld);\n      techTypeSet.insert(Feedback);\n      techTypeSet.insert(Optical_Flare);\n      techTypeSet.insert(Maelstrom);\n      techTypeSet.insert(Lurker_Aspect);\n      techTypeSet.insert(Healing);\n      techTypeSet.insert(None);\n      techTypeSet.insert(Unknown);\n      techTypeSet.insert(Nuclear_Strike);\n\n      foreach(TechType i, techTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        techTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingTechType = false;\n    }\n  }\n  TechType::TechType()\n  {\n    this->id = TechTypes::None.id;\n  }\n  TechType::TechType(int id)\n  {\n    this->id = id;\n    if (!initializingTechType && (id < 0 || id >= 47 || techTypeData[id].name.length() == 0))\n      this->id = TechTypes::Unknown.id;\n  }\n  TechType::TechType(const TechType& other)\n  {\n    this->id = other.id;\n  }\n  TechType& TechType::operator=(const TechType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool TechType::operator==(const TechType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool TechType::operator!=(const TechType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool TechType::operator<(const TechType& other) const\n  {\n    return this->id < other.id;\n  }\n  int TechType::getID() const\n  {\n    return this->id;\n  }\n  std::string TechType::getName() const\n  {\n    return techTypeData[this->id].name;\n  }\n  Race TechType::getRace() const\n  {\n    return techTypeData[this->id].race;\n  }\n  int TechType::mineralPrice() const\n  {\n    return techTypeData[this->id].mineralPrice;\n  }\n  int TechType::gasPrice() const\n  {\n    return techTypeData[this->id].gasPrice;\n  }\n  int TechType::researchTime() const\n  {\n    return techTypeData[this->id].researchTime;\n  }\n  int TechType::energyUsed() const\n  {\n    return techTypeData[this->id].energyUsed;\n  }\n  UnitType TechType::whatResearches() const\n  {\n    return techTypeData[this->id].whatResearches;\n  }\n  WeaponType TechType::getWeapon() const\n  {\n    return techTypeData[this->id].weapon;\n  }\n  const std::set<UnitType>& TechType::whatUses() const\n  {\n    return techTypeData[this->id].whatUses;\n  }\n  TechType TechTypes::getTechType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, TechType>::iterator i = techTypeMap.find(name);\n    if (i == techTypeMap.end()) \n      return TechTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<TechType>& TechTypes::allTechTypes()\n  {\n    return techTypeSet;\n  }\n}\n\n"
  },
  {
    "path": "SparCraft/bwapidata/include/TilePosition.cpp",
    "content": "#include <BWAPI/Constants.h>\n#include <BWAPI/TilePosition.h>\n#include <BWAPI/Position.h>\n#include <BWAPI/Game.h>\n\n#include <math.h>\n\nnamespace BWAPI\n{\n  namespace TilePositions\n  {\n    const TilePosition Invalid(1000, 1000);\n    const TilePosition None(1000, 1001);\n    const TilePosition Unknown(1000, 1002);\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  TilePosition::TilePosition()\n      : _x(0)\n      , _y(0)\n  {\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  TilePosition::TilePosition(int x, int y)\n      : _x(x)\n      , _y(y)\n  {\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  TilePosition::TilePosition(const Position& position)\n      : _x(position.x() / TILE_SIZE)\n      , _y(position.y() / TILE_SIZE)\n  {\n  }\n  //---------------------------------------------- OPERATOR == -----------------------------------------------\n  bool TilePosition::operator == (const TilePosition& TilePosition) const\n  {\n    return this->x() == TilePosition.x() &&\n           this->y() == TilePosition.y();\n  }\n  //---------------------------------------------- OPERATOR != -----------------------------------------------\n  bool TilePosition::operator != (const TilePosition& TilePosition) const\n  {\n    return this->x() != TilePosition.x() ||\n           this->y() != TilePosition.y();\n  }\n  //---------------------------------------------- OPERATOR < ------------------------------------------------\n  bool TilePosition::operator < (const TilePosition& TilePosition) const\n  {\n    return this->x() < TilePosition.x() ||\n           (this->x() == TilePosition.x() && this->y() < TilePosition.y());\n  }\n  //---------------------------------------------- IS VALID --------------------------------------------------\n  bool TilePosition::isValid() const\n  {\n    return (_x >= 0 && _y >= 0 && _x < Broodwar->mapWidth() && _y < Broodwar->mapHeight());\n  }\n  //----------------------------------------------------------------------------------------------------------\n  TilePosition TilePosition::operator+(const TilePosition& position) const\n  {\n    return TilePosition(this->x() + position.x(), this->y() + position.y());\n  }\n  //----------------------------------------------------------------------------------------------------------\n  TilePosition TilePosition::operator-(const TilePosition& position) const\n  {\n    return TilePosition(this->x() - position.x(), this->y() - position.y());\n  }\n  //-------------------------------------------- MAKE VALID --------------------------------------------------\n  TilePosition& TilePosition::makeValid()\n  {\n    if (_x > Broodwar->mapWidth() - 1)\n      _x = Broodwar->mapWidth() - 1;\n    if (_y > Broodwar->mapHeight() - 1)\n      _y = Broodwar->mapHeight() - 1;\n    if (_x < 0)\n      _x = 0;\n    if (_y < 0)\n      _y = 0;\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  TilePosition& TilePosition::operator+=(const TilePosition& position)\n  {\n    this->x() += position.x();\n    this->y() += position.y();\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  TilePosition& TilePosition::operator-=(const TilePosition& position)\n  {\n    this->x() -= position.x();\n    this->y() -= position.y();\n    return *this;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double TilePosition::getDistance(const TilePosition& position) const\n  {\n    return ((*this) - position).getLength();\n  }\n  //----------------------------------------------------------------------------------------------------------\n  double TilePosition::getLength() const\n  {\n    double x = this->x();\n    double y = this->y();\n    return sqrt(x * x + y * y);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int& TilePosition::x()\n  {\n    return this->_x;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int& TilePosition::y()\n  {\n    return this->_y;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int TilePosition::x() const\n  {\n    return this->_x;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  int TilePosition::y() const\n  {\n    return this->_y;\n  }\n  //----------------------------------------------------------------------------------------------------------\n};\n"
  },
  {
    "path": "SparCraft/bwapidata/include/UnitCommandType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/UnitCommandType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingUnitCommandType = true;\n  std::string unitCommandTypeName[45];\n  std::map<std::string, UnitCommandType> unitCommandTypeMap;\n  std::set< UnitCommandType > unitCommandTypeSet;\n  namespace UnitCommandTypes\n  {\n    const UnitCommandType Attack_Move(0);\n    const UnitCommandType Attack_Unit(1);\n    const UnitCommandType Build(2);\n    const UnitCommandType Build_Addon(3);\n    const UnitCommandType Train(4);\n    const UnitCommandType Morph(5);\n    const UnitCommandType Research(6);\n    const UnitCommandType Upgrade(7);\n    const UnitCommandType Set_Rally_Position(8);\n    const UnitCommandType Set_Rally_Unit(9);\n    const UnitCommandType Move(10);\n    const UnitCommandType Patrol(11);\n    const UnitCommandType Hold_Position(12);\n    const UnitCommandType Stop(13);\n    const UnitCommandType Follow(14);\n    const UnitCommandType Gather(15);\n    const UnitCommandType Return_Cargo(16);\n    const UnitCommandType Repair(17);\n    const UnitCommandType Burrow(18);\n    const UnitCommandType Unburrow(19);\n    const UnitCommandType Cloak(20);\n    const UnitCommandType Decloak(21);\n    const UnitCommandType Siege(22);\n    const UnitCommandType Unsiege(23);\n    const UnitCommandType Lift(24);\n    const UnitCommandType Land(25);\n    const UnitCommandType Load(26);\n    const UnitCommandType Unload(27);\n    const UnitCommandType Unload_All(28);\n    const UnitCommandType Unload_All_Position(29);\n    const UnitCommandType Right_Click_Position(30);\n    const UnitCommandType Right_Click_Unit(31);\n    const UnitCommandType Halt_Construction(32);\n    const UnitCommandType Cancel_Construction(33);\n    const UnitCommandType Cancel_Addon(34);\n    const UnitCommandType Cancel_Train(35);\n    const UnitCommandType Cancel_Train_Slot(36);\n    const UnitCommandType Cancel_Morph(37);\n    const UnitCommandType Cancel_Research(38);\n    const UnitCommandType Cancel_Upgrade(39);\n    const UnitCommandType Use_Tech(40);\n    const UnitCommandType Use_Tech_Position(41);\n    const UnitCommandType Use_Tech_Unit(42);\n    const UnitCommandType None(43);\n    const UnitCommandType Unknown(44);\n\n    void init()\n    {\n      unitCommandTypeName[Attack_Move.getID()]          = \"Attack Move\";\n      unitCommandTypeName[Attack_Unit.getID()]          = \"Attack Unit\";\n      unitCommandTypeName[Build.getID()]                = \"Build\";\n      unitCommandTypeName[Build_Addon.getID()]          = \"Build Addon\";\n      unitCommandTypeName[Train.getID()]                = \"Train\";\n      unitCommandTypeName[Morph.getID()]                = \"Morph\";\n      unitCommandTypeName[Research.getID()]             = \"Research\";\n      unitCommandTypeName[Upgrade.getID()]              = \"Upgrade\";\n      unitCommandTypeName[Set_Rally_Position.getID()]   = \"Set Rally Position\";\n      unitCommandTypeName[Set_Rally_Unit.getID()]       = \"Set Rally Unit\";\n      unitCommandTypeName[Move.getID()]                 = \"Move\";\n      unitCommandTypeName[Patrol.getID()]               = \"Patrol\";\n      unitCommandTypeName[Hold_Position.getID()]        = \"Hold Position\";\n      unitCommandTypeName[Stop.getID()]                 = \"Stop\";\n      unitCommandTypeName[Follow.getID()]               = \"Follow\";\n      unitCommandTypeName[Gather.getID()]               = \"Gather\";\n      unitCommandTypeName[Return_Cargo.getID()]         = \"Return Cargo\";\n      unitCommandTypeName[Repair.getID()]               = \"Repair\";\n      unitCommandTypeName[Burrow.getID()]               = \"Burrow\";\n      unitCommandTypeName[Unburrow.getID()]             = \"Unburrow\";\n      unitCommandTypeName[Cloak.getID()]                = \"Cloak\";\n      unitCommandTypeName[Decloak.getID()]              = \"Decloak\";\n      unitCommandTypeName[Siege.getID()]                = \"Siege\";\n      unitCommandTypeName[Unsiege.getID()]              = \"Unsiege\";\n      unitCommandTypeName[Lift.getID()]                 = \"Lift\";\n      unitCommandTypeName[Land.getID()]                 = \"Land\";\n      unitCommandTypeName[Load.getID()]                 = \"Load\";\n      unitCommandTypeName[Unload.getID()]               = \"Unload\";\n      unitCommandTypeName[Unload_All.getID()]           = \"Unload All\";\n      unitCommandTypeName[Unload_All_Position.getID()]  = \"Unload All Position\";\n      unitCommandTypeName[Right_Click_Position.getID()] = \"Right Click Position\";\n      unitCommandTypeName[Right_Click_Unit.getID()]     = \"Right Click Unit\";\n      unitCommandTypeName[Halt_Construction.getID()]    = \"Halt Construction\";\n      unitCommandTypeName[Cancel_Construction.getID()]  = \"Cancel Construction\";\n      unitCommandTypeName[Cancel_Addon.getID()]         = \"Cancel Addon\";\n      unitCommandTypeName[Cancel_Train.getID()]         = \"Cancel Train\";\n      unitCommandTypeName[Cancel_Train_Slot.getID()]    = \"Cancel Train Slot\";\n      unitCommandTypeName[Cancel_Morph.getID()]         = \"Cancel Morph\";\n      unitCommandTypeName[Cancel_Research.getID()]      = \"Cancel Research\";\n      unitCommandTypeName[Cancel_Upgrade.getID()]       = \"Cancel Upgrade\";\n      unitCommandTypeName[Use_Tech.getID()]             = \"Use Tech\";\n      unitCommandTypeName[Use_Tech_Position.getID()]    = \"Use Tech Position\";\n      unitCommandTypeName[Use_Tech_Unit.getID()]        = \"Use Tech Unit\";\n      unitCommandTypeName[None.getID()]                 = \"None\";\n      unitCommandTypeName[Unknown.getID()]              = \"Unknown\";\n\n      unitCommandTypeSet.insert(Attack_Move);\n      unitCommandTypeSet.insert(Attack_Unit);\n      unitCommandTypeSet.insert(Build);\n      unitCommandTypeSet.insert(Build_Addon);\n      unitCommandTypeSet.insert(Train);\n      unitCommandTypeSet.insert(Morph);\n      unitCommandTypeSet.insert(Research);\n      unitCommandTypeSet.insert(Upgrade);\n      unitCommandTypeSet.insert(Set_Rally_Position);\n      unitCommandTypeSet.insert(Set_Rally_Unit);\n      unitCommandTypeSet.insert(Move);\n      unitCommandTypeSet.insert(Patrol);\n      unitCommandTypeSet.insert(Hold_Position);\n      unitCommandTypeSet.insert(Stop);\n      unitCommandTypeSet.insert(Follow);\n      unitCommandTypeSet.insert(Gather);\n      unitCommandTypeSet.insert(Return_Cargo);\n      unitCommandTypeSet.insert(Repair);\n      unitCommandTypeSet.insert(Burrow);\n      unitCommandTypeSet.insert(Unburrow);\n      unitCommandTypeSet.insert(Cloak);\n      unitCommandTypeSet.insert(Decloak);\n      unitCommandTypeSet.insert(Siege);\n      unitCommandTypeSet.insert(Unsiege);\n      unitCommandTypeSet.insert(Lift);\n      unitCommandTypeSet.insert(Land);\n      unitCommandTypeSet.insert(Load);\n      unitCommandTypeSet.insert(Unload);\n      unitCommandTypeSet.insert(Unload_All);\n      unitCommandTypeSet.insert(Unload_All_Position);\n      unitCommandTypeSet.insert(Right_Click_Position);\n      unitCommandTypeSet.insert(Right_Click_Unit);\n      unitCommandTypeSet.insert(Halt_Construction);\n      unitCommandTypeSet.insert(Cancel_Construction);\n      unitCommandTypeSet.insert(Cancel_Addon);\n      unitCommandTypeSet.insert(Cancel_Train);\n      unitCommandTypeSet.insert(Cancel_Train_Slot);\n      unitCommandTypeSet.insert(Cancel_Morph);\n      unitCommandTypeSet.insert(Cancel_Research);\n      unitCommandTypeSet.insert(Cancel_Upgrade);\n      unitCommandTypeSet.insert(Use_Tech);\n      unitCommandTypeSet.insert(Use_Tech_Position);\n      unitCommandTypeSet.insert(Use_Tech_Unit);\n      unitCommandTypeSet.insert(None);\n      unitCommandTypeSet.insert(Unknown);\n\n      foreach(UnitCommandType i, unitCommandTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        unitCommandTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingUnitCommandType = false;\n    }\n  }\n  UnitCommandType::UnitCommandType()\n  {\n    this->id = UnitCommandTypes::None.id;\n  }\n  UnitCommandType::UnitCommandType(int id)\n  {\n    this->id = id;\n    if (!initializingUnitCommandType && (id < 0 || id >= 45))\n      this->id = UnitCommandTypes::Unknown.id;\n  }\n  UnitCommandType::UnitCommandType(const UnitCommandType& other)\n  {\n    this->id = other.id;\n  }\n  UnitCommandType& UnitCommandType::operator=(const UnitCommandType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool UnitCommandType::operator==(const UnitCommandType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool UnitCommandType::operator!=(const UnitCommandType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool UnitCommandType::operator<(const UnitCommandType& other) const\n  {\n    return this->id < other.id;\n  }\n  int UnitCommandType::getID() const\n  {\n    return this->id;\n  }\n  std::string UnitCommandType::getName() const\n  {\n    return unitCommandTypeName[this->id];\n  }\n  UnitCommandType UnitCommandTypes::getUnitCommandType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, UnitCommandType>::iterator i = unitCommandTypeMap.find(name);\n    if (i == unitCommandTypeMap.end())\n      return UnitCommandTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<UnitCommandType>& UnitCommandTypes::allUnitCommandTypes()\n  {\n    return unitCommandTypeSet;\n  }\n}\n\n"
  },
  {
    "path": "SparCraft/bwapidata/include/UnitSizeType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/UnitSizeType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingUnitSizeType = true;\n  std::string unitSizeTypeName[6];\n  std::map<std::string, UnitSizeType> unitSizeTypeMap;\n  std::set< UnitSizeType > unitSizeTypeSet;\n  namespace UnitSizeTypes\n  {\n    const UnitSizeType Independent(0);\n    const UnitSizeType Small(1);\n    const UnitSizeType Medium(2);\n    const UnitSizeType Large(3);\n    const UnitSizeType None(4);\n    const UnitSizeType Unknown(5);\n\n    void init()\n    {\n      unitSizeTypeName[Independent.getID()] = \"Independent\";\n      unitSizeTypeName[Small.getID()]       = \"Small\";\n      unitSizeTypeName[Medium.getID()]      = \"Medium\";\n      unitSizeTypeName[Large.getID()]       = \"Large\";\n      unitSizeTypeName[None.getID()]        = \"None\";\n      unitSizeTypeName[Unknown.getID()]     = \"Unknown\";\n\n      unitSizeTypeSet.insert(Independent);\n      unitSizeTypeSet.insert(Small);\n      unitSizeTypeSet.insert(Medium);\n      unitSizeTypeSet.insert(Large);\n      unitSizeTypeSet.insert(None);\n      unitSizeTypeSet.insert(Unknown);\n\n      foreach(UnitSizeType i, unitSizeTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        unitSizeTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingUnitSizeType = false;\n    }\n  }\n  UnitSizeType::UnitSizeType()\n  {\n    this->id = UnitSizeTypes::None.id;\n  }\n  UnitSizeType::UnitSizeType(int id)\n  {\n    this->id = id;\n    if (!initializingUnitSizeType && (id < 0 || id >= 6))\n      this->id = UnitSizeTypes::Unknown.id;\n  }\n  UnitSizeType::UnitSizeType(const UnitSizeType& other)\n  {\n    this->id = other.id;\n  }\n  UnitSizeType& UnitSizeType::operator=(const UnitSizeType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool UnitSizeType::operator==(const UnitSizeType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool UnitSizeType::operator!=(const UnitSizeType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool UnitSizeType::operator<(const UnitSizeType& other) const\n  {\n    return this->id < other.id;\n  }\n  int UnitSizeType::getID() const\n  {\n    return this->id;\n  }\n  std::string UnitSizeType::getName() const\n  {\n    return unitSizeTypeName[this->id];\n  }\n  UnitSizeType UnitSizeTypes::getUnitSizeType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, UnitSizeType>::iterator i = unitSizeTypeMap.find(name);\n    if (i == unitSizeTypeMap.end())\n      return UnitSizeTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<UnitSizeType>& UnitSizeTypes::allUnitSizeTypes()\n  {\n    return unitSizeTypeSet;\n  }\n}\n\n"
  },
  {
    "path": "SparCraft/bwapidata/include/UnitType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n\n#include <Util/Foreach.h>\n\n#include <BWAPI/UnitType.h>\n#include <BWAPI/WeaponType.h>\n#include <BWAPI/UnitSizeType.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/Race.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingUnitType = true;\n  class UnitTypeInternal\n  {\n    public:\n      UnitTypeInternal() {valid = false;}\n      void set(const char* name, Race race, bool isHero, UnitType whatBuilds, int whatBuildsAmt, UnitType requiredUnit1, UnitType requiredUnit2, TechType requiredTech, TechType ability1, TechType ability2, TechType ability3, TechType ability4, UpgradeType armorUpgrade, int maxHitPoints, int maxShields, int maxEnergy, int armor,  int mineralPrice, int gasPrice, int buildTime, int supplyRequired, int supplyProvided, int spaceRequired, int spaceProvided, int buildScore, int destroyScore, UnitSizeType unitSizeType, int tileWidth, int tileHeight, int dimensionLeft, int dimensionUp, int dimensionRight, int dimensionDown,  int seekRange, int sightRange, WeaponType groundWeapon, int maxGroundHits, WeaponType airWeapon, int maxAirHits, double topSpeed, int acceleration, int haltDistance, int turnRadius, bool canProduce, bool canMove, bool isFlyer, bool regeneratesHP, bool hasPermanentCloak, bool isInvincible, bool isOrganic, bool isMechanical, bool isRobotic, bool isDetector, bool isResourceContainer, bool isResourceDepot, bool isWorker, bool requiresPsi, bool requiresCreep, bool isTwoUnitsInOneEgg, bool isBurrowable, bool isCloakable, bool isBuilding, bool isAddon, bool isFlyingBuilding, bool isNeutral, bool isRefinery)\n      {\n        if (initializingUnitType)\n        {\n          this->name   = name;\n          this->race   = race;\n          this->isHero = isHero;\n\n          this->whatBuilds = std::make_pair(whatBuilds, whatBuildsAmt);\n\n          if ( whatBuilds != UnitTypes::None && whatBuildsAmt > 0 )\n            this->requiredUnits.insert(this->whatBuilds);\n\n          if ( requiredUnit1 != UnitTypes::None )\n            this->requiredUnits.insert(std::make_pair(requiredUnit1, 1));\n\n          if ( requiredUnit2 != UnitTypes::None )\n            this->requiredUnits.insert(std::make_pair(requiredUnit2, 1));\n\n          this->requiredTech = requiredTech;\n          if (ability1 != TechTypes::None)\n            this->abilities.insert(ability1);\n\n          if (ability2 != TechTypes::None)\n            this->abilities.insert(ability2);\n\n          if (ability3 != TechTypes::None)\n            this->abilities.insert(ability3);\n\n          if (ability4 != TechTypes::None)\n            this->abilities.insert(ability4);\n\n          this->cloakingTech = TechTypes::None;\n\n          if ( this->abilities.find(TechTypes::Cloaking_Field) != this->abilities.end() )\n            cloakingTech = TechTypes::Cloaking_Field;\n          if ( this->abilities.find(TechTypes::Personnel_Cloaking) != this->abilities.end() )\n            cloakingTech = TechTypes::Personnel_Cloaking;\n\n          this->armorUpgrade = armorUpgrade;\n          this->maxHitPoints = maxHitPoints;\n          this->maxShields   = maxShields;\n          this->maxEnergy    = maxEnergy;\n          this->armor        = armor;\n\n          this->mineralPrice = mineralPrice;\n          this->gasPrice     = gasPrice;\n          this->buildTime    = buildTime;\n\n          this->supplyRequired = supplyRequired;\n          this->supplyProvided = supplyProvided;\n          this->spaceRequired  = spaceRequired;\n          this->spaceProvided  = spaceProvided;\n          this->buildScore     = buildScore;\n          this->destroyScore   = destroyScore;\n\n          this->unitSizeType   = unitSizeType;\n          this->tileWidth      = tileWidth;\n          this->tileHeight     = tileHeight;\n          this->dimensionLeft  = dimensionLeft;\n          this->dimensionUp    = dimensionUp;\n          this->dimensionRight = dimensionRight;\n          this->dimensionDown  = dimensionDown;\n\n          this->seekRange     = seekRange;\n          this->sightRange    = sightRange;\n          this->groundWeapon  = groundWeapon;\n          this->maxGroundHits = maxGroundHits;\n          this->airWeapon     = airWeapon;\n          this->maxAirHits    = maxAirHits;\n\n          this->topSpeed     = topSpeed;\n          this->acceleration = acceleration;\n          this->haltDistance = haltDistance;\n          this->turnRadius   = turnRadius;\n\n          this->canProduce = canProduce;\n          this->canAttack  = groundWeapon != WeaponTypes::None || airWeapon != WeaponTypes::None;\n          this->canMove    = canMove;\n\n          this->isFlyer             = isFlyer;\n          this->regeneratesHP       = regeneratesHP;\n          this->isSpellcaster       = maxEnergy > 0;\n          this->hasPermanentCloak   = hasPermanentCloak;\n          this->isInvincible        = isInvincible;\n          this->isOrganic           = isOrganic;\n          this->isMechanical        = isMechanical;\n          this->isRobotic           = isRobotic;\n          this->isDetector          = isDetector;\n          this->isResourceContainer = isResourceContainer;\n          this->isResourceDepot     = isResourceDepot;\n          this->isWorker            = isWorker;\n          this->requiresPsi         = requiresPsi;\n          this->requiresCreep       = requiresCreep;\n          this->isTwoUnitsInOneEgg  = isTwoUnitsInOneEgg;\n          this->isBurrowable        = isBurrowable;\n          this->isCloakable         = isCloakable;\n          this->isBuilding          = isBuilding;\n          this->isAddon             = isAddon;\n          this->isFlyingBuilding    = isFlyingBuilding;\n          this->isNeutral           = isNeutral;\n          this->isRefinery          = isRefinery;\n\n          this->isSpecialBuilding = this->isBuilding && this->whatBuilds.second == 0;\n\n          this->valid = true;\n        }\n      }\n      std::string name;\n      Race        race;\n\n      std::pair<UnitType, int> whatBuilds;\n      std::map<UnitType, int>  requiredUnits;\n      TechType                 requiredTech;\n      TechType                 cloakingTech;\n      std::set<TechType>       abilities;\n      std::set<UpgradeType>    upgrades;\n      UpgradeType              armorUpgrade;\n\n      int maxHitPoints;\n      int maxShields;\n      int maxEnergy;\n      int armor;\n\n      int mineralPrice;\n      int gasPrice;\n      int buildTime;\n\n      int supplyRequired;\n      int supplyProvided;\n      int spaceRequired;\n      int spaceProvided;\n      int buildScore;\n      int destroyScore;\n\n      UnitSizeType unitSizeType;\n      int tileWidth;\n      int tileHeight;\n      int dimensionLeft;\n      int dimensionUp;\n      int dimensionRight;\n      int dimensionDown;\n\n      int seekRange;\n      int sightRange;\n      WeaponType groundWeapon;\n      int maxGroundHits;\n      WeaponType airWeapon;\n      int maxAirHits;\n\n      double topSpeed;\n      int acceleration;\n      int haltDistance;\n      int turnRadius;\n\n      bool canProduce;\n      bool canAttack;\n      bool canMove;\n      bool isFlyer;\n      bool regeneratesHP;\n      bool isSpellcaster;\n      bool hasPermanentCloak;\n      bool isInvincible;\n      bool isOrganic;\n      bool isMechanical;\n      bool isRobotic;\n      bool isDetector;\n      bool isResourceContainer;\n      bool isResourceDepot;\n      bool isWorker;\n      bool requiresPsi;\n      bool requiresCreep;\n      bool isTwoUnitsInOneEgg;\n      bool isBurrowable;\n      bool isCloakable;\n      bool isBuilding;\n      bool isAddon;\n      bool isFlyingBuilding;\n      bool isNeutral;\n      bool isRefinery;\n      bool isHero;\n      bool isSpecialBuilding;\n\n      bool valid;\n  };\n  UnitTypeInternal unitTypeData[245];\n  std::map<std::string, UnitType> unitTypeMap;\n  std::set< UnitType > unitTypeSet;\n  namespace UnitTypes\n  {\n    const UnitType Terran_Marine(0);\n    const UnitType Hero_Jim_Raynor_Marine(20);\n    const UnitType Terran_Ghost(1);\n    const UnitType Hero_Sarah_Kerrigan(16);\n    const UnitType Hero_Samir_Duran(99);\n    const UnitType Hero_Infested_Duran(104);\n    const UnitType Hero_Alexei_Stukov(100);\n    const UnitType Terran_Vulture(2);\n    const UnitType Hero_Jim_Raynor_Vulture(19);\n    const UnitType Terran_Goliath(3);\n    const UnitType Hero_Alan_Schezar(17);\n    const UnitType Terran_Siege_Tank_Tank_Mode(5);\n    const UnitType Hero_Edmund_Duke_Tank_Mode(23);\n    const UnitType Terran_SCV(7);\n    const UnitType Terran_Wraith(8);\n    const UnitType Hero_Tom_Kazansky(21);\n    const UnitType Terran_Science_Vessel(9);\n    const UnitType Hero_Magellan(22);\n    const UnitType Terran_Dropship(11);\n    const UnitType Terran_Battlecruiser(12);\n    const UnitType Hero_Arcturus_Mengsk(27);\n    const UnitType Hero_Hyperion(28);\n    const UnitType Hero_Norad_II(29);\n    const UnitType Hero_Gerard_DuGalle(102);\n    const UnitType Terran_Vulture_Spider_Mine(13);\n    const UnitType Terran_Nuclear_Missile(14);\n    const UnitType Terran_Siege_Tank_Siege_Mode(30);\n    const UnitType Hero_Edmund_Duke_Siege_Mode(25);\n    const UnitType Terran_Firebat(32);\n    const UnitType Hero_Gui_Montag(10);\n    const UnitType Spell_Scanner_Sweep(33);\n    const UnitType Terran_Medic(34);\n    const UnitType Terran_Civilian(15);\n    const UnitType Zerg_Larva(35);\n    const UnitType Zerg_Egg(36);\n    const UnitType Zerg_Zergling(37);\n    const UnitType Hero_Devouring_One(54);\n    const UnitType Hero_Infested_Kerrigan(51);\n    const UnitType Zerg_Hydralisk(38);\n    const UnitType Hero_Hunter_Killer(53);\n    const UnitType Zerg_Ultralisk(39);\n    const UnitType Hero_Torrasque(48);\n    const UnitType Zerg_Broodling(40);\n    const UnitType Zerg_Drone(41);\n    const UnitType Zerg_Overlord(42);\n    const UnitType Hero_Yggdrasill(57);\n    const UnitType Zerg_Mutalisk(43);\n    const UnitType Hero_Kukulza_Mutalisk(55);\n    const UnitType Zerg_Guardian(44);\n    const UnitType Hero_Kukulza_Guardian(56);\n    const UnitType Zerg_Queen(45);\n    const UnitType Hero_Matriarch(49);\n    const UnitType Zerg_Defiler(46);\n    const UnitType Hero_Unclean_One(52);\n    const UnitType Zerg_Scourge(47);\n    const UnitType Zerg_Infested_Terran(50);\n    const UnitType Terran_Valkyrie(58);\n    const UnitType Zerg_Cocoon(59);\n    const UnitType Protoss_Corsair(60);\n    const UnitType Hero_Raszagal(98);\n    const UnitType Protoss_Dark_Templar(61);\n    const UnitType Hero_Dark_Templar(74);\n    const UnitType Hero_Zeratul(75);\n    const UnitType Zerg_Devourer(62);\n    const UnitType Protoss_Dark_Archon(63);\n    const UnitType Protoss_Probe(64);\n    const UnitType Protoss_Zealot(65);\n    const UnitType Hero_Fenix_Zealot(77);\n    const UnitType Protoss_Dragoon(66);\n    const UnitType Hero_Fenix_Dragoon(78);\n    const UnitType Protoss_High_Templar(67);\n    const UnitType Hero_Tassadar(79);\n    const UnitType Hero_Aldaris(87);\n    const UnitType Protoss_Archon(68);\n    const UnitType Hero_Tassadar_Zeratul_Archon(76);\n    const UnitType Protoss_Shuttle(69);\n    const UnitType Protoss_Scout(70);\n    const UnitType Hero_Mojo(80);\n    const UnitType Hero_Artanis(88);\n    const UnitType Protoss_Arbiter(71);\n    const UnitType Hero_Danimoth(86);\n    const UnitType Protoss_Carrier(72);\n    const UnitType Hero_Gantrithor(82);\n    const UnitType Protoss_Interceptor(73);\n    const UnitType Protoss_Reaver(83);\n    const UnitType Hero_Warbringer(81);\n    const UnitType Protoss_Observer(84);\n    const UnitType Protoss_Scarab(85);\n    const UnitType Critter_Rhynadon(89);\n    const UnitType Critter_Bengalaas(90);\n    const UnitType Critter_Scantid(93);\n    const UnitType Critter_Kakaru(94);\n    const UnitType Critter_Ragnasaur(95);\n    const UnitType Critter_Ursadon(96);\n    const UnitType Zerg_Lurker_Egg(97);\n    const UnitType Zerg_Lurker(103);\n    const UnitType Spell_Disruption_Web(105);\n    const UnitType Terran_Command_Center(106);\n    const UnitType Terran_Comsat_Station(107);\n    const UnitType Terran_Nuclear_Silo(108);\n    const UnitType Terran_Supply_Depot(109);\n    const UnitType Terran_Refinery(110);\n    const UnitType Terran_Barracks(111);\n    const UnitType Terran_Academy(112);\n    const UnitType Terran_Factory(113);\n    const UnitType Terran_Starport(114);\n    const UnitType Terran_Control_Tower(115);\n    const UnitType Terran_Science_Facility(116);\n    const UnitType Terran_Covert_Ops(117);\n    const UnitType Terran_Physics_Lab(118);\n    const UnitType Terran_Machine_Shop(120);\n    const UnitType Terran_Engineering_Bay(122);\n    const UnitType Terran_Armory(123);\n    const UnitType Terran_Missile_Turret(124);\n    const UnitType Terran_Bunker(125);\n    const UnitType Special_Crashed_Norad_II(126);\n    const UnitType Special_Ion_Cannon(127);\n    const UnitType Zerg_Infested_Command_Center(130);\n    const UnitType Zerg_Hatchery(131);\n    const UnitType Zerg_Lair(132);\n    const UnitType Zerg_Hive(133);\n    const UnitType Zerg_Nydus_Canal(134);\n    const UnitType Zerg_Hydralisk_Den(135);\n    const UnitType Zerg_Defiler_Mound(136);\n    const UnitType Zerg_Greater_Spire(137);\n    const UnitType Zerg_Queens_Nest(138);\n    const UnitType Zerg_Evolution_Chamber(139);\n    const UnitType Zerg_Ultralisk_Cavern(140);\n    const UnitType Zerg_Spire(141);\n    const UnitType Zerg_Spawning_Pool(142);\n    const UnitType Zerg_Creep_Colony(143);\n    const UnitType Zerg_Spore_Colony(144);\n    const UnitType Zerg_Sunken_Colony(146);\n    const UnitType Special_Overmind_With_Shell(147);\n    const UnitType Special_Overmind(148);\n    const UnitType Zerg_Extractor(149);\n    const UnitType Special_Mature_Chrysalis(150);\n    const UnitType Special_Cerebrate(151);\n    const UnitType Special_Cerebrate_Daggoth(152);\n    const UnitType Protoss_Nexus(154);\n    const UnitType Protoss_Robotics_Facility(155);\n    const UnitType Protoss_Pylon(156);\n    const UnitType Protoss_Assimilator(157);\n    const UnitType Protoss_Observatory(159);\n    const UnitType Protoss_Gateway(160);\n    const UnitType Protoss_Photon_Cannon(162);\n    const UnitType Protoss_Citadel_of_Adun(163);\n    const UnitType Protoss_Cybernetics_Core(164);\n    const UnitType Protoss_Templar_Archives(165);\n    const UnitType Protoss_Forge(166);\n    const UnitType Protoss_Stargate(167);\n    const UnitType Special_Stasis_Cell_Prison(168);\n    const UnitType Protoss_Fleet_Beacon(169);\n    const UnitType Protoss_Arbiter_Tribunal(170);\n    const UnitType Protoss_Robotics_Support_Bay(171);\n    const UnitType Protoss_Shield_Battery(172);\n    const UnitType Special_Khaydarin_Crystal_Form(173);\n    const UnitType Special_Protoss_Temple(174);\n    const UnitType Special_XelNaga_Temple(175);\n    const UnitType Resource_Mineral_Field(176);\n    const UnitType Resource_Vespene_Geyser(188);\n    const UnitType Special_Warp_Gate(189);\n    const UnitType Special_Psi_Disrupter(190);\n    const UnitType Special_Power_Generator(200);\n    const UnitType Special_Overmind_Cocoon(201);\n    const UnitType Special_Zerg_Beacon(194);\n    const UnitType Special_Terran_Beacon(195);\n    const UnitType Special_Protoss_Beacon(196);\n    const UnitType Special_Zerg_Flag_Beacon(197);\n    const UnitType Special_Terran_Flag_Beacon(198);\n    const UnitType Special_Protoss_Flag_Beacon(199);\n    const UnitType Spell_Dark_Swarm(202);\n    const UnitType Powerup_Uraj_Crystal(128);\n    const UnitType Powerup_Khalis_Crystal(129);\n    const UnitType Powerup_Flag(215);\n    const UnitType Powerup_Young_Chrysalis(216);\n    const UnitType Powerup_Psi_Emitter(217);\n    const UnitType Powerup_Data_Disk(218);\n    const UnitType Powerup_Khaydarin_Crystal(219);\n    const UnitType None(228);\n    const UnitType Unknown(229);\n\n    void init()\n    {\n      unitTypeData[Terran_Marine.getID()].set(\"Terran Marine\", Races::Terran, 0, Terran_Barracks, 1, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 40, 0, 0, 0, 50, 0, 360, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 128, 224, WeaponTypes::Gauss_Rifle, 1, WeaponTypes::Gauss_Rifle, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Jim_Raynor_Marine.getID()].set(\"Hero Jim Raynor Marine\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 200, 0, 0, 3, 50, 0, 1, 0, 0, 1, 0, 0, 200, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 128, 224, WeaponTypes::Gauss_Rifle_Jim_Raynor, 1, WeaponTypes::Gauss_Rifle_Jim_Raynor, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Ghost.getID()].set(\"Terran Ghost\", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, Terran_Covert_Ops, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::Nuclear_Strike, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 45, 0, 200, 0, 25, 75, 750, 2, 0, 1, 0, 175, 350, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 288, WeaponTypes::C_10_Canister_Rifle, 1, WeaponTypes::C_10_Canister_Rifle, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Sarah_Kerrigan.getID()].set(\"Hero Sarah Kerrigan\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 250, 0, 250, 3, 50, 150, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Sarah_Kerrigan, 1, WeaponTypes::C_10_Canister_Rifle_Sarah_Kerrigan, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Samir_Duran.getID()].set(\"Hero Samir Duran\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 200, 0, 250, 2, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 320, WeaponTypes::C_10_Canister_Rifle_Samir_Duran, 1, WeaponTypes::C_10_Canister_Rifle_Samir_Duran, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Infested_Duran.getID()].set(\"Hero Infested Duran\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::Consume, TechTypes::None, UpgradeTypes::Zerg_Carapace, 300, 0, 250, 3, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Infested_Duran, 1, WeaponTypes::C_10_Canister_Rifle_Infested_Duran, 1, 4, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Alexei_Stukov.getID()].set(\"Hero Alexei Stukov\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 250, 0, 250, 3, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Alexei_Stukov, 1, WeaponTypes::C_10_Canister_Rifle_Alexei_Stukov, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Vulture.getID()].set(\"Terran Vulture\", Races::Terran, 0, Terran_Factory, 1, None, None, TechTypes::None, TechTypes::Spider_Mines, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 80, 0, 0, 0, 75, 0, 450, 4, 0, 2, 0, 75, 150, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 160, 256, WeaponTypes::Fragmentation_Grenade, 1, WeaponTypes::None, 0, 6.4, 100, 14569, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Jim_Raynor_Vulture.getID()].set(\"Hero Jim Raynor Vulture\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Spider_Mines, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 300, 0, 0, 3, 150, 0, 900, 0, 0, 2, 0, 0, 300, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 160, 256, WeaponTypes::Fragmentation_Grenade_Jim_Raynor, 1, WeaponTypes::None, 0, 6.4, 100, 14569, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Goliath.getID()].set(\"Terran Goliath\", Races::Terran, 0, Terran_Factory, 1, Terran_Armory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 125, 0, 0, 1, 100, 50, 600, 4, 0, 2, 0, 200, 400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 192, 256, WeaponTypes::Twin_Autocannons, 1, WeaponTypes::Hellfire_Missile_Pack, 1, 4.57, 1, 1, 17, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Alan_Schezar.getID()].set(\"Hero Alan Schezar\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 300, 0, 0, 3, 200, 100, 1200, 0, 0, 2, 0, 0, 800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 192, 256, WeaponTypes::Twin_Autocannons_Alan_Schezar, 1, WeaponTypes::Hellfire_Missile_Pack_Alan_Schezar, 1, 4.57, 1, 1, 17, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Siege_Tank_Tank_Mode.getID()].set(\"Terran Siege Tank Tank Mode\", Races::Terran, 0, Terran_Factory, 1, Terran_Machine_Shop, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 150, 0, 0, 1, 150, 100, 750, 4, 0, 4, 0, 350, 700, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::Arclite_Cannon, 1, WeaponTypes::None, 0, 4, 1, 1, 13, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Edmund_Duke_Tank_Mode.getID()].set(\"Hero Edmund Duke Tank Mode\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 400, 0, 0, 3, 300, 200, 1500, 0, 0, 4, 0, 0, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::Arclite_Cannon_Edmund_Duke, 1, WeaponTypes::None, 0, 4, 1, 1, 13, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_SCV.getID()].set(\"Terran SCV\", Races::Terran, 0, Terran_Command_Center, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 60, 0, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 224, WeaponTypes::Fusion_Cutter, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Wraith.getID()].set(\"Terran Wraith\", Races::Terran, 0, Terran_Starport, 1, None, None, TechTypes::None, TechTypes::Cloaking_Field, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 120, 0, 200, 0, 150, 100, 900, 4, 0, 255, 0, 400, 800, UnitSizeTypes::Large, 1, 1, 19, 15, 18, 14, 160, 224, WeaponTypes::Burst_Lasers, 1, WeaponTypes::Gemini_Missiles, 1, 6.67, 67, 21745, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Tom_Kazansky.getID()].set(\"Hero Tom Kazansky\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Cloaking_Field, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 500, 0, 250, 4, 400, 200, 1800, 0, 0, 255, 0, 0, 1600, UnitSizeTypes::Large, 1, 1, 19, 15, 18, 14, 160, 224, WeaponTypes::Burst_Lasers_Tom_Kazansky, 1, WeaponTypes::Gemini_Missiles_Tom_Kazansky, 1, 6.67, 67, 21745, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Science_Vessel.getID()].set(\"Terran Science Vessel\", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Science_Facility, TechTypes::None, TechTypes::EMP_Shockwave, TechTypes::Defensive_Matrix, TechTypes::Irradiate, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 200, 0, 200, 1, 100, 225, 1200, 4, 0, 255, 0, 625, 1250, UnitSizeTypes::Large, 2, 2, 32, 33, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 50, 5120, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Magellan.getID()].set(\"Hero Magellan\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::EMP_Shockwave, TechTypes::Defensive_Matrix, TechTypes::Irradiate, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 800, 0, 250, 4, 50, 600, 2400, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 2, 2, 32, 33, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 50, 5120, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Dropship.getID()].set(\"Terran Dropship\", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 150, 0, 0, 1, 100, 100, 750, 4, 0, 255, 8, 300, 600, UnitSizeTypes::Large, 2, 2, 24, 16, 24, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 5.47, 17, 37756, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Battlecruiser.getID()].set(\"Terran Battlecruiser\", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Physics_Lab, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 500, 0, 200, 3, 400, 300, 2000, 12, 0, 255, 0, 1200, 2400, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery, 1, WeaponTypes::ATA_Laser_Battery, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Arcturus_Mengsk.getID()].set(\"Hero Arcturus Mengsk\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 1000, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 256, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Hyperion.getID()].set(\"Hero Hyperion\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 850, 0, 250, 4, 800, 600, 2400, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hyperion, 1, WeaponTypes::ATA_Laser_Battery_Hyperion, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Norad_II.getID()].set(\"Hero Norad II\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 700, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Gerard_DuGalle.getID()].set(\"Hero Gerard DuGalle\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 700, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Vulture_Spider_Mine.getID()].set(\"Terran Vulture Spider Mine\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 20, 0, 0, 0, 1, 0, 1, 0, 0, 255, 0, 0, 25, UnitSizeTypes::Small, 1, 1, 7, 7, 7, 7, 96, 96, WeaponTypes::Spider_Mines, 1, WeaponTypes::None, 0, 16, 1, 1, 127, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Nuclear_Missile.getID()].set(\"Terran Nuclear Missile\", Races::Terran, 0, Terran_Nuclear_Silo, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100, 0, 0, 0, 200, 200, 1500, 16, 0, 255, 0, 800, 0, UnitSizeTypes::Independent, 1, 1, 7, 14, 7, 14, 0, 96, WeaponTypes::None, 0, WeaponTypes::None, 0, 33.33, 33, 1103213, 127, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Siege_Tank_Siege_Mode.getID()].set(\"Terran Siege Tank Siege Mode\", Races::Terran, 0, Terran_Factory, 1, Terran_Machine_Shop, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 150, 0, 0, 1, 150, 100, 750, 4, 0, 255, 0, 0, 700, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 384, 320, WeaponTypes::Arclite_Shock_Cannon, 1, WeaponTypes::None, 0, 0, 1, 1, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Edmund_Duke_Siege_Mode.getID()].set(\"Hero Edmund Duke Siege Mode\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 400, 0, 0, 3, 300, 200, 1500, 0, 0, 255, 0, 0, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 384, 320, WeaponTypes::Arclite_Shock_Cannon_Edmund_Duke, 1, WeaponTypes::None, 0, 0, 1, 1, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Firebat.getID()].set(\"Terran Firebat\", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 50, 0, 0, 1, 50, 25, 360, 2, 0, 1, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 11, 7, 11, 14, 96, 224, WeaponTypes::Flame_Thrower, 3, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Gui_Montag.getID()].set(\"Hero Gui Montag\", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 160, 0, 0, 3, 100, 50, 720, 0, 0, 1, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 11, 7, 11, 14, 96, 224, WeaponTypes::Flame_Thrower_Gui_Montag, 3, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Spell_Scanner_Sweep.getID()].set(\"Spell Scanner Sweep\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 13, 13, 13, 17, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Medic.getID()].set(\"Terran Medic\", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, None, TechTypes::None, TechTypes::Restoration, TechTypes::Optical_Flare, TechTypes::Healing, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 60, 0, 200, 1, 50, 25, 450, 2, 0, 1, 0, 125, 250, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 288, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Civilian.getID()].set(\"Terran Civilian\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 40, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Larva.getID()].set(\"Zerg Larva\", Races::Zerg, 0, Zerg_Hatchery, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 25, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 8, 8, 7, 7, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 1, 1, 20, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Egg.getID()].set(\"Zerg Egg\", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 25, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Zergling.getID()].set(\"Zerg Zergling\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 35, 0, 0, 0, 50, 0, 420, 1, 0, 1, 0, 25, 50, UnitSizeTypes::Small, 1, 1, 8, 4, 7, 11, 96, 160, WeaponTypes::Claws, 1, WeaponTypes::None, 0, 5.49, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Devouring_One.getID()].set(\"Hero Devouring One\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 120, 0, 0, 3, 100, 0, 840, 0, 0, 1, 0, 0, 100, UnitSizeTypes::Small, 1, 1, 8, 4, 7, 11, 96, 160, WeaponTypes::Claws_Devouring_One, 1, WeaponTypes::None, 0, 5.49, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Infested_Kerrigan.getID()].set(\"Hero Infested Kerrigan\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Personnel_Cloaking, TechTypes::Ensnare, TechTypes::Psionic_Storm, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 400, 0, 250, 2, 200, 300, 1500, 0, 0, 1, 0, 0, 4000, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 96, 288, WeaponTypes::Claws_Infested_Kerrigan, 1, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Hydralisk.getID()].set(\"Zerg Hydralisk\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Hydralisk_Den, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 80, 0, 0, 0, 75, 25, 420, 2, 0, 2, 0, 125, 350, UnitSizeTypes::Medium, 1, 1, 10, 10, 10, 12, 128, 192, WeaponTypes::Needle_Spines, 1, WeaponTypes::Needle_Spines, 1, 3.66, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Hunter_Killer.getID()].set(\"Hero Hunter Killer\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 160, 0, 0, 2, 150, 50, 780, 0, 0, 2, 0, 0, 500, UnitSizeTypes::Medium, 1, 1, 10, 10, 10, 12, 128, 256, WeaponTypes::Needle_Spines_Hunter_Killer, 1, WeaponTypes::Needle_Spines_Hunter_Killer, 1, 3.66, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Ultralisk.getID()].set(\"Zerg Ultralisk\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Ultralisk_Cavern, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 400, 0, 0, 1, 200, 200, 900, 8, 0, 4, 0, 650, 1300, UnitSizeTypes::Large, 2, 2, 19, 16, 18, 15, 96, 224, WeaponTypes::Kaiser_Blades, 1, WeaponTypes::None, 0, 5.12, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Torrasque.getID()].set(\"Hero Torrasque\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 800, 0, 0, 4, 400, 400, 1800, 0, 0, 4, 0, 0, 2600, UnitSizeTypes::Large, 2, 2, 19, 16, 18, 15, 96, 224, WeaponTypes::Kaiser_Blades_Torrasque, 1, WeaponTypes::None, 0, 5.12, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Broodling.getID()].set(\"Zerg Broodling\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 30, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 25, UnitSizeTypes::Small, 1, 1, 9, 9, 9, 9, 96, 160, WeaponTypes::Toxic_Spores, 1, WeaponTypes::None, 0, 6, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Drone.getID()].set(\"Zerg Drone\", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 40, 0, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 224, WeaponTypes::Spines, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Overlord.getID()].set(\"Zerg Overlord\", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 200, 0, 0, 0, 100, 0, 600, 0, 16, 255, 8, 100, 200, UnitSizeTypes::Large, 2, 2, 25, 25, 24, 24, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0.83, 27, 840, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Yggdrasill.getID()].set(\"Hero Yggdrasill\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 1000, 0, 0, 4, 200, 0, 1200, 0, 60, 255, 8, 0, 400, UnitSizeTypes::Large, 2, 2, 25, 25, 24, 24, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0.83, 27, 840, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Mutalisk.getID()].set(\"Zerg Mutalisk\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 120, 0, 0, 0, 100, 100, 600, 4, 0, 255, 0, 300, 600, UnitSizeTypes::Small, 2, 2, 22, 22, 21, 21, 96, 224, WeaponTypes::Glave_Wurm, 1, WeaponTypes::Glave_Wurm, 1, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Kukulza_Mutalisk.getID()].set(\"Hero Kukulza Mutalisk\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 300, 0, 0, 3, 200, 200, 1200, 0, 0, 255, 0, 0, 1200, UnitSizeTypes::Small, 2, 2, 22, 22, 21, 21, 96, 224, WeaponTypes::Glave_Wurm_Kukulza, 1, WeaponTypes::Glave_Wurm_Kukulza, 1, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Guardian.getID()].set(\"Zerg Guardian\", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 150, 0, 0, 2, 50, 100, 600, 4, 0, 255, 0, 550, 1100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 256, 352, WeaponTypes::Acid_Spore, 1, WeaponTypes::None, 0, 2.5, 27, 7585, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Kukulza_Guardian.getID()].set(\"Hero Kukulza Guardian\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 400, 0, 0, 4, 100, 200, 1200, 0, 0, 255, 0, 0, 2200, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 256, 352, WeaponTypes::Acid_Spore_Kukulza, 1, WeaponTypes::None, 0, 2.5, 27, 7585, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Queen.getID()].set(\"Zerg Queen\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Queens_Nest, None, TechTypes::None, TechTypes::Infestation, TechTypes::Spawn_Broodlings, TechTypes::Ensnare, TechTypes::Parasite, UpgradeTypes::Zerg_Flyer_Carapace, 120, 0, 200, 0, 100, 100, 750, 4, 0, 255, 0, 400, 800, UnitSizeTypes::Medium, 2, 2, 24, 24, 23, 23, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Matriarch.getID()].set(\"Hero Matriarch\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Infestation, TechTypes::Spawn_Broodlings, TechTypes::Ensnare, TechTypes::Parasite, UpgradeTypes::Zerg_Flyer_Carapace, 300, 0, 250, 3, 200, 300, 1500, 0, 0, 255, 0, 0, 1600, UnitSizeTypes::Medium, 2, 2, 24, 24, 23, 23, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Defiler.getID()].set(\"Zerg Defiler\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Defiler_Mound, None, TechTypes::None, TechTypes::Burrowing, TechTypes::Dark_Swarm, TechTypes::Plague, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 80, 0, 200, 1, 50, 150, 750, 4, 0, 2, 0, 225, 450, UnitSizeTypes::Medium, 1, 1, 13, 12, 13, 12, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Unclean_One.getID()].set(\"Hero Unclean One\", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::Dark_Swarm, TechTypes::Plague, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 250, 0, 250, 3, 50, 200, 1500, 0, 0, 2, 0, 0, 900, UnitSizeTypes::Medium, 1, 1, 13, 12, 13, 12, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Scourge.getID()].set(\"Zerg Scourge\", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 25, 0, 0, 0, 25, 75, 450, 1, 0, 255, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 12, 12, 11, 11, 96, 160, WeaponTypes::None, 0, WeaponTypes::Suicide_Scourge, 1, 6.67, 107, 13616, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Infested_Terran.getID()].set(\"Zerg Infested Terran\", Races::Zerg, 0, Zerg_Infested_Command_Center, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 60, 0, 0, 0, 100, 50, 600, 2, 0, 1, 0, 200, 400, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 96, 160, WeaponTypes::Suicide_Infested_Terran, 1, WeaponTypes::None, 0, 5.82, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Terran_Valkyrie.getID()].set(\"Terran Valkyrie\", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Armory, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 200, 0, 0, 2, 250, 125, 750, 6, 0, 255, 0, 400, 800, UnitSizeTypes::Large, 2, 2, 24, 16, 24, 20, 192, 256, WeaponTypes::None, 0, WeaponTypes::Halo_Rockets, 4, 6.6, 65, 21901, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Cocoon.getID()].set(\"Zerg Cocoon\", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 1100, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Corsair.getID()].set(\"Protoss Corsair\", Races::Protoss, 0, Protoss_Stargate, 1, None, None, TechTypes::None, TechTypes::Disruption_Web, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 100, 80, 200, 1, 150, 100, 600, 4, 0, 255, 0, 350, 700, UnitSizeTypes::Medium, 1, 1, 18, 16, 17, 15, 288, 288, WeaponTypes::None, 0, WeaponTypes::Neutron_Flare, 1, 6.67, 67, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Raszagal.getID()].set(\"Hero Raszagal\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Disruption_Web, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 100, 60, 250, 0, 150, 100, 750, 0, 0, 255, 0, 0, 1300, UnitSizeTypes::Medium, 1, 1, 18, 16, 17, 15, 288, 288, WeaponTypes::None, 0, WeaponTypes::Neutron_Flare, 1, 6.67, 67, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Dark_Templar.getID()].set(\"Protoss Dark Templar\", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::Dark_Archon_Meld, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 40, 0, 1, 125, 100, 750, 4, 0, 2, 0, 325, 650, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Dark_Templar.getID()].set(\"Hero Dark Templar\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 40, 80, 0, 0, 150, 150, 750, 1, 0, 2, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades_Hero, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Zeratul.getID()].set(\"Hero Zeratul\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 60, 400, 0, 0, 100, 300, 1500, 0, 0, 2, 0, 0, 800, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades_Zeratul, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Devourer.getID()].set(\"Zerg Devourer\", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 250, 0, 0, 2, 150, 50, 600, 4, 0, 255, 0, 550, 1100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 224, 320, WeaponTypes::None, 0, WeaponTypes::Corrosive_Acid, 1, 5, 48, 17067, 30, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Dark_Archon.getID()].set(\"Protoss Dark Archon\", Races::Protoss, 0, Protoss_Dark_Templar, 2, None, None, TechTypes::None, TechTypes::Mind_Control, TechTypes::Feedback, TechTypes::Maelstrom, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 25, 200, 200, 1, 0, 0, 300, 8, 0, 4, 0, 650, 1300, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 224, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Probe.getID()].set(\"Protoss Probe\", Races::Protoss, 0, Protoss_Nexus, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 20, 20, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 256, WeaponTypes::Particle_Beam, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Zealot.getID()].set(\"Protoss Zealot\", Races::Protoss, 0, Protoss_Gateway, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 60, 0, 1, 100, 0, 600, 4, 0, 2, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 11, 5, 11, 13, 96, 224, WeaponTypes::Psi_Blades, 2, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Fenix_Zealot.getID()].set(\"Hero Fenix Zealot\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 240, 240, 0, 2, 200, 0, 1200, 0, 0, 2, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 11, 5, 11, 13, 96, 224, WeaponTypes::Psi_Blades_Fenix, 2, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Dragoon.getID()].set(\"Protoss Dragoon\", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 80, 0, 1, 125, 50, 750, 4, 0, 4, 0, 250, 500, UnitSizeTypes::Large, 1, 1, 15, 15, 16, 16, 128, 256, WeaponTypes::Phase_Disruptor, 1, WeaponTypes::Phase_Disruptor, 1, 5, 1, 1, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Fenix_Dragoon.getID()].set(\"Hero Fenix Dragoon\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 240, 240, 0, 3, 300, 100, 1500, 0, 0, 4, 0, 0, 1000, UnitSizeTypes::Large, 1, 1, 15, 15, 16, 16, 128, 256, WeaponTypes::Phase_Disruptor_Fenix, 1, WeaponTypes::Phase_Disruptor_Fenix, 1, 5, 1, 1, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_High_Templar.getID()].set(\"Protoss High Templar\", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::Psionic_Storm, TechTypes::Hallucination, TechTypes::Archon_Warp, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 40, 40, 200, 0, 50, 150, 750, 4, 0, 2, 0, 350, 700, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Tassadar.getID()].set(\"Hero Tassadar\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Psionic_Storm, TechTypes::Hallucination, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 300, 250, 2, 100, 300, 1500, 0, 0, 2, 0, 0, 1400, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::Psi_Assault, 1, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Aldaris.getID()].set(\"Hero Aldaris\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 300, 250, 2, 100, 300, 1500, 0, 0, 2, 0, 0, 1400, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::Psi_Assault, 1, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Archon.getID()].set(\"Protoss Archon\", Races::Protoss, 0, Protoss_High_Templar, 2, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 10, 350, 0, 0, 0, 0, 300, 8, 0, 4, 0, 700, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 96, 256, WeaponTypes::Psionic_Shockwave, 1, WeaponTypes::Psionic_Shockwave, 1, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Tassadar_Zeratul_Archon.getID()].set(\"Hero Tassadar Zeratul Archon\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 800, 0, 3, 0, 0, 600, 0, 0, 4, 0, 0, 2800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 96, 256, WeaponTypes::Psionic_Shockwave_TZ_Archon, 1, WeaponTypes::Psionic_Shockwave_TZ_Archon, 1, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Shuttle.getID()].set(\"Protoss Shuttle\", Races::Protoss, 0, Protoss_Robotics_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 80, 60, 0, 1, 200, 0, 900, 4, 0, 255, 8, 200, 400, UnitSizeTypes::Large, 2, 1, 20, 16, 19, 15, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 4.43, 17, 37756, 20, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Scout.getID()].set(\"Protoss Scout\", Races::Protoss, 0, Protoss_Stargate, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 150, 100, 0, 0, 275, 125, 1200, 6, 0, 255, 0, 650, 1300, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 256, WeaponTypes::Dual_Photon_Blasters, 1, WeaponTypes::Anti_Matter_Missiles, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Mojo.getID()].set(\"Hero Mojo\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 400, 400, 0, 3, 600, 300, 2400, 0, 0, 255, 0, 0, 2600, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 320, WeaponTypes::Dual_Photon_Blasters_Mojo, 1, WeaponTypes::Anti_Matter_Missiles_Mojo, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Artanis.getID()].set(\"Hero Artanis\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 250, 250, 0, 3, 600, 300, 2400, 0, 0, 255, 0, 0, 2400, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 320, WeaponTypes::Dual_Photon_Blasters_Artanis, 1, WeaponTypes::Anti_Matter_Missiles_Artanis, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Arbiter.getID()].set(\"Protoss Arbiter\", Races::Protoss, 0, Protoss_Stargate, 1, Protoss_Arbiter_Tribunal, None, TechTypes::None, TechTypes::Recall, TechTypes::Stasis_Field, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 200, 150, 200, 1, 100, 350, 2400, 8, 0, 255, 0, 1025, 2050, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 160, 288, WeaponTypes::Phase_Disruptor_Cannon, 1, WeaponTypes::Phase_Disruptor_Cannon, 1, 5, 33, 24824, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Danimoth.getID()].set(\"Hero Danimoth\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Recall, TechTypes::Stasis_Field, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 600, 500, 250, 3, 50, 1000, 4800, 0, 0, 255, 0, 0, 4100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 160, 288, WeaponTypes::Phase_Disruptor_Cannon_Danimoth, 1, WeaponTypes::Phase_Disruptor_Cannon_Danimoth, 1, 5, 33, 24824, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Carrier.getID()].set(\"Protoss Carrier\", Races::Protoss, 0, Protoss_Stargate, 1, Protoss_Fleet_Beacon, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 300, 150, 0, 4, 350, 250, 2100, 12, 0, 255, 0, 950, 1900, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 256, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Gantrithor.getID()].set(\"Hero Gantrithor\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 800, 500, 0, 4, 700, 600, 4200, 0, 0, 255, 0, 0, 3800, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 256, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Interceptor.getID()].set(\"Protoss Interceptor\", Races::Protoss, 0, Protoss_Carrier, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 40, 40, 0, 0, 25, 0, 300, 0, 0, 255, 0, 30, 60, UnitSizeTypes::Small, 1, 1, 8, 8, 7, 7, 128, 192, WeaponTypes::Pulse_Cannon, 1, WeaponTypes::Pulse_Cannon, 1, 13.33, 427, 13640, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Reaver.getID()].set(\"Protoss Reaver\", Races::Protoss, 0, Protoss_Robotics_Facility, 1, Protoss_Robotics_Support_Bay, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 80, 0, 0, 200, 100, 1050, 8, 0, 4, 0, 400, 800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1.78, 1, 1, 20, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Hero_Warbringer.getID()].set(\"Hero Warbringer\", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 200, 400, 0, 3, 400, 200, 1800, 0, 0, 4, 0, 0, 1600, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1.78, 1, 1, 20, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Observer.getID()].set(\"Protoss Observer\", Races::Protoss, 0, Protoss_Robotics_Facility, 1, Protoss_Observatory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 40, 20, 0, 0, 25, 75, 600, 2, 0, 255, 0, 225, 450, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Protoss_Scarab.getID()].set(\"Protoss Scarab\", Races::Protoss, 0, Protoss_Reaver, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 20, 10, 0, 0, 15, 0, 105, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Small, 1, 1, 2, 2, 2, 2, 128, 160, WeaponTypes::Scarab, 1, WeaponTypes::None, 0, 16, 1, 1, 27, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Critter_Rhynadon.getID()].set(\"Critter Rhynadon\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Bengalaas.getID()].set(\"Critter Bengalaas\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Scantid.getID()].set(\"Critter Scantid\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Kakaru.getID()].set(\"Critter Kakaru\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 16, 51200, 14, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Ragnasaur.getID()].set(\"Critter Ragnasaur\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Critter_Ursadon.getID()].set(\"Critter Ursadon\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Zerg_Lurker_Egg.getID()].set(\"Zerg Lurker Egg\", Races::Zerg, 0, Zerg_Hydralisk, 1, None, None, TechTypes::Lurker_Aspect, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 500, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Zerg_Lurker.getID()].set(\"Zerg Lurker\", Races::Zerg, 0, Zerg_Hydralisk, 1, None, None, TechTypes::Lurker_Aspect, TechTypes::Lurker_Aspect, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 125, 0, 0, 1, 50, 100, 600, 4, 0, 4, 0, 250, 500, UnitSizeTypes::Medium, 1, 1, 15, 15, 16, 16, 192, 256, WeaponTypes::Subterranean_Spines, 1, WeaponTypes::None, 0, 5.82, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Spell_Disruption_Web.getID()].set(\"Spell Disruption Web\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 250, 250, 2400, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 4, 3, 60, 40, 59, 39, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Terran_Command_Center.getID()].set(\"Terran Command Center\", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 400, 0, 1800, 0, 20, 255, 0, 400, 1200, UnitSizeTypes::Large, 4, 3, 58, 41, 58, 41, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Comsat_Station.getID()].set(\"Terran Comsat Station\", Races::Terran, 0, Terran_Command_Center, 1, Terran_Academy, None, TechTypes::None, TechTypes::Scanner_Sweep, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 200, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 37, 16, 31, 25, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Nuclear_Silo.getID()].set(\"Terran Nuclear Silo\", Races::Terran, 0, Terran_Command_Center, 1, Terran_Science_Facility, Terran_Covert_Ops, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 100, 100, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 37, 16, 31, 25, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Supply_Depot.getID()].set(\"Terran Supply Depot\", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 0, 1, 100, 0, 600, 0, 16, 255, 0, 50, 150, UnitSizeTypes::Large, 3, 2, 38, 22, 38, 26, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Terran_Refinery.getID()].set(\"Terran Refinery\", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 100, 0, 600, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 4, 2, 56, 32, 56, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1);\n      unitTypeData[Terran_Barracks.getID()].set(\"Terran Barracks\", Races::Terran, 0, Terran_SCV, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1000, 0, 0, 1, 150, 0, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 4, 3, 48, 40, 56, 32, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Academy.getID()].set(\"Terran Academy\", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 150, 0, 1200, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 32, 44, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Terran_Factory.getID()].set(\"Terran Factory\", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1250, 0, 0, 1, 200, 100, 1200, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 4, 3, 56, 40, 56, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Starport.getID()].set(\"Terran Starport\", Races::Terran, 0, Terran_SCV, 1, Terran_Factory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1300, 0, 0, 1, 150, 100, 1050, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 4, 3, 48, 40, 48, 38, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Control_Tower.getID()].set(\"Terran Control Tower\", Races::Terran, 0, Terran_Starport, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Science_Facility.getID()].set(\"Terran Science Facility\", Races::Terran, 0, Terran_SCV, 1, Terran_Starport, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 150, 900, 0, 0, 255, 0, 275, 825, UnitSizeTypes::Large, 4, 3, 48, 38, 48, 38, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Covert_Ops.getID()].set(\"Terran Covert Ops\", Races::Terran, 0, Terran_Science_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Physics_Lab.getID()].set(\"Terran Physics Lab\", Races::Terran, 0, Terran_Science_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Machine_Shop.getID()].set(\"Terran Machine Shop\", Races::Terran, 0, Terran_Factory, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 39, 24, 31, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);\n      unitTypeData[Terran_Engineering_Bay.getID()].set(\"Terran Engineering Bay\", Races::Terran, 0, Terran_SCV, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 125, 0, 900, 0, 0, 255, 0, 65, 195, UnitSizeTypes::Large, 4, 3, 48, 32, 48, 28, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Terran_Armory.getID()].set(\"Terran Armory\", Races::Terran, 0, Terran_SCV, 1, Terran_Factory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 100, 50, 1200, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Terran_Missile_Turret.getID()].set(\"Terran Missile Turret\", Races::Terran, 0, Terran_SCV, 1, Terran_Engineering_Bay, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 200, 0, 0, 0, 75, 0, 450, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 2, 2, 16, 32, 16, 16, 224, 352, WeaponTypes::None, 0, WeaponTypes::Longbolt_Missile, 1, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Terran_Bunker.getID()].set(\"Terran Bunker\", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 350, 0, 0, 1, 100, 0, 450, 0, 0, 255, 4, 50, 150, UnitSizeTypes::Large, 3, 2, 32, 24, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Crashed_Norad_II.getID()].set(\"Special Crashed Norad II\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 700, 0, 0, 1, 800, 600, 4800, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Ion_Cannon.getID()].set(\"Special Ion Cannon\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 200, 0, 900, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Infested_Command_Center.getID()].set(\"Zerg Infested Command Center\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 1, 1, 1800, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 58, 41, 58, 41, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);\n      unitTypeData[Zerg_Hatchery.getID()].set(\"Zerg Hatchery\", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1250, 0, 0, 1, 300, 0, 1800, 0, 2, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Lair.getID()].set(\"Zerg Lair\", Races::Zerg, 0, Zerg_Hatchery, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1800, 0, 0, 1, 150, 100, 1500, 0, 2, 255, 0, 100, 1200, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Hive.getID()].set(\"Zerg Hive\", Races::Zerg, 0, Zerg_Lair, 1, Zerg_Queens_Nest, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 200, 150, 1800, 0, 2, 255, 0, 100, 1500, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Nydus_Canal.getID()].set(\"Zerg Nydus Canal\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 0, 0, 1, 150, 0, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Hydralisk_Den.getID()].set(\"Zerg Hydralisk Den\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 50, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 32, 40, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Defiler_Mound.getID()].set(\"Zerg Defiler Mound\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 100, 900, 0, 0, 255, 0, 150, 450, UnitSizeTypes::Large, 4, 2, 48, 32, 48, 4, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Greater_Spire.getID()].set(\"Zerg Greater Spire\", Races::Zerg, 0, Zerg_Spire, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1000, 0, 0, 1, 100, 150, 1800, 0, 0, 255, 0, 200, 1350, UnitSizeTypes::Large, 2, 2, 28, 32, 28, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Queens_Nest.getID()].set(\"Zerg Queens Nest\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Lair, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 150, 100, 900, 0, 0, 255, 0, 175, 525, UnitSizeTypes::Large, 3, 2, 38, 28, 32, 28, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Evolution_Chamber.getID()].set(\"Zerg Evolution Chamber\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hatchery, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 75, 0, 600, 0, 0, 255, 0, 40, 120, UnitSizeTypes::Large, 3, 2, 44, 32, 32, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Ultralisk_Cavern.getID()].set(\"Zerg Ultralisk Cavern\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 150, 200, 1200, 0, 0, 255, 0, 275, 825, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Spire.getID()].set(\"Zerg Spire\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Lair, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 200, 150, 1800, 0, 0, 255, 0, 250, 750, UnitSizeTypes::Large, 2, 2, 28, 32, 28, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Spawning_Pool.getID()].set(\"Zerg Spawning Pool\", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hatchery, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 200, 0, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 3, 2, 36, 28, 40, 18, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Creep_Colony.getID()].set(\"Zerg Creep Colony\", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 400, 0, 0, 0, 75, 0, 300, 0, 0, 255, 0, 40, 120, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Spore_Colony.getID()].set(\"Zerg Spore Colony\", Races::Zerg, 0, Zerg_Creep_Colony, 1, Zerg_Creep_Colony, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 400, 0, 0, 0, 50, 0, 300, 0, 0, 255, 0, 25, 195, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 224, 320, WeaponTypes::None, 0, WeaponTypes::Seeker_Spores, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Sunken_Colony.getID()].set(\"Zerg Sunken Colony\", Races::Zerg, 0, Zerg_Creep_Colony, 1, Zerg_Creep_Colony, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 300, 0, 0, 2, 50, 0, 300, 0, 0, 255, 0, 40, 240, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 224, 320, WeaponTypes::Subterranean_Tentacle, 1, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Overmind_With_Shell.getID()].set(\"Special Overmind With Shell\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 5000, 0, 0, 1, 1, 1, 1, 0, 0, 255, 0, 0, 10000, UnitSizeTypes::Large, 5, 3, 80, 32, 79, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Overmind.getID()].set(\"Special Overmind\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 1, 1, 1, 0, 0, 255, 0, 0, 10000, UnitSizeTypes::Large, 5, 3, 80, 32, 79, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Zerg_Extractor.getID()].set(\"Zerg Extractor\", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 0, 600, 0, 0, 255, 0, 25, 75, UnitSizeTypes::Large, 4, 2, 64, 32, 63, 31, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1);\n      unitTypeData[Special_Mature_Chrysalis.getID()].set(\"Special Mature Chrysalis\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Cerebrate.getID()].set(\"Special Cerebrate\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Cerebrate_Daggoth.getID()].set(\"Special Cerebrate Daggoth\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Nexus.getID()].set(\"Protoss Nexus\", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 750, 0, 1, 400, 0, 1800, 0, 18, 255, 0, 400, 1200, UnitSizeTypes::Large, 4, 3, 56, 39, 56, 39, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Robotics_Facility.getID()].set(\"Protoss Robotics Facility\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 200, 1200, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 3, 2, 36, 16, 40, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Pylon.getID()].set(\"Protoss Pylon\", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 300, 300, 0, 0, 100, 0, 450, 0, 16, 255, 0, 50, 150, UnitSizeTypes::Large, 2, 2, 16, 12, 16, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Assimilator.getID()].set(\"Protoss Assimilator\", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 100, 0, 600, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 4, 2, 48, 32, 48, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1);\n      unitTypeData[Protoss_Observatory.getID()].set(\"Protoss Observatory\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Robotics_Facility, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 250, 0, 1, 50, 100, 450, 0, 0, 255, 0, 175, 525, UnitSizeTypes::Large, 3, 2, 44, 16, 44, 28, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Gateway.getID()].set(\"Protoss Gateway\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Nexus, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 150, 0, 900, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 4, 3, 48, 32, 48, 40, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Photon_Cannon.getID()].set(\"Protoss Photon Cannon\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Forge, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100, 100, 0, 0, 150, 0, 750, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 2, 2, 20, 16, 20, 16, 224, 352, WeaponTypes::STS_Photon_Cannon, 1, WeaponTypes::STA_Photon_Cannon, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Citadel_of_Adun.getID()].set(\"Protoss Citadel of Adun\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 150, 100, 900, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 3, 2, 24, 24, 40, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Cybernetics_Core.getID()].set(\"Protoss Cybernetics Core\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Gateway, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 0, 900, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 24, 40, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Templar_Archives.getID()].set(\"Protoss Templar Archives\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Citadel_of_Adun, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 150, 200, 900, 0, 0, 255, 0, 250, 750, UnitSizeTypes::Large, 3, 2, 32, 24, 32, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Forge.getID()].set(\"Protoss Forge\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Nexus, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 550, 550, 0, 1, 150, 0, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 36, 24, 36, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Stargate.getID()].set(\"Protoss Stargate\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 600, 0, 1, 150, 150, 1050, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 48, 40, 48, 32, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Stasis_Cell_Prison.getID()].set(\"Special Stasis Cell Prison\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 150, 0, 1, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 4, 3, 64, 48, 63, 47, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Fleet_Beacon.getID()].set(\"Protoss Fleet Beacon\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Stargate, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 300, 200, 900, 0, 0, 255, 0, 350, 1050, UnitSizeTypes::Large, 3, 2, 40, 32, 47, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Arbiter_Tribunal.getID()].set(\"Protoss Arbiter Tribunal\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 150, 900, 0, 0, 255, 0, 450, 1350, UnitSizeTypes::Large, 3, 2, 44, 28, 44, 28, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Robotics_Support_Bay.getID()].set(\"Protoss Robotics Support Bay\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Robotics_Facility, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 150, 100, 450, 0, 0, 255, 0, 125, 375, UnitSizeTypes::Large, 3, 2, 32, 32, 32, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Protoss_Shield_Battery.getID()].set(\"Protoss Shield Battery\", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Gateway, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 200, 200, 200, 1, 100, 0, 450, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 3, 2, 32, 16, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Khaydarin_Crystal_Form.getID()].set(\"Special Khaydarin Crystal Form\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 1, 250, 0, 1, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 4, 3, 64, 48, 63, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Protoss_Temple.getID()].set(\"Special Protoss Temple\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 250, 0, 1, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 7, 3, 112, 48, 111, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_XelNaga_Temple.getID()].set(\"Special XelNaga Temple\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 5000, 0, 0, 1, 1500, 500, 4800, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 5, 4, 80, 34, 79, 63, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Resource_Mineral_Field.getID()].set(\"Resource Mineral Field\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 10, 10, UnitSizeTypes::Independent, 2, 1, 32, 16, 31, 15, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0);\n      unitTypeData[Resource_Vespene_Geyser.getID()].set(\"Resource Vespene Geyser\", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 10, 10, UnitSizeTypes::Independent, 4, 2, 64, 32, 63, 31, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0);\n      unitTypeData[Special_Warp_Gate.getID()].set(\"Special Warp Gate\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 700, 0, 0, 1, 600, 200, 2400, 0, 0, 255, 0, 0, 2000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Psi_Disrupter.getID()].set(\"Special Psi Disrupter\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 1000, 400, 4800, 0, 0, 255, 0, 0, 3600, UnitSizeTypes::Large, 5, 3, 80, 38, 69, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Power_Generator.getID()].set(\"Special Power Generator\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 1, 200, 50, 2400, 0, 0, 255, 0, 0, 600, UnitSizeTypes::Large, 4, 3, 56, 28, 63, 43, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Overmind_Cocoon.getID()].set(\"Special Overmind Cocoon\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 1000, 500, 2400, 0, 0, 255, 0, 0, 4000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Zerg_Beacon.getID()].set(\"Special Zerg Beacon\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 250, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Terran_Beacon.getID()].set(\"Special Terran Beacon\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 50, 50, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Protoss_Beacon.getID()].set(\"Special Protoss Beacon\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 100, 100, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Zerg_Flag_Beacon.getID()].set(\"Special Zerg Flag Beacon\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 250, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Terran_Flag_Beacon.getID()].set(\"Special Terran Flag Beacon\", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 50, 50, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Special_Protoss_Flag_Beacon.getID()].set(\"Special Protoss Flag Beacon\", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 100, 100, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);\n      unitTypeData[Spell_Dark_Swarm.getID()].set(\"Spell Dark Swarm\", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 250, 200, 2400, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 5, 5, 80, 80, 79, 79, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);\n      unitTypeData[Powerup_Uraj_Crystal.getID()].set(\"Powerup Uraj Crystal\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Khalis_Crystal.getID()].set(\"Powerup Khalis Crystal\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Flag.getID()].set(\"Powerup Flag\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Young_Chrysalis.getID()].set(\"Powerup Young Chrysalis\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Psi_Emitter.getID()].set(\"Powerup Psi Emitter\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Data_Disk.getID()].set(\"Powerup Data Disk\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Powerup_Khaydarin_Crystal.getID()].set(\"Powerup Khaydarin Crystal\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[None.getID()].set(\"None\", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, UnitSizeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n      unitTypeData[Unknown.getID()].set(\"Unknown\", Races::Unknown, 0, Unknown, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, UnitSizeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n\n      foreach(UpgradeType i, UpgradeTypes::allUpgradeTypes())\n      {\n        foreach (UnitType ut, i.whatUses())\n          unitTypeData[ut.getID()].upgrades.insert(i);\n      }\n\n      unitTypeSet.insert(Terran_Marine);\n      unitTypeSet.insert(Hero_Jim_Raynor_Marine);\n      unitTypeSet.insert(Terran_Ghost);\n      unitTypeSet.insert(Hero_Sarah_Kerrigan);\n      unitTypeSet.insert(Hero_Samir_Duran);\n      unitTypeSet.insert(Hero_Infested_Duran);\n      unitTypeSet.insert(Hero_Alexei_Stukov);\n      unitTypeSet.insert(Terran_Vulture);\n      unitTypeSet.insert(Hero_Jim_Raynor_Vulture);\n      unitTypeSet.insert(Terran_Goliath);\n      unitTypeSet.insert(Hero_Alan_Schezar);\n      unitTypeSet.insert(Terran_Siege_Tank_Tank_Mode);\n      unitTypeSet.insert(Hero_Edmund_Duke_Tank_Mode);\n      unitTypeSet.insert(Terran_SCV);\n      unitTypeSet.insert(Terran_Wraith);\n      unitTypeSet.insert(Hero_Tom_Kazansky);\n      unitTypeSet.insert(Terran_Science_Vessel);\n      unitTypeSet.insert(Hero_Magellan);\n      unitTypeSet.insert(Terran_Dropship);\n      unitTypeSet.insert(Terran_Battlecruiser);\n      unitTypeSet.insert(Hero_Arcturus_Mengsk);\n      unitTypeSet.insert(Hero_Hyperion);\n      unitTypeSet.insert(Hero_Norad_II);\n      unitTypeSet.insert(Hero_Gerard_DuGalle);\n      unitTypeSet.insert(Terran_Vulture_Spider_Mine);\n      unitTypeSet.insert(Terran_Nuclear_Missile);\n      unitTypeSet.insert(Terran_Siege_Tank_Siege_Mode);\n      unitTypeSet.insert(Hero_Edmund_Duke_Siege_Mode);\n      unitTypeSet.insert(Terran_Firebat);\n      unitTypeSet.insert(Hero_Gui_Montag);\n      unitTypeSet.insert(Spell_Scanner_Sweep);\n      unitTypeSet.insert(Terran_Medic);\n      unitTypeSet.insert(Terran_Civilian);\n      unitTypeSet.insert(Zerg_Larva);\n      unitTypeSet.insert(Zerg_Egg);\n      unitTypeSet.insert(Zerg_Zergling);\n      unitTypeSet.insert(Hero_Devouring_One);\n      unitTypeSet.insert(Hero_Infested_Kerrigan);\n      unitTypeSet.insert(Zerg_Hydralisk);\n      unitTypeSet.insert(Hero_Hunter_Killer);\n      unitTypeSet.insert(Zerg_Ultralisk);\n      unitTypeSet.insert(Hero_Torrasque);\n      unitTypeSet.insert(Zerg_Broodling);\n      unitTypeSet.insert(Zerg_Drone);\n      unitTypeSet.insert(Zerg_Overlord);\n      unitTypeSet.insert(Hero_Yggdrasill);\n      unitTypeSet.insert(Zerg_Mutalisk);\n      unitTypeSet.insert(Hero_Kukulza_Mutalisk);\n      unitTypeSet.insert(Zerg_Guardian);\n      unitTypeSet.insert(Hero_Kukulza_Guardian);\n      unitTypeSet.insert(Zerg_Queen);\n      unitTypeSet.insert(Hero_Matriarch);\n      unitTypeSet.insert(Zerg_Defiler);\n      unitTypeSet.insert(Hero_Unclean_One);\n      unitTypeSet.insert(Zerg_Scourge);\n      unitTypeSet.insert(Zerg_Infested_Terran);\n      unitTypeSet.insert(Terran_Valkyrie);\n      unitTypeSet.insert(Zerg_Cocoon);\n      unitTypeSet.insert(Protoss_Corsair);\n      unitTypeSet.insert(Hero_Raszagal);\n      unitTypeSet.insert(Protoss_Dark_Templar);\n      unitTypeSet.insert(Hero_Dark_Templar);\n      unitTypeSet.insert(Hero_Zeratul);\n      unitTypeSet.insert(Zerg_Devourer);\n      unitTypeSet.insert(Protoss_Dark_Archon);\n      unitTypeSet.insert(Protoss_Probe);\n      unitTypeSet.insert(Protoss_Zealot);\n      unitTypeSet.insert(Hero_Fenix_Zealot);\n      unitTypeSet.insert(Protoss_Dragoon);\n      unitTypeSet.insert(Hero_Fenix_Dragoon);\n      unitTypeSet.insert(Protoss_High_Templar);\n      unitTypeSet.insert(Hero_Tassadar);\n      unitTypeSet.insert(Hero_Aldaris);\n      unitTypeSet.insert(Protoss_Archon);\n      unitTypeSet.insert(Hero_Tassadar_Zeratul_Archon);\n      unitTypeSet.insert(Protoss_Shuttle);\n      unitTypeSet.insert(Protoss_Scout);\n      unitTypeSet.insert(Hero_Mojo);\n      unitTypeSet.insert(Hero_Artanis);\n      unitTypeSet.insert(Protoss_Arbiter);\n      unitTypeSet.insert(Hero_Danimoth);\n      unitTypeSet.insert(Protoss_Carrier);\n      unitTypeSet.insert(Hero_Gantrithor);\n      unitTypeSet.insert(Protoss_Interceptor);\n      unitTypeSet.insert(Protoss_Reaver);\n      unitTypeSet.insert(Hero_Warbringer);\n      unitTypeSet.insert(Protoss_Observer);\n      unitTypeSet.insert(Protoss_Scarab);\n      unitTypeSet.insert(Critter_Rhynadon);\n      unitTypeSet.insert(Critter_Bengalaas);\n      unitTypeSet.insert(Critter_Scantid);\n      unitTypeSet.insert(Critter_Kakaru);\n      unitTypeSet.insert(Critter_Ragnasaur);\n      unitTypeSet.insert(Critter_Ursadon);\n      unitTypeSet.insert(Zerg_Lurker_Egg);\n      unitTypeSet.insert(Zerg_Lurker);\n      unitTypeSet.insert(Spell_Disruption_Web);\n      unitTypeSet.insert(Terran_Command_Center);\n      unitTypeSet.insert(Terran_Comsat_Station);\n      unitTypeSet.insert(Terran_Nuclear_Silo);\n      unitTypeSet.insert(Terran_Supply_Depot);\n      unitTypeSet.insert(Terran_Refinery);\n      unitTypeSet.insert(Terran_Barracks);\n      unitTypeSet.insert(Terran_Academy);\n      unitTypeSet.insert(Terran_Factory);\n      unitTypeSet.insert(Terran_Starport);\n      unitTypeSet.insert(Terran_Control_Tower);\n      unitTypeSet.insert(Terran_Science_Facility);\n      unitTypeSet.insert(Terran_Covert_Ops);\n      unitTypeSet.insert(Terran_Physics_Lab);\n      unitTypeSet.insert(Terran_Machine_Shop);\n      unitTypeSet.insert(Terran_Engineering_Bay);\n      unitTypeSet.insert(Terran_Armory);\n      unitTypeSet.insert(Terran_Missile_Turret);\n      unitTypeSet.insert(Terran_Bunker);\n      unitTypeSet.insert(Special_Crashed_Norad_II);\n      unitTypeSet.insert(Special_Ion_Cannon);\n      unitTypeSet.insert(Zerg_Infested_Command_Center);\n      unitTypeSet.insert(Zerg_Hatchery);\n      unitTypeSet.insert(Zerg_Lair);\n      unitTypeSet.insert(Zerg_Hive);\n      unitTypeSet.insert(Zerg_Nydus_Canal);\n      unitTypeSet.insert(Zerg_Hydralisk_Den);\n      unitTypeSet.insert(Zerg_Defiler_Mound);\n      unitTypeSet.insert(Zerg_Greater_Spire);\n      unitTypeSet.insert(Zerg_Queens_Nest);\n      unitTypeSet.insert(Zerg_Evolution_Chamber);\n      unitTypeSet.insert(Zerg_Ultralisk_Cavern);\n      unitTypeSet.insert(Zerg_Spire);\n      unitTypeSet.insert(Zerg_Spawning_Pool);\n      unitTypeSet.insert(Zerg_Creep_Colony);\n      unitTypeSet.insert(Zerg_Spore_Colony);\n      unitTypeSet.insert(Zerg_Sunken_Colony);\n      unitTypeSet.insert(Special_Overmind_With_Shell);\n      unitTypeSet.insert(Special_Overmind);\n      unitTypeSet.insert(Zerg_Extractor);\n      unitTypeSet.insert(Special_Mature_Chrysalis);\n      unitTypeSet.insert(Special_Cerebrate);\n      unitTypeSet.insert(Special_Cerebrate_Daggoth);\n      unitTypeSet.insert(Protoss_Nexus);\n      unitTypeSet.insert(Protoss_Robotics_Facility);\n      unitTypeSet.insert(Protoss_Pylon);\n      unitTypeSet.insert(Protoss_Assimilator);\n      unitTypeSet.insert(Protoss_Observatory);\n      unitTypeSet.insert(Protoss_Gateway);\n      unitTypeSet.insert(Protoss_Photon_Cannon);\n      unitTypeSet.insert(Protoss_Citadel_of_Adun);\n      unitTypeSet.insert(Protoss_Cybernetics_Core);\n      unitTypeSet.insert(Protoss_Templar_Archives);\n      unitTypeSet.insert(Protoss_Forge);\n      unitTypeSet.insert(Protoss_Stargate);\n      unitTypeSet.insert(Special_Stasis_Cell_Prison);\n      unitTypeSet.insert(Protoss_Fleet_Beacon);\n      unitTypeSet.insert(Protoss_Arbiter_Tribunal);\n      unitTypeSet.insert(Protoss_Robotics_Support_Bay);\n      unitTypeSet.insert(Protoss_Shield_Battery);\n      unitTypeSet.insert(Special_Khaydarin_Crystal_Form);\n      unitTypeSet.insert(Special_Protoss_Temple);\n      unitTypeSet.insert(Special_XelNaga_Temple);\n      unitTypeSet.insert(Resource_Mineral_Field);\n      unitTypeSet.insert(Resource_Vespene_Geyser);\n      unitTypeSet.insert(Special_Warp_Gate);\n      unitTypeSet.insert(Special_Psi_Disrupter);\n      unitTypeSet.insert(Special_Power_Generator);\n      unitTypeSet.insert(Special_Overmind_Cocoon);\n      unitTypeSet.insert(Special_Zerg_Beacon);\n      unitTypeSet.insert(Special_Terran_Beacon);\n      unitTypeSet.insert(Special_Protoss_Beacon);\n      unitTypeSet.insert(Special_Zerg_Flag_Beacon);\n      unitTypeSet.insert(Special_Terran_Flag_Beacon);\n      unitTypeSet.insert(Special_Protoss_Flag_Beacon);\n      unitTypeSet.insert(Spell_Dark_Swarm);\n      unitTypeSet.insert(Powerup_Uraj_Crystal);\n      unitTypeSet.insert(Powerup_Khalis_Crystal);\n      unitTypeSet.insert(Powerup_Flag);\n      unitTypeSet.insert(Powerup_Young_Chrysalis);\n      unitTypeSet.insert(Powerup_Psi_Emitter);\n      unitTypeSet.insert(Powerup_Data_Disk);\n      unitTypeSet.insert(Powerup_Khaydarin_Crystal);\n      unitTypeSet.insert(None);\n      unitTypeSet.insert(Unknown);\n\n      foreach(UnitType i, unitTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        unitTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingUnitType = false;\n    }\n  }\n  UnitType::UnitType()\n  {\n    this->id = UnitTypes::None.id;\n  }\n  UnitType::UnitType(int id)\n  {\n    this->id = id;\n    if (!initializingUnitType && (id < 0 || id >= 230 || !unitTypeData[id].valid))\n      this->id = UnitTypes::Unknown.id;\n  }\n  UnitType::UnitType(const UnitType& other)\n  {\n    this->id = other.id;\n  }\n  UnitType& UnitType::operator=(const UnitType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool UnitType::operator==(const UnitType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool UnitType::operator!=(const UnitType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool UnitType::operator<(const UnitType& other) const\n  {\n    return this->id < other.id;\n  }\n  int UnitType::getID() const\n  {\n    return this->id;\n  }\n  std::string UnitType::getName() const\n  {\n    return unitTypeData[this->id].name;\n  }\n  Race UnitType::getRace() const\n  {\n    return unitTypeData[this->id].race;\n  }\n  const std::pair<  UnitType, int> UnitType::whatBuilds() const\n  {\n    return unitTypeData[this->id].whatBuilds;\n  }\n  const std::map<  UnitType, int >& UnitType::requiredUnits() const\n  {\n    return unitTypeData[this->id].requiredUnits;\n  }\n  TechType UnitType::requiredTech() const\n  {\n    return unitTypeData[this->id].requiredTech;\n  }\n  TechType UnitType::cloakingTech() const\n  {\n    return unitTypeData[this->id].cloakingTech;\n  }\n  const std::set< TechType >& UnitType::abilities() const\n  {\n    return unitTypeData[this->id].abilities;\n  }\n  const std::set< UpgradeType >& UnitType::upgrades() const\n  {\n    return unitTypeData[this->id].upgrades;\n  }\n  UpgradeType UnitType::armorUpgrade() const\n  {\n    return unitTypeData[this->id].armorUpgrade;\n  }\n  int UnitType::maxHitPoints() const\n  {\n    return unitTypeData[this->id].maxHitPoints;\n  }\n  int UnitType::maxShields() const\n  {\n    return unitTypeData[this->id].maxShields;\n  }\n  int UnitType::maxEnergy() const\n  {\n    return unitTypeData[this->id].maxEnergy;\n  }\n  int UnitType::armor() const\n  {\n    return unitTypeData[this->id].armor;\n  }\n  int UnitType::mineralPrice() const\n  {\n    return unitTypeData[this->id].mineralPrice;\n  }\n  int UnitType::gasPrice() const\n  {\n    return unitTypeData[this->id].gasPrice;\n  }\n  int UnitType::buildTime() const\n  {\n    return unitTypeData[this->id].buildTime;\n  }\n  int UnitType::supplyRequired() const\n  {\n    return unitTypeData[this->id].supplyRequired;\n  }\n  int UnitType::supplyProvided() const\n  {\n    return unitTypeData[this->id].supplyProvided;\n  }\n  int UnitType::spaceRequired() const\n  {\n    return unitTypeData[this->id].spaceRequired;\n  }\n  int UnitType::spaceProvided() const\n  {\n    return unitTypeData[this->id].spaceProvided;\n  }\n  int UnitType::buildScore() const\n  {\n    return unitTypeData[this->id].buildScore;\n  }\n  int UnitType::destroyScore() const\n  {\n    return unitTypeData[this->id].destroyScore;\n  }\n  UnitSizeType UnitType::size() const\n  {\n    return unitTypeData[this->id].unitSizeType;\n  }\n  int UnitType::tileWidth() const\n  {\n    return unitTypeData[this->id].tileWidth;\n  }\n  int UnitType::tileHeight() const\n  {\n    return unitTypeData[this->id].tileHeight;\n  }\n  int UnitType::dimensionLeft() const\n  {\n    return unitTypeData[this->id].dimensionLeft;\n  }\n  int UnitType::dimensionUp() const\n  {\n    return unitTypeData[this->id].dimensionUp;\n  }\n  int UnitType::dimensionRight() const\n  {\n    return unitTypeData[this->id].dimensionRight;\n  }\n  int UnitType::dimensionDown() const\n  {\n    return unitTypeData[this->id].dimensionDown;\n  }\n  int UnitType::seekRange() const\n  {\n    return unitTypeData[this->id].seekRange;\n  }\n  int UnitType::sightRange() const\n  {\n    return unitTypeData[this->id].sightRange;\n  }\n  WeaponType UnitType::groundWeapon() const\n  {\n    return unitTypeData[this->id].groundWeapon;\n  }\n  int UnitType::maxGroundHits() const\n  {\n    return unitTypeData[this->id].maxGroundHits;\n  }\n  WeaponType UnitType::airWeapon() const\n  {\n    return unitTypeData[this->id].airWeapon;\n  }\n  int UnitType::maxAirHits() const\n  {\n    return unitTypeData[this->id].maxAirHits;\n  }\n  double UnitType::topSpeed() const\n  {\n    return unitTypeData[this->id].topSpeed;\n  }\n  int UnitType::acceleration() const\n  {\n    return unitTypeData[this->id].acceleration;\n  }\n  int UnitType::haltDistance() const\n  {\n    return unitTypeData[this->id].haltDistance;\n  }\n  int UnitType::turnRadius() const\n  {\n    return unitTypeData[this->id].turnRadius;\n  }\n  bool UnitType::canProduce() const\n  {\n    return unitTypeData[this->id].canProduce;\n  }\n  bool UnitType::canAttack() const\n  {\n    return unitTypeData[this->id].canAttack;\n  }\n  bool UnitType::canMove() const\n  {\n    return unitTypeData[this->id].canMove;\n  }\n  bool UnitType::isFlyer() const\n  {\n    return unitTypeData[this->id].isFlyer;\n  }\n  bool UnitType::regeneratesHP() const\n  {\n    return unitTypeData[this->id].regeneratesHP;\n  }\n  bool UnitType::isSpellcaster() const\n  {\n    return unitTypeData[this->id].isSpellcaster;\n  }\n  bool UnitType::hasPermanentCloak() const\n  {\n    return unitTypeData[this->id].hasPermanentCloak;\n  }\n  bool UnitType::isInvincible() const\n  {\n    return unitTypeData[this->id].isInvincible;\n  }\n  bool UnitType::isOrganic() const\n  {\n    return unitTypeData[this->id].isOrganic;\n  }\n  bool UnitType::isMechanical() const\n  {\n    return unitTypeData[this->id].isMechanical;\n  }\n  bool UnitType::isRobotic() const\n  {\n    return unitTypeData[this->id].isRobotic;\n  }\n  bool UnitType::isDetector() const\n  {\n    return unitTypeData[this->id].isDetector;\n  }\n  bool UnitType::isResourceContainer() const\n  {\n    return unitTypeData[this->id].isResourceContainer;\n  }\n  bool UnitType::isResourceDepot() const\n  {\n    return unitTypeData[this->id].isResourceDepot;\n  }\n  bool UnitType::isRefinery() const\n  {\n    return unitTypeData[this->id].isRefinery;\n  }\n  bool UnitType::isWorker() const\n  {\n    return unitTypeData[this->id].isWorker;\n  }\n  bool UnitType::requiresPsi() const\n  {\n    return unitTypeData[this->id].requiresPsi;\n  }\n  bool UnitType::requiresCreep() const\n  {\n    return unitTypeData[this->id].requiresCreep;\n  }\n  bool UnitType::isTwoUnitsInOneEgg() const\n  {\n    return unitTypeData[this->id].isTwoUnitsInOneEgg;\n  }\n  bool UnitType::isBurrowable() const\n  {\n    return unitTypeData[this->id].isBurrowable;\n  }\n  bool UnitType::isCloakable() const\n  {\n    return unitTypeData[this->id].isCloakable;\n  }\n  bool UnitType::isBuilding() const\n  {\n    return unitTypeData[this->id].isBuilding;\n  }\n  bool UnitType::isAddon() const\n  {\n    return unitTypeData[this->id].isAddon;\n  }\n  bool UnitType::isFlyingBuilding() const\n  {\n    return unitTypeData[this->id].isFlyingBuilding;\n  }\n  bool UnitType::isNeutral() const\n  {\n    return unitTypeData[this->id].isNeutral;\n  }\n  bool UnitType::isHero() const\n  {\n    return unitTypeData[this->id].isHero ||\n           this->id == UnitTypes::Hero_Dark_Templar.id ||\n           this->id == UnitTypes::Terran_Civilian.id;\n  }\n  bool UnitType::isPowerup() const\n  {\n    return this->id == UnitTypes::Powerup_Uraj_Crystal.id ||\n           this->id == UnitTypes::Powerup_Khalis_Crystal.id ||\n           (this->id >= UnitTypes::Powerup_Flag.id && this->id < UnitTypes::None.id);\n  }\n  bool UnitType::isBeacon() const\n  {\n    return this->id == UnitTypes::Special_Zerg_Beacon.id ||\n           this->id == UnitTypes::Special_Terran_Beacon.id ||\n           this->id == UnitTypes::Special_Protoss_Beacon.id;\n  }\n  bool UnitType::isFlagBeacon() const\n  {\n    return this->id == UnitTypes::Special_Zerg_Flag_Beacon.id ||\n           this->id == UnitTypes::Special_Terran_Flag_Beacon.id ||\n           this->id == UnitTypes::Special_Protoss_Flag_Beacon.id;\n  }\n  bool UnitType::isSpecialBuilding() const\n  {\n    return unitTypeData[this->id].isSpecialBuilding && this->id != UnitTypes::Zerg_Infested_Command_Center.id;\n  }\n  bool UnitType::isSpell() const\n  {\n    return this->id == UnitTypes::Spell_Dark_Swarm.id ||\n           this->id == UnitTypes::Spell_Disruption_Web.id ||\n           this->id == UnitTypes::Spell_Scanner_Sweep.id;\n  }\n  bool UnitType::producesLarva() const\n  {\n    return this->id == UnitTypes::Zerg_Hatchery.id || \n           this->id == UnitTypes::Zerg_Lair.id     || \n           this->id == UnitTypes::Zerg_Hive.id;\n  }\n  UnitType UnitTypes::getUnitType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, UnitType>::iterator i = unitTypeMap.find(name);\n    if (i == unitTypeMap.end())\n      return UnitTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<UnitType>& UnitTypes::allUnitTypes()\n  {\n    return unitTypeSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/UpgradeType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/Race.h>\n#include <BWAPI/UnitType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingUpgradeType = true;\n  class UpgradeTypeInternal\n  {\n    public:\n      UpgradeTypeInternal() {valid = false;}\n      void set(const char* name, int mineralPriceBase, int mineralPriceFactor, int gasPriceBase, int gasPriceFactor, int upgradeTimeBase, int upgradeTimeFactor, BWAPI::UnitType whatUpgrades, Race race, BWAPI::UnitType whatUses, int maxRepeats)\n      {\n        if (initializingUpgradeType)\n        {\n          this->name               = name;\n          this->mineralPriceBase   = mineralPriceBase;\n          this->mineralPriceFactor = mineralPriceFactor;\n          this->gasPriceBase       = gasPriceBase;\n          this->gasPriceFactor     = gasPriceFactor;\n          this->upgradeTimeBase    = upgradeTimeBase;\n          this->upgradeTimeFactor  = upgradeTimeFactor;\n          this->whatUpgrades       = whatUpgrades;\n          this->race               = race;\n          if (whatUses != UnitTypes::None)\n            this->whatUses.insert(whatUses);\n\n          this->maxRepeats = maxRepeats;\n          this->valid      = true;\n        }\n      }\n      std::string name;\n      int mineralPriceBase;\n      int mineralPriceFactor;\n      int gasPriceBase;\n      int gasPriceFactor;\n      int upgradeTimeBase;\n      int upgradeTimeFactor;\n      BWAPI::UnitType whatUpgrades;\n      Race race;\n      int maxRepeats;\n      std::set<BWAPI::UnitType> whatUses;\n      bool valid;\n  };\n  UpgradeTypeInternal upgradeTypeData[63];\n  std::map<std::string, UpgradeType> upgradeTypeMap;\n  std::set< UpgradeType > upgradeTypeSet;\n  namespace UpgradeTypes\n  {\n    const UpgradeType Terran_Infantry_Armor(0);\n    const UpgradeType Terran_Vehicle_Plating(1);\n    const UpgradeType Terran_Ship_Plating(2);\n    const UpgradeType Zerg_Carapace(3);\n    const UpgradeType Zerg_Flyer_Carapace(4);\n    const UpgradeType Protoss_Ground_Armor(5);\n    const UpgradeType Protoss_Air_Armor(6);\n    const UpgradeType Terran_Infantry_Weapons(7);\n    const UpgradeType Terran_Vehicle_Weapons(8);\n    const UpgradeType Terran_Ship_Weapons(9);\n    const UpgradeType Zerg_Melee_Attacks(10);\n    const UpgradeType Zerg_Missile_Attacks(11);\n    const UpgradeType Zerg_Flyer_Attacks(12);\n    const UpgradeType Protoss_Ground_Weapons(13);\n    const UpgradeType Protoss_Air_Weapons(14);\n    const UpgradeType Protoss_Plasma_Shields(15);\n    const UpgradeType U_238_Shells(16);\n    const UpgradeType Ion_Thrusters(17);\n    const UpgradeType Titan_Reactor(19);\n    const UpgradeType Ocular_Implants(20);\n    const UpgradeType Moebius_Reactor(21);\n    const UpgradeType Apollo_Reactor(22);\n    const UpgradeType Colossus_Reactor(23);\n    const UpgradeType Ventral_Sacs(24);\n    const UpgradeType Antennae(25);\n    const UpgradeType Pneumatized_Carapace(26);\n    const UpgradeType Metabolic_Boost(27);\n    const UpgradeType Adrenal_Glands(28);\n    const UpgradeType Muscular_Augments(29);\n    const UpgradeType Grooved_Spines(30);\n    const UpgradeType Gamete_Meiosis(31);\n    const UpgradeType Metasynaptic_Node(32);\n    const UpgradeType Singularity_Charge(33);\n    const UpgradeType Leg_Enhancements(34);\n    const UpgradeType Scarab_Damage(35);\n    const UpgradeType Reaver_Capacity(36);\n    const UpgradeType Gravitic_Drive(37);\n    const UpgradeType Sensor_Array(38);\n    const UpgradeType Gravitic_Boosters(39);\n    const UpgradeType Khaydarin_Amulet(40);\n    const UpgradeType Apial_Sensors(41);\n    const UpgradeType Gravitic_Thrusters(42);\n    const UpgradeType Carrier_Capacity(43);\n    const UpgradeType Khaydarin_Core(44);\n    const UpgradeType Argus_Jewel(47);\n    const UpgradeType Argus_Talisman(49);\n    const UpgradeType Caduceus_Reactor(51);\n    const UpgradeType Chitinous_Plating(52);\n    const UpgradeType Anabolic_Synthesis(53);\n    const UpgradeType Charon_Boosters(54);\n    const UpgradeType None(61);\n    const UpgradeType Unknown(62);\n\n    void init()\n    {\n      upgradeTypeData[Terran_Infantry_Armor.getID()].set(\"Terran Infantry Armor\"    , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Engineering_Bay      , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].set(\"Terran Vehicle Plating\"  , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Armory               , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Ship_Plating.getID()].set(\"Terran Ship Plating\"        , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Terran_Armory               , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Carapace.getID()].set(\"Zerg Carapace\"                    , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber      , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].set(\"Zerg Flyer Carapace\"        , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Zerg_Spire                  , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].set(\"Protoss Ground Armor\"      , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Protoss_Forge               , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Air_Armor.getID()].set(\"Protoss Air Armor\"            , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Protoss_Cybernetics_Core    , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Infantry_Weapons.getID()].set(\"Terran Infantry Weapons\", 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Engineering_Bay      , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].set(\"Terran Vehicle Weapons\"  , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Armory               , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Terran_Ship_Weapons.getID()].set(\"Terran Ship Weapons\"        , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Terran_Armory               , Races::Terran , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Melee_Attacks.getID()].set(\"Zerg Melee Attacks\"          , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber      , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Missile_Attacks.getID()].set(\"Zerg Missile Attacks\"      , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber      , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Zerg_Flyer_Attacks.getID()].set(\"Zerg Flyer Attacks\"          , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Zerg_Spire                  , Races::Zerg   , UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Ground_Weapons.getID()].set(\"Protoss Ground Weapons\"  , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Protoss_Forge               , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].set(\"Protoss Air Weapons\"        , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Protoss_Cybernetics_Core    , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].set(\"Protoss Plasma Shields\"  , 200, 100, 200, 100, 4000, 480, UnitTypes::Protoss_Forge               , Races::Protoss, UnitTypes::None                 , 3);\n      upgradeTypeData[U_238_Shells.getID()].set(\"U-238 Shells\"                      , 150, 0  , 150, 0  , 1500, 0  , UnitTypes::Terran_Academy              , Races::Terran , UnitTypes::Terran_Marine        , 1);\n      upgradeTypeData[Ion_Thrusters.getID()].set(\"Ion Thrusters\"                    , 100, 0  , 100, 0  , 1500, 0  , UnitTypes::Terran_Machine_Shop         , Races::Terran , UnitTypes::Terran_Vulture       , 1);\n      upgradeTypeData[Titan_Reactor.getID()].set(\"Titan Reactor\"                    , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Terran_Science_Facility     , Races::Terran , UnitTypes::Terran_Science_Vessel, 1);\n      upgradeTypeData[Ocular_Implants.getID()].set(\"Ocular Implants\"                , 100, 0  , 100, 0  , 2500, 0  , UnitTypes::Terran_Covert_Ops           , Races::Terran , UnitTypes::Terran_Ghost         , 1);\n      upgradeTypeData[Moebius_Reactor.getID()].set(\"Moebius Reactor\"                , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Terran_Covert_Ops           , Races::Terran , UnitTypes::Terran_Ghost         , 1);\n      upgradeTypeData[Apollo_Reactor.getID()].set(\"Apollo Reactor\"                  , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Terran_Control_Tower        , Races::Terran , UnitTypes::Terran_Wraith        , 1);\n      upgradeTypeData[Colossus_Reactor.getID()].set(\"Colossus Reactor\"              , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Terran_Physics_Lab          , Races::Terran , UnitTypes::Terran_Battlecruiser , 1);\n      upgradeTypeData[Ventral_Sacs.getID()].set(\"Ventral Sacs\"                      , 200, 0  , 200, 0  , 2400, 0  , UnitTypes::Zerg_Lair                   , Races::Zerg   , UnitTypes::Zerg_Overlord        , 1);\n      upgradeTypeData[Antennae.getID()].set(\"Antennae\"                              , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Zerg_Lair                   , Races::Zerg   , UnitTypes::Zerg_Overlord        , 1);\n      upgradeTypeData[Pneumatized_Carapace.getID()].set(\"Pneumatized Carapace\"      , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Zerg_Lair                   , Races::Zerg   , UnitTypes::Zerg_Overlord        , 1);\n      upgradeTypeData[Metabolic_Boost.getID()].set(\"Metabolic Boost\"                , 100, 0  , 100, 0  , 1500, 0  , UnitTypes::Zerg_Spawning_Pool          , Races::Zerg   , UnitTypes::Zerg_Zergling        , 1);\n      upgradeTypeData[Adrenal_Glands.getID()].set(\"Adrenal Glands\"                  , 200, 0  , 200, 0  , 1500, 0  , UnitTypes::Zerg_Spawning_Pool          , Races::Zerg   , UnitTypes::Zerg_Zergling        , 1);\n      upgradeTypeData[Muscular_Augments.getID()].set(\"Muscular Augments\"            , 150, 0  , 150, 0  , 1500, 0  , UnitTypes::Zerg_Hydralisk_Den          , Races::Zerg   , UnitTypes::Zerg_Hydralisk       , 1);\n      upgradeTypeData[Grooved_Spines.getID()].set(\"Grooved Spines\"                  , 150, 0  , 150, 0  , 1500, 0  , UnitTypes::Zerg_Hydralisk_Den          , Races::Zerg   , UnitTypes::Zerg_Hydralisk       , 1);\n      upgradeTypeData[Gamete_Meiosis.getID()].set(\"Gamete Meiosis\"                  , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Zerg_Queens_Nest            , Races::Zerg   , UnitTypes::Zerg_Queen           , 1);\n      upgradeTypeData[Metasynaptic_Node.getID()].set(\"Metasynaptic Node\"            , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Zerg_Defiler_Mound          , Races::Zerg   , UnitTypes::Zerg_Defiler         , 1);\n      upgradeTypeData[Singularity_Charge.getID()].set(\"Singularity Charge\"          , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Protoss_Cybernetics_Core    , Races::Protoss, UnitTypes::Protoss_Dragoon      , 1);\n      upgradeTypeData[Leg_Enhancements.getID()].set(\"Leg Enhancements\"              , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Protoss_Citadel_of_Adun     , Races::Protoss, UnitTypes::Protoss_Zealot       , 1);\n      upgradeTypeData[Scarab_Damage.getID()].set(\"Scarab Damage\"                    , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Scarab       , 1);\n      upgradeTypeData[Reaver_Capacity.getID()].set(\"Reaver Capacity\"                , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Reaver       , 1);\n      upgradeTypeData[Gravitic_Drive.getID()].set(\"Gravitic Drive\"                  , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Shuttle      , 1);\n      upgradeTypeData[Sensor_Array.getID()].set(\"Sensor Array\"                      , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Protoss_Observatory         , Races::Protoss, UnitTypes::Protoss_Observer     , 1);\n      upgradeTypeData[Gravitic_Boosters.getID()].set(\"Gravitic Boosters\"            , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Protoss_Observatory         , Races::Protoss, UnitTypes::Protoss_Observer     , 1);\n      upgradeTypeData[Khaydarin_Amulet.getID()].set(\"Khaydarin Amulet\"              , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Protoss_Templar_Archives    , Races::Protoss, UnitTypes::Protoss_High_Templar , 1);\n      upgradeTypeData[Apial_Sensors.getID()].set(\"Apial Sensors\"                    , 100, 0  , 100, 0  , 2500, 0  , UnitTypes::Protoss_Fleet_Beacon        , Races::Protoss, UnitTypes::Protoss_Scout        , 1);\n      upgradeTypeData[Gravitic_Thrusters.getID()].set(\"Gravitic Thrusters\"          , 200, 0  , 200, 0  , 2500, 0  , UnitTypes::Protoss_Fleet_Beacon        , Races::Protoss, UnitTypes::Protoss_Scout        , 1);\n      upgradeTypeData[Carrier_Capacity.getID()].set(\"Carrier Capacity\"              , 100, 0  , 100, 0  , 1500, 0  , UnitTypes::Protoss_Fleet_Beacon        , Races::Protoss, UnitTypes::Protoss_Carrier      , 1);\n      upgradeTypeData[Khaydarin_Core.getID()].set(\"Khaydarin Core\"                  , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Protoss_Arbiter_Tribunal    , Races::Protoss, UnitTypes::Protoss_Arbiter      , 1);\n      upgradeTypeData[Argus_Jewel.getID()].set(\"Argus Jewel\"                        , 100, 0  , 100, 0  , 2500, 0  , UnitTypes::Protoss_Fleet_Beacon        , Races::Protoss, UnitTypes::Protoss_Corsair      , 1);\n      upgradeTypeData[Argus_Talisman.getID()].set(\"Argus Talisman\"                  , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Protoss_Templar_Archives    , Races::Protoss, UnitTypes::Protoss_Dark_Archon  , 1);\n      upgradeTypeData[Caduceus_Reactor.getID()].set(\"Caduceus Reactor\"              , 150, 0  , 150, 0  , 2500, 0  , UnitTypes::Terran_Academy              , Races::Terran , UnitTypes::Terran_Medic         , 1);\n      upgradeTypeData[Chitinous_Plating.getID()].set(\"Chitinous Plating\"            , 150, 0  , 150, 0  , 2000, 0  , UnitTypes::Zerg_Ultralisk_Cavern       , Races::Zerg   , UnitTypes::Zerg_Ultralisk       , 1);\n      upgradeTypeData[Anabolic_Synthesis.getID()].set(\"Anabolic Synthesis\"          , 200, 0  , 200, 0  , 2000, 0  , UnitTypes::Zerg_Ultralisk_Cavern       , Races::Zerg   , UnitTypes::Zerg_Ultralisk       , 1);\n      upgradeTypeData[Charon_Boosters.getID()].set(\"Charon Boosters\"                , 100, 0  , 100, 0  , 2000, 0  , UnitTypes::Terran_Machine_Shop         , Races::Terran , UnitTypes::Terran_Goliath       , 1);\n      upgradeTypeData[None.getID()].set(\"None\"                                      , 0  , 0  , 0  , 0  , 0   , 0  , UnitTypes::None                        , Races::None   , UnitTypes::None                 , 0);\n      upgradeTypeData[Unknown.getID()].set(\"Unknown\"                                , 0  , 0  , 0  , 0  , 0   , 0  , UnitTypes::None                        , Races::Unknown, UnitTypes::None                 , 0);\n\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Firebat);\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Ghost);\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Marine);\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Medic);\n      upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_SCV);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Goliath);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Siege_Mode);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Tank_Mode);\n      upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Vulture);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Battlecruiser);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Dropship);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Science_Vessel);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Valkyrie);\n      upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Wraith);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Broodling);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Defiler);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Drone);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Hydralisk);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Infested_Terran);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Larva);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Lurker);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Ultralisk);\n      upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Zergling);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Devourer);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Guardian);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Mutalisk);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Overlord);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Queen);\n      upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Scourge);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Archon);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Archon);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_High_Templar);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Probe);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Reaver);\n      upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Zealot);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Carrier);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Corsair);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Observer);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Scout);\n      upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Shuttle);\n      upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Firebat);\n      upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Ghost);\n      upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Marine);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Goliath);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Siege_Mode);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Tank_Mode);\n      upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Vulture);\n      upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Battlecruiser);\n      upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Valkyrie);\n      upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Wraith);\n      upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Broodling);\n      upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Ultralisk);\n      upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Zergling);\n      upgradeTypeData[Zerg_Missile_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Hydralisk);\n      upgradeTypeData[Zerg_Missile_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Lurker);\n      upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Devourer);\n      upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Guardian);\n      upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Mutalisk);\n      upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar);\n      upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon);\n      upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Zealot);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Corsair);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor);\n      upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Scout);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter_Tribunal);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Archon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Assimilator);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Carrier);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Citadel_of_Adun);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Corsair);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Cybernetics_Core);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Archon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Fleet_Beacon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Forge);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Gateway);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_High_Templar);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Nexus);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Observatory);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Observer);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Photon_Cannon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Probe);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Pylon);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Reaver);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Robotics_Facility);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Robotics_Support_Bay);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Scarab);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Scout);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Shield_Battery);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Shuttle);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Stargate);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Templar_Archives);\n      upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Zealot);\n\n      upgradeTypeSet.insert(Terran_Infantry_Armor);\n      upgradeTypeSet.insert(Terran_Vehicle_Plating);\n      upgradeTypeSet.insert(Terran_Ship_Plating);\n      upgradeTypeSet.insert(Zerg_Carapace);\n      upgradeTypeSet.insert(Zerg_Flyer_Carapace);\n      upgradeTypeSet.insert(Protoss_Ground_Armor);\n      upgradeTypeSet.insert(Protoss_Air_Armor);\n      upgradeTypeSet.insert(Terran_Infantry_Weapons);\n      upgradeTypeSet.insert(Terran_Vehicle_Weapons);\n      upgradeTypeSet.insert(Terran_Ship_Weapons);\n      upgradeTypeSet.insert(Zerg_Melee_Attacks);\n      upgradeTypeSet.insert(Zerg_Missile_Attacks);\n      upgradeTypeSet.insert(Zerg_Flyer_Attacks);\n      upgradeTypeSet.insert(Protoss_Ground_Weapons);\n      upgradeTypeSet.insert(Protoss_Air_Weapons);\n      upgradeTypeSet.insert(Protoss_Plasma_Shields);\n      upgradeTypeSet.insert(U_238_Shells);\n      upgradeTypeSet.insert(Ion_Thrusters);\n      upgradeTypeSet.insert(Titan_Reactor);\n      upgradeTypeSet.insert(Ocular_Implants);\n      upgradeTypeSet.insert(Moebius_Reactor);\n      upgradeTypeSet.insert(Apollo_Reactor);\n      upgradeTypeSet.insert(Colossus_Reactor);\n      upgradeTypeSet.insert(Ventral_Sacs);\n      upgradeTypeSet.insert(Antennae);\n      upgradeTypeSet.insert(Pneumatized_Carapace);\n      upgradeTypeSet.insert(Metabolic_Boost);\n      upgradeTypeSet.insert(Adrenal_Glands);\n      upgradeTypeSet.insert(Muscular_Augments);\n      upgradeTypeSet.insert(Grooved_Spines);\n      upgradeTypeSet.insert(Gamete_Meiosis);\n      upgradeTypeSet.insert(Metasynaptic_Node);\n      upgradeTypeSet.insert(Singularity_Charge);\n      upgradeTypeSet.insert(Leg_Enhancements);\n      upgradeTypeSet.insert(Scarab_Damage);\n      upgradeTypeSet.insert(Reaver_Capacity);\n      upgradeTypeSet.insert(Gravitic_Drive);\n      upgradeTypeSet.insert(Sensor_Array);\n      upgradeTypeSet.insert(Gravitic_Boosters);\n      upgradeTypeSet.insert(Khaydarin_Amulet);\n      upgradeTypeSet.insert(Apial_Sensors);\n      upgradeTypeSet.insert(Gravitic_Thrusters);\n      upgradeTypeSet.insert(Carrier_Capacity);\n      upgradeTypeSet.insert(Khaydarin_Core);\n      upgradeTypeSet.insert(Argus_Jewel);\n      upgradeTypeSet.insert(Argus_Talisman);\n      upgradeTypeSet.insert(Caduceus_Reactor);\n      upgradeTypeSet.insert(Chitinous_Plating);\n      upgradeTypeSet.insert(Anabolic_Synthesis);\n      upgradeTypeSet.insert(Charon_Boosters);\n      upgradeTypeSet.insert(None);\n      upgradeTypeSet.insert(Unknown);\n\n      foreach(UpgradeType i, upgradeTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        upgradeTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingUpgradeType = false;\n    }\n  }\n  UpgradeType::UpgradeType()\n  {\n    this->id = UpgradeTypes::None.id;\n  }\n  UpgradeType::UpgradeType(int id)\n  {\n    this->id = id;\n    if (!initializingUpgradeType && (id < 0 || id >= 63 || !upgradeTypeData[id].valid) )\n      this->id = UpgradeTypes::Unknown.id;\n  }\n  UpgradeType::UpgradeType(const UpgradeType& other)\n  {\n    this->id = other.id;\n  }\n  UpgradeType& UpgradeType::operator=(const UpgradeType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool UpgradeType::operator==(const UpgradeType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool UpgradeType::operator!=(const UpgradeType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool UpgradeType::operator<(const UpgradeType& other) const\n  {\n    return this->id < other.id;\n  }\n  int UpgradeType::getID() const\n  {\n    return this->id;\n  }\n  std::string UpgradeType::getName() const\n  {\n    return upgradeTypeData[this->id].name;\n  }\n  Race UpgradeType::getRace() const\n  {\n    return upgradeTypeData[this->id].race;\n  }\n  int UpgradeType::mineralPrice() const\n  {\n    return upgradeTypeData[this->id].mineralPriceBase;\n  }\n  int UpgradeType::mineralPriceFactor() const\n  {\n    return upgradeTypeData[this->id].mineralPriceFactor;\n  }\n  int UpgradeType::gasPrice() const\n  {\n    return upgradeTypeData[this->id].gasPriceBase;\n  }\n  int UpgradeType::gasPriceFactor() const\n  {\n    return upgradeTypeData[this->id].gasPriceFactor;\n  }\n  int UpgradeType::upgradeTime() const\n  {\n    return upgradeTypeData[this->id].upgradeTimeBase;\n  }\n  int UpgradeType::upgradeTimeFactor() const\n  {\n    return upgradeTypeData[this->id].upgradeTimeFactor;\n  }\n  UnitType UpgradeType::whatUpgrades() const\n  {\n    return upgradeTypeData[this->id].whatUpgrades;\n  }\n  const std::set<UnitType>& UpgradeType::whatUses() const\n  {\n    return upgradeTypeData[this->id].whatUses;\n  }\n  int UpgradeType::maxRepeats() const\n  {\n    return upgradeTypeData[this->id].maxRepeats;\n  }\n  UpgradeType UpgradeTypes::getUpgradeType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, UpgradeType>::iterator i = upgradeTypeMap.find(name);\n    if (i == upgradeTypeMap.end())\n      return UpgradeTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<UpgradeType>& UpgradeTypes::allUpgradeTypes()\n  {\n    return upgradeTypeSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Bitmask.h",
    "content": "#pragma once\n/** Custom help classes not connected with the project */\nnamespace Util\n{\n  /** \n   * Representation of list of bool values using binary.\n   * Size of the bitmask is always the same as Type (so it can be mapped in bw structurs)\n   * This also means, that the bitmas has sizeof(Type)*8 values.\n   */\n  template <class Type>\n  class BitMask\n  {\n    public :\n      bool getBit(Type bit) const;\n      void setBit(Type bit, bool val);\n    Type value;\n  };\n  //------------------------------------------------ GET BIT -------------------------------------------------\n  template <class Type>\n  bool BitMask<Type>::getBit(Type bit) const\n  {\n    return (value & bit) != 0;\n  }\n  //------------------------------------------------ SET BIT -------------------------------------------------\n  template <class Type>\n  void BitMask<Type>::setBit(Type bit, bool val)\n  {\n    if (val)\n      value |= bit;\n    else\n      value &= ~bit;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Exceptions.cpp",
    "content": "#include \"Exceptions.h\"\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nGeneralException::GeneralException(const std::string &message)\n:message(message)\n{\n}\n//----------------------------------------------- GET MESSAGE ------------------------------------------------\nconst std::string GeneralException::getMessage(void)\n{\n  return this->message;\n}\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nFileException::FileException(const std::string &message) : GeneralException(message)\n{\n}\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nConfigException::ConfigException(const std::string &message) : GeneralException(message)\n{\n}\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nXmlException::XmlException(const std::string& message, const std::string& fileName, const long lineNumber) \n:GeneralException(message)\n,fileName(fileName)\n,lineNumber(lineNumber)\n{\n}\n//----------------------------------------------- CONSTRUCTOR ------------------------------------------------\nParseException::ParseException(const std::string& message)\n:GeneralException(message)\n{\n}\n//------------------------------------------------------------------------------------------------------------\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Exceptions.h",
    "content": "#pragma once\n#include <string>\nclass MultiString;\n/**\n * Represents any exception that can be thrown during to program run,\n * it doesn't contain expressions that can be thrown by tinyXml\n */\nclass GeneralException\n{\n  private :\n    /**\n     * Represents the property key of the exception message, but in some special\n     *   cases, the messageKey can contain the message itself\n     */\n   std::string message;\n  public:\n    /** Creates exception with the specified message */\n    GeneralException(const std::string &messageKey);\n    const std::string getMessage(void);\n};\n\n/**\n * Can be thrown when the configuration files are invalid, or contain invalid\n * information.\n */\nclass ConfigException : public GeneralException\n{\n  public :\n    ConfigException(const std::string &message);\n};\n\n/** Can be thrown when some required files are not found. */\nclass FileException : public GeneralException\n{\n  public :\n   FileException(const std::string &message);\n};\n\n/** Can be thrown when the xml file structure is invalid. */\nclass XmlException : public GeneralException\n{\n    std::string fileName;\n    long lineNumber;\n  public :\n    XmlException(const std::string& message, const std::string& fileName = \"\", const long lineNumber = 0);\n};\n\n/** Can be thrown during parsin (non integer paremters that should be numbers for example) */\nclass ParseException : public GeneralException\n{\n  public :\n    ParseException(const std::string& message);\n};\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/FileLogger.cpp",
    "content": "#include \"FileLogger.h\"\n\n#include <ctime>\n\nnamespace Util\n{\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  FileLogger::FileLogger(const std::string& fileName, Util::LogLevel::Enum logLevel, bool showTime)\n  :Logger(logLevel)\n  ,fileName(fileName + \".log\")\n  ,showTime(showTime)\n  {\n  }\n  //------------------------------------------------- FLUSH --------------------------------------------------\n  bool FileLogger::flush(const char* data)\n  {\n    FILE *f = fopen(fileName.c_str(),\"at\");\n    if (!f)\n      return false;\n    if (showTime)\n    {\n      char time[9];\n      _strtime(time);\n      fprintf(f, \"%s \", time);\n    }\n    fprintf(f, \"%s \\n\", data);\n    fclose(f);\n    return true;\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/FileLogger.h",
    "content": "#pragma once\n\n#include \"Logger.h\"\n\nnamespace Util\n{\n  /** Mutation of logger that prints messages to file. */\n  class FileLogger : public Logger\n  {\n    public :\n      FileLogger(const std::string& fileName, Util::LogLevel::Enum logLevel, bool showTime = true);\n    protected :\n      virtual bool flush(const char* data);\n    private :\n      std::string fileName;\n      bool showTime;\n  };\n}  \n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Foreach.h",
    "content": "#pragma once\n\n#ifdef __GNUC__\n#define foreach(element, collection) \\\n    for(typeof((collection).begin()) _foreach_iter = (collection).begin(); _foreach_iter != (collection).end(); ++_foreach_iter) \\\n    if(bool _foreach_loop = false) {} else \\\n    for(element = *_foreach_iter; !_foreach_loop; _foreach_loop = true)\n#else\n#define foreach(element, collection) for each(element in collection)\n#endif\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Gnu.h",
    "content": "#pragma once\n\n#ifdef __GNUC__\n#include <string.h>\n\n#define fprintf_s fprintf\n#define sprintf_s snprintf\n#define vsnprintf_s(buf, s1, s2, fmt, ap) vsnprintf(buf, s1, fmt, ap)\n#define memcpy_s(dest, ds, src, ss) memcpy(dest, src, ss)\n\ninline void strcpy_s(char* dest, size_t size, char* src) {\n    size_t s = strlen(src);\n    if(s > size - 1) {\n        s = size - 1;\n    }\n    memcpy(dest, src, s);\n    dest[s] = 0;\n}\n#endif\n\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/LogLevel.h",
    "content": "\nnamespace Util\n{\n  /** The level of detail of the log. */\n  namespace LogLevel\n  {\n    enum Enum\n    {\n      DontLog       = 0, /**< No logs will be printed by logger with this logLevel specification. Shouldn't be used by the Logger#log for obvious reasons. */\n      Critical      = 1, /**< Mostly errors, very important. */\n      Important     = 2, /**< Bigger events. */\n      Normal        = 2, /**< Normal events, like commands ordered etc. */\n      Commmon       = 3, /**< Common things. */\n      Detailed      = 4, /**< Detailed events mainly for investigation of problems. */\n      MicroDetailed = 5  /**< Super often occuring event's like calling common functions etc, used mainly for searching bugs. */\n    };\n  }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Logger.cpp",
    "content": "#include \"Logger.h\"\n\n#include <stdio.h>\n#include <stdarg.h>\n\n#include \"FileLogger.h\"\n#include \"Foreach.h\"\n#include \"Gnu.h\"\n\nnamespace Util\n{\n  Logger* Logger::globalLog = new FileLogger(\"global\", LogLevel::MicroDetailed);\n  char Logger::buffer[BUFFER_SIZE];\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  Logger::Logger(LogLevel::Enum levelToLog)\n  :levelToLog(levelToLog)\n  {\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  Logger::~Logger()\n  {\n    for (std::list<Logger*>::iterator i = this->connectedLoggers.begin();\n         i != this->connectedLoggers.end();\n         ++i)\n      delete *i;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::log(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Normal, ap);\n    va_end(ap);\n    return true;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logDetailed(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Detailed, ap);\n    va_end(ap);\n    return true;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logCommon(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Commmon, ap);\n    va_end(ap);\n    return true;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logImportant(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Important, ap);\n    va_end(ap);\n    return true;\n  }\n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logCritical(const char* message, ...)\n  {\n    va_list ap;\n    va_start(ap, message);\n    logInternal(message, LogLevel::Critical, ap);\n    va_end(ap);\n    return true;\n  }  \n  //-------------------------------------------------- LOG ---------------------------------------------------\n  bool Logger::logInternal(const char* message, LogLevel::Enum logLevel, va_list ap)\n  {\n    if (logLevel > this->levelToLog)\n      return true;\n\n    vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE, message, ap); \n    this->flushInternal(buffer);\n    \n    if (globalLog != NULL &&\n        this != globalLog)\n      globalLog->logInternal(message, logLevel, ap);\n    return true;\n  }\n  //-------------------------------------------- REGISTER LOGGER ---------------------------------------------\n  void Logger::registerLogger(Logger* logger)\n  {\n    this->connectedLoggers.push_back(logger);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  bool Logger::flushInternal(const char* buffer)\n  {\n    foreach (Logger* i, this->connectedLoggers)\n     i->flush(buffer);\n    return this->flush(buffer);\n  }\n  //----------------------------------------------------------------------------------------------------------\n  \n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Logger.h",
    "content": "#pragma once\n\n#include <stdio.h>\n#include <cstdarg>\n#include <string>\n#include <list>\n\n#include \"LogLevel.h\"\n\nnamespace Util\n{\n  /** \n   * Utility for logging debug output.\n   * This class defines abstract logger interface, every descentant needs to define the flush function to be\n   * instantiable.\n   * Every kind of log should have it's own instance of this class, don't log different things to same log.\n   * Different log instances can be later used to combine different logs with different detailLevels.\n   */\n  class Logger\n  {\n    public :\n      /**\n       * Creates new logger.\n       * @param levelToLog All log inputs with less importancy will be not\n       *        logged in this log\n       */\n      Logger(LogLevel::Enum levelToLog);\n      virtual ~Logger();\n      /**\n       * Logs the message using printf formatting style.\n       * This function use Normal Log level.\n       * @param message message to be logged.\n       * @param ... Parameters of the printf style format.\n       */\n      bool log         (const char* message, ...);\n      bool logDetailed (const char* message, ...);\n      bool logCommon   (const char* message, ...);\n      bool logImportant(const char* message, ...);\n      bool logCritical (const char* message, ...);      \n      void registerLogger(Logger* logger);\n      /** Every log message will be also posted to this global log. */\n      static Logger* globalLog;\n      static bool deleteLogsAtStart;\n    protected :\n      virtual bool flush(const char* data) = 0;\n      bool flushInternal(const char* data);      \n    private :\n      bool logInternal(const char* message, LogLevel::Enum, va_list ap);\n      LogLevel::Enum levelToLog;\n      static const unsigned int BUFFER_SIZE = 2048;\n      static char buffer[BUFFER_SIZE];\n      std::list<Logger*> connectedLoggers;\n  };\n};\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/RectangleArray.h",
    "content": "#pragma once\n\n#include <stdio.h>\n#include <string.h>\n#include \"Exceptions.h\"\n\nnamespace Util\n{\n  /**\n   * Template used for work with dynamically initialized array with dimension 2.\n   */\n  template <class Type>\n  class RectangleArray\n   {\n     public :\n       /**\n        * Creates the array with the specified proportions.\n        * @param width Width of the new array.\n        * @param height Height of the new array.\n        */\n       RectangleArray(unsigned int width = 1, unsigned int height = 1, Type* data = NULL);\n       /** Copy constructor */\n       RectangleArray(const RectangleArray<Type>& rectangleArray);\n       /** Destorys the array and deletes all content of array. */\n       ~RectangleArray(void);\n       /**\n        * Gets the width of the array.\n        * @return width of the array.\n        */\n       unsigned int getWidth(void) const;\n       /**\n        * Gets the height of the array.\n        * @return height of the array.\n        */\n       unsigned int getHeight(void) const;\n       /**\n        * Gets item of the array on the specified position.\n        * @param x horizontal index of the array position.\n        * @param y vertical index of the array position.\n        * @return item on the specified position.\n        */\n       Type* getItem(unsigned int x, unsigned int y);\n       inline Type* operator[](int i) { return this->getColumn(i); }\n       inline Type const * const operator[](int i) const {return this->getColumn(i); }\n       /**\n        * Sets item of the array on the specified position.\n        * @param x horizontal index of the array position.\n        * @param y vertical index of the array position.\n        * @param item new value of the field.\n        */\n       void setItem(unsigned int x, unsigned int y, Type *item);\n       void resize(unsigned int width, unsigned int height);\n       void printToFile(FILE* f);\n       void saveToFile(const std::string& fileName);\n       /** Sets all fields of the array to the specified value */\n       void setTo(const Type& value);\n       void setBorderTo(const Type& value);\n     private :\n       bool owner;\n       /** width of array */\n       unsigned int width;\n       /** height of array */\n       unsigned int height;\n       /** Array data, stored as linear array of size width*height */\n       Type *data;\n       /** Pointers to begins of lines*/\n       Type **columns;\n       /**\n        * Gets data item on the specified index\n        * @param index index of the data to be returned.\n        */\n       Type getData(unsigned int index);\n       /**\n        * Gets the pointer in data to the beginning of line with the specified\n        * index.\n        * @param index index of the line.\n        */\n       Type *getColumn(unsigned int index);\n       /**\n        * Gets the pointer in data to the beginning of line with the specified\n        * index.\n        * @param index index of the line.\n        */\n       const Type *getColumn(unsigned int index) const;\n       /**\n        * Sets the width of the array.\n        * @param width New width of the array.\n        */\n       void setWidth(unsigned int width);\n       /**\n        * Sets the height of the array.\n        * @param height New height of the array.\n        */\n       void setHeight(unsigned int height);       \n   };\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  template <class Type>\n  RectangleArray<Type>::RectangleArray(unsigned int width, unsigned int height, Type* data)\n  {\n    this->setWidth(width);\n    this->setHeight(height);\n    this->owner = (data == NULL);\n    if (this->owner)\n      this->data = new Type[this->getWidth()*this->getHeight()];\n    else\n      this->data = data;\n\n    columns = new Type*[this->getWidth()];\n    unsigned int i = 0;\n    for (unsigned int position = 0;i < width; i ++,position += height)\n      columns[i] = &this->data[position];\n  }\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  template <class Type>\n  RectangleArray<Type>::RectangleArray(const RectangleArray<Type>& rectangleArray)\n  :owner(true)\n  {\n    this->setWidth(rectangleArray.getWidth());\n    this->setHeight(rectangleArray.getHeight());\n    this->data = new Type[this->getWidth()*this->getHeight()];\n    columns = new Type*[this->getWidth()];\n    \n    unsigned int i = 0;\n    for (unsigned int position = 0;i < width; i ++,position += height)\n      columns[i] = &data[position];\n    memcpy(this->data, rectangleArray.data, sizeof(Type)*this->getWidth()*this->getHeight());\n  }\n  //----------------------------------------------- DESTRUCTOR -----------------------------------------------\n  template <class Type>\n  RectangleArray<Type>::~RectangleArray(void)\n  {\n     delete [] columns;\n     if (this->owner)\n       delete [] data;\n  }\n  //----------------------------------------------- GET WIDTH ------------------------------------------------\n  template <class Type>\n  unsigned int RectangleArray<Type>::getWidth(void) const\n  {\n    return this->width;\n  }\n  //----------------------------------------------- SET WIDTH ------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setWidth(unsigned int width)\n  {\n    this->width = width;\n  }\n  //----------------------------------------------- GET HEIGHT -----------------------------------------------\n  template <class Type>\n  unsigned int RectangleArray<Type>::getHeight(void) const\n  {\n    return this->height;\n  }\n  //----------------------------------------------- SET HEIGHT -----------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setHeight(unsigned int height)\n  {\n    this->height = height;\n  }\n  //------------------------------------------------ GET ITEM ------------------------------------------------\n  template <class Type>\n  Type* RectangleArray<Type>::getItem(unsigned int x, unsigned int y)\n  {\n    return this->getColumn(x)[y];\n  }\n  //------------------------------------------------ SET ITEM ------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setItem(unsigned int x, unsigned int y, Type* item)\n  {\n    this->getColumn(x)[y] = item;\n  }\n  //------------------------------------------------ GET LINE ------------------------------------------------\n  template <class Type>\n  Type* RectangleArray<Type>::getColumn(unsigned int index)\n  {\n    return columns[index];\n  }\n  //------------------------------------------------ GET LINE ------------------------------------------------\n  template <class Type>\n  const Type* RectangleArray<Type>::getColumn(unsigned int index) const\n  {\n    return columns[index];\n  }\n  //------------------------------------------------- RESIZE -------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::resize(unsigned int width, unsigned int height)\n  {\n    if (!this->owner)\n      throw GeneralException(\"Can't resize array that doesn't own the data\");\n    if (this->getWidth() == width &&\n        this->getHeight() == height)\n      return;\n\n    delete [] this->columns;\n    delete [] this->data;  \n\n    this->setWidth(width);\n    this->setHeight(height);\n\n    this->data = new Type[this->width * this->height];\n\n    this->columns = new Type*[this->width];\n    unsigned int i = 0;\n    for (unsigned int position = 0;i < this->width; i ++,position += this->height)\n      columns[i] = &data[position];\n  }\n  //--------------------------------------------- PRINT TO FILE ----------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::printToFile(FILE* f)\n  {\n    for (unsigned int y = 0; y < this->getHeight(); y++)\n    {\n      for (unsigned int x = 0; x < this->getWidth(); x++)\n      {\n        char ch = this->getColumn(x)[y];\n        fprintf(f, \"%c\", ch);\n      }\n      fprintf(f, \"\\n\");\n    }\n  }\n  //---------------------------------------------- SAVE TO FILE ----------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::saveToFile(const std::string& fileName)\n  {\n    FILE* f = fopen(fileName.c_str(), \"wt\");\n    if (!f)\n      throw FileException(\"RectangleArray::saveToFile Couldn't open file \" + fileName + \"for writing\");\n    this->printToFile(f);\n    fclose(f);\n  }\n  //------------------------------------------------- SET TO -------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setTo(const Type& value)\n  {\n    for (unsigned int i = 0; i < this->getWidth()*this->getHeight(); i++)\n      this->data[i] = value;\n  }\n  //--------------------------------------------- SET BORDER TO ----------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setBorderTo(const Type& value)\n  {\n    for (unsigned int i = 0; i < this->width; i++)\n    {\n      this->getColumn(i)[0] = value;\n      this->getColumn(i)[this->height - 1] = value;\n    }\n    for (unsigned int i = 0; i < this->height; i++)\n    {\n      this->getColumn(0)[i] = value;\n      this->getColumn(this->width - 1)[i] = value;\n    }    \n  }\n  //----------------------------------------------------------------------------------------------------------\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/RegionQuadTree.h",
    "content": "#pragma once\n\n#include <list>\n\nnamespace Util\n{\n  /**\n   * Structure representing 2D space containing objects of the specified type. This structure is optimised for\n   * effective way of finding of objects in certain area. The top level of the structure contains single list\n   * of all objects included, it divides into 2-4 partitions containing lists of units on respective quoters\n   * of the space, and so on until sthe width/height size is reached. The structure works with list of\n   * pointers of the type and doesn't act as owner, so removing items or deleting the whole quad tree will not\n   * result in delatation of contained items.\n   */\n  template <class Type>\n  class RegionQuadTree\n   {\n     public :\n       /**\n        * Creates the quad tree with the specified dimensions.\n        * @param width Width of the highest detail level partition.\n        * @param height Height of the highest detail level partition.\n        */\n       RegionQuadTree(unsigned int width = 1, unsigned int height = 1);\n       /** Destorys the array, but doesn't delete inserted objects. */\n       ~RegionQuadTree(void);\n       /**\n        * Gets the width of the array.\n        * @return width of the array.\n        */\n       unsigned int getWidth(void) const;\n       /**\n        * Gets the height of the array.\n        * @return height of the array.\n        */\n       unsigned int getHeight(void) const;\n       /**\n        * Gets list of items in the specified region.\n        * @param x horizontal index of the region.\n        * @param y vertical index of the region.\n        * @return list of items on the specified region\n        */\n       std::list<Type*>* getItems(unsigned int x, unsigned int y, unsigned int level = 0);\n       /**\n        * Sets item of the array on the specified position.\n        * @param x horizontal index of the array position.\n        * @param y vertical index of the array position.\n        * @param item new value of the field.\n        */\n       void addItem(unsigned int x, unsigned int y, Type *item);\n       void clear(unsigned int x, unsigned int y);\n     private :\n       /** width of array */\n       unsigned int width;\n       /** height of array */\n       unsigned int height;\n       /** array of rectangle arrays of lists of objects. \n        * The 1. item of the array corresponds with the lowest (most detailed) level of the region resolution.\n        * Every other level correspons to 4 times less detailed resolution.\n        */\n       RectangleArray<std::list<Type*> >* data;\n       /** depth = log2(max(width,height)), but is here for optimalisation reasons. */\n       unsigned int depth;\n   };\n  //---------------------------------------------- CONSTRUCTOR -----------------------------------------------\n  template <class Type>\n  RegionQuadTree<Type>::RegionQuadTree(unsigned int width, unsigned int height)\n  :width(width)\n  ,height(height)\n  ,depth(ceil(log2(max(width,height)))\n  {\n    this->data = new RectangleArray<std::list<Type*> >[depth];\n    unsigned int localWidth = width;\n    unsigned int localHeight = height;\n    for (unsigned int i = 0; i < this->depth; i++)\n    {\n      this->data[i].resize(localWidth, localHeight);\n      localWidth = (localWidth >= 2) (localWidth+1)/2 : 1;\n      localHeight = (localHeight >=2) (localHeight+1)/2 : 1;\n    }\n  }\n  //----------------------------------------------- DESTRUCTOR -----------------------------------------------\n  template <class Type>\n  RectangleArray<Type>::~RectangleArray(void)\n  {\n    delete [] data;\n  }\n  //----------------------------------------------- GET WIDTH ------------------------------------------------\n  template <class Type>\n  unsigned int RectangleArray<Type>::getWidth(void) const\n  {\n    return this->width;\n  }\n  //----------------------------------------------- SET WIDTH ------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::setWidth(unsigned int width)\n  {\n    this->width = width;\n  }\n  //----------------------------------------------- GET HEIGHT -----------------------------------------------\n  template <class Type>\n  unsigned int RectangleArray<Type>::getHeight(void) const\n  {\n    return this->height;\n  }\n  //------------------------------------------------ GET ITEM ------------------------------------------------\n  template <class Type>\n  std::list<Type*>* getItems(unsigned int x, unsigned int y, unsigned int level = 0);\n  {\n    return this->data[level][x][y];\n  }\n  //------------------------------------------------ ADD ITEM ------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::addItem(unsigned int x, unsigned int y, Type* item)\n  {\n    for (unsigned int i = 0; i < this->depth; i++)\n      this->data[i][x<<i][y<<i].push_bach(item);\n  }\n  //------------------------------------------------- CLEAR --------------------------------------------------\n  template <class Type>\n  void RectangleArray<Type>::clear(unsigned int x, unsigned int y)\n  {\n    for (unsigned int i = 0; i < this->depth; i++)\n      this->data[i][x<<i][y<<i].clear();\n  }  \n  //----------------------------------------------------------------------------------------------------------\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Strings.cpp",
    "content": "#include \"Strings.h\"\n\n#include <math.h>\n#include <stdarg.h>\n\n#include \"Exceptions.h\"\n#include \"Gnu.h\"\n\nnamespace Util\n{\n  //--------------------------------------------- INT TO STRING ----------------------------------------------\n  std::string Strings::intToString(long value)\n  {\n    if (value == 0)\n      return \"0\";\n    std::string returnValue;\n    while (value != 0)\n    {\n      returnValue = (char) (48+(value % 10)) + returnValue;\n      value/=10;\n    }\n    if (value >= 0)\n      return returnValue;\n    else\n      return \"-\" + returnValue;\n  }\n  //--------------------------------------------- STRING TO INT ----------------------------------------------\n  unsigned long Strings::stringToInt(const std::string &input, const unsigned long begin, const int distance)\n  {\n    unsigned long returnValue = 0;\n    for (unsigned long i = begin; i < distance + begin && i < input.size();i++)\n    {\n      if (!isdigit(input[i]))\n        throw ParseException::ParseException(\"Strings::stringToInt - String \" + input + \" is not a number.\");\n      returnValue*=10;\n      returnValue += (input[i] - '0');\n    }\n    return returnValue;\n  }\n  //---------------------------------------- STRING TO VARIABLE NAME -----------------------------------------\n  std::string Strings::stringToVariableName(const std::string &input)\n  {\n    std::string variableName;\n    for(unsigned int i=0;i<input.length();i++)\n    {\n      if (input[i]==' ')\n      {\n        variableName.push_back('_');\n      }\n      else if(input[i]=='\\'')\n      {\n      }\n      else if(input[i]=='\\\"')\n      {\n      }\n      else if(input[i]=='-')\n      {\n        variableName.push_back('_');\n      }\n      else\n      {\n        variableName.push_back(input[i]);\n      }\n    }\n    return variableName;\n  }\n  //--------------------------------------------- STRING TO FILE ---------------------------------------------\n  void Strings::stringToFile(const std::string &input,FILE* f)\n  {\n    size_t length = input.size();\n    fwrite(&length,sizeof(unsigned long),1,f);\n    fwrite(input.c_str(),length*sizeof(char),1,f);\n  }\n  //---------------------------------------------- SAVE TO FILE ----------------------------------------------\n  void Strings::saveToFile(const std::string &input,const std::string &fileName)\n  {\n     FILE *f = fopen(fileName.c_str(), \"wt\");\n     fwrite(input.c_str(),input.length()*sizeof(char),1,f);\n     fclose(f);\n  }\n  //--------------------------------------------- LOAD FROM FILE ---------------------------------------------\n  std::string Strings::loadFromFile(FILE* f)\n  {\n    unsigned long Length;\n    fread(&Length,sizeof(unsigned long),1,f);\n    char* Buffer = new char[Length + 1];\n    Buffer[Length] = 0;\n    if (Length != 0)\n      fread(Buffer,Length*sizeof(char),1,f);\n    std::string ReturnValue = Buffer;;\n    delete [] Buffer;\n    return ReturnValue;\n  }\n  //------------------------------------------- BEGINS WIHT NUMBER -------------------------------------------\n  bool Strings::beginsWithNumber(const std::string &input)\n  {\n    if (input.length() >= 1)\n      return input[0]>='0' && input[0]<= '9';\n    return false;\n  }\n  //-------------------------------------------- ENDS WITH NUMBER --------------------------------------------\n  bool Strings::endsWithNumber(const std::string &input)\n  {\n    if (input.length() >= 1)\n      return input[input.length() - 1]>='0' && input[input.length() - 1] <= '9';\n    return false;\n  }\n  //--------------------------------------------- LOAD FROM FILE ---------------------------------------------\n\n  void Strings::loadFromFile(const std::string &fileName, std::string &target,const long bufferSize)\n  {\n    char* buffer = new char[bufferSize];\n    FILE* f = fopen(fileName.c_str(),\"rt\");\n    size_t fileSize;\n    if (f)\n    {\n      fileSize = fread(buffer,1,bufferSize,f);\n      fclose(f);\n      buffer[fileSize] = 0;\n      target = buffer;\n    }\n    else\n      throw new FileException(\"Couldn't open file \" + fileName);\n    delete [] buffer;\n  }\n  //------------------------------------------------ TRIM ALL ------------------------------------------------\n  std::string Strings::trimAll(std::string input)\n  {\n    size_t length = input.size();\n    char* buffer = new char[length + 1];\n    long pos = 0;\n    for (size_t i = 0;i < length;i++)\n    {\n      if (!isspace(input[i]))\n      {\n        buffer[pos] = input[i];\n        pos++;\n      }\n    }\n    buffer[pos] = 0;\n    std::string returnValue = buffer;\n    delete [] buffer;\n    return returnValue;\n  }\n  //------------------------------------------------ TRIM ALL ------------------------------------------------\n  std::string Strings::trim(std::string input)\n  {\n    size_t i, j;\n    for (i = 0; i < input.length() && isspace(input[i]);i++);\n    if (i == input.length())\n      return  \"\";\n    for (j = input.length() - 1; j > 0 && isspace(input[j]);j--);\n    if (i == 0 && j == input.length())\n      return input;\n    else\n      return input.substr(i,j - i + 1);\n  }\n\n  char Strings::buffer[STRING_UTIL_BUFFER_SIZE];\n  //----------------------------------------------- READ LINE ------------------------------------------------\n  std::string Strings::readLine(FILE* f)\n  {\n    std::string result;\n    readNextBlock:\n    int position = 0;\n    fread(buffer, sizeof(char), 1, f);\n    while (buffer[position] != 13 && buffer[position] != 10 && position < STRING_UTIL_BUFFER_SIZE - 1 && !feof(f))\n    {\n      position++;\n      fread(&buffer[position], 1, 1,f);\n    }\n\n    if (buffer[position] == 13 || buffer[position] == 10 || feof(f))\n    {\n      buffer[position] = 0;\n      result.append(buffer);\n      return result;\n    }\n    else\n    {\n      buffer[position + 1] = 0;\n      result.append(buffer);\n      goto readNextBlock;\n    }\n  }\n  //----------------------------------------------------------------------------------------------------------\n  const std::string& Strings::dereferenceString(const std::string* const input)\n  {\n    return *input;\n  }\n  //----------------------------------------------------------------------------------------------------------\n  RectangleArray<char> Strings::makeBorder(const RectangleArray<char>& input, bool coordinates)\n  {\n    int leftBorder = (int)log10((float)input.getHeight()) + 2;\n    int topBorder = 3;\n    RectangleArray<char> returnValue = RectangleArray<char>(input.getWidth() + leftBorder*2, input.getHeight() + topBorder*2);\n    for (unsigned int x = 0; x < returnValue.getWidth(); x++)\n      for (unsigned int y = 0; y < returnValue.getHeight(); y++)  \n        returnValue[x][y] = ' ';\n    Strings::makeWindow(returnValue,\n                        leftBorder - 1, \n                        topBorder - 1,\n                        input.getWidth() + 2, \n                        input.getHeight() + 2);      \n    for (unsigned int x = 0; x < input.getWidth(); x++)\n      for (unsigned int y = 0; y < input.getHeight(); y++)  \n        returnValue[x + leftBorder ][y + topBorder] = input[x][y];\n    for (unsigned int i = 0; i < input.getWidth(); i+=10)\n    {\n      Strings::printTo(returnValue, Strings::intToString(i), i + leftBorder, 0);\n      Strings::printTo(returnValue, Strings::intToString(i), i + leftBorder, returnValue.getHeight() - 1);\n    }\n    for (unsigned int i = 0; i < input.getWidth(); i++)\n    {\n      Strings::printTo(returnValue, Strings::intToString(i%10), i + leftBorder, 1);\n      Strings::printTo(returnValue, Strings::intToString(i%10), i + leftBorder, returnValue.getHeight() - 2);\n    }\n    \n    for (unsigned int i = 0; i < input.getHeight(); i++)\n    {\n      Strings::printTo(returnValue, Strings::intToString(i), 0 , i + topBorder);\n      Strings::printTo(returnValue, Strings::intToString(i), leftBorder + input.getWidth() + 1, i + topBorder);\n    }\n\n    return returnValue;\n  }\n  char Strings::FrameCharacters[2][6] = \n  {\n    {\n      char(205),\n      char(186),\n      char(201),\n      char(187),\n      char(200),\n      char(188)\n    },\n    {\n      char(196),\n      char(179),\n      char(218),\n      char(191),\n      char(192),\n      char(217)\n    }\n  };\n   \n  //----------------------------------------------------------------------------------------------------------\n  void Strings::makeWindow(RectangleArray<char>& input, \n                           unsigned int x, \n                           unsigned int y, \n                           unsigned int width, \n                           unsigned int height, \n                           unsigned int frameType)\n  {\n    for (unsigned int i = x + 1; i < x + width - 1 && x < input.getWidth(); i++)\n    {\n      input[i][y] = Strings::FrameCharacters[frameType][0];\n      input[i][y + height - 1] = Strings::FrameCharacters[frameType][0];\n    }\n    \n    for (unsigned int i = y + 1; i < y + height - 1 && y < input.getHeight(); i++)\n    {\n      input[x][i] = Strings::FrameCharacters[frameType][1];\n      input[x + width - 1][i] = Strings::FrameCharacters[frameType][1];\n    }\n    input[x][y] = Strings::FrameCharacters[frameType][2];\n    input[x + width - 1][y] = Strings::FrameCharacters[frameType][3];\n    input[x][y + height - 1] = Strings::FrameCharacters[frameType][4];\n    input[x + width - 1][y + height- 1] = Strings::FrameCharacters[frameType][5];\n  }\n  //------------------------------------------------ PRINT TO ------------------------------------------------\n  void Strings::printTo(RectangleArray<char>& input, \n                           const std::string& text, \n                           unsigned int x, \n                           unsigned int y)\n  {\n    for (unsigned int i = 0; text[i] != 0; i++)\n      input[x + i][y] = text[i];\n  }\n  //---------------------------------------------- SPLIT STRING ----------------------------------------------\n  std::vector<std::string> Strings::splitString(const std::string& input,\n                                                const std::string& delimiters)\n  {\n    // Skip delims at beginning, find start of first token\n    std::string::size_type lastPos = input.find_first_not_of(delimiters, 0);\n    // Find next delimiter @ end of token\n    std::string::size_type pos = input.find_first_of(delimiters, lastPos);\n\n    // output vector\n    std::vector<std::string> tokens;\n\n    while (std::string::npos != pos || std::string::npos != lastPos)\n    {\n      // Found a token, add it to the vector.\n      tokens.push_back(input.substr(lastPos, pos - lastPos));\n      // Skip delims.  Note the \"not_of\". this is beginning of token\n      lastPos = input.find_first_not_of(delimiters, pos);\n      // Find next delimiter at end of token.\n      pos = input.find_first_of(delimiters, lastPos);\n    }\n    return tokens;\n  }\n  //----------------------------------------------- GET BINARY ------------------------------------------------\n  template <class Type>\n  std::string Strings::getBinary(Type value)\n  {\n   std::string result;\n    for (int i = 0; i < sizeof(Type)*8; i++)\n      if (value  & (1 << (sizeof(Type)*8-1-i)))\n         result += \"1\";\n      else\n         result += \"0\";\n    return result;\n  }\n //----------------------------------------------- SKIP SPACE ------------------------------------------------\n void Strings::skipSpace(const std::string& text, size_t& position)\n {\n   while (isspace(text[position]))\n     position ++;\n }\n //------------------------------------------------ READ WORD ------------------------------------------------\n std::string Strings::readWord(const std::string& text, size_t& position)\n {\n   std::string result;\n   while (isalpha(text[position]))\n   {\n     result += text[position];\n     position++;\n   }\n  return result;  \n }\n //------------------------------------------------ READ WORD ------------------------------------------------\n std::string Strings::readNumber(const std::string& text, size_t& position)\n {\n   std::string result;\n   while (isdigit(text[position]) || text[position] == '.')\n   {\n     result += text[position];\n     position++;\n   }\n  return result;  \n }  \n const int BUFFER_SIZE = 4096;\n char buffer[BUFFER_SIZE];\n //-----------------------------------------------------------------------------------------------------------\n std::string Strings::ssprintf(const char* format, ...)\n {\n    va_list ap;\n    va_start(ap, format);\n    vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE, format, ap); \n    va_end(ap);\n    return buffer;\n }\n //-----------------------------------------------------------------------------------------------------------\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Strings.h",
    "content": "#pragma once\n#define STRING_UTIL_BUFFER_SIZE 100\n\n#include <string>\n#include <vector>\n\n#include \"RectangleArray.h\"\n\nnamespace Util\n{\n  /** Collection of std::string utilities */\n  class Strings\n   {\n     private :\n       /** The class is abstract, so it has private constructor */\n       Strings(void);\n       static char buffer[STRING_UTIL_BUFFER_SIZE];\n     public :\n       /**\n        * Gets textual representation of the specified number.\n        * @param value Number to be converted to std::string.\n        * @return Textual representation of the specified number.\n        */\n       static std::string intToString(long value);\n       /**\n        * Converts textual representation of number to number.\n        * @param input String containing number representation.\n        * @param begin Position of the first caracter of the number in the input\n        *        std::string.\n        * @param distance Maximum count of characters to read.\n        * @return Returns textual representation of the specified std::string.\n        * @throws ParseException if the text can't be converted to integer\n        *         (non-numerical characters)\n        */\n       static unsigned long stringToInt(const std::string &input, const unsigned long begin = 0, const int distance = 9);\n       static std::string stringToVariableName(const std::string &input);\n       static void stringToFile(const std::string &input, FILE* f);\n       static void saveToFile(const std::string &input, const std::string &fileName);\n       static bool beginsWithNumber(const std::string &input);\n       static bool endsWithNumber(const std::string &input);\n       static std::string loadFromFile(FILE* f);\n       static void loadFromFile(const std::string &fileName,std::string &Target,const long bufferSize);\n       static std::string UTF8ToWindows1250(const std::string &input);\n       static std::string Windows1250ToUTF8(const std::string &input);\n       static std::string trimAll(std::string input);\n       static std::string trim(std::string input);\n       static std::string replace(const std::string &input, MultiString* values, const std::string &replacement);\n       static RectangleArray<char> makeBorder(const RectangleArray<char>& input, bool coordinates = true);\n       static char FrameCharacters[2][6];\n       static void makeWindow(RectangleArray<char>& input, \n                              unsigned int x, \n                              unsigned int y, \n                              unsigned int width, \n                              unsigned int height, \n                              unsigned int frameType = 0);\n       static void printTo(RectangleArray<char>& input, const std::string& text, unsigned int x, unsigned int y);\n       /**\n        * Reads one line from the input stream.\n        * @param f Input stream.\n        * @return Content of the line.\n        */\n       static std::string readLine(FILE* f);\n       static const std::string& dereferenceString(const std::string* const input);\n       /**\n        * convert input string into vector of string tokens.\n        *\n        * @note consecutive delimiters will be treated as single delimiter\n        * @note delimiters are _not_ included in return data\n        *\n        * @param input string to be parsed\n        * @param delimiters list of delimiters.\n        * I was too lazy and took it from http://www.rosettacode.org/wiki/Tokenizing_A_String\n        */\n       static std::vector<std::string> splitString(const std::string& input,\n                                                   const std::string& delimiters = \" \\t\");\n       template <class Type>\n       std::string getBinary(Type value);\n       static void skipSpace(const std::string& text, size_t& position);\n       /** Reads words consting of alphaNumeric characters */\n       static std::string readWord(const std::string& text, size_t& position);\n       static std::string readNumber(const std::string& text, size_t& position);\n       static std::string ssprintf(const char* format, ...);\n   };\n }\n\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/Types.h",
    "content": "#pragma once\n\ntypedef unsigned char      u8;\ntypedef signed char        s8;\n\ntypedef unsigned short     u16;\ntypedef signed short       s16;\n\ntypedef unsigned int       u32;\ntypedef signed int         s32;\n\ntypedef unsigned long long u64;\ntypedef signed long long s64;\n\ntypedef u8              _UNKNOWN;\n\ntypedef unsigned char   BYTE;\ntypedef unsigned short  WORD;\ntypedef unsigned long   DWORD;\ntypedef void*           PVOID;\ntypedef int             BOOL;\ntypedef void*           HANDLE;\n\n#ifdef NULL\n#undef NULL\n#endif\n#define NULL 0\n\n#define ever (;;)\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/sha1.cpp",
    "content": "/*\nCopyright (c) 2009, Micael Hildenborg\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Micael Hildenborg nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, ACTIONS, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/*\nContributors:\nGustav\nSeveral members in the gamedev.se forum.\n*/\n \n#include \"sha1.h\"\n#include <string.h>\n\nnamespace sha1\n{\n        namespace // local\n        {\n                inline const unsigned int rol(const unsigned int num, const unsigned int cnt)\n                {\n                        return((num << cnt) | (num >> (32-cnt)));\n                }\n \n                void innerHash(unsigned int *result, unsigned int *w)\n                {\n                        unsigned int save[5];\n                        save[0]=result[0];\n                        save[1]=result[1];\n                        save[2]=result[2];\n                        save[3]=result[3];\n                        save[4]=result[4];\n\n                        #define a result[0]\n                        #define b result[1]\n                        #define c result[2]\n                        #define d result[3]\n                        #define e result[4]\n \n                        int j=0;\n                        #define sha1macro(func,val) \\\n                                {const unsigned int t = rol(a, 5)+(func)+e+val+w[j]; \\\n                                e = d; d = c; \\\n                                c = rol(b, 30); \\\n                                b = a; a = t;}\n                        while(j<16)\n                        {\n                                sha1macro((b&c)|(~b&d),0x5A827999)\n                                j++;\n                        }\n                        while(j<20)\n                        {\n                                w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1);\n                                sha1macro((b&c)|(~b&d),0x5A827999)\n                                j++;\n                        }\n                        while(j<40)\n                        {\n                                w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1);\n                                sha1macro(b^c^d,0x6ED9EBA1)\n                                j++;\n                        }\n                        while(j<60)\n                        {\n                                w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1);\n                                sha1macro((b&c)|(b&d)|(c&d),0x8F1BBCDC)\n                                j++;\n                        }\n                        while(j<80)\n                        {\n                                w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1);\n                                sha1macro(b^c^d,0xCA62C1D6)\n                                j++;\n                        }\n                        #undef sha1macro\n                        #undef a\n                        #undef b\n                        #undef c\n                        #undef d\n                        #undef e\n\n                        result[0]+=save[0];\n                        result[1]+=save[1];\n                        result[2]+=save[2];\n                        result[3]+=save[3];\n                        result[4]+=save[4];\n                }\n        }\n\n        void calc(const void *src, const int bytelength, unsigned char *hash)\n        {\n                // Init the result array, and create references to the five unsigned integers for better readabillity.\n                unsigned int result[5]={0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0};\n\n                const unsigned char *sarray=(const unsigned char*)src;\n                // The variables\n                unsigned int w[80];\n                int j,i,i1;\n                j=0;\n                // Loop through all complete 64byte blocks.\n                for(i=0,i1=64; i<=(bytelength-64); i=i1,i1+=64) \n                {\n                        int k=0;\n                        for(j=i;j<i1;j+=4)\n                        {\n                                // This line will swap endian on big endian and keep endian on little endian.\n                                w[k++]=(unsigned int)sarray[j+3]|(((unsigned int)sarray[j+2])<<8)|(((unsigned int)sarray[j+1])<<16)|(((unsigned int)sarray[j])<<24);\n                        }\n                        innerHash(result,w);\n                }\n                // fill in reminder\n                i1=bytelength-i;\n                memset(w,0,sizeof(unsigned int)*16);\n                for(j=0;j<i1;j++)\n                {\n                        w[j>>2]|=(unsigned int)sarray[j+i]<<((3-(j&3))<<3);\n                }\n                w[j>>2]|=0x80<<((3-(j&3))<<3);\n                if(i1>=56)\n                {\n                        innerHash(result,w);\n                        memset(w,0,sizeof(unsigned int)*16);\n                }\n                w[15]=bytelength<<3;\n                innerHash(result,w);\n                // Store hash in result pointer, and make sure we get in in the correct order on both endian models.\n                for(i=20;--i>=0;) \n                {\n                        hash[i]=(result[i>>2]>>(((3-i)&0x3)<<3))&0xFF;\n                }\n        }\n\n        void toHexString(const unsigned char *hash, char *hexstring)\n        {\n                const char tab[]={\"0123456789abcdef\"};\n                for(int i=20;--i>=0;) \n                {\n                        hexstring[i<<1]=tab[(hash[i]>>4)&0xF];\n                        hexstring[(i<<1)+1]=tab[hash[i]&0xF];\n                }\n                hexstring[40]=0;\n        }\n}\n"
  },
  {
    "path": "SparCraft/bwapidata/include/Util/sha1.h",
    "content": "// sha1.h and sha1.cpp are from code.google.com/p/smallsha1/\n/*\nCopyright (c) 2009, Micael Hildenborg\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Micael Hildenborg nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, ACTIONS, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef SHA1_DEFINED\n#define SHA1_DEFINED\n\nnamespace sha1\n{\n        /**\n                @param src points to any kind of data to be hashed.\n                @param bytelength the number of bytes to hash from the src pointer.\n                @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.\n        */\n        void calc(const void *src, const int bytelength, unsigned char *hash);\n        /**\n                @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.\n                @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.\n        */\n        void toHexString(const unsigned char *hash, char *hexstring);\n}; // namespace sha1\n\n#endif // SHA1_DEFINED\n\n"
  },
  {
    "path": "SparCraft/bwapidata/include/WeaponType.cpp",
    "content": "#include <string>\n#include <map>\n#include <set>\n#include <BWAPI/UnitType.h>\n#include <BWAPI/WeaponType.h>\n#include <BWAPI/TechType.h>\n#include <BWAPI/UpgradeType.h>\n#include <BWAPI/DamageType.h>\n#include <BWAPI/ExplosionType.h>\n#include <Util/Foreach.h>\n\n#include \"Common.h\"\n\nnamespace BWAPI\n{\n  bool initializingWeaponType = true;\n  class WeaponTypeInternal\n  {\n    public:\n      WeaponTypeInternal() {valid = false;}\n      void set(const char* name, TechType techType, int damageAmount, int damageBonus, int damageCooldown, int damageFactor, UpgradeType upgradeType, DamageType damageType, ExplosionType explosionType, int minRange, int maxRange, int innerSplashRadius, int medianSplashRadius, int outerSplashRadius, bool targetsAir, bool targetsGround, bool targetsMechanical, bool targetsOrganic, bool targetsNonBuilding, bool targetsNonRobotic, bool targetsTerrain, bool targetsOrgOrMech, bool targetsOwn, UnitType whatUses)\n      {\n        if (initializingWeaponType)\n        {\n          this->name               = name;\n          this->techType           = techType;\n          this->damageAmount       = damageAmount;\n          this->damageBonus        = damageBonus;\n          this->damageCooldown     = damageCooldown;\n          this->damageFactor       = damageFactor;\n          this->upgradeType        = upgradeType;\n          this->damageType         = damageType;\n          this->explosionType      = explosionType;\n          this->minRange           = minRange;\n          this->maxRange           = maxRange;\n          this->innerSplashRadius  = innerSplashRadius;\n          this->medianSplashRadius = medianSplashRadius;\n          this->outerSplashRadius  = outerSplashRadius;\n          this->targetsAir         = targetsAir;\n          this->targetsGround      = targetsGround;\n          this->targetsMechanical  = targetsMechanical;\n          this->targetsOrganic     = targetsOrganic;\n          this->targetsNonBuilding = targetsNonBuilding;\n          this->targetsNonRobotic  = targetsNonRobotic;\n          this->targetsTerrain     = targetsTerrain;\n          this->targetsOrgOrMech   = targetsOrgOrMech;\n          this->targetsOwn         = targetsOwn;\n          this->whatUses           = whatUses;\n          this->valid              = true;\n        }\n      }\n      std::string name;\n      TechType techType;\n      UnitType whatUses;\n      int damageAmount;\n      int damageBonus;\n      int damageCooldown;\n      int damageFactor;\n      UpgradeType upgradeType;\n      DamageType damageType;\n      ExplosionType explosionType;\n      int minRange;\n      int maxRange;\n      int innerSplashRadius;\n      int medianSplashRadius;\n      int outerSplashRadius;\n      bool targetsAir;\n      bool targetsGround;\n      bool targetsMechanical;\n      bool targetsOrganic;\n      bool targetsNonBuilding;\n      bool targetsNonRobotic;\n      bool targetsTerrain;\n      bool targetsOrgOrMech;\n      bool targetsOwn;\n      bool valid;\n  };\n  WeaponTypeInternal weaponTypeData[132];\n  std::map<std::string, WeaponType> weaponTypeMap;\n  std::set< WeaponType > weaponTypeSet;\n  std::set< WeaponType > specialWeaponTypeSet;\n  std::set< WeaponType > normalWeaponTypeSet;\n  namespace WeaponTypes\n  {\n    const WeaponType Gauss_Rifle(0);\n    const WeaponType Gauss_Rifle_Jim_Raynor(1);\n    const WeaponType C_10_Canister_Rifle(2);\n    const WeaponType C_10_Canister_Rifle_Sarah_Kerrigan(3);\n    const WeaponType C_10_Canister_Rifle_Samir_Duran(112);\n    const WeaponType C_10_Canister_Rifle_Infested_Duran(113);\n    const WeaponType C_10_Canister_Rifle_Alexei_Stukov(116);\n    const WeaponType Fragmentation_Grenade(4);\n    const WeaponType Fragmentation_Grenade_Jim_Raynor(5);\n    const WeaponType Spider_Mines(6);\n    const WeaponType Twin_Autocannons(7);\n    const WeaponType Twin_Autocannons_Alan_Schezar(9);\n    const WeaponType Hellfire_Missile_Pack(8);\n    const WeaponType Hellfire_Missile_Pack_Alan_Schezar(10);\n    const WeaponType Arclite_Cannon(11);\n    const WeaponType Arclite_Cannon_Edmund_Duke(12);\n    const WeaponType Fusion_Cutter(13);\n    const WeaponType Gemini_Missiles(15);\n    const WeaponType Gemini_Missiles_Tom_Kazansky(17);\n    const WeaponType Burst_Lasers(16);\n    const WeaponType Burst_Lasers_Tom_Kazansky(18);\n    const WeaponType ATS_Laser_Battery(19);\n    const WeaponType ATS_Laser_Battery_Hero(21);\n    const WeaponType ATS_Laser_Battery_Hyperion(23);\n    const WeaponType ATA_Laser_Battery(20);\n    const WeaponType ATA_Laser_Battery_Hero(22);\n    const WeaponType ATA_Laser_Battery_Hyperion(24);\n    const WeaponType Flame_Thrower(25);\n    const WeaponType Flame_Thrower_Gui_Montag(26);\n    const WeaponType Arclite_Shock_Cannon(27);\n    const WeaponType Arclite_Shock_Cannon_Edmund_Duke(28);\n    const WeaponType Longbolt_Missile(29);\n    const WeaponType Claws(35);\n    const WeaponType Claws_Devouring_One(36);\n    const WeaponType Claws_Infested_Kerrigan(37);\n    const WeaponType Needle_Spines(38);\n    const WeaponType Needle_Spines_Hunter_Killer(39);\n    const WeaponType Kaiser_Blades(40);\n    const WeaponType Kaiser_Blades_Torrasque(41);\n    const WeaponType Toxic_Spores(42);\n    const WeaponType Spines(43);\n    const WeaponType Acid_Spore(46);\n    const WeaponType Acid_Spore_Kukulza(47);\n    const WeaponType Glave_Wurm(48);\n    const WeaponType Glave_Wurm_Kukulza(49);\n    const WeaponType Seeker_Spores(52);\n    const WeaponType Subterranean_Tentacle(53);\n    const WeaponType Suicide_Infested_Terran(54);\n    const WeaponType Suicide_Scourge(55);\n    const WeaponType Particle_Beam(62);\n    const WeaponType Psi_Blades(64);\n    const WeaponType Psi_Blades_Fenix(65);\n    const WeaponType Phase_Disruptor(66);\n    const WeaponType Phase_Disruptor_Fenix(67);\n    const WeaponType Psi_Assault(69);\n    const WeaponType Psionic_Shockwave(70);\n    const WeaponType Psionic_Shockwave_TZ_Archon(71);\n    const WeaponType Dual_Photon_Blasters(73);\n    const WeaponType Dual_Photon_Blasters_Mojo(75);\n    const WeaponType Dual_Photon_Blasters_Artanis(114);\n    const WeaponType Anti_Matter_Missiles(74);\n    const WeaponType Anti_Matter_Missiles_Mojo(76);\n    const WeaponType Anti_Matter_Missiles_Artanis(115);\n    const WeaponType Phase_Disruptor_Cannon(77);\n    const WeaponType Phase_Disruptor_Cannon_Danimoth(78);\n    const WeaponType Pulse_Cannon(79);\n    const WeaponType STS_Photon_Cannon(80);\n    const WeaponType STA_Photon_Cannon(81);\n    const WeaponType Scarab(82);\n    const WeaponType Subterranean_Spines(109);\n    const WeaponType Warp_Blades(111);\n    const WeaponType Warp_Blades_Hero(86);\n    const WeaponType Warp_Blades_Zeratul(85);\n    const WeaponType Neutron_Flare(100);\n    const WeaponType Halo_Rockets(103);\n\n    const WeaponType Yamato_Gun(30);\n    const WeaponType Nuclear_Strike(31);\n    const WeaponType Lockdown(32);\n    const WeaponType EMP_Shockwave(33);\n    const WeaponType Irradiate(34);\n    const WeaponType Parasite(56);\n    const WeaponType Spawn_Broodlings(57);\n    const WeaponType Ensnare(58);\n    const WeaponType Dark_Swarm(59);\n    const WeaponType Plague(60);\n    const WeaponType Consume(61);\n    const WeaponType Stasis_Field(83);\n    const WeaponType Psionic_Storm(84);\n    const WeaponType Disruption_Web(101);\n    const WeaponType Restoration(102);\n    const WeaponType Corrosive_Acid(104);\n    const WeaponType Mind_Control(105);\n    const WeaponType Feedback(106);\n    const WeaponType Optical_Flare(107);\n    const WeaponType Maelstrom(108);\n    const WeaponType None(130);\n    const WeaponType Unknown(131);\n\n    void init()\n    {\n      weaponTypeData[Gauss_Rifle.getID()].set(\"Gauss Rifle\", TechTypes::None, 6, 1, 15, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Marine);\n      weaponTypeData[Gauss_Rifle_Jim_Raynor.getID()].set(\"Gauss Rifle (Jim Raynor)\", TechTypes::None, 18, 1, 15, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Jim_Raynor_Marine);\n      weaponTypeData[C_10_Canister_Rifle.getID()].set(\"C-10 Canister Rifle\", TechTypes::None, 10, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Ghost);\n      weaponTypeData[C_10_Canister_Rifle_Sarah_Kerrigan.getID()].set(\"C-10 Canister Rifle (Sarah Kerrigan)\", TechTypes::None, 30, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Sarah_Kerrigan);\n      weaponTypeData[C_10_Canister_Rifle_Samir_Duran.getID()].set(\"C-10 Canister Rifle (Samir Duran)\", TechTypes::None, 25, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Samir_Duran);\n      weaponTypeData[C_10_Canister_Rifle_Infested_Duran.getID()].set(\"C-10 Canister Rifle (Infested Duran)\", TechTypes::None, 25, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Infested_Duran);\n      weaponTypeData[C_10_Canister_Rifle_Alexei_Stukov.getID()].set(\"C-10 Canister Rifle (Alexei Stukov)\", TechTypes::None, 30, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alexei_Stukov);\n      weaponTypeData[Fragmentation_Grenade.getID()].set(\"Fragmentation Grenade\", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Vulture);\n      weaponTypeData[Fragmentation_Grenade_Jim_Raynor.getID()].set(\"Fragmentation Grenade (Jim Raynor)\", TechTypes::None, 30, 2, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Jim_Raynor_Vulture);\n      weaponTypeData[Spider_Mines.getID()].set(\"Spider Mines\", TechTypes::Spider_Mines, 125, 0, 22, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 0, 10, 50, 75, 100, 0, 1, 0, 0, 1, 0, 0, 0, 0, UnitTypes::Terran_Vulture_Spider_Mine);\n      weaponTypeData[Twin_Autocannons.getID()].set(\"Twin Autocannons\", TechTypes::None, 12, 1, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Goliath);\n      weaponTypeData[Twin_Autocannons_Alan_Schezar.getID()].set(\"Twin Autocannons (Alan Schezar)\", TechTypes::None, 24, 1, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alan_Schezar);\n      weaponTypeData[Hellfire_Missile_Pack.getID()].set(\"Hellfire Missile Pack\", TechTypes::None, 10, 2, 22, 2, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Goliath);\n      weaponTypeData[Hellfire_Missile_Pack_Alan_Schezar.getID()].set(\"Hellfire Missile Pack (Alan Schezar)\", TechTypes::None, 20, 1, 22, 2, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alan_Schezar);\n      weaponTypeData[Arclite_Cannon.getID()].set(\"Arclite Cannon\", TechTypes::None, 30, 3, 37, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Siege_Tank_Tank_Mode);\n      weaponTypeData[Arclite_Cannon_Edmund_Duke.getID()].set(\"Arclite Cannon (Edmund Duke)\", TechTypes::None, 70, 3, 37, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Edmund_Duke_Tank_Mode);\n      weaponTypeData[Fusion_Cutter.getID()].set(\"Fusion Cutter\", TechTypes::None, 5, 1, 15, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_SCV);\n      weaponTypeData[Gemini_Missiles.getID()].set(\"Gemini Missiles\", TechTypes::None, 20, 2, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Wraith);\n      weaponTypeData[Gemini_Missiles_Tom_Kazansky.getID()].set(\"Gemini Missiles (Tom Kazansky)\", TechTypes::None, 40, 2, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tom_Kazansky);\n      weaponTypeData[Burst_Lasers.getID()].set(\"Burst Lasers\", TechTypes::None, 8, 1, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Wraith);\n      weaponTypeData[Burst_Lasers_Tom_Kazansky.getID()].set(\"Burst Lasers (Tom Kazansky)\", TechTypes::None, 16, 1, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tom_Kazansky);\n      weaponTypeData[ATS_Laser_Battery.getID()].set(\"ATS Laser Battery\", TechTypes::None, 25, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser);\n      weaponTypeData[ATS_Laser_Battery_Hero.getID()].set(\"ATS Laser Battery (Hero)\", TechTypes::None, 50, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Norad_II);\n      weaponTypeData[ATS_Laser_Battery_Hyperion.getID()].set(\"ATS Laser Battery (Hyperion)\", TechTypes::None, 30, 3, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hyperion);\n      weaponTypeData[ATA_Laser_Battery.getID()].set(\"ATA Laser Battery\", TechTypes::None, 25, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser);\n      weaponTypeData[ATA_Laser_Battery_Hero.getID()].set(\"ATA Laser Battery (Hero)\", TechTypes::None, 50, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Norad_II);\n      weaponTypeData[ATA_Laser_Battery_Hyperion.getID()].set(\"ATA Laser Battery (Hyperion)\", TechTypes::None, 30, 3, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hyperion);\n      weaponTypeData[Flame_Thrower.getID()].set(\"Flame Thrower\", TechTypes::None, 8, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Enemy_Splash, 0, 32, 15, 20, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Firebat);\n      weaponTypeData[Flame_Thrower_Gui_Montag.getID()].set(\"Flame Thrower (Gui Montag)\", TechTypes::None, 16, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Enemy_Splash, 0, 32, 15, 20, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Firebat);\n      weaponTypeData[Arclite_Shock_Cannon.getID()].set(\"Arclite Shock Cannon\", TechTypes::None, 70, 5, 75, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 64, 384, 10, 25, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Siege_Tank_Siege_Mode);\n      weaponTypeData[Arclite_Shock_Cannon_Edmund_Duke.getID()].set(\"Arclite Shock Cannon (Edmund Duke)\", TechTypes::None, 150, 5, 75, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 64, 384, 10, 25, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Edmund_Duke_Siege_Mode);\n      weaponTypeData[Longbolt_Missile.getID()].set(\"Longbolt Missile\", TechTypes::None, 20, 0, 15, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Missile_Turret);\n      weaponTypeData[Yamato_Gun.getID()].set(\"Yamato Gun\", TechTypes::Yamato_Gun, 260, 0, 15, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Yamato_Gun, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser);\n      weaponTypeData[Nuclear_Strike.getID()].set(\"Nuclear Strike\", TechTypes::Nuclear_Strike, 600, 0, 1, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Nuclear_Missile, 0, 3, 128, 192, 256, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Ghost);\n      weaponTypeData[Lockdown.getID()].set(\"Lockdown\", TechTypes::Lockdown, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Concussive, ExplosionTypes::Lockdown, 0, 256, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, UnitTypes::Terran_Ghost);\n      weaponTypeData[EMP_Shockwave.getID()].set(\"EMP Shockwave\", TechTypes::EMP_Shockwave, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Concussive, ExplosionTypes::EMP_Shockwave, 0, 256, 64, 64, 64, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Science_Vessel);\n      weaponTypeData[Irradiate.getID()].set(\"Irradiate\", TechTypes::Irradiate, 250, 0, 75, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Irradiate, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Science_Vessel);\n      weaponTypeData[Claws.getID()].set(\"Claws\", TechTypes::None, 5, 1, 8, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Zergling);\n      weaponTypeData[Claws_Devouring_One.getID()].set(\"Claws (Devouring One)\", TechTypes::None, 10, 1, 8, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Devouring_One);\n      weaponTypeData[Claws_Infested_Kerrigan.getID()].set(\"Claws (Infested Kerrigan)\", TechTypes::None, 50, 1, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Infested_Kerrigan);\n      weaponTypeData[Needle_Spines.getID()].set(\"Needle Spines\", TechTypes::None, 10, 1, 15, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Hydralisk);\n      weaponTypeData[Needle_Spines_Hunter_Killer.getID()].set(\"Needle Spines (Hunter Killer)\", TechTypes::None, 20, 1, 15, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hunter_Killer);\n      weaponTypeData[Kaiser_Blades.getID()].set(\"Kaiser Blades\", TechTypes::None, 20, 3, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 25, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Ultralisk);\n      weaponTypeData[Kaiser_Blades_Torrasque.getID()].set(\"Kaiser Blades (Torrasque)\", TechTypes::None, 50, 3, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 25, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Torrasque);\n      weaponTypeData[Toxic_Spores.getID()].set(\"Toxic Spores\", TechTypes::None, 4, 1, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Broodling);\n      weaponTypeData[Spines.getID()].set(\"Spines\", TechTypes::None, 5, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Drone);\n      weaponTypeData[Acid_Spore.getID()].set(\"Acid Spore\", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 256, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Guardian);\n      weaponTypeData[Acid_Spore_Kukulza.getID()].set(\"Acid Spore (Kukulza)\", TechTypes::None, 40, 2, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 256, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Kukulza_Guardian);\n      weaponTypeData[Glave_Wurm.getID()].set(\"Glave Wurm\", TechTypes::None, 9, 1, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Mutalisk);\n      weaponTypeData[Glave_Wurm_Kukulza.getID()].set(\"Glave Wurm (Kukulza)\", TechTypes::None, 18, 1, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Kukulza_Mutalisk);\n      weaponTypeData[Seeker_Spores.getID()].set(\"Seeker Spores\", TechTypes::None, 15, 0, 15, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Spore_Colony);\n      weaponTypeData[Subterranean_Tentacle.getID()].set(\"Subterranean Tentacle\", TechTypes::None, 40, 0, 32, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Sunken_Colony);\n      weaponTypeData[Suicide_Infested_Terran.getID()].set(\"Suicide Infested Terran\", TechTypes::None, 500, 0, 1, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 0, 3, 20, 40, 60, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Infested_Terran);\n      weaponTypeData[Suicide_Scourge.getID()].set(\"Suicide Scourge\", TechTypes::None, 110, 0, 1, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Scourge);\n      weaponTypeData[Parasite.getID()].set(\"Parasite\", TechTypes::Parasite, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Parasite, 0, 384, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, UnitTypes::Zerg_Queen);\n      weaponTypeData[Spawn_Broodlings.getID()].set(\"Spawn Broodlings\", TechTypes::Spawn_Broodlings, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Broodlings, 0, 288, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, UnitTypes::Zerg_Queen);\n      weaponTypeData[Ensnare.getID()].set(\"Ensnare\", TechTypes::Ensnare, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Ensnare, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Zerg_Queen);\n      weaponTypeData[Dark_Swarm.getID()].set(\"Dark Swarm\", TechTypes::Dark_Swarm, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Dark_Swarm, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Defiler);\n      weaponTypeData[Plague.getID()].set(\"Plague\", TechTypes::Plague, 300, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Plague, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Zerg_Defiler);\n      weaponTypeData[Consume.getID()].set(\"Consume\", TechTypes::Consume, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Consume, 0, 16, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, UnitTypes::Zerg_Defiler);\n      weaponTypeData[Particle_Beam.getID()].set(\"Particle Beam\", TechTypes::None, 5, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Probe);\n      weaponTypeData[Psi_Blades.getID()].set(\"Psi Blades\", TechTypes::None, 8, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Zealot);\n      weaponTypeData[Psi_Blades_Fenix.getID()].set(\"Psi Blades (Fenix)\", TechTypes::None, 20, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Fenix_Zealot);\n      weaponTypeData[Phase_Disruptor.getID()].set(\"Phase Disruptor\", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Dragoon);\n      weaponTypeData[Phase_Disruptor_Fenix.getID()].set(\"Phase Disruptor (Fenix)\", TechTypes::None, 45, 2, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Fenix_Dragoon);\n      weaponTypeData[Psi_Assault.getID()].set(\"Psi Assault\", TechTypes::None, 20, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tassadar);\n      weaponTypeData[Psionic_Shockwave.getID()].set(\"Psionic Shockwave\", TechTypes::None, 30, 3, 20, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 64, 3, 15, 30, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Archon);\n      weaponTypeData[Psionic_Shockwave_TZ_Archon.getID()].set(\"Psionic Shockwave (Tassadar/Zeratul Archon)\", TechTypes::None, 60, 3, 20, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 64, 3, 15, 30, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tassadar_Zeratul_Archon);\n      weaponTypeData[Dual_Photon_Blasters.getID()].set(\"Dual Photon Blasters\", TechTypes::None, 8, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scout);\n      weaponTypeData[Dual_Photon_Blasters_Mojo.getID()].set(\"Dual Photon Blasters (Mojo)\", TechTypes::None, 20, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Mojo);\n      weaponTypeData[Dual_Photon_Blasters_Artanis.getID()].set(\"Dual Photon Blasters (Artanis)\", TechTypes::None, 20, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Artanis);\n      weaponTypeData[Anti_Matter_Missiles.getID()].set(\"Anti-Matter Missiles\", TechTypes::None, 14, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scout);\n      weaponTypeData[Anti_Matter_Missiles_Mojo.getID()].set(\"Anti-Matter Missiles (Mojo)\", TechTypes::None, 28, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Mojo);\n      weaponTypeData[Anti_Matter_Missiles_Artanis.getID()].set(\"Anti-Matter Missiles (Artanis)\", TechTypes::None, 28, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Artanis);\n      weaponTypeData[Phase_Disruptor_Cannon.getID()].set(\"Phase Disruptor Cannon\", TechTypes::None, 10, 1, 45, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Arbiter);\n      weaponTypeData[Phase_Disruptor_Cannon_Danimoth.getID()].set(\"Phase Disruptor Cannon (Danimoth)\", TechTypes::None, 20, 1, 45, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Danimoth);\n      weaponTypeData[Pulse_Cannon.getID()].set(\"Pulse Cannon\", TechTypes::None, 6, 1, 1, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Interceptor);\n      weaponTypeData[STS_Photon_Cannon.getID()].set(\"STS Photon Cannon\", TechTypes::None, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Photon_Cannon);\n      weaponTypeData[STA_Photon_Cannon.getID()].set(\"STA Photon Cannon\", TechTypes::None, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Photon_Cannon);\n      weaponTypeData[Scarab.getID()].set(\"Scarab\", TechTypes::None, 100, 25, 1, 1, UpgradeTypes::Scarab_Damage, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 128, 20, 40, 60, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scarab);\n      weaponTypeData[Stasis_Field.getID()].set(\"Stasis Field\", TechTypes::Stasis_Field, 0, 1, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Stasis_Field, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Arbiter);\n      weaponTypeData[Psionic_Storm.getID()].set(\"Psionic Storm\", TechTypes::Psionic_Storm, 14, 1, 45, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Radial_Splash, 0, 288, 48, 48, 48, 1, 1, 0, 0, 1, 0, 1, 0, 0, UnitTypes::Protoss_High_Templar);\n      weaponTypeData[Neutron_Flare.getID()].set(\"Neutron Flare\", TechTypes::None, 5, 1, 8, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Air_Splash, 0, 160, 5, 50, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Corsair);\n      weaponTypeData[Disruption_Web.getID()].set(\"Disruption Web\", TechTypes::Disruption_Web, 0, 0, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Disruption_Web, 0, 288, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Corsair);\n      weaponTypeData[Restoration.getID()].set(\"Restoration\", TechTypes::Restoration, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Restoration, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Medic);\n      weaponTypeData[Halo_Rockets.getID()].set(\"Halo Rockets\", TechTypes::None, 6, 1, 64, 2, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Air_Splash, 0, 192, 5, 50, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Valkyrie);\n      weaponTypeData[Corrosive_Acid.getID()].set(\"Corrosive Acid\", TechTypes::None, 25, 2, 100, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Explosive, ExplosionTypes::Corrosive_Acid, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Devourer);\n      weaponTypeData[Mind_Control.getID()].set(\"Mind Control\", TechTypes::Mind_Control, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Mind_Control, 0, 256, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon);\n      weaponTypeData[Feedback.getID()].set(\"Feedback\", TechTypes::Feedback, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Feedback, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon);\n      weaponTypeData[Optical_Flare.getID()].set(\"Optical Flare\", TechTypes::Optical_Flare, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Optical_Flare, 0, 288, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Medic);\n      weaponTypeData[Maelstrom.getID()].set(\"Maelstrom\", TechTypes::Maelstrom, 0, 1, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Maelstrom, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon);\n      weaponTypeData[Subterranean_Spines.getID()].set(\"Subterranean Spines\", TechTypes::None, 20, 2, 37, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 192, 20, 20, 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Lurker);\n      weaponTypeData[Warp_Blades.getID()].set(\"Warp Blades\", TechTypes::None, 40, 3, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Dark_Templar);\n      weaponTypeData[Warp_Blades_Hero.getID()].set(\"Warp Blades (Hero)\", TechTypes::None, 45, 1, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Dark_Templar);\n      weaponTypeData[Warp_Blades_Zeratul.getID()].set(\"Warp Blades (Zeratul)\", TechTypes::None, 100, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Zeratul);\n      weaponTypeData[None.getID()].set(\"None\", TechTypes::None, 0, 0, 0, 0, UpgradeTypes::None, DamageTypes::None, ExplosionTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::None);\n      weaponTypeData[Unknown.getID()].set(\"Unknown\", TechTypes::None, 0, 0, 0, 0, UpgradeTypes::None, DamageTypes::None, ExplosionTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::None);\n\n      weaponTypeSet.insert(Gauss_Rifle);\n      weaponTypeSet.insert(Gauss_Rifle_Jim_Raynor);\n      weaponTypeSet.insert(C_10_Canister_Rifle);\n      weaponTypeSet.insert(C_10_Canister_Rifle_Sarah_Kerrigan);\n      weaponTypeSet.insert(C_10_Canister_Rifle_Samir_Duran);\n      weaponTypeSet.insert(C_10_Canister_Rifle_Infested_Duran);\n      weaponTypeSet.insert(C_10_Canister_Rifle_Alexei_Stukov);\n      weaponTypeSet.insert(Fragmentation_Grenade);\n      weaponTypeSet.insert(Fragmentation_Grenade_Jim_Raynor);\n      weaponTypeSet.insert(Spider_Mines);\n      weaponTypeSet.insert(Twin_Autocannons);\n      weaponTypeSet.insert(Twin_Autocannons_Alan_Schezar);\n      weaponTypeSet.insert(Hellfire_Missile_Pack);\n      weaponTypeSet.insert(Hellfire_Missile_Pack_Alan_Schezar);\n      weaponTypeSet.insert(Arclite_Cannon);\n      weaponTypeSet.insert(Arclite_Cannon_Edmund_Duke);\n      weaponTypeSet.insert(Fusion_Cutter);\n      weaponTypeSet.insert(Gemini_Missiles);\n      weaponTypeSet.insert(Gemini_Missiles_Tom_Kazansky);\n      weaponTypeSet.insert(Burst_Lasers);\n      weaponTypeSet.insert(Burst_Lasers_Tom_Kazansky);\n      weaponTypeSet.insert(ATS_Laser_Battery);\n      weaponTypeSet.insert(ATS_Laser_Battery_Hero);\n      weaponTypeSet.insert(ATS_Laser_Battery_Hyperion);\n      weaponTypeSet.insert(ATA_Laser_Battery);\n      weaponTypeSet.insert(ATA_Laser_Battery_Hero);\n      weaponTypeSet.insert(ATA_Laser_Battery_Hyperion);\n      weaponTypeSet.insert(Flame_Thrower);\n      weaponTypeSet.insert(Flame_Thrower_Gui_Montag);\n      weaponTypeSet.insert(Arclite_Shock_Cannon);\n      weaponTypeSet.insert(Arclite_Shock_Cannon_Edmund_Duke);\n      weaponTypeSet.insert(Longbolt_Missile);\n      weaponTypeSet.insert(Claws);\n      weaponTypeSet.insert(Claws_Devouring_One);\n      weaponTypeSet.insert(Claws_Infested_Kerrigan);\n      weaponTypeSet.insert(Needle_Spines);\n      weaponTypeSet.insert(Needle_Spines_Hunter_Killer);\n      weaponTypeSet.insert(Kaiser_Blades);\n      weaponTypeSet.insert(Kaiser_Blades_Torrasque);\n      weaponTypeSet.insert(Toxic_Spores);\n      weaponTypeSet.insert(Spines);\n      weaponTypeSet.insert(Acid_Spore);\n      weaponTypeSet.insert(Acid_Spore_Kukulza);\n      weaponTypeSet.insert(Glave_Wurm);\n      weaponTypeSet.insert(Glave_Wurm_Kukulza);\n      weaponTypeSet.insert(Seeker_Spores);\n      weaponTypeSet.insert(Subterranean_Tentacle);\n      weaponTypeSet.insert(Suicide_Infested_Terran);\n      weaponTypeSet.insert(Suicide_Scourge);\n      weaponTypeSet.insert(Particle_Beam);\n      weaponTypeSet.insert(Psi_Blades);\n      weaponTypeSet.insert(Psi_Blades_Fenix);\n      weaponTypeSet.insert(Phase_Disruptor);\n      weaponTypeSet.insert(Phase_Disruptor_Fenix);\n      weaponTypeSet.insert(Psi_Assault);\n      weaponTypeSet.insert(Psionic_Shockwave);\n      weaponTypeSet.insert(Psionic_Shockwave_TZ_Archon);\n      weaponTypeSet.insert(Dual_Photon_Blasters);\n      weaponTypeSet.insert(Dual_Photon_Blasters_Mojo);\n      weaponTypeSet.insert(Dual_Photon_Blasters_Artanis);\n      weaponTypeSet.insert(Anti_Matter_Missiles);\n      weaponTypeSet.insert(Anti_Matter_Missiles_Mojo);\n      weaponTypeSet.insert(Anti_Matter_Missiles_Artanis);\n      weaponTypeSet.insert(Phase_Disruptor_Cannon);\n      weaponTypeSet.insert(Phase_Disruptor_Cannon_Danimoth);\n      weaponTypeSet.insert(Pulse_Cannon);\n      weaponTypeSet.insert(STS_Photon_Cannon);\n      weaponTypeSet.insert(STA_Photon_Cannon);\n      weaponTypeSet.insert(Scarab);\n      weaponTypeSet.insert(Neutron_Flare);\n      weaponTypeSet.insert(Halo_Rockets);\n      weaponTypeSet.insert(Corrosive_Acid);\n      weaponTypeSet.insert(Subterranean_Spines);\n      weaponTypeSet.insert(Warp_Blades);\n      weaponTypeSet.insert(Warp_Blades_Hero);\n      weaponTypeSet.insert(Warp_Blades_Zeratul);\n\n      normalWeaponTypeSet.insert(Gauss_Rifle);\n      normalWeaponTypeSet.insert(Gauss_Rifle_Jim_Raynor);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle_Sarah_Kerrigan);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle_Samir_Duran);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle_Infested_Duran);\n      normalWeaponTypeSet.insert(C_10_Canister_Rifle_Alexei_Stukov);\n      normalWeaponTypeSet.insert(Fragmentation_Grenade);\n      normalWeaponTypeSet.insert(Fragmentation_Grenade_Jim_Raynor);\n      normalWeaponTypeSet.insert(Spider_Mines);\n      normalWeaponTypeSet.insert(Twin_Autocannons);\n      normalWeaponTypeSet.insert(Twin_Autocannons_Alan_Schezar);\n      normalWeaponTypeSet.insert(Hellfire_Missile_Pack);\n      normalWeaponTypeSet.insert(Hellfire_Missile_Pack_Alan_Schezar);\n      normalWeaponTypeSet.insert(Arclite_Cannon);\n      normalWeaponTypeSet.insert(Arclite_Cannon_Edmund_Duke);\n      normalWeaponTypeSet.insert(Fusion_Cutter);\n      normalWeaponTypeSet.insert(Gemini_Missiles);\n      normalWeaponTypeSet.insert(Gemini_Missiles_Tom_Kazansky);\n      normalWeaponTypeSet.insert(Burst_Lasers);\n      normalWeaponTypeSet.insert(Burst_Lasers_Tom_Kazansky);\n      normalWeaponTypeSet.insert(ATS_Laser_Battery);\n      normalWeaponTypeSet.insert(ATS_Laser_Battery_Hero);\n      normalWeaponTypeSet.insert(ATS_Laser_Battery_Hyperion);\n      normalWeaponTypeSet.insert(ATA_Laser_Battery);\n      normalWeaponTypeSet.insert(ATA_Laser_Battery_Hero);\n      normalWeaponTypeSet.insert(ATA_Laser_Battery_Hyperion);\n      normalWeaponTypeSet.insert(Flame_Thrower);\n      normalWeaponTypeSet.insert(Flame_Thrower_Gui_Montag);\n      normalWeaponTypeSet.insert(Arclite_Shock_Cannon);\n      normalWeaponTypeSet.insert(Arclite_Shock_Cannon_Edmund_Duke);\n      normalWeaponTypeSet.insert(Longbolt_Missile);\n      normalWeaponTypeSet.insert(Claws);\n      normalWeaponTypeSet.insert(Claws_Devouring_One);\n      normalWeaponTypeSet.insert(Claws_Infested_Kerrigan);\n      normalWeaponTypeSet.insert(Needle_Spines);\n      normalWeaponTypeSet.insert(Needle_Spines_Hunter_Killer);\n      normalWeaponTypeSet.insert(Kaiser_Blades);\n      normalWeaponTypeSet.insert(Kaiser_Blades_Torrasque);\n      normalWeaponTypeSet.insert(Toxic_Spores);\n      normalWeaponTypeSet.insert(Spines);\n      normalWeaponTypeSet.insert(Acid_Spore);\n      normalWeaponTypeSet.insert(Acid_Spore_Kukulza);\n      normalWeaponTypeSet.insert(Glave_Wurm);\n      normalWeaponTypeSet.insert(Glave_Wurm_Kukulza);\n      normalWeaponTypeSet.insert(Seeker_Spores);\n      normalWeaponTypeSet.insert(Subterranean_Tentacle);\n      normalWeaponTypeSet.insert(Suicide_Infested_Terran);\n      normalWeaponTypeSet.insert(Suicide_Scourge);\n      normalWeaponTypeSet.insert(Particle_Beam);\n      normalWeaponTypeSet.insert(Psi_Blades);\n      normalWeaponTypeSet.insert(Psi_Blades_Fenix);\n      normalWeaponTypeSet.insert(Phase_Disruptor);\n      normalWeaponTypeSet.insert(Phase_Disruptor_Fenix);\n      normalWeaponTypeSet.insert(Psi_Assault);\n      normalWeaponTypeSet.insert(Psionic_Shockwave);\n      normalWeaponTypeSet.insert(Psionic_Shockwave_TZ_Archon);\n      normalWeaponTypeSet.insert(Dual_Photon_Blasters);\n      normalWeaponTypeSet.insert(Dual_Photon_Blasters_Mojo);\n      normalWeaponTypeSet.insert(Dual_Photon_Blasters_Artanis);\n      normalWeaponTypeSet.insert(Anti_Matter_Missiles);\n      normalWeaponTypeSet.insert(Anti_Matter_Missiles_Mojo);\n      normalWeaponTypeSet.insert(Anti_Matter_Missiles_Artanis);\n      normalWeaponTypeSet.insert(Phase_Disruptor_Cannon);\n      normalWeaponTypeSet.insert(Phase_Disruptor_Cannon_Danimoth);\n      normalWeaponTypeSet.insert(Pulse_Cannon);\n      normalWeaponTypeSet.insert(STS_Photon_Cannon);\n      normalWeaponTypeSet.insert(STA_Photon_Cannon);\n      normalWeaponTypeSet.insert(Scarab);\n      normalWeaponTypeSet.insert(Neutron_Flare);\n      normalWeaponTypeSet.insert(Halo_Rockets);\n      normalWeaponTypeSet.insert(Corrosive_Acid);\n      normalWeaponTypeSet.insert(Subterranean_Spines);\n      normalWeaponTypeSet.insert(Warp_Blades);\n      normalWeaponTypeSet.insert(Warp_Blades_Hero);\n      normalWeaponTypeSet.insert(Warp_Blades_Zeratul);\n\n      weaponTypeSet.insert(Yamato_Gun);\n      weaponTypeSet.insert(Nuclear_Strike);\n      weaponTypeSet.insert(Lockdown);\n      weaponTypeSet.insert(EMP_Shockwave);\n      weaponTypeSet.insert(Irradiate);\n      weaponTypeSet.insert(Parasite);\n      weaponTypeSet.insert(Spawn_Broodlings);\n      weaponTypeSet.insert(Ensnare);\n      weaponTypeSet.insert(Dark_Swarm);\n      weaponTypeSet.insert(Plague);\n      weaponTypeSet.insert(Consume);\n      weaponTypeSet.insert(Stasis_Field);\n      weaponTypeSet.insert(Psionic_Storm);\n      weaponTypeSet.insert(Disruption_Web);\n      weaponTypeSet.insert(Restoration);\n      weaponTypeSet.insert(Mind_Control);\n      weaponTypeSet.insert(Feedback);\n      weaponTypeSet.insert(Optical_Flare);\n      weaponTypeSet.insert(Maelstrom);\n\n      specialWeaponTypeSet.insert(Yamato_Gun);\n      specialWeaponTypeSet.insert(Nuclear_Strike);\n      specialWeaponTypeSet.insert(Lockdown);\n      specialWeaponTypeSet.insert(EMP_Shockwave);\n      specialWeaponTypeSet.insert(Irradiate);\n      specialWeaponTypeSet.insert(Parasite);\n      specialWeaponTypeSet.insert(Spawn_Broodlings);\n      specialWeaponTypeSet.insert(Ensnare);\n      specialWeaponTypeSet.insert(Dark_Swarm);\n      specialWeaponTypeSet.insert(Plague);\n      specialWeaponTypeSet.insert(Consume);\n      specialWeaponTypeSet.insert(Stasis_Field);\n      specialWeaponTypeSet.insert(Psionic_Storm);\n      specialWeaponTypeSet.insert(Disruption_Web);\n      specialWeaponTypeSet.insert(Restoration);\n      specialWeaponTypeSet.insert(Mind_Control);\n      specialWeaponTypeSet.insert(Feedback);\n      specialWeaponTypeSet.insert(Optical_Flare);\n      specialWeaponTypeSet.insert(Maelstrom);\n\n      weaponTypeSet.insert(None);\n      weaponTypeSet.insert(Unknown);\n\n      foreach(WeaponType i, weaponTypeSet)\n      {\n        std::string name = i.getName();\n        fixName(&name);\n        weaponTypeMap.insert(std::make_pair(name, i));\n      }\n      initializingWeaponType = false;\n    }\n  }\n  WeaponType::WeaponType()\n  {\n    this->id = WeaponTypes::None.id;\n  }\n  WeaponType::WeaponType(int id)\n  {\n    this->id = id;\n    if (!initializingWeaponType && (id < 0 || id >= 132 || !weaponTypeData[id].valid))\n      this->id = WeaponTypes::Unknown.id;\n  }\n  WeaponType::WeaponType(const WeaponType& other)\n  {\n    this->id = other.id;\n  }\n  WeaponType& WeaponType::operator=(const WeaponType& other)\n  {\n    this->id = other.id;\n    return *this;\n  }\n  bool WeaponType::operator==(const WeaponType& other) const\n  {\n    return this->id == other.id;\n  }\n  bool WeaponType::operator!=(const WeaponType& other) const\n  {\n    return this->id != other.id;\n  }\n  bool WeaponType::operator<(const WeaponType& other) const\n  {\n    return this->id < other.id;\n  }\n  int WeaponType::getID() const\n  {\n    return this->id;\n  }\n  std::string WeaponType::getName() const\n  {\n    return weaponTypeData[this->id].name;\n  }\n  TechType WeaponType::getTech() const\n  {\n    return weaponTypeData[this->id].techType;\n  }\n  UnitType WeaponType::whatUses() const\n  {\n    return weaponTypeData[this->id].whatUses;\n  }\n  int WeaponType::damageAmount() const\n  {\n    return weaponTypeData[this->id].damageAmount;\n  }\n  int WeaponType::damageBonus() const\n  {\n    return weaponTypeData[this->id].damageBonus;\n  }\n  int WeaponType::damageCooldown() const\n  {\n    return weaponTypeData[this->id].damageCooldown;\n  }\n  int WeaponType::damageFactor() const\n  {\n    return weaponTypeData[this->id].damageFactor;\n  }\n  UpgradeType WeaponType::upgradeType() const\n  {\n    return weaponTypeData[this->id].upgradeType;\n  }\n  DamageType WeaponType::damageType() const\n  {\n    return weaponTypeData[this->id].damageType;\n  }\n  ExplosionType WeaponType::explosionType() const\n  {\n    return weaponTypeData[this->id].explosionType;\n  }\n  int WeaponType::minRange() const\n  {\n    return weaponTypeData[this->id].minRange;\n  }\n  int WeaponType::maxRange() const\n  {\n    return weaponTypeData[this->id].maxRange;\n  }\n  int WeaponType::innerSplashRadius() const\n  {\n    return weaponTypeData[this->id].innerSplashRadius;\n  }\n  int WeaponType::medianSplashRadius() const\n  {\n    return weaponTypeData[this->id].medianSplashRadius;\n  }\n  int WeaponType::outerSplashRadius() const\n  {\n    return weaponTypeData[this->id].outerSplashRadius;\n  }\n  bool WeaponType::targetsAir() const\n  {\n    return weaponTypeData[this->id].targetsAir;\n  }\n  bool WeaponType::targetsGround() const\n  {\n    return weaponTypeData[this->id].targetsGround;\n  }\n  bool WeaponType::targetsMechanical() const\n  {\n    return weaponTypeData[this->id].targetsMechanical;\n  }\n  bool WeaponType::targetsOrganic() const\n  {\n    return weaponTypeData[this->id].targetsOrganic;\n  }\n  bool WeaponType::targetsNonBuilding() const\n  {\n    return weaponTypeData[this->id].targetsNonBuilding;\n  }\n  bool WeaponType::targetsNonRobotic() const\n  {\n    return weaponTypeData[this->id].targetsNonRobotic;\n  }\n  bool WeaponType::targetsTerrain() const\n  {\n    return weaponTypeData[this->id].targetsTerrain;\n  }\n  bool WeaponType::targetsOrgOrMech() const\n  {\n    return weaponTypeData[this->id].targetsOrgOrMech;\n  }\n  bool WeaponType::targetsOwn() const\n  {\n    return weaponTypeData[this->id].targetsOwn;\n  }\n  WeaponType WeaponTypes::getWeaponType(std::string name)\n  {\n    fixName(&name);\n    std::map<std::string, WeaponType>::iterator i = weaponTypeMap.find(name);\n    if (i == weaponTypeMap.end())\n      return WeaponTypes::Unknown;\n    return (*i).second;\n  }\n  std::set<WeaponType>& WeaponTypes::allWeaponTypes()\n  {\n    return weaponTypeSet;\n  }\n  std::set<WeaponType>& WeaponTypes::normalWeaponTypes()\n  {\n    return weaponTypeSet;\n  }\n  std::set<WeaponType>& WeaponTypes::specialWeaponTypes()\n  {\n    return weaponTypeSet;\n  }\n}\n"
  },
  {
    "path": "SparCraft/sample_experiment/sample_exp.txt",
    "content": "####################################################################################################\n#\n#  SparCraft Experiment File Format\n#  David Churchill - dave.churchill@gmail.com\n#  \n#  # denotes commented lines\n#\n#  Specify the players in the experiment\n#\n#  Format:\n#  \n#  PlayerNum PlayerType [Params]*\n#\n#  ,---------------------------------------------------------,\n#  | Scripted Player Syntax                                  |\n#  |---------------------------------------------------------|\n#  | Player X ScriptName                                     |\n#  '---------------------------------------------------------'\n#\n#  ,----------------------------------------------------------,\n#  | Portfolio Greedy Search Player Syntax                    |\n#  |----------------------------------------------------------|\n#  | Player X PortfolioGreedySearch Seed Iterations Responses |\n#  '----------------------------------------------------------'\n#\n#  ,---------------------------------------------------------,\n#  | Recursive Greedy Search Player Syntax                   |\n#  |---------------------------------------------------------|\n#  | Player X RecursiveGreedySearch Seed Iterations          |\n#  '---------------------------------------------------------'\n#\n#  ,---------------------------------------------------------------------------------------------------------------------------------------------,\n#  | AlphaBeta Player Syntax + Options                                        (Scripts for Playouts)                                             |\n#  |---------------------------------------------------------------------------------------------------------------------------------------------|\n#  | Player X AlphaBeta  TimeLimitMS   MaxChildren  MoveOrdering  EvalMethod  P0Script     P1Script     PlayerToMoveMethod   OpponentModelScript |\n#  |---------------------------------------------------------------------------------------------------------------------------------------------|\n#  |                     Integer       Integer      ScriptFirst   Playout     ScriptName   ScriptName   Alternate            ScriptName          |\n#  |                                   0 = NoMax    None          LTD                                   NotAlternate         None                |\n#  |                                                              LTD2                                  Random                                   |\n#  '---------------------------------------------------------------------------------------------------------------------------------------------'\n#\n#  ,--------------------------------------------------------------------------------------------------------------------------------------------------------------,\n#  | UCT Player Syntax + Options                                                        (Scripts for Playouts)                                                    |\n#  |--------------------------------------------------------------------------------------------------------------------------------------------------------------|\n#  | Player X UCT  TimeLimitMS  CValue  MaxTraversals  MaxChildren  MoveOrdering  EvalMethod   P0Script     P1Script     PlayerToMoveMethod   OpponentModelScript |\n#  |--------------------------------------------------------------------------------------------------------------------------------------------------------------|\n#  |               Integer      Double  Integer        Integer      ScriptFirst   Playout      ScriptName   ScriptName   Alternate            ScriptName          |\n#  |                                                                None          LTD                                    NotAlternate         None                |\n#  |                                                                              LTD2                                   Random                                   |\n#  '--------------------------------------------------------------------------------------------------------------------------------------------------------------'\n#\n####################################################################################################\n\n# Sample AlphaBeta Players\nPlayer 0 AlphaBeta 10 20 ScriptFirst Playout NOKDPS NOKDPS Alternate None\n#Player 1 AlphaBeta 5 20 ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n\n# Sample UCT Players\nPlayer 1 UCT 10 1.6 5000 20 ScriptFirst Playout NOKDPS NOKDPS Alternate None\n#Player 0 UCT 5 1.6 5000 20 ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n\n# Sample PortfolioGreedySearch Players\n#Player 0 PortfolioGreedySearch 0 NOKDPS 1 0\n\n# Sample Scripted Players\n#Player 0 NOKDPS\n#Player 1 NOKDPS\n\n####################################################\n#\n# Set player upgrade and tech levels\n#\n# Format:\n# PlayerUpgrade PlayerID UpgradeName UpgradeLevel\n# PlayerTech PlayerID TechName\n#\n####################################################\n\n#PlayerUpgrade 0 Protoss_Ground_Weapons 1\n#PlayerUpgrade 1 Protoss_Ground_Armor 3\n#PlayerUpgrade 1 Singularity_Charge 1\n#PlayerUpgrade 1 Zerg_Melee_Attacks 1\n\n##################################################\n#\n#  Specify the states in the experiment\n#  See map file description to specify legal unit positions\n#\n#  State StateSymmetric NumStates MaxX MaxY [UnitType UnitNum]+\n#  State SeparatedState NumStates RandX RandY cx1 cy1 cx2 cy2 [UnitType UnitNum]+\n#  State StateDescriptionFile NumStates FileName \n#\n#  For SeparatedState, NumStates / 2 mirrored copies will be created for fairness\n#\n##################################################\n\n# Sample StateDescriptionFile States\n#State StateDescriptionFile 10 PATH_TO\\sample_state.txt\n\n# Sample SeparatedState States\nState SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 50\nState SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling 50\nState SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 25 Protoss_Zealot 25\nState SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 25 Terran_Marine 25\nState SeparatedState 100 128 128 400 360 840 360 Terran_Marine 25 Zerg_Zergling 25\n\n# Sample Symmetric State States\n#State StateSymmetric 10 128 128 Protoss_Dragoon 8\n#State StateSymmetric 10 128 128 Zerg_Zergling 8\n#State StateSymmetric 10 128 128 Protoss_Dragoon 16 Protoss_Zealot 16\n#State StateSymmetric 10 128 128 Protoss_Dragoon 16 Terran_Marine 16\n#State StateSymmetric 10 128 128 Terran_Marine 16 Zerg_Zergling 16\n\n##################################################\n#\n#  File where results will be stored\n#  Boolean at the end indicates whether to append time stamp\n#  .txt will be added to the end of the file automatically\n#\n#  Format\n#  ResultsFile FILENAME BOOL\n#\n##################################################\n\nResultsFile PATH_TO\\sample_exp true\n\n##################################################\n#\n#  Map file to use for the simulation, all states will use this map.\n#  Map file is used to define walkable boundaries for the simulation\n#  Comment out line to use no map\n#  No Map - Default map size is 1280*720 pixels all tiles walkable\n#  If this map is specified, all units must be placed on walkable tiles within map boundaries or experiment will not run\n#\n##################################################\n\n#MapFile PATH_TO\\destination.txt\n\n##################################################\n#\n#  Show visualization? Only works if libraries enabled in Common.h\n#\n#  Format\n#  Display BOOL ImageDir\n#\n#  This directory is included with SparCraft in folder SparCraft\\starcraft_images\\\n#  Be sure to use forward slash \"\\\" and include the final \"\\\" character\n#  No spaces allowed!\n#\n##################################################\n\nDisplay true PATH_TO\\starcraft_images\\\n"
  },
  {
    "path": "SparCraft/sample_experiment/sample_exp_linux.txt",
    "content": "####################################################################################################\n#\n#  SparCraft Experiment File Format\n#  David Churchill - dave.churchill@gmail.com\n#  \n#  # denotes commented lines\n#\n#  Specify the players in the experiment\n#\n#  Format:\n#  \n#  PlayerNum PlayerType [Params]*\n#\n#  ,---------------------------------------------------------,\n#  | Scripted Player Syntax                                  |\n#  |---------------------------------------------------------|\n#  | Player X ScriptName                                     |\n#  '---------------------------------------------------------'\n#\n#  ,----------------------------------------------------------,\n#  | Portfolio Greedy Search Player Syntax                    |\n#  |----------------------------------------------------------|\n#  | Player X PortfolioGreedySearch Seed Iterations Responses |\n#  '----------------------------------------------------------'\n#\n#  ,---------------------------------------------------------,\n#  | Recursive Greedy Search Player Syntax                   |\n#  |---------------------------------------------------------|\n#  | Player X RecursiveGreedySearch Seed Iterations          |\n#  '---------------------------------------------------------'\n#\n#  ,---------------------------------------------------------------------------------------------------------------------------------------------,\n#  | AlphaBeta Player Syntax + Options                                        (Scripts for Playouts)                                             |\n#  |---------------------------------------------------------------------------------------------------------------------------------------------|\n#  | Player X AlphaBeta  TimeLimitMS   MaxChildren  MoveOrdering  EvalMethod  P0Script     P1Script     PlayerToMoveMethod   OpponentModelScript |\n#  |---------------------------------------------------------------------------------------------------------------------------------------------|\n#  |                     Integer       Integer      ScriptFirst   Playout     ScriptName   ScriptName   Alternate            ScriptName          |\n#  |                                   0 = NoMax    None          LTD                                   NotAlternate         None                |\n#  |                                                              LTD2                                  Random                                   |\n#  '---------------------------------------------------------------------------------------------------------------------------------------------'\n#\n#  ,--------------------------------------------------------------------------------------------------------------------------------------------------------------,\n#  | UCT Player Syntax + Options                                                        (Scripts for Playouts)                                                    |\n#  |--------------------------------------------------------------------------------------------------------------------------------------------------------------|\n#  | Player X UCT  TimeLimitMS  CValue  MaxTraversals  MaxChildren  MoveOrdering  EvalMethod   P0Script     P1Script     PlayerToMoveMethod   OpponentModelScript |\n#  |--------------------------------------------------------------------------------------------------------------------------------------------------------------|\n#  |               Integer      Double  Integer        Integer      ScriptFirst   Playout      ScriptName   ScriptName   Alternate            ScriptName          |\n#  |                                                                None          LTD                                    NotAlternate         None                |\n#  |                                                                              LTD2                                   Random                                   |\n#  '--------------------------------------------------------------------------------------------------------------------------------------------------------------'\n#\n####################################################################################################\n\n# Sample AlphaBeta Players\n#Player 0 AlphaBeta 40 20 ScriptFirst Playout NOKDPS NOKDPS Alternate None\n#Player 1 AlphaBeta 40 20 ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n\n# Sample UCT Players\n#Player 0 UCT 40 1.6 5000 20 ScriptFirst Playout NOKDPS NOKDPS Alternate None\n#Player 0 UCT 40 1.6 5000 20 ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n\n# Sample PortfolioGreedySearch Players\nPlayer 0 PortfolioGreedySearch 0 NOKDPS 1 0\n\n# Sample Scripted Players\nPlayer 0 NOKDPS\nPlayer 1 NOKDPS\n\n####################################################\n#\n# Set player upgrade and tech levels\n#\n# Format:\n# PlayerUpgrade PlayerID UpgradeName UpgradeLevel\n# PlayerTech PlayerID TechName\n#\n####################################################\n\n#PlayerUpgrade 0 Protoss_Ground_Weapons 1\n#PlayerUpgrade 1 Protoss_Ground_Armor 3\n#PlayerUpgrade 1 Singularity_Charge 1\n#PlayerUpgrade 1 Zerg_Melee_Attacks 1\n\n##################################################\n#\n#  Specify the states in the experiment\n#  See map file description to specify legal unit positions\n#\n#  State StateSymmetric NumStates MaxX MaxY [UnitType UnitNum]+\n#  State SeparatedState NumStates RandX RandY cx1 cy1 cx2 cy2 [UnitType UnitNum]+\n#  State StateDescriptionFile NumStates FileName \n#\n#  For SeparatedState, NumStates / 2 mirrored copies will be created for fairness\n#\n##################################################\n\n# Sample StateDescriptionFile States\n#State StateDescriptionFile 10 PATH_TO\\sample_state.txt\n\n# Sample SeparatedState States\nState SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 50\nState SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling 50\nState SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 25 Protoss_Zealot 25\nState SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 25 Terran_Marine 25\nState SeparatedState 100 128 128 400 360 840 360 Terran_Marine 25 Zerg_Zergling 25\n\n# Sample Symmetric State States\n#State StateSymmetric 10 128 128 Protoss_Dragoon 8\n#State StateSymmetric 10 128 128 Zerg_Zergling 8\n#State StateSymmetric 10 128 128 Protoss_Dragoon 16 Protoss_Zealot 16\n#State StateSymmetric 10 128 128 Protoss_Dragoon 16 Terran_Marine 16\n#State StateSymmetric 10 128 128 Terran_Marine 16 Zerg_Zergling 16\n\n##################################################\n#\n#  File where results will be stored\n#  Boolean at the end indicates whether to append time stamp\n#  .txt will be added to the end of the file automatically\n#\n#  Format\n#  ResultsFile FILENAME BOOL\n#\n##################################################\n\nResultsFile PATH_TO\\sample_exp true\n\n##################################################\n#\n#  Map file to use for the simulation, all states will use this map.\n#  Map file is used to define walkable boundaries for the simulation\n#  Comment out line to use no map\n#  No Map - Default map size is 1280*720 pixels all tiles walkable\n#  If this map is specified, all units must be placed on walkable tiles within map boundaries or experiment will not run\n#\n##################################################\n\n#MapFile PATH_TO\\destination.txt\n\n##################################################\n#\n#  Show visualization? Only works if libraries enabled in Common.h\n#\n#  Format\n#  Display BOOL ImageDir\n#\n#  This directory is included with SparCraft in folder SparCraft\\starcraft_images\\\n#  Be sure to use forward slash \"\\\" and include the final \"\\\" character\n#  No spaces allowed!\n#\n##################################################\n\nDisplay true PATH_TO\\starcraft_images\\"
  },
  {
    "path": "SparCraft/sample_experiment/sample_map_files/destination.txt",
    "content": "384\n512\n000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000001111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000001110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000001111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000001101110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000001111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000001011100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000011011100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000001111001100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000011111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000111011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000001111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000001110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000011000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000001111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000011110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000001101110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000011110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000101110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000010000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000100110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000010000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000001111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000001100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111100001111111111111111111111111111000000011111111100000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111000000011111111111111111111111110000000000111111000000000111111111111111111111111111111111111111111111111111111111111111111111000111111111111\n000000000000000000000000000000110111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111000000001111111111111111111111110000000000111111000000000011111111111111111111111111111111111111111111111111111111111111111111000111111111111\n000000000000000000000000000000110011000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011110000000000011111111111111111111110000000000011110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000011111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000011111111111111110000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111011111111111\n000000000000000000000000000000111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000011111111110000000000000000000000000011000000000011111111111111111111111111111111111111111111111111111111111111111000111111111\n000000000000000000000000000000011100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111100000000000000000000000000111100000000001111111111111111111111111111111111111111111111111111111111111111000011111111\n000000000000000000000000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111100000000000000000000000011111111000000001111111111111111111111111111111111111111111111111111111111111111000011111111\n000000000000000000000000000000010000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000111111100000000000000000000000001111111000000000111111111111111111111111111111111111111111111111111111111111111100000001111\n000000000000000000000000000000010000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000011011100000000000000000000000000011110000000000011111111111111111111111111111111111111111111111111111111111111111000001111\n000000000000000000000000000000110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000011011100000000000000000000000000001110000000000011111111111111111111111111111111111111111111111111111111111111111100000001\n000000000000000000000000000011110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000001001100000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111111111111111111100000001\n000000000000000000000000000001111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111100000111111111111111111111111111111111111111111111111111111110000000\n000000000000000000000000000001110111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000111100000000000000000000000000000000111000000001111111111111111111111111111111111111111111111111111111100000\n000000000000000000000000000001110111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000011111111111111100011000000000000111100000000000000000000000000111111000000000000000000000000000000111000000000000111111111111111111111111111111111111111111111111111110000\n000000000000000000000000000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000001111111111111110011110000000011111111000000000000000000000000111111110000000000000000000000000000110000000000000111111111111111111111111111111111111111111111111111110000\n000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111101111111111111111111111111111111111111111\n000000000000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000111111111101111111111111111111111111111111111111111\n000000000000000000000000000000000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111111111000111111111111111111111111111111111111111\n000000000000000000000000000000000000111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111110000111111111111111111111111111111111111111\n000000000000000000000000000000000000001111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011110000110000000111111111111111111111111111111111\n000000000000000000000000000000000000001101110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011000000001100000011111111111111111111111111111111\n000000000000000000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111000000000011000000001110000001111111111111111111111111111111\n000000000000000000000000000000000000000000110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111000000000011000000001111000001111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111110000000000111000000001111000000001111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111100000000000111000000001111000000001111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111100000000000111000000001000000000111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111000000000000011111111111000000011111111111111111111111111111111\n000000000000000000000000000000000000000000000001000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000010000000000000001000011110000000011111111111111111111111111111111\n000000000000000000000000000000000000000000000001000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000010000000000000001000011000000000111111111111111111111111111111111\n000000000000000000000000000000000000000000000011000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000110000000000000011000010000000001111111111111111111111111111111111\n000000000000000000000000000000000000000000001111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011110000000000001111111100000000111111111111111111111111111111111111\n000000000000000000000000000000000000000011111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000001111111111111111111111111111111111111111\n000000000000000000000000000000000000000001111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000011111111111111111111111111111111111111111\n000000000000000000000000000000000000001101110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111\n000000000000000000000000000000000000001100110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111\n000000000000000000000000000000001100001111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111111111\n000000000000000000000000000000001100001111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000001111111111111111111111111111111111111111111\n000000000000001100000000000000111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000011111111111111111111111111111111111111111\n000000000000001100000000000000111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111\n000000001111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011100000000000000011111111111111111111111111111111111111111\n000000001111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011100000000000000011111111111111111111111111111111111111111\n000000001111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011100000000000000111111111111111111111111111111111111111111\n000000001111111111111111111111111111111111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011100000000111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111100000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000001101110111000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000101110111000000011111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000110011000011111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001100000011000011111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000100000000111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001100000000111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111110000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000111100000000111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011100000000111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000100000000111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111000000000000000000001111110000000001111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111000000000000000000001111000000000001111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000011111111111111111111111111100000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000001111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111100000000000001000000000000000000000000000111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000001000000000000000000000000011111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111110000000000000000000000000000000001111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111100000000111100000000000000000000001111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111000000111111000000000000000000111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111100000000000111111111111111111111000000000011111111111100000000000011111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111100000000000000000000001100000011100001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000111111111111111110000000000000111111111111111111111000000000011111111111100000000001111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111100000000000000000000000000000111000001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111110000000000000000000111111111111111100000000000001111111111100000000111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111100000000000000000000000000001111000001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111100000000000000000000111111111111111100000000000001111111111100000011111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111000000000000000000000000111111000001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001111111000000000000000000000000001111110000000000000000000111111111111111111111111111111111111111110000000000000000000000000000000000000011111111111111111111111111111111111111111111100001100000000000000000000011111100001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000001111000000000000000000000000000000011000000000000000000000111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111111100001100000000000000000000000111100001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111100000000000000000000000011110001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111110000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111000111111111100000000000000000000000000000001111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111000000011111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000011100000000000000000000000000011111111111111111111111111111111111111110000000000000000000000000000000000111111111111111111111111111000001111111111110000000001111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000011110000000000000000000000001111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111100000001111111111110000000000111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000111111111111000000000000000011111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111110000000000000011111110000000000000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000011111111111111000000000000000011111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111111111000000000000000011111110000000000000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000001111111111111111110000000000001111111111111111111111111111111111111111111111111111000000000000000000000011111111111111111111111111100000000000000000011111110000000000000000000000000000000000001110000000000011111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000001111111111111111111100000000111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111110000000000000000000000011100000000000000000000000000000000000001110000011111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000001100011111111111111111111110000111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000001100000011111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001000001111111111111111111110000111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011000000111111111111111111110000111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000001111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011000011111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000001000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000011110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000001111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000011111100000000000000000000111111111111111111111111111111111111111111111111111111111111111111100000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000001111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001111000001111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111100000\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111100000\n011111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000001111100011111111000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111100000\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000001111000000110111000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000001110000000010111000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111100000\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000001100000000000011000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000111110000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000111100000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011110000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111\n011111110000000000000011111111111111111111111111110000111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000011100000000001111111111111111111111111111111111111111111111111111111111111111111\n011111110000000000000011111111111111111111111111110000111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000011100000000011111111111111111111111111111111111111111111111111111111111111111111\n011111110000000000000000111111111111111111111111111111110000011111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000011100000001111111111111111111111111111111111111111111111111111111111111111111111\n011111110000000000000000111111111111111111111111111111110000000111111111111111111111111111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000011100000111111111111111111111111111111111111111111111111111111111111111111111111\n010000000000000000000000000000110000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000011000000111111111111111111111111111111111111111111111111111111111111111111111111\n010000000000000000000000000000110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111100000000000000011111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111100000001111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000011111000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111100000000000011111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000011111000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111000000001111111111111111111100111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001111111000011111000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001111100000000111000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001000000000000111110000000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001000000000000011110000000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111100000000000000000000111111111111000011111000000111100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011110000000000110000000000011111111100000001111000000010000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000001111000000000001111000000000000111110000010000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000111111110000000000111000000000000011111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001111111111111111000000000000000000000000000111110000000011111111111011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000011111111111111111100000000000000110000000000011110000000011111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000111111111111111111110000000000001111000000000001110000000011111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000011111111111111111111111100000000111111110000000000111111111111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000001111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111100000000011111111110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111100001111111111111111111111111111111111110000000001111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111000000111111111111111111111111111111111111100000000001110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111000000111111111111111111111111111111111111111110000000000000001111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111000000111111111111111111111111111111111111111111000000000000111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000011111111111111111111111111111111111111111111111111100000000001111111111111111111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000011111111111111111111111111111111111111111111111111111000000001111111111111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000011111111111111111111111111111111111111111111111111111111111111111111111111000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000011\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000001110000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011\n011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000001111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000001111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000001000000000000000000001111000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001\n011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001\n011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111111111000000000000000000000000011111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111110000000000011000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111100000000000111100110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111000000000011111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000001111110000000000111110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001000000111000000000000011110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011110000010000000000000011110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111101111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011100000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100011111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100001111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100001111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111110000000111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111100000111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111110000000111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111110000000111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111011111111111111111000000000011111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111011111111111111111110000000001111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111110001111111111111111111000000000111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001111111111111111111111111111111111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111100001111111111111111111000000000011\n011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111100000001111111111111111100000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111000000111111111111111110000000\n011111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111000000\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111110000011111111111111111110000\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000011111111111111111111111111111111111111111110000000000000000000000000000000011111111111111111111111111111111111111111110000011111111111111111111111110000000001111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111000000011111111111111111111111110000000111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111000000000000000000000000111111111111111111111111111111111111111111100000000000001111111111111111111100000000111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111110000000000000000011111111111111110000000001111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000111111111111111111111111111111111111111111100000011110000001111111111111111111111111111111111111111111000000000000000000001111111111111100000000011111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111100000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111111000011110000111111111111111111111111111111111111111111100000000000000000000001111111111110000000001111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111000000000000000000001111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000001111111111100000000000111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111110000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000001011110000000000100000011111111111111111111111111\n011111111111111111111111111111111111111111111111111111111110000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000011011100000000001111000001111111111111111111111111\n011111111111111111111111111111111111111111111111111111111110000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000001111001100000000111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111110000000000000111111111100001100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111000000000111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111000000000000110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000011110000000000011111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001110000000000011111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001100000000000011111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111000000000111000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001000000000000001111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111110000000000011000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000001000000000000011111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111100000000000011110000010000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000011000000000001111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111000000001111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000011111000110000001111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011110000000000011111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000111111111111111111111111111111111111111111100000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011100000000000111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000001111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011000000000011111111111111111111111111111111111111111111\n011111111111111111111111111111110000011111111111111111111111000000000111110000000000001111111111111111111111111111111111111111111111111111111111111111111100000000000000011111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111111111111111111111110000001100000000000000001111000000000000111111111111111111111111111111111111111111111111\n011111111111111111111111111111110000001111111111111111111111000000000111110000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111110000000100000000000000001110000000000001111111111111111111111111111111111111111111111111\n011111111111111111111111111111111100000111111111111111110000000000000011000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111100000100000000000000111110000000000011111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111110000000000000001000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000000000000000011111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111100000000001111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111110000000000011111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100011111111111100000000011111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111110000000000011111000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111100000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000001110111110000000000111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001110100000000000001111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001100100000000000111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111100000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111100000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111110000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111\n010000111111111111111111111111111000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111\n010000111111111111111111111111111110000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111000011111111111111100011000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111100000001111111111111110011110000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111\n000011111110000000000000111111111111111111100000100000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111\n000011111000000000000000111111111111111111000000100000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001110000000000111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000011111111111111100000000110000000000000000000000111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001110000000000011111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000001111111111111100000000111100000000000000000011111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001100000000000011111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000111111111111111000000111111110000000000001111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000011000000001100000000000111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000011111111111111110000111111110000000000111111111111111111111111111111111111111111100000000000000000000001111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000001100000000001111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000111111111111111000111111110000000011111111111111111111111111111111111111111110000000000000000000000000011111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000001100000000111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000000011111111111111111111111110000001111111111111111111111111111111111111111111000000000000000000000000000000111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000000000111111000000000011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000000000111111110000000111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000011111000000111110000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000011110000000011110000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000001111100000000001111100000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111000000000000111100000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000001111111100000000000000000001111100000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111100000000001100000000000011100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111000000000011110000000000011100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111000000001111111100000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111110000000000000011111111111000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001110000000000000000011111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000001111110000001111111111111111111111111111111111111111111111111111111111111111111000111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000001111110000011111111111111111111111111111111111111111111111111111111111111111111000111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111111000111111111111111111111111111111111111111111111111111111111111111111111000111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000001100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111110111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111\n011100000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111\n011100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111\n000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111\n000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110001111111111111110000111111111111111111111111111111111111111111111111111111111111111111\n000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110011111111111111100000001111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111000001\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000011111111111111111111111111111111111111111111111110000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111110000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000001111111111111111111111100000000000011111111110000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000001111111111111111111110000000000000000111111110000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111100000000000000000001111110000001\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000111111111111111100000000000000000000111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000011111110000000000000000000000000111111100000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111100000000000000000001111000000000000000000000000000011110000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011111110000000000000000001110000000000000000000000000000011100000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000001110000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001100000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111100000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011100000000000000000000000000000111111100000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011100000000000000000000000000000111011110000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011000000000000000000000000000000111011110000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000110011110000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000111100000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000111100000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111110111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111110111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111100000001111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111000000111111111111100000000001111111110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111110000001111111111111100000000001111111100000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111110000011111111111111100000000000111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111110000000011111111100011000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111110000000011111111000000000001100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111100000000011110000000000011110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000110000000000000000000000000000000000000000000111\n011111111111111111111111111111111111111111111111111111111111111111111111000000011100000000001111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000110000000000000000000000000000000000000000000111\n011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000111111000000000000000000000111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111000000000000000011111111\n011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111000000000000000000000111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111000000000000000011111111\n011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000001111111111111111111111111110000000011111111111111111111111111111111111000000000000011111111\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011111111111111111111111111100000011111111111111111111111111111111111000000000000011111111\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000001111000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000011000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000011100000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000111111111111111111111111111111111111111111111111111110000000000000000000110000000000000000011100000000000000000000000000000000000011111111111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000011111111111111111111111111111111111111111111111111110000000000000000011110000000000000000001100000000000000000000000000000000001111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000011111111111111111111111111111111111111111111111111100000000000000111100000000000000000000111111111000000000000000000000000000111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111100000000000000000000000000000011000111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n010000011111111111111111111111111111111111111111111111111110000000000000011100000000000000000000000101111000000000000000000000000011111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111100000000001111111111111111111100000000000000000000000000000010000011111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011000011111111111111111111111111111111111111111111111111111100000000000011100000000000000000000000001111100000000000000000000001111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111100000000001111111111111111111110000000000000000000000000000110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111111111100000000001100000000000000000000000000111111000000000000000000111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111100000000000000000000000011111000001111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000011111111111100000000000011111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111000000000000000001111111110000000011110000000000000000110000111110001111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111000000010000000000000000000000000000000000001111111111100000000001111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111111110000000001100000000000111111100000000001110000000000000000110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111000000011000000000000000000000000000000000001111111111111100000111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111111100000000011110000000000011111100000000001111100000000000000110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111000000111110000000000000000000000000000000000111111111111100011111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111110000000001111111100000000001111100000000001111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111110000111000001111100000000000000000000000000000000000111111111111111111111111111111111111111110000000000000000000000000000000000000011111111111111111111111111111111111111100001100000011111111111111110000000011000000000000110000111111111111000111111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000001000001111100000000000000000000011100000000000111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111000000000000111111111111111111000000000000001100000000000011101111100000011101111100000001111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000001000011100000000000000000000001111111100000000111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111000000000001111111111111111111100000000000011110000000000011101111000000011101000000000000111111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000001111111100000000000000000000001111111100000011111111111111111111111111111111111110000000000000000000000000000000000000111111111111111111111111111111111111111111111000000000111111111111111111111111000000001111111100000000011100110000000011001000000000000011111111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000001111000000000000000000000000011111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111110000001100000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000001110000000000000000000000000001111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111000000000000001100000000000000110000000000011111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000001100000000000000000000000000001111111111111111111111111111111111111111111111110000000000000000000000000000000000111111111111111111111110000011111111111111110000000000111111111111111111111111111111111111111111111111111100000000000011110000000000001111000000000001111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111111100000000000000000000000000000111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111000000011111111111111110000000011111111111111111111111111111111111111111111111111111111000000001111111100000000111111110000000000111111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111100000000000000000111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111110000000000000000000001111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111000000000000000000000011111111111111111111111000000000000000000000000111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111100000000000000000000000000110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111110000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111110000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111100000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111000000001111111111111111111111100000000000000000000000000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111000000111111111111111111111110000000000000000000000000000000111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111100000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111110000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000110111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000110011000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111100000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111110000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000110000011100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111100000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000011111111000011110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000011111100000001110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111000000001110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111000000000000110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111100000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111111110000000011110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111\n011111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111000011110000000000001111\n011111111111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111000011110000000000001111\n011111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111000011110000000000000000\n011111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111110000000000000000\n011111111111111111111111111111111111111111110000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111110000000000000000000000\n011111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111110000000000000000000000\n011111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111000000000000000000000000\n011111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111000000000000000000000000\n011111111111111111111111111111111111111110000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111110000000000000000000000000000\n011111111111111111111111111111111111111110000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111000000000000000000000000000000\n011111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111110000000000000000000000000000000\n011111111111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111110000000000000000000000000000000\n011111111111111111111111111111111111111111100000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000111111111110000000000000000000000000000000\n011111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111110000000000000000000000000000000\n011111111111111111111111111111111111111100000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111000000000000000000000000000000\n011111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111110000000000000000000000000000\n011111111111111111111111111111111110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111110000000000000000000000000000\n011111111111111111111111111111111110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111000000000000000000000000000000\n011111111111111111111111111111100000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001110000000000000000000000000000000\n011111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000110000000000000000000000000000000\n011111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000010000000000000000000000000000000\n011111111111111111111111111111100000000000000000000000000000000001111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000010000000000000000000000000000000\n011111111111111111111111111111100000000000000011110000000000000001110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011000000000000000000000000000000\n011111111111111111111111111111110000000000001111110000000000000000110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011110000000000000000000000000000\n011111111111111111111111111111111000000011000011111000000000111111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111110111100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111000000000000000000000000\n011111111111111111111111111111111110000000000000111000000000011101110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111110001100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000010111000000000000000000000000\n011111111111111111111111111111111111100000000000110000000000011101110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000110000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111110000000000000000000000\n011111111111111111111111111111111111110000000000100000000000001100110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011110000000000000000000000\n011111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111100000000000000000000\n011111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000011110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001110110000000000000000000000\n011111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000010000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001110100000000000000000000000\n011111111111111111111111111111111111111111111111000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000010000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001100100000000000000000000000\n011111111111111111111111111111111111111111111111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111101111111111111111100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111101111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000\n010000111111111111111111111111111111111111111111110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111000111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000\n000000011111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111110000111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000\n000000001111111111111111111111111111111111111111100000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000\n000000001111111111111111111111111111111111111111100000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000\n000000000111111111111111111111111111111111111111110000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000\n000000000011111111111111111111111111111111111111111100000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000\n000000000001111111111111111111111111111111111111111111110000000000000000000000000000000100000000000011111111111011111111111111111111111111111110000011111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111000000000000000000000000000000000000000\n000000000000111111111111111111111111111111111111111111110000000000000000000000000000000110000000000001111111100000011111111110000011111111111000000001111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011101000000000000000000000000000000000000000\n000000000000001111111111111111111111111111111111111111111100000000000011000000000000001111000000000001111000000000001111111100000001111110000000000001111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011101100000000000000000000000000000000000000\n000000000000000111111111111111111111111111111111111111111111000000001111000000001111111111110000000001111000000000001111111100000000001110000000000000111000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000011001111000000000000000000000000000000000000\n000000000000011111111111111111111111111111111111111111111111111111111111111000000000011111100000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000111111111100000000000000000000000000000000\n010000000000111111111111111111111111111111111111111111111111111111111111111000000000000110000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111000000000000000000000000000000000\n011100000001111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111011000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000110011000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000001111111100000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111110000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000111111100000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111011000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000110111111111000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111010000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000110011111111110000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000110010000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000011111111111111110000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001110000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111100000000011111111111111111110000000000000111000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001110000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111111111100000011111111111111111111111100000000111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111111111100000011111111111111111111111111000000111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111110000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111110000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111011110000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110001111111111111110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110011111111111111100000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000110000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001100000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111100000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111100000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000110000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000010000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110001100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111100000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001110100000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001110110000000000000000000000000000000000000000000000\n011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001100111100000000000000000000000000000000000000000000\n000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111100000000000000000000000000000000000000000000\n000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001110110000000000000000000000000000000000000000000000\n000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001110100000000000000000000000000000000000000000000000\n000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001100100000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "SparCraft/sample_experiment/sample_map_files/map_file_format.txt",
    "content": "Map files are in ASCII format.\n\nFirst two lines specify WIDTH, HEIGHT in WalkTile resolution (8x8 pixel)\n\nNext HEIGHT lines (each with WIDTH columns) specify walkable tiles\n\n0 = blocked, 1 = walkable\n\nSparCraft::Position p translates into map WalkTile position (p.x() / 8, p.y() / 8)\n\nSample 20x10 map with all tiles walkable:\n\n20\n10\n11111111111111111111\n11111111111111111111\n11111111111111111111\n11111111111111111111\n11111111111111111111\n11111111111111111111\n11111111111111111111\n11111111111111111111\n11111111111111111111\n11111111111111111111\n\nIf no map is specified in experiment , default map has size: \n\n40x22 BuildTile == 160x88 WalkTile == 1280x704\n\nThis size was chosen to best fit the Display's 1280*720 pixel size, and is also a decent sized arena\n\nIf a GameState contains any initial unit whose Position is on a non-walkable tile, the experiment will not run"
  },
  {
    "path": "SparCraft/sample_experiment/sample_results/sample_exp_2013-03-22_17-49-13_config.txt",
    "content": "Player 0 NOKDPS\nPlayer 1 KiterDPS\nState SeparatedState 10 128 128 400 360 840 360 Protoss_Dragoon 50\nState SeparatedState 10 128 128 400 360 840 360 Zerg_Zergling 50\nState SeparatedState 10 128 128 400 360 840 360 Protoss_Dragoon 25 Protoss_Zealot 25\nState SeparatedState 10 128 128 400 360 840 360 Protoss_Dragoon 25 Terran_Marine 25\nState SeparatedState 10 128 128 400 360 840 360 Terran_Marine 25 Zerg_Zergling 25\nResultsFile c:\\users\\dave\\desktop\\results\\sample_exp true\nDisplay true\n"
  },
  {
    "path": "SparCraft/sample_experiment/sample_results/sample_exp_2013-03-22_17-49-13_results_raw.txt",
    "content": "   P1    P2    ST  UNIT       EVAL    RND           MS | UnitType PlayerID CurrentHP XPos YPos\n    0     0     0    50     100131    638       890.66 | Protoss_Dragoon 0 140 646 474 | Protoss_Dragoon 0 180 647 472 | Protoss_Dragoon 0 100 628 499 | Protoss_Dragoon 0 180 680 465 | Protoss_Dragoon 0 180 619 509 | Protoss_Dragoon 0 160 632 488 | Protoss_Dragoon 0 180 638 488\n    0     0     1    50     100244    523       701.88 | Protoss_Dragoon 0 180 574 312 | Protoss_Dragoon 0 180 585 275 | Protoss_Dragoon 0 180 616 276 | Protoss_Dragoon 0 20 502 282 | Protoss_Dragoon 0 100 637 283 | Protoss_Dragoon 0 120 513 274 | Protoss_Dragoon 0 140 613 303 | Protoss_Dragoon 0 160 576 303 | Protoss_Dragoon 0 160 556 294 | Protoss_Dragoon 0 160 589 305 | Protoss_Dragoon 0 100 586 276 | Protoss_Dragoon 0 160 609 280 | Protoss_Dragoon 0 180 602 289 | Protoss_Dragoon 0 160 618 264\n    0     0     2    50     100190    571       911.32 | Protoss_Dragoon 0 180 750 366 | Protoss_Dragoon 0 140 694 332 | Protoss_Dragoon 0 140 756 391 | Protoss_Dragoon 0 140 764 380 | Protoss_Dragoon 0 160 746 376 | Protoss_Dragoon 0 180 746 394 | Protoss_Dragoon 0 40 733 376 | Protoss_Dragoon 0 100 693 326 | Protoss_Dragoon 0 160 756 380 | Protoss_Dragoon 0 120 700 310 | Protoss_Dragoon 0 160 690 305\n    0     0     3    50     100186    562       890.04 | Protoss_Dragoon 0 100 530 401 | Protoss_Dragoon 0 140 492 319 | Protoss_Dragoon 0 160 515 377 | Protoss_Dragoon 0 140 479 362 | Protoss_Dragoon 0 180 492 373 | Protoss_Dragoon 0 180 542 379 | Protoss_Dragoon 0 160 502 335 | Protoss_Dragoon 0 180 537 421 | Protoss_Dragoon 0 160 526 408 | Protoss_Dragoon 0 180 521 389\n    0     0     4    50     100110    649       884.54 | Protoss_Dragoon 0 120 733 353 | Protoss_Dragoon 0 160 721 348 | Protoss_Dragoon 0 20 702 325 | Protoss_Dragoon 0 160 704 320 | Protoss_Dragoon 0 100 721 337 | Protoss_Dragoon 0 120 752 349 | Protoss_Dragoon 0 160 702 317\n    0     0     5    50     100099    639       790.77 | Protoss_Dragoon 0 60 506 448 | Protoss_Dragoon 0 100 545 467 | Protoss_Dragoon 0 120 506 355 | Protoss_Dragoon 0 160 466 238 | Protoss_Dragoon 0 140 503 282 | Protoss_Dragoon 0 180 500 384\n    0     0     6    50     100209    535       729.48 | Protoss_Dragoon 0 180 694 399 | Protoss_Dragoon 0 180 743 323 | Protoss_Dragoon 0 60 668 412 | Protoss_Dragoon 0 180 769 293 | Protoss_Dragoon 0 20 751 334 | Protoss_Dragoon 0 180 721 359 | Protoss_Dragoon 0 120 672 457 | Protoss_Dragoon 0 180 710 370 | Protoss_Dragoon 0 140 713 362 | Protoss_Dragoon 0 180 745 343 | Protoss_Dragoon 0 140 734 357 | Protoss_Dragoon 0 180 725 354\n    0     0     7    50     100220    512       699.67 | Protoss_Dragoon 0 80 471 480 | Protoss_Dragoon 0 140 519 271 | Protoss_Dragoon 0 160 472 263 | Protoss_Dragoon 0 180 514 327 | Protoss_Dragoon 0 160 501 379 | Protoss_Dragoon 0 180 487 295 | Protoss_Dragoon 0 80 543 270 | Protoss_Dragoon 0 180 519 448 | Protoss_Dragoon 0 180 536 390 | Protoss_Dragoon 0 180 538 394 | Protoss_Dragoon 0 160 482 446 | Protoss_Dragoon 0 180 498 366\n    0     0     8    50     100200    562       754.78 | Protoss_Dragoon 0 40 688 482 | Protoss_Dragoon 0 40 773 282 | Protoss_Dragoon 0 160 686 440 | Protoss_Dragoon 0 160 744 323 | Protoss_Dragoon 0 180 744 327 | Protoss_Dragoon 0 160 805 253 | Protoss_Dragoon 0 100 701 367 | Protoss_Dragoon 0 140 731 332 | Protoss_Dragoon 0 160 706 478 | Protoss_Dragoon 0 180 780 307 | Protoss_Dragoon 0 80 788 271 | Protoss_Dragoon 0 180 734 341\n    0     0     9    50     100139    588       859.14 | Protoss_Dragoon 0 20 480 381 | Protoss_Dragoon 0 80 519 253 | Protoss_Dragoon 0 40 493 372 | Protoss_Dragoon 0 100 493 363 | Protoss_Dragoon 0 140 467 403 | Protoss_Dragoon 0 180 487 377 | Protoss_Dragoon 0 140 503 368 | Protoss_Dragoon 0 180 498 370 | Protoss_Dragoon 0 180 512 353\n    0     0    10    50     100450    117       200.41 | Zerg_Zergling 0 20 640 383 | Zerg_Zergling 0 35 638 423 | Zerg_Zergling 0 35 642 374 | Zerg_Zergling 0 35 657 383 | Zerg_Zergling 0 35 662 365 | Zerg_Zergling 0 15 631 450 | Zerg_Zergling 0 20 653 387 | Zerg_Zergling 0 25 655 354 | Zerg_Zergling 0 25 668 396 | Zerg_Zergling 0 30 656 403 | Zerg_Zergling 0 35 643 404 | Zerg_Zergling 0 35 643 408 | Zerg_Zergling 0 35 644 418 | Zerg_Zergling 0 35 653 399 | Zerg_Zergling 0 35 671 414 | Zerg_Zergling 0 35 672 412 | Zerg_Zergling 0 35 674 405 | Zerg_Zergling 0 35 675 404 | Zerg_Zergling 0 35 676 410 | Zerg_Zergling 0 35 641 441 | Zerg_Zergling 0 35 643 500 | Zerg_Zergling 0 20 634 478 | Zerg_Zergling 0 35 640 430 | Zerg_Zergling 0 35 657 428\n    0     0    11    50     100388    125       202.70 | Zerg_Zergling 0 5 578 323 | Zerg_Zergling 0 35 568 320 | Zerg_Zergling 0 35 568 332 | Zerg_Zergling 0 35 572 267 | Zerg_Zergling 0 5 567 331 | Zerg_Zergling 0 10 570 279 | Zerg_Zergling 0 20 572 341 | Zerg_Zergling 0 25 569 270 | Zerg_Zergling 0 30 564 336 | Zerg_Zergling 0 35 565 332 | Zerg_Zergling 0 35 574 314 | Zerg_Zergling 0 35 567 329 | Zerg_Zergling 0 35 577 315 | Zerg_Zergling 0 35 571 329 | Zerg_Zergling 0 20 579 323 | Zerg_Zergling 0 35 566 334 | Zerg_Zergling 0 35 569 325 | Zerg_Zergling 0 30 569 326 | Zerg_Zergling 0 35 563 337 | Zerg_Zergling 0 35 565 325 | Zerg_Zergling 0 30 568 327 | Zerg_Zergling 0 35 565 268\n    0     0    12    50     100458    117       213.22 | Zerg_Zergling 0 5 670 334 | Zerg_Zergling 0 15 653 273 | Zerg_Zergling 0 35 668 313 | Zerg_Zergling 0 5 670 296 | Zerg_Zergling 0 10 663 309 | Zerg_Zergling 0 15 666 303 | Zerg_Zergling 0 20 643 316 | Zerg_Zergling 0 30 662 296 | Zerg_Zergling 0 30 664 296 | Zerg_Zergling 0 30 665 304 | Zerg_Zergling 0 30 666 304 | Zerg_Zergling 0 35 651 323 | Zerg_Zergling 0 35 651 324 | Zerg_Zergling 0 35 653 305 | Zerg_Zergling 0 35 657 302 | Zerg_Zergling 0 35 661 307 | Zerg_Zergling 0 35 671 298 | Zerg_Zergling 0 35 674 295 | Zerg_Zergling 0 35 676 292 | Zerg_Zergling 0 35 669 283 | Zerg_Zergling 0 35 671 290 | Zerg_Zergling 0 35 673 291 | Zerg_Zergling 0 15 669 271 | Zerg_Zergling 0 35 660 282 | Zerg_Zergling 0 5 670 300 | Zerg_Zergling 0 30 662 288 | Zerg_Zergling 0 30 673 288\n    0     0    13    50     100395    119       198.95 | Zerg_Zergling 0 15 575 345 | Zerg_Zergling 0 25 576 471 | Zerg_Zergling 0 25 586 386 | Zerg_Zergling 0 30 579 373 | Zerg_Zergling 0 35 569 366 | Zerg_Zergling 0 35 575 365 | Zerg_Zergling 0 35 587 447 | Zerg_Zergling 0 25 585 393 | Zerg_Zergling 0 35 562 397 | Zerg_Zergling 0 35 566 405 | Zerg_Zergling 0 35 568 391 | Zerg_Zergling 0 35 568 392 | Zerg_Zergling 0 35 579 401 | Zerg_Zergling 0 35 599 432 | Zerg_Zergling 0 20 596 438 | Zerg_Zergling 0 25 585 408 | Zerg_Zergling 0 30 571 396 | Zerg_Zergling 0 35 583 411 | Zerg_Zergling 0 35 577 387 | Zerg_Zergling 0 10 593 454 | Zerg_Zergling 0 15 578 392 | Zerg_Zergling 0 30 580 393\n    0     0    14    50     100425    117       198.66 | Zerg_Zergling 0 20 669 390 | Zerg_Zergling 0 25 661 393 | Zerg_Zergling 0 30 613 415 | Zerg_Zergling 0 30 651 391 | Zerg_Zergling 0 30 652 397 | Zerg_Zergling 0 35 653 400 | Zerg_Zergling 0 10 652 408 | Zerg_Zergling 0 35 655 430 | Zerg_Zergling 0 35 662 422 | Zerg_Zergling 0 35 656 399 | Zerg_Zergling 0 35 661 410 | Zerg_Zergling 0 30 605 423 | Zerg_Zergling 0 30 627 423 | Zerg_Zergling 0 35 637 412 | Zerg_Zergling 0 35 658 424 | Zerg_Zergling 0 35 667 431 | Zerg_Zergling 0 20 634 423 | Zerg_Zergling 0 25 657 420 | Zerg_Zergling 0 30 654 428 | Zerg_Zergling 0 35 627 414 | Zerg_Zergling 0 35 631 423 | Zerg_Zergling 0 35 632 420 | Zerg_Zergling 0 35 649 413\n    0     0    15    50     100371    127       270.19 | Zerg_Zergling 0 5 606 302 | Zerg_Zergling 0 15 588 293 | Zerg_Zergling 0 25 587 301 | Zerg_Zergling 0 25 592 298 | Zerg_Zergling 0 30 582 288 | Zerg_Zergling 0 35 587 284 | Zerg_Zergling 0 35 589 276 | Zerg_Zergling 0 35 589 286 | Zerg_Zergling 0 35 592 276 | Zerg_Zergling 0 35 597 294 | Zerg_Zergling 0 5 635 297 | Zerg_Zergling 0 30 600 305 | Zerg_Zergling 0 5 579 292 | Zerg_Zergling 0 35 576 283 | Zerg_Zergling 0 35 578 284 | Zerg_Zergling 0 35 584 290 | Zerg_Zergling 0 5 584 281 | Zerg_Zergling 0 30 588 291 | Zerg_Zergling 0 30 591 291 | Zerg_Zergling 0 35 577 279 | Zerg_Zergling 0 35 586 282 | Zerg_Zergling 0 35 586 282\n    0     0    16    50     100434    129       222.76 | Zerg_Zergling 0 10 652 471 | Zerg_Zergling 0 35 653 479 | Zerg_Zergling 0 35 657 459 | Zerg_Zergling 0 35 661 463 | Zerg_Zergling 0 35 628 461 | Zerg_Zergling 0 35 654 477 | Zerg_Zergling 0 35 656 471 | Zerg_Zergling 0 35 656 477 | Zerg_Zergling 0 35 662 462 | Zerg_Zergling 0 35 662 473 | Zerg_Zergling 0 35 667 460 | Zerg_Zergling 0 20 658 469 | Zerg_Zergling 0 30 652 469 | Zerg_Zergling 0 25 639 464 | Zerg_Zergling 0 20 667 477 | Zerg_Zergling 0 30 606 466 | Zerg_Zergling 0 35 644 463 | Zerg_Zergling 0 35 650 478 | Zerg_Zergling 0 35 651 473 | Zerg_Zergling 0 35 653 474 | Zerg_Zergling 0 35 654 478 | Zerg_Zergling 0 35 657 470 | Zerg_Zergling 0 35 652 480\n    0     0    17    50     100422    125       260.57 | Zerg_Zergling 0 35 576 280 | Zerg_Zergling 0 35 581 290 | Zerg_Zergling 0 35 581 295 | Zerg_Zergling 0 35 582 298 | Zerg_Zergling 0 35 588 281 | Zerg_Zergling 0 35 589 294 | Zerg_Zergling 0 35 600 258 | Zerg_Zergling 0 30 582 285 | Zerg_Zergling 0 30 586 269 | Zerg_Zergling 0 30 634 270 | Zerg_Zergling 0 35 595 262 | Zerg_Zergling 0 20 649 261 | Zerg_Zergling 0 30 596 257 | Zerg_Zergling 0 35 592 259 | Zerg_Zergling 0 35 599 262 | Zerg_Zergling 0 35 618 272 | Zerg_Zergling 0 15 602 268 | Zerg_Zergling 0 35 589 258 | Zerg_Zergling 0 35 599 255 | Zerg_Zergling 0 35 605 263 | Zerg_Zergling 0 35 606 262 | Zerg_Zergling 0 35 609 267\n    0     0    18    50     100404    123       219.80 | Zerg_Zergling 0 5 649 287 | Zerg_Zergling 0 20 613 234 | Zerg_Zergling 0 20 645 286 | Zerg_Zergling 0 35 621 287 | Zerg_Zergling 0 35 622 304 | Zerg_Zergling 0 35 639 294 | Zerg_Zergling 0 35 649 288 | Zerg_Zergling 0 35 626 280 | Zerg_Zergling 0 35 636 285 | Zerg_Zergling 0 35 631 285 | Zerg_Zergling 0 35 655 278 | Zerg_Zergling 0 30 627 294 | Zerg_Zergling 0 30 645 297 | Zerg_Zergling 0 35 616 288 | Zerg_Zergling 0 35 647 298 | Zerg_Zergling 0 30 645 288 | Zerg_Zergling 0 35 643 297 | Zerg_Zergling 0 35 646 296 | Zerg_Zergling 0 20 624 258 | Zerg_Zergling 0 30 625 252 | Zerg_Zergling 0 30 642 288 | Zerg_Zergling 0 30 653 290\n    0     0    19    50     100475    117       243.03 | Zerg_Zergling 0 5 602 432 | Zerg_Zergling 0 15 637 462 | Zerg_Zergling 0 25 606 424 | Zerg_Zergling 0 35 581 429 | Zerg_Zergling 0 35 594 419 | Zerg_Zergling 0 35 594 429 | Zerg_Zergling 0 35 601 423 | Zerg_Zergling 0 35 603 417 | Zerg_Zergling 0 10 630 449 | Zerg_Zergling 0 30 579 449 | Zerg_Zergling 0 30 596 444 | Zerg_Zergling 0 35 575 450 | Zerg_Zergling 0 35 582 456 | Zerg_Zergling 0 35 587 448 | Zerg_Zergling 0 35 588 451 | Zerg_Zergling 0 35 593 446 | Zerg_Zergling 0 35 595 456 | Zerg_Zergling 0 35 608 445 | Zerg_Zergling 0 35 616 471 | Zerg_Zergling 0 35 611 447 | Zerg_Zergling 0 35 641 475 | Zerg_Zergling 0 15 577 427 | Zerg_Zergling 0 15 601 421 | Zerg_Zergling 0 35 631 452 | Zerg_Zergling 0 10 600 440 | Zerg_Zergling 0 20 581 447 | Zerg_Zergling 0 30 578 446\n    0     0    20    50     100191    585       796.46 | Protoss_Dragoon 0 60 797 394 | Protoss_Dragoon 0 180 825 362 | Protoss_Dragoon 0 60 774 381 | Protoss_Dragoon 0 140 737 470 | Protoss_Dragoon 0 180 786 366 | Protoss_Dragoon 0 160 824 367 | Protoss_Dragoon 0 60 740 508 | Protoss_Dragoon 0 140 816 356 | Protoss_Dragoon 0 160 768 409 | Protoss_Dragoon 0 160 811 383 | Protoss_Dragoon 0 180 782 397 | Protoss_Dragoon 0 20 822 372\n    0     0    21    50     100226    585       826.56 | Protoss_Dragoon 0 60 431 374 | Protoss_Dragoon 0 180 402 364 | Protoss_Dragoon 0 160 414 364 | Protoss_Dragoon 0 160 411 364 | Protoss_Dragoon 0 180 441 238 | Protoss_Dragoon 0 180 444 242 | Protoss_Dragoon 0 180 452 239 | Protoss_Dragoon 0 180 394 364 | Protoss_Dragoon 0 140 453 245 | Protoss_Dragoon 0 80 413 353 | Protoss_Dragoon 0 80 438 223 | Protoss_Dragoon 0 140 368 381 | Protoss_Dragoon 0 140 400 369\n    0     0    22    50     100133    671       866.03 | Protoss_Dragoon 0 20 960 423 | Protoss_Dragoon 0 180 933 378 | Protoss_Dragoon 0 40 928 352 | Protoss_Dragoon 0 180 952 395 | Protoss_Dragoon 0 180 955 396 | Protoss_Dragoon 0 160 943 390 | Protoss_Dragoon 0 180 925 329 | Protoss_Dragoon 0 180 940 384\n    0     0    23    50     100065    772      1006.42 | Protoss_Dragoon 0 140 339 406 | Protoss_Dragoon 0 160 334 384 | Protoss_Dragoon 0 180 323 377 | Protoss_Dragoon 0 40 336 405\n    0     0    24    50     100151    628       822.37 | Protoss_Dragoon 0 180 884 409 | Protoss_Dragoon 0 20 881 397 | Protoss_Dragoon 0 180 868 318 | Protoss_Dragoon 0 60 896 406 | Protoss_Dragoon 0 180 896 396 | Protoss_Dragoon 0 140 884 367 | Protoss_Dragoon 0 160 885 407 | Protoss_Dragoon 0 140 882 388 | Protoss_Dragoon 0 180 880 242\n    0     0    25    50     100191    620       871.43 | Protoss_Dragoon 0 180 425 298 | Protoss_Dragoon 0 100 468 354 | Protoss_Dragoon 0 140 457 402 | Protoss_Dragoon 0 180 440 330 | Protoss_Dragoon 0 160 435 329 | Protoss_Dragoon 0 160 459 415 | Protoss_Dragoon 0 180 420 311 | Protoss_Dragoon 0 180 428 307 | Protoss_Dragoon 0 40 473 368 | Protoss_Dragoon 0 160 424 308 | Protoss_Dragoon 0 100 436 337\n    0     0    26    50     100121    662       857.16 | Protoss_Dragoon 0 180 861 390 | Protoss_Dragoon 0 60 849 393 | Protoss_Dragoon 0 100 833 401 | Protoss_Dragoon 0 180 853 388 | Protoss_Dragoon 0 120 894 386 | Protoss_Dragoon 0 180 874 381 | Protoss_Dragoon 0 180 885 378\n    0     0    27    50     100146    619       867.06 | Protoss_Dragoon 0 160 387 316 | Protoss_Dragoon 0 140 409 283 | Protoss_Dragoon 0 180 419 287 | Protoss_Dragoon 0 40 362 318 | Protoss_Dragoon 0 100 413 287 | Protoss_Dragoon 0 180 407 292 | Protoss_Dragoon 0 180 391 311 | Protoss_Dragoon 0 140 395 314 | Protoss_Dragoon 0 40 387 310\n    0     0    28    50     100227    617       826.62 | Protoss_Dragoon 0 20 863 388 | Protoss_Dragoon 0 140 736 459 | Protoss_Dragoon 0 160 866 460 | Protoss_Dragoon 0 180 883 420 | Protoss_Dragoon 0 180 891 411 | Protoss_Dragoon 0 120 887 371 | Protoss_Dragoon 0 160 881 390 | Protoss_Dragoon 0 100 889 370 | Protoss_Dragoon 0 140 872 348 | Protoss_Dragoon 0 180 742 470 | Protoss_Dragoon 0 180 863 431 | Protoss_Dragoon 0 180 866 377 | Protoss_Dragoon 0 160 884 325\n    0     0    29    50     100265    544       828.52 | Protoss_Dragoon 0 84 409 476 | Protoss_Dragoon 0 120 376 282 | Protoss_Dragoon 0 180 392 261 | Protoss_Dragoon 0 180 407 285 | Protoss_Dragoon 0 180 416 420 | Protoss_Dragoon 0 180 417 407 | Protoss_Dragoon 0 164 399 281 | Protoss_Dragoon 0 180 372 264 | Protoss_Dragoon 0 180 383 280 | Protoss_Dragoon 0 180 388 283 | Protoss_Dragoon 0 160 432 425 | Protoss_Dragoon 0 180 438 420 | Protoss_Dragoon 0 180 423 420 | Protoss_Dragoon 0 180 425 406\n    0     0    30    50     100297    446       552.35 | Protoss_Dragoon 0 100 680 400 | Protoss_Dragoon 0 140 738 326 | Protoss_Dragoon 0 140 765 330 | Protoss_Dragoon 0 180 697 379 | Protoss_Dragoon 0 140 692 382 | Protoss_Dragoon 0 60 744 331 | Protoss_Dragoon 0 100 691 377 | Protoss_Dragoon 0 160 685 386 | Protoss_Dragoon 0 120 695 380 | Protoss_Dragoon 0 180 691 385 | Protoss_Dragoon 0 180 685 384\n    0     0    31    50     100292    462       617.72 | Protoss_Dragoon 0 22 491 352 | Protoss_Dragoon 0 160 522 338 | Protoss_Dragoon 0 60 561 247 | Protoss_Dragoon 0 120 540 344 | Protoss_Dragoon 0 160 523 350 | Protoss_Dragoon 0 160 528 320 | Protoss_Dragoon 0 160 511 362 | Protoss_Dragoon 0 180 517 351 | Protoss_Dragoon 0 20 502 362 | Protoss_Dragoon 0 160 485 375 | Protoss_Dragoon 0 160 496 357 | Protoss_Dragoon 0 60 491 368\n    0     0    32    50     100110    615       666.12 | Protoss_Dragoon 0 100 717 408 | Protoss_Dragoon 0 140 689 447 | Protoss_Dragoon 0 160 665 442 | Protoss_Dragoon 0 160 687 441\n    0     0    33    50     100213    525       646.77 | Protoss_Dragoon 0 40 590 307 | Protoss_Dragoon 0 160 537 340 | Protoss_Dragoon 0 180 562 326 | Protoss_Dragoon 0 140 598 302 | Protoss_Dragoon 0 140 553 343 | Protoss_Dragoon 0 160 539 328 | Protoss_Dragoon 0 80 551 337 | Protoss_Dragoon 0 180 575 326\n    0     0    34    50     100203    518       680.20 | Protoss_Dragoon 0 160 718 348 | Protoss_Dragoon 0 180 734 324 | Protoss_Dragoon 0 140 722 339 | Protoss_Dragoon 0 100 729 332 | Protoss_Dragoon 0 54 730 351 | Protoss_Dragoon 0 80 741 343 | Protoss_Dragoon 0 140 741 343 | Protoss_Dragoon 0 120 719 361\n    0     0    35    50     100199    528       616.97 | Protoss_Dragoon 0 180 527 329 | Protoss_Dragoon 0 60 537 337 | Protoss_Dragoon 0 140 545 315 | Protoss_Dragoon 0 180 522 340 | Protoss_Dragoon 0 160 515 345 | Protoss_Dragoon 0 180 511 340 | Protoss_Dragoon 0 160 506 364\n    0     0    36    50     100247    490       636.46 | Protoss_Dragoon 0 180 703 392 | Protoss_Dragoon 0 160 688 408 | Protoss_Dragoon 0 160 717 388 | Protoss_Dragoon 0 60 732 384 | Protoss_Dragoon 0 180 720 404 | Protoss_Dragoon 0 180 719 384 | Protoss_Dragoon 0 160 664 457 | Protoss_Dragoon 0 180 706 405 | Protoss_Dragoon 0 40 698 413\n    0     0    37    50     100201    527       685.14 | Protoss_Dragoon 0 120 523 337 | Protoss_Dragoon 0 180 505 336 | Protoss_Dragoon 0 20 560 262 | Protoss_Dragoon 0 100 478 368 | Protoss_Dragoon 0 140 488 348 | Protoss_Dragoon 0 120 520 328 | Protoss_Dragoon 0 120 519 325 | Protoss_Dragoon 0 180 521 328\n    0     0    38    50     100178    536       670.64 | Protoss_Dragoon 0 60 749 425 | Protoss_Dragoon 0 140 722 347 | Protoss_Dragoon 0 180 700 327 | Protoss_Dragoon 0 180 730 324 | Protoss_Dragoon 0 20 731 345 | Protoss_Dragoon 0 180 757 367 | Protoss_Dragoon 0 140 740 342\n    0     0    39    50     100146    565       648.46 | Protoss_Dragoon 0 180 594 407 | Protoss_Dragoon 0 20 500 330 | Protoss_Dragoon 0 80 578 396 | Protoss_Dragoon 0 120 466 339 | Protoss_Dragoon 0 134 554 375 | Protoss_Dragoon 0 180 566 405\n    0     0    40    50     100186    270       364.42 | Terran_Marine 0 40 675 353 | Terran_Marine 0 40 682 364 | Terran_Marine 0 28 694 361 | Terran_Marine 0 40 675 320 | Terran_Marine 0 40 680 365 | Terran_Marine 0 40 697 334 | Terran_Marine 0 34 662 398 | Terran_Marine 0 34 690 351 | Terran_Marine 0 40 681 366 | Terran_Marine 0 28 671 418 | Terran_Marine 0 16 654 409 | Terran_Marine 0 40 654 409\n    0     0    41    50     100187    269       381.94 | Terran_Marine 0 4 522 359 | Terran_Marine 0 34 531 365 | Terran_Marine 0 40 532 372 | Terran_Marine 0 40 533 372 | Terran_Marine 0 40 534 355 | Terran_Marine 0 40 534 359 | Terran_Marine 0 40 533 362 | Terran_Marine 0 40 527 353 | Terran_Marine 0 40 534 350 | Terran_Marine 0 40 535 368 | Terran_Marine 0 34 546 381 | Terran_Marine 0 40 537 370\n    0     0    42    50     100226    250       394.14 | Terran_Marine 0 4 713 484 | Terran_Marine 0 40 680 469 | Terran_Marine 0 40 698 280 | Terran_Marine 0 40 690 464 | Terran_Marine 0 40 683 374 | Terran_Marine 0 40 702 413 | Terran_Marine 0 40 678 430 | Terran_Marine 0 40 690 338 | Terran_Marine 0 40 694 335 | Terran_Marine 0 40 697 307 | Terran_Marine 0 16 706 311 | Terran_Marine 0 34 690 289 | Terran_Marine 0 34 694 313 | Terran_Marine 0 22 694 427 | Terran_Marine 0 40 695 323\n    0     0    43    50     100180    276       417.00 | Terran_Marine 0 4 561 365 | Terran_Marine 0 40 549 346 | Terran_Marine 0 40 547 284 | Terran_Marine 0 40 566 361 | Terran_Marine 0 10 558 292 | Terran_Marine 0 40 540 307 | Terran_Marine 0 40 554 350 | Terran_Marine 0 40 563 382 | Terran_Marine 0 34 578 385 | Terran_Marine 0 40 546 341 | Terran_Marine 0 40 526 339 | Terran_Marine 0 40 527 341\n    0     0    44    50     100213    256       394.30 | Terran_Marine 0 40 717 346 | Terran_Marine 0 40 721 349 | Terran_Marine 0 40 723 350 | Terran_Marine 0 34 728 367 | Terran_Marine 0 40 726 364 | Terran_Marine 0 40 734 371 | Terran_Marine 0 28 738 355 | Terran_Marine 0 40 727 346 | Terran_Marine 0 40 729 358 | Terran_Marine 0 34 729 354 | Terran_Marine 0 4 727 350 | Terran_Marine 0 40 721 366 | Terran_Marine 0 34 723 358 | Terran_Marine 0 28 722 348\n    0     0    45    50     100169    275       419.11 | Terran_Marine 0 40 513 318 | Terran_Marine 0 10 575 395 | Terran_Marine 0 34 517 330 | Terran_Marine 0 40 535 350 | Terran_Marine 0 22 542 349 | Terran_Marine 0 40 551 358 | Terran_Marine 0 40 541 355 | Terran_Marine 0 40 547 354 | Terran_Marine 0 34 551 362 | Terran_Marine 0 40 524 337 | Terran_Marine 0 40 529 342\n    0     0    46    50     100223    256       413.34 | Terran_Marine 0 40 693 381 | Terran_Marine 0 40 697 387 | Terran_Marine 0 40 698 388 | Terran_Marine 0 22 690 379 | Terran_Marine 0 22 694 389 | Terran_Marine 0 40 677 364 | Terran_Marine 0 40 685 384 | Terran_Marine 0 40 693 374 | Terran_Marine 0 34 696 381 | Terran_Marine 0 34 682 382 | Terran_Marine 0 40 660 365 | Terran_Marine 0 40 695 380 | Terran_Marine 0 40 682 373 | Terran_Marine 0 40 696 382\n    0     0    47    50     100237    250       414.02 | Terran_Marine 0 10 576 347 | Terran_Marine 0 34 587 356 | Terran_Marine 0 40 577 364 | Terran_Marine 0 40 580 367 | Terran_Marine 0 40 583 371 | Terran_Marine 0 40 574 338 | Terran_Marine 0 40 576 346 | Terran_Marine 0 40 541 328 | Terran_Marine 0 40 567 340 | Terran_Marine 0 40 579 351 | Terran_Marine 0 40 582 347 | Terran_Marine 0 40 575 349 | Terran_Marine 0 22 570 348 | Terran_Marine 0 40 586 359 | Terran_Marine 0 40 583 358\n    0     0    48    50     100204    262       404.37 | Terran_Marine 0 40 647 338 | Terran_Marine 0 40 681 380 | Terran_Marine 0 40 695 386 | Terran_Marine 0 40 681 374 | Terran_Marine 0 40 701 390 | Terran_Marine 0 16 701 383 | Terran_Marine 0 40 655 357 | Terran_Marine 0 40 687 385 | Terran_Marine 0 16 659 353 | Terran_Marine 0 40 692 373 | Terran_Marine 0 40 695 376 | Terran_Marine 0 40 680 369 | Terran_Marine 0 34 663 355\n    0     0    49    50     100176    266       418.56 | Terran_Marine 0 34 516 335 | Terran_Marine 0 34 553 363 | Terran_Marine 0 40 499 322 | Terran_Marine 0 40 509 324 | Terran_Marine 0 40 549 365 | Terran_Marine 0 22 507 324 | Terran_Marine 0 34 556 378 | Terran_Marine 0 40 502 322 | Terran_Marine 0 40 511 345 | Terran_Marine 0 40 517 351 | Terran_Marine 0 40 544 367\n"
  },
  {
    "path": "SparCraft/sample_experiment/sample_results/sample_exp_2013-03-22_17-49-13_results_summary.txt",
    "content": "   1.0000000 \n"
  },
  {
    "path": "SparCraft/sample_experiment/sample_state.txt",
    "content": "Protoss_Dragoon 0 300 300\nProtoss_Dragoon 0 300 320\nProtoss_Dragoon 0 300 340\nProtoss_Dragoon 0 300 360\nProtoss_Dragoon 1 600 300\nProtoss_Dragoon 1 600 320\nProtoss_Dragoon 1 600 340\nProtoss_Dragoon 1 600 360"
  },
  {
    "path": "SparCraft/source/Action.cpp",
    "content": "#include \"Action.h\"\n\nusing namespace SparCraft;\n\nAction::Action()\n\t: _unit(255)\n\t, _player(255)\n\t, _moveType(ActionTypes::NONE)\n\t, _moveIndex(255)\n{\n\n}\n\nAction::Action( const size_t & unitIndex, const size_t & player, const size_t & type, const size_t & moveIndex, const Position & dest)\n    : _unit(unitIndex)\n    , _player(player)\n    , _moveType(type)\n    , _moveIndex(moveIndex)\n    , _p(dest)\n{\n        \n}\n\nAction::Action( const size_t & unitIndex, const size_t & player, const size_t & type, const size_t & moveIndex)\n\t: _unit(unitIndex)\n\t, _player(player)\n\t, _moveType(type)\n\t, _moveIndex(moveIndex)\n{\n\t\t\n}\n\nconst bool Action::operator == (const Action & rhs)\n{\n\treturn _unit == rhs._unit && _player == rhs._player && _moveType == rhs._moveType && _moveIndex == rhs._moveIndex && _p == rhs._p;\n}\n\nconst size_t & Action::unit() const\t\n{ \n    return _unit; \n}\n\nconst size_t & Action::player() const\t\n{ \n    return _player; \n}\n\nconst size_t & Action::type() const\t\n{ \n    return _moveType; \n}\n\nconst size_t & Action::index() const\t\n{ \n    return _moveIndex; \n}\n\nconst Position & Action::pos() const   \n{ \n    return _p; \n}\n\nconst std::string Action::moveString() const\n{\n\tif (_moveType == ActionTypes::ATTACK) \n\t{\n\t\treturn \"ATTACK\";\n\t}\n\telse if (_moveType == ActionTypes::MOVE)\n\t{\n\t\treturn \"MOVE\";\n\t}\n\telse if (_moveType == ActionTypes::RELOAD)\n\t{\n\t\treturn \"RELOAD\";\n\t}\n\telse if (_moveType == ActionTypes::PASS)\n\t{\n\t\treturn \"PASS\";\n\t}\n\telse if (_moveType == ActionTypes::HEAL)\n\t{\n\t\treturn \"HEAL\";\n\t}\n\n\treturn \"NONE\";\n}\n\nconst Position Action::getDir() const\n{\n\treturn Position(Constants::Move_Dir[_moveIndex][0], Constants::Move_Dir[_moveIndex][1]);\n}\n\nconst std::string Action::debugString() const\n{\n    std::stringstream ss;\n    ss << moveString() << \": (\" << (int)unit() << \",\" << (int)player() << \",\" << (int)type() << \",\" << (int)index() << \")  \" << \"(\" << pos().x() << \",\" << pos().y()   << \")\";\n    return ss.str();\n}\n\n"
  },
  {
    "path": "SparCraft/source/Action.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Position.hpp\"\n\nnamespace SparCraft\n{\n\nnamespace ActionTypes\n{\n\tenum {NONE, ATTACK, RELOAD, MOVE, PASS, HEAL};\n};\n\nclass Action \n{\n\tsize_t  _unit;\n\tsize_t\t_player;\n\tsize_t\t_moveType;\n\tsize_t\t_moveIndex;\n\n    Position _p;\n\npublic:\n\n\n\tAction();\n\n    Action( const size_t & unitIndex, const size_t & player, const size_t & type, const size_t & moveIndex, const Position & dest);\n\n\tAction( const size_t & unitIndex, const size_t & player, const size_t & type, const size_t & moveIndex);\n\n\tconst bool operator == (const Action & rhs);\n\n\tconst size_t & unit()\tconst;\n\tconst size_t & player() const;\n\tconst size_t & type()\tconst;\n\tconst size_t & index()\tconst;\n    const Position & pos()  const;\n\n\tconst std::string moveString() const;\n\n\tconst Position getDir() const;\n\n    const std::string debugString() const;\n\n};\n\n}"
  },
  {
    "path": "SparCraft/source/AllPlayers.cpp",
    "content": "#include \"AllPlayers.h\"\n    \nusing namespace SparCraft;\n\nPlayer * AllPlayers::getPlayer(const size_t & playerID, const size_t & type)\n{\n\tif\t\t\t(type == PlayerModels::AttackClosest)\t\t{ return new Player_AttackClosest(playerID); }\n\telse if\t\t(type == PlayerModels::AttackDPS)\t\t\t{ return new Player_AttackDPS(playerID); }\n\telse if\t\t(type == PlayerModels::AttackWeakest)\t\t{ return new Player_AttackWeakest(playerID); }\n\telse if\t\t(type == PlayerModels::Kiter)\t\t\t\t{ return new Player_Kiter(playerID); }\n\telse if\t\t(type == PlayerModels::KiterDPS)\t\t\t{ return new Player_KiterDPS(playerID); }\n    else if\t\t(type == PlayerModels::Kiter_NOKDPS)\t\t{ return new Player_Kiter_NOKDPS(playerID); }\n    else if\t\t(type == PlayerModels::Cluster)\t\t    \t{ return new Player_Cluster(playerID); }\n\telse if\t\t(type == PlayerModels::NOKDPS)              { return new Player_NOKDPS(playerID); }\n\telse if\t\t(type == PlayerModels::Random)\t\t\t\t{ return new Player_Random(playerID); }\n\telse\t\t\t\t\t\t\t\t\t\t\t\t\t{ return NULL; }\n}\n\nPlayerPtr AllPlayers::getPlayerPtr(const size_t & playerID, const size_t & type)\n{\n\tif\t\t\t(type == PlayerModels::AttackClosest)\t\t{ return PlayerPtr(new Player_AttackClosest(playerID)); }\n\telse if\t\t(type == PlayerModels::AttackDPS)\t\t\t{ return PlayerPtr(new Player_AttackDPS(playerID)); }\n\telse if\t\t(type == PlayerModels::AttackWeakest)\t\t{ return PlayerPtr(new Player_AttackWeakest(playerID)); }\n\telse if\t\t(type == PlayerModels::Kiter)\t\t\t\t{ return PlayerPtr(new Player_Kiter(playerID)); }\n\telse if\t\t(type == PlayerModels::KiterDPS)\t\t\t{ return PlayerPtr(new Player_KiterDPS(playerID)); }\n    else if\t\t(type == PlayerModels::Kiter_NOKDPS)\t\t{ return PlayerPtr(new Player_Kiter_NOKDPS(playerID)); }\n    else if\t\t(type == PlayerModels::Cluster)\t\t    \t{ return PlayerPtr(new Player_Cluster(playerID)); }\n\telse if\t\t(type == PlayerModels::NOKDPS)              { return PlayerPtr(new Player_NOKDPS(playerID)); }\n\telse if\t\t(type == PlayerModels::Random)\t\t\t\t{ return PlayerPtr(new Player_Random(playerID)); }\n\telse\t\t\t\t\t\t\t\t\t\t\t\t\t{ return PlayerPtr(new Player_NOKDPS(playerID)); }\n}\n"
  },
  {
    "path": "SparCraft/source/AllPlayers.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n#include <memory>\n\n// search-based players\n#include \"Player_AlphaBeta.h\"\n#include \"Player_PortfolioGreedySearch.h\"\n#include \"Player_UCT.h\"\n\n// script-based players\n#include \"Player_AttackClosest.h\"\n#include \"Player_AttackDPS.h\"\n#include \"Player_AttackWeakest.h\"\n#include \"Player_Kiter.h\"\n#include \"Player_KiterDPS.h\"\n#include \"Player_NOKDPS.h\"\n#include \"Player_Kiter_NOKDPS.h\"\n#include \"Player_Cluster.h\"\n#include \"Player_Random.h\"\n\nnamespace SparCraft\n{\n    \ntypedef std::shared_ptr<SparCraft::Player> PlayerPtr;\n\nnamespace AllPlayers\n{\n    Player * getPlayer(const size_t & playerID, const size_t & type);\n    PlayerPtr getPlayerPtr(const size_t & playerID, const size_t & type);\n}\n}"
  },
  {
    "path": "SparCraft/source/AlphaBetaMove.cpp",
    "content": "#include \"AlphaBetaMove.h\"\n\nusing namespace SparCraft;\n\nAlphaBetaMove::AlphaBetaMove()\n    : _isValid(false)\n{\n}\n\nAlphaBetaMove::AlphaBetaMove(const std::vector<Action> & move,const bool & isValid)\n    : _move(move)\n    ,_isValid(isValid)\n{\n}\n\nconst bool AlphaBetaMove::isValid() const \n{ \n    return _isValid; \n}\n\nconst std::vector<Action> & AlphaBetaMove::moveVec() const \n{ \n    return _move; \n}\n\nTTBestMove::TTBestMove()\n{\n}\n\nTTBestMove::TTBestMove(const AlphaBetaMove & first,const AlphaBetaMove & second)\n    : _firstMove(first)\n    ,_secondMove(second)\n{\n}\n\nconst AlphaBetaMove & TTBestMove::firstMove() const \n{ \n    return _firstMove; \n}\n\nconst AlphaBetaMove & TTBestMove::secondMove() const \n{ \n    return _secondMove; \n}\n\nAlphaBetaValue::AlphaBetaValue()\n{\n}\n\nAlphaBetaValue::AlphaBetaValue(const StateEvalScore & score,const AlphaBetaMove & abMove)\n    : _score(score)\n    ,_move(abMove)\n{\n}\n\nconst StateEvalScore & AlphaBetaValue::score() const \n{ \n    return _score; \n}\n\nconst AlphaBetaMove & AlphaBetaValue::abMove() const \n{ \n    return _move; \n}"
  },
  {
    "path": "SparCraft/source/AlphaBetaMove.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Position.hpp\"\n#include \"Action.h\"\n\nnamespace SparCraft\n{\n\nclass AlphaBetaMove\n{\n\tstd::vector<Action> _move;\n\tbool _isValid;\n\npublic:\n\n\tAlphaBetaMove();\n\n\tAlphaBetaMove(const std::vector<Action> & move, const bool & isValid);\n\n\tconst bool isValid() const;\n\tconst std::vector<Action> & moveVec() const;\n};\n\nclass TTBestMove\n{\n\tAlphaBetaMove _firstMove;\n\tAlphaBetaMove _secondMove;\n\npublic:\n\n\tTTBestMove();\n\n\tTTBestMove(const AlphaBetaMove & first, const AlphaBetaMove & second);\n\n\tconst AlphaBetaMove & firstMove() const;\n\tconst AlphaBetaMove & secondMove() const;\n};\n\n\nclass AlphaBetaValue\n{\t\n\tStateEvalScore\t_score;\n\tAlphaBetaMove\t_move;\n\npublic:\n\n\tAlphaBetaValue();\n\n\tAlphaBetaValue(const StateEvalScore & score, const AlphaBetaMove & abMove);\n\n\tconst StateEvalScore & score() const;\n\tconst AlphaBetaMove & abMove() const;\n};\n}"
  },
  {
    "path": "SparCraft/source/AlphaBetaSearch.cpp",
    "content": "#include \"AlphaBetaSearch.h\"\n\nusing namespace SparCraft;\n\nAlphaBetaSearch::AlphaBetaSearch(const AlphaBetaSearchParameters & params, TTPtr TT) \n\t: _params(params)\n\t, _currentRootDepth(0)\n\t, _TT(TT ? TT : TTPtr(new TranspositionTable()))\n{\n    for (size_t p(0); p<Constants::Num_Players; ++p)\n    {\n        // set ordered move script player objects\n        for (size_t s(0); s<_params.getOrderedMoveScripts().size(); ++s)\n        {\n            _allScripts[p].push_back(AllPlayers::getPlayerPtr(p, _params.getOrderedMoveScripts()[s]));\n        }\n\n        // set player model objects\n        if (_params.playerModel(p) != PlayerModels::None)\n        {\n            _playerModels[p] = AllPlayers::getPlayerPtr(p, _params.playerModel(p));\n        }\n    }\n}\n\nvoid AlphaBetaSearch::doSearch(GameState & initialState)\n{\n\t_searchTimer.start();\n\n\tStateEvalScore alpha(-10000000, 1000000);\n\tStateEvalScore beta\t( 10000000, 1000000);\n\n\tAlphaBetaValue val;\n\n\tif (_params.searchMethod() == SearchMethods::AlphaBeta)\n\t{\n\t\tval = alphaBeta(initialState, _params.maxDepth(), Players::Player_None, NULL, alpha, beta);\n\t}\n\telse if (_params.searchMethod() == SearchMethods::IDAlphaBeta)\n\t{\n\t\tval = IDAlphaBeta(initialState, _params.maxDepth());\n\t}\n\n\t_results.timeElapsed = _searchTimer.getElapsedTimeInMilliSec();\n}\n\nAlphaBetaValue AlphaBetaSearch::IDAlphaBeta(GameState & initialState, const size_t & maxDepth)\n{\n\tAlphaBetaValue val;\n\t_results.nodesExpanded = 0;\n\t_results.maxDepthReached = 0;\n\n\tfor (size_t d(1); d < maxDepth; ++d)\n\t{\n\t\t\n\t\tStateEvalScore alpha(-10000000, 999999);\n\t\tStateEvalScore beta\t( 10000000, 999999);\n\t\t\n\t\t_results.maxDepthReached = d;\n\t\t_currentRootDepth = d;\n\n\t\t// perform ID-AB until time-out\n\t\ttry\n\t\t{\n\t\t\tval = alphaBeta(initialState, d, Players::Player_None, NULL, alpha, beta);\n\n\t\t\t_results.bestMoves = val.abMove().moveVec();\n\t\t\t_results.abValue = val.score().val();\n\t\t}\n\t\t// if we do time-out\n\t\tcatch (int e)\n\t\t{\n\t\t\te += 1;\n\n\t\t\t// if we didn't finish the first depth, set the move to the best script move\n\t\t\tif (d == 1)\n\t\t\t{\n\t\t\t\tMoveArray moves;\n\t\t\t\tconst size_t playerToMove(getPlayerToMove(initialState, 1, Players::Player_None, true));\n\t\t\t\tinitialState.generateMoves(moves, playerToMove);\n\t\t\t\tPlayerPtr bestScript(new Player_NOKDPS(playerToMove));\n\t\t\t\tbestScript->getMoves(initialState, moves, _results.bestMoves);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\n\t\tlong long unsigned nodes = _results.nodesExpanded;\n\t\tdouble ms = _searchTimer.getElapsedTimeInMilliSec();\n\n\t\t//printTTResults();\n\t\t//fprintf(stdout, \"%s %8d %9d %9d %13.4lf %14llu %12d %12llu %15.2lf\\n\", \"IDA\", d, val.score().val(), (int)val.abMove().moveTuple(), ms, nodes, (int)_TT->numFound(), getResults().ttcuts, 1000*nodes/ms);\n\t}\n\n\treturn val;\n}\n\n// Transposition Table save \nvoid AlphaBetaSearch::TTsave(\tGameState & state, const StateEvalScore & value, const StateEvalScore & alpha, const StateEvalScore & beta, const size_t & depth, \n\t\t\t\t\t\tconst size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove) \n{\n\t// IF THE DEPTH OF THE ENTRY IS BIGGER THAN CURRENT DEPTH, DO NOTHING\n\tTTEntry * entry = _TT->lookupScan(state.calculateHash(0), state.calculateHash(1));\n\tbool valid = entry && entry->isValid();\n\tsize_t edepth = entry ? entry->getDepth() : 0;\n\n\t_results.ttSaveAttempts++;\n\t\n\tif (valid && (edepth > depth)) \n\t{\n\t\treturn;\n\t}\n\t\n\tint type(TTEntry::NONE);\n\n\tif      (value <= alpha) type = TTEntry::UPPER;\n\telse if (value >= beta)  type = TTEntry::LOWER;\n\telse                     type = TTEntry::ACCURATE;\n\n\t// SAVE A NEW ENTRY IN THE TRANSPOSITION TABLE\n\t_TT->save(state.calculateHash(0), state.calculateHash(1), value, depth, type, firstPlayer, bestFirstMove, bestSecondMove);\n}\n\n// Transposition Table look up + alpha/beta update\nTTLookupValue AlphaBetaSearch::TTlookup(const GameState & state, StateEvalScore & alpha, StateEvalScore & beta, const size_t & depth)\n{\n\tTTEntry * entry = _TT->lookupScan(state.calculateHash(0), state.calculateHash(1));\n\tif (entry && (entry->getDepth() == depth)) \n\t{\n\t\t// get the value and type of the entry\n\t\tStateEvalScore TTvalue = entry->getScore();\n\t\t\n\t\t// set alpha and beta depending on the type of entry in the TT\n\t\tif (entry->getType() == TTEntry::LOWER)\n\t\t{\n\t\t\tif (TTvalue > alpha) \n\t\t\t{\n\t\t\t\talpha = TTvalue;\n\t\t\t}\n\t\t}\n\t\telse if (entry->getType() == TTEntry::UPPER) \n\t\t{\n\t\t\tif (TTvalue < beta)\n\t\t\t{\n\t\t\t\tbeta  = TTvalue;\n\t\t\t}\n\t\t} \n\t\telse\n\t\t{\n\t\t\tprintf(\"LOL\\n\");\n\t\t\talpha = TTvalue;\n\t\t\tbeta = TTvalue;\n\t\t}\n\t\t\n\t\tif (alpha >= beta) \n\t\t{\n\t\t\t// this will be a cut\n\t\t\t_results.ttcuts++;\n\t\t\treturn TTLookupValue(true, true, entry);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// found but no cut\n\t\t\t_results.ttFoundNoCut++;\n\t\t\treturn TTLookupValue(true, false, entry);\n\t\t}\n\t}\n\telse if (entry)\n\t{\n\t\t_results.ttFoundLessDepth++;\n\t\treturn TTLookupValue(true, false, entry);\n\t}\n\n\treturn TTLookupValue(false, false, entry);\n}\n\nconst bool AlphaBetaSearch::searchTimeOut()\n{\n\treturn (_params.timeLimit() && (_results.nodesExpanded % 50 == 0) && (_searchTimer.getElapsedTimeInMilliSec() >= _params.timeLimit()));\n}\n\nconst bool AlphaBetaSearch::terminalState(GameState & state, const size_t & depth) const\n{\n\treturn (depth <= 0 || state.isTerminal());\n}\n\nconst AlphaBetaMove & AlphaBetaSearch::getAlphaBetaMove(const TTLookupValue & TTval, const size_t & playerToMove) const\n{\n\tconst size_t enemyPlayer(getEnemy(playerToMove));\n\n\t// if we have a valid first move for this player, use it\n\tif (TTval.entry()->getBestMove(playerToMove).firstMove().isValid())\n\t{\n\t\treturn TTval.entry()->getBestMove(playerToMove).firstMove();\n\t}\n\t// otherwise return the response to an opponent move, if it doesn't exist it will just be invalid\n\telse\n\t{\n\t\treturn TTval.entry()->getBestMove(enemyPlayer).secondMove();\n\t}\n}\n\nvoid AlphaBetaSearch::generateOrderedMoves(GameState & state, MoveArray & moves, const TTLookupValue & TTval, const size_t & playerToMove, const size_t & depth)\n{\n\t// get the array where we will store the moves and clear it\n\tArray<std::vector<Action>, Constants::Max_Ordered_Moves> & orderedMoves(_orderedMoves[depth]);\n\torderedMoves.clear();\n\n\t// if we are using opponent modeling, get the move and then return, we don't want to put any more moves in\n\tif (_params.playerModel(playerToMove) != PlayerModels::None)\n\t{\n        // put the vector into the ordered moves array\n        orderedMoves.add(std::vector<Action>());\n\n        // generate the moves into that vector\n        _playerModels[playerToMove]->getMoves(state, moves, orderedMoves[0]);\n\t\t\n\t\treturn;\n\t}\n\n\t// if there is a transposition table entry for this state\n\t/*if (TTval.found())\n\t{\n\t\t// get the abMove we stored for this player\n\t\tconst AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove);\n\n\t\t_results.ttFoundCheck++;\n\n\t\t// Two checks:\n\t\t// 1) Is the move 'valid' ie: was it actually set inside the TT\n\t\t// TODO:: Possibly validate this move a second time somehow\n        //        Was previously done with move tuple numbers\n\t\tif (abMove.isValid())\n\t\t{\n\t\t\torderedMoves.add(abMove.moveVec());\n\t\t\t_results.ttMoveOrders++;\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_results.ttFoundButNoMove++;\n\t\t}\n\t}*/\n\n    if (depth == 2)\n    {\n        int a = 6;\n    }\n\n    // if we are using script move ordering, insert the script moves we want\n    if (_params.moveOrderingMethod() == MoveOrderMethod::ScriptFirst)\n    {\n        for (size_t s(0); s<_params.getOrderedMoveScripts().size(); s++)\n\t    {\n            std::vector<Action> moveVec;\n\t\t    _allScripts[playerToMove][s]->getMoves(state, moves, moveVec);\n\t\t    orderedMoves.add(moveVec);\n\t    }\n\n        if (orderedMoves.size() < 2)\n        {\n            int a = 6;\n        }\n    }\n}\n\nbool AlphaBetaSearch::getNextMoveVec(size_t playerToMove, MoveArray & moves, const size_t & moveNumber, const TTLookupValue & TTval, const size_t & depth, std::vector<Action> & moveVec) const\n{\n    if (_params.maxChildren() && (moveNumber >= _params.maxChildren()))\n    {\n        return false;\n    }\n\n    // if this move is beyond the first, check to see if we are only using a single move\n    if (moveNumber == 1)\n    {\n        // if we are player modeling, we should have only generated the first move\n        if (_params.playerModel(playerToMove) != PlayerModels::None)\n\t    {\n            // so return false\n\t\t    return false;\n\t    }\n\n\t    // if there is a transposition table entry for this state\n\t    if (TTval.found())\n\t    {\n\t\t    // if there was a valid move found with higher depth, just do that one\n\t\t    const AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove);\n\t\t    if ((TTval.entry()->getDepth() >= depth) && abMove.isValid())\n\t\t    {\n                // so return false\n\t\t\t    return false;\n\t\t    }\n\t    }\n    }\n\n\tconst Array<std::vector<Action>, Constants::Max_Ordered_Moves> & orderedMoves(_orderedMoves[depth]);\n    moveVec.clear();\n   \n\t// if this move should be from the ordered list, return it from the list\n\tif (moveNumber < orderedMoves.size())\n\t{\n        moveVec.assign(orderedMoves[moveNumber].begin(), orderedMoves[moveNumber].end());\n        return true;\n\t}\n\t// otherwise return the next move vector starting from the beginning\n\telse\n\t{\n        if (moves.hasMoreMoves())\n        {\n            moves.getNextMoveVec(moveVec);\n            return true;\n        }\n        else\n        {\n            return false;\n        }\n\t}\n}\n\nconst size_t AlphaBetaSearch::getPlayerToMove(GameState & state, const size_t & depth, const size_t & lastPlayerToMove, const bool isFirstSimMove) const\n{\n\tconst size_t whoCanMove(state.whoCanMove());\n\n\t// if both players can move\n\tif (whoCanMove == Players::Player_Both)\n\t{\n\t\t// no matter what happens, the 2nd player to move is always the enemy of the first\n\t\tif (!isFirstSimMove)\n\t\t{\n\t\t\treturn getEnemy(lastPlayerToMove);\n\t\t}\n\n\t\t// pick the first move based on our policy\n\t\tconst size_t policy(_params.playerToMoveMethod());\n\t\tconst size_t maxPlayer(_params.maxPlayer());\n\n\t\tif (policy == SparCraft::PlayerToMove::Alternate)\n\t\t{\n\t\t\treturn isRoot(depth) ? maxPlayer : getEnemy(lastPlayerToMove);\n\t\t}\n\t\telse if (policy == SparCraft::PlayerToMove::Not_Alternate)\n\t\t{\n\t\t\treturn isRoot(depth) ? maxPlayer : lastPlayerToMove;\n\t\t}\n\t\telse if (policy == SparCraft::PlayerToMove::Random)\n\t\t{\n\t\t\t// srand(state.calculateHash(0));\n\t\t\treturn isRoot(depth) ? maxPlayer : rand() % 2;\n\t\t}\n\n\t\t// we should never get to this state\n\t\tSystem::FatalError(\"AlphaBeta Error: Nobody can move for some reason\");\n\t\treturn Players::Player_None;\n\t}\n\telse\n\t{\n\t\treturn whoCanMove;\n\t}\n}\n\nconst bool AlphaBetaSearch::isTranspositionLookupState(GameState & state, const std::vector<Action> * firstSimMove) const\n{\n\treturn !state.bothCanMove() || (state.bothCanMove() && !firstSimMove);\n}\n\nAlphaBetaValue AlphaBetaSearch::alphaBeta(GameState & state, size_t depth, const size_t lastPlayerToMove, std::vector<Action> * prevSimMove, StateEvalScore alpha, StateEvalScore beta)\n{\n\t// update statistics\n\t_results.nodesExpanded++;\n\n\tif (searchTimeOut())\n\t{\n\t\tthrow 1;\n\t}\n    \n\tif (terminalState(state, depth))\n\t{\n\t\t// return the value, but the move will not be valid since none was performed\n        StateEvalScore evalScore = state.eval(_params.maxPlayer(), _params.evalMethod(), _params.simScript(Players::Player_One), _params.simScript(Players::Player_Two));\n\t\t\n\t\treturn AlphaBetaValue(StateEvalScore(evalScore.val(), state.getNumMovements(_params.maxPlayer()) + evalScore.numMoves() ), AlphaBetaMove());\n\t}\n\n\t// figure out which player is to move\n\tconst size_t playerToMove(getPlayerToMove(state, depth, lastPlayerToMove, !prevSimMove));\n\n\t// is the player to move the max player?\n\tbool maxPlayer = (playerToMove == _params.maxPlayer());\n\n\t// Transposition Table Logic\n\tTTLookupValue TTval;\n\tif (isTranspositionLookupState(state, prevSimMove))\n\t{\n\t\tTTval = TTlookup(state, alpha, beta, depth);\n\n\t\t// if this is a TT cut, return the proper value\n\t\tif (TTval.cut())\n\t\t{\n\t\t\treturn AlphaBetaValue(TTval.entry()->getScore(), getAlphaBetaMove(TTval, playerToMove));\n\t\t}\n\t}\n\n\tbool bestMoveSet(false);\n\n\t// move generation\n\tMoveArray & moves = _allMoves[depth];\n\tstate.generateMoves(moves, playerToMove);\n    moves.shuffleMoveActions();\n\tgenerateOrderedMoves(state, moves, TTval, playerToMove, depth);\n\n\t// while we have more simultaneous moves\n\tAlphaBetaMove bestMove, bestSimResponse;\n\t    \n    size_t moveNumber(0);\n    std::vector<Action> moveVec;\n\n    // for each child\n    while (getNextMoveVec(playerToMove, moves, moveNumber, TTval, depth, moveVec))\n\t{\n        // the value of the recursive AB we will call\n\t\tAlphaBetaValue val;\n\t\t\n\t\t// generate the child state\n\t\tGameState child(state);\n\n\t\tbool firstMove = true;\n\n\t\t// if this is the first player in a simultaneous move state\n\t\tif (state.bothCanMove() && !prevSimMove && (depth != 1))\n\t\t{\n\t\t\tfirstMove = true;\n\t\t\t// don't generate a child yet, just pass on the move we are investigating\n\t\t\tval = alphaBeta(state, depth-1, playerToMove, &moveVec, alpha, beta);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfirstMove = false;\n\n\t\t\t// if this is the 2nd move of a simultaneous move state\n\t\t\tif (prevSimMove)\n\t\t\t{\n\t\t\t\t// do the previous move selected by the first player to move during this state\n                child.makeMoves(*prevSimMove);\n\t\t\t}\n\n\t\t\t// do the moves of the current player\n            child.makeMoves(moveVec);\n\t\t\tchild.finishedMoving();\n\n\t\t\t// get the alpha beta value\n\t\t\tval = alphaBeta(child, depth-1, playerToMove, NULL, alpha, beta);\n\t\t}\n\n\t\t// set alpha or beta based on maxplayer\n\t\tif (maxPlayer && (val.score() > alpha)) \n\t\t{\n\t\t\talpha = val.score();\n\t\t\tbestMove = AlphaBetaMove(moveVec, true);\n\t\t\tbestMoveSet = true;\n\n\t\t\tif (state.bothCanMove() && !prevSimMove)\n\t\t\t{\n\t\t\t\tbestSimResponse = val.abMove();\n\t\t\t}\n\n\t\t\t// if this is depth 1 of the first try at depth 1, store the best in results\n\t\t}\n\t\telse if (!maxPlayer && (val.score() < beta))\n\t\t{\n\t\t\tbeta = val.score();\n\t\t\tbestMove = AlphaBetaMove(moveVec, true);\n\t\t\tbestMoveSet = true;\n\n\t\t\tif (state.bothCanMove() && prevSimMove)\n\t\t\t{\n\t\t\t\tbestSimResponse = val.abMove();\n\t\t\t}\n\t\t}\n\n\t\tif (alpha.val() == -10000000 && beta.val() == 10000000)\n\t\t{\n\t\t\tfprintf(stderr, \"\\n\\nALPHA BETA ERROR, NO VALUE SET\\n\\n\");\n\t\t}\n\n\t\t// alpha-beta cut\n\t\tif (alpha >= beta) \n\t\t{ \n\t\t\tbreak; \n\t\t}\n\n        moveNumber++;\n\t}\n\t\n\tif (isTranspositionLookupState(state, prevSimMove))\n\t{\n\t\tTTsave(state, maxPlayer ? alpha : beta, alpha, beta, depth, playerToMove, bestMove, bestSimResponse);\n\t}\n\n\treturn maxPlayer ? AlphaBetaValue(alpha, bestMove) : AlphaBetaValue(beta, bestMove);\n}\n\n\nAlphaBetaSearchResults & AlphaBetaSearch::getResults()\n{\n\treturn _results;\n}\n\nconst size_t AlphaBetaSearch::getEnemy(const size_t & player) const\n{\n\treturn (player + 1) % 2;\n}\n\nconst bool AlphaBetaSearch::isRoot(const size_t & depth) const\n{\n\treturn depth == _currentRootDepth;\n}\n\nvoid AlphaBetaSearch::printTTResults() const\n{\n\tprintf(\"\\n\");\n\tprintf(\"Total Usage            %9d\\n\", (int)_TT->getUsage());\n\tprintf(\"Save Attempt           %9d\\n\", (int)_results.ttSaveAttempts);\n\tprintf(\"   Save Succeed        %9d\\n\", (int)_TT->numSaves());\n\tprintf(\"      Save Empty       %9d\\n\", (int)_TT->saveEmpty);\n\tprintf(\"      Save Self        %9d\\n\", (int)_TT->saveOverwriteSelf);\n\tprintf(\"      Save Other       %9d\\n\", (int)_TT->saveOverwriteOther);\n\tprintf(\"Look-Up                %9d\\n\", (int)_TT->numLookups());\n\tprintf(\"   Not Found           %9d\\n\", (int)_TT->numNotFound());\n\tprintf(\"   Collisions          %9d\\n\", (int)_TT->numCollisions());\n\tprintf(\"   Found               %9d\\n\", (int)_TT->numFound());\n\tprintf(\"      Less Depth       %9d\\n\", (int)_results.ttFoundLessDepth);\n\tprintf(\"      More Depth       %9d\\n\", ((int)_results.ttFoundCheck + (int)_results.ttcuts));\n\tprintf(\"         Cut           %9d\\n\", (int)_results.ttcuts);\n\tprintf(\"         Move          %9d\\n\", (int)_results.ttMoveOrders);\n\tprintf(\"         No Move       %9d\\n\", (int)_results.ttFoundButNoMove);\n\tprintf(\"\\n\");\n}\n"
  },
  {
    "path": "SparCraft/source/AlphaBetaSearch.h",
    "content": "#pragma once\n\n#include <limits>\n\n#include \"AllPlayers.h\"\n#include \"Timer.h\"\n#include \"GameState.h\"\n#include \"Action.h\"\n#include \"Array.hpp\"\n#include \"MoveArray.h\"\n#include \"TranspositionTable.h\"\n#include \"Player.h\"\n\n#include \"AlphaBetaSearchResults.hpp\"\n#include \"AlphaBetaSearchParameters.hpp\"\n#include \"GraphViz.hpp\"\n\nnamespace SparCraft\n{\n\nclass Game;\nclass AlphaBetaSearchParameters;\nclass Player;\n\n\nclass AlphaBetaSearch\n{\n\tAlphaBetaSearchParameters               _params;\n\tAlphaBetaSearchResults                  _results;\n\tSparCraft::Timer                        _searchTimer;\n\n\tsize_t                                  _currentRootDepth;\n\n\tArray<MoveArray, \n          Constants::Max_Search_Depth>      _allMoves;\n\n\tArray2D<std::vector<Action>, \n\t\t\tConstants::Max_Search_Depth, \n\t\t\tConstants::Max_Ordered_Moves>   _orderedMoves;\n\n    std::vector<PlayerPtr>\t\t\t\t\t_allScripts[Constants::Num_Players];\n    PlayerPtr                               _playerModels[Constants::Num_Players];\n\n\tTTPtr                                   _TT;\n\npublic:\n\n\tAlphaBetaSearch(const AlphaBetaSearchParameters & params, TTPtr TT = TTPtr((TranspositionTable *)NULL));\n\n\tvoid doSearch(GameState & initialState);\n\n\t// search functions\n\tAlphaBetaValue IDAlphaBeta(GameState & initialState, const size_t & maxDepth);\n\tAlphaBetaValue alphaBeta(GameState & state, size_t depth, const size_t lastPlayerToMove, std::vector<Action> * firstSimMove, StateEvalScore alpha, StateEvalScore beta);\n\n\t// Transposition Table\n\tTTLookupValue TTlookup(const GameState & state, StateEvalScore & alpha, StateEvalScore & beta, const size_t & depth);\n\tvoid TTsave(GameState & state, const StateEvalScore & value, const StateEvalScore & alpha, const StateEvalScore & beta, const size_t & depth, \n\t\t\t\tconst size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove);\n\n\t// Transposition Table look up + alpha/beta update\n\n\t// get the results from the search\n\tAlphaBetaSearchResults & getResults();\n    \t\n\tvoid generateOrderedMoves(GameState & state, MoveArray & moves, const TTLookupValue & TTval, const size_t & playerToMove, const size_t & depth);\n\tconst size_t getEnemy(const size_t & player) const;\n\tconst size_t getPlayerToMove(GameState & state, const size_t & depth, const size_t & lastPlayerToMove, const bool isFirstSimMove) const;\n\tbool getNextMoveVec(size_t playerToMove, MoveArray & moves, const size_t & moveNumber, const TTLookupValue & TTval, const size_t & depth, std::vector<Action> & moveVec) const;\n\tconst size_t getNumMoves(MoveArray & moves, const TTLookupValue & TTval, const size_t & playerToMove, const size_t & depth) const;\n\tconst AlphaBetaMove & getAlphaBetaMove(const TTLookupValue & TTval, const size_t & playerToMove) const;\n\tconst bool searchTimeOut();\n\tconst bool isRoot(const size_t & depth) const;\n\tconst bool terminalState(GameState & state, const size_t & depth) const;\n\tconst bool isTranspositionLookupState(GameState & state, const std::vector<Action> * firstSimMove) const;\n\n\tvoid printTTResults() const;\n};\n}"
  },
  {
    "path": "SparCraft/source/AlphaBetaSearchParameters.hpp",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace SparCraft\n{\n    class AlphaBetaSearchParameters;\n}\n\nclass SparCraft::AlphaBetaSearchParameters\n{\t\t\t\t\t\t\t\t\t\t\t        // DEFAULT\t\t\t\tDESCRIPTION\n    size_t          _searchMethod;                  // ID-AB                The Method to use for AB Search\n    size_t\t\t    _maxPlayer;\t\t\t\t\t    // Player_One\t\t\tThe player who will make maximizing moves\n    size_t          _maxDepth;                      // Max_Depth            Maximum depth of AB search to allow\n\n\tsize_t\t\t    _timeLimit;\t\t\t\t\t    // 0\t\t\t\t\tSearch time limit. 0 means no time limit\n    size_t          _maxChildren;                   // 10                   Max children at each node\n    size_t          _moveOrdering;                  // ScriptFirst          Move ordering method for child generation\n\tsize_t\t\t    _evalMethod;\t\t\t\t    // LTD\t\t\t\tEvaluation function type\n    size_t          _simScripts[2];                 // NOKDPS               Policy to use for playouts\n\tsize_t\t\t    _playerToMoveMethod;\t\t    // Alternate\t\t\tThe player to move policy\n\tsize_t\t\t    _playerModel[2];                // None                 Player model to use for each player\n\n    std::string     _graphVizFilename;              // \"\"                   File name to output graph viz file\n\n    std::vector<size_t> _orderedMoveScripts;\n\n    std::vector<std::vector<std::string> > _desc;    // 2-column description vector\n\npublic:\n\n\t// default constructor\n\tAlphaBetaSearchParameters() \n        : _searchMethod         (SearchMethods::IDAlphaBeta)\n        , _maxPlayer            (Players::Player_One)\n        , _maxDepth             (Constants::Max_Search_Depth)\n\t    , _timeLimit            (0)\n        , _maxChildren          (10)\n        , _moveOrdering         (MoveOrderMethod::ScriptFirst)\n        , _evalMethod           (SparCraft::EvaluationMethods::Playout)\n\t    , _playerToMoveMethod   (SparCraft::PlayerToMove::Alternate)\n    {\n\t    setPlayerModel(Players::Player_One, PlayerModels::None);\n\t    setPlayerModel(Players::Player_Two, PlayerModels::None);\n        setSimScripts(PlayerModels::NOKDPS, PlayerModels::NOKDPS);\n    }\n\n    const size_t & searchMethod()\t\t\t\t\t\t\t    const   { return _searchMethod; }\n    const size_t & maxPlayer()\t\t\t\t\t\t\t        const   { return _maxPlayer; }\n    const size_t & maxDepth()\t\t\t\t\t\t\t        const   { return _maxDepth; }\n    const size_t & timeLimit()\t\t\t\t\t\t\t        const   { return _timeLimit; }\n    const size_t & maxChildren()                                const   { return _maxChildren; }\n    const size_t & moveOrderingMethod()                         const   { return _moveOrdering; }\n    const size_t & evalMethod()\t\t\t\t\t\t            const   { return _evalMethod; }\n    const size_t & simScript(const size_t & player)             const   { return _simScripts[player]; }\n    const size_t & playerToMoveMethod()\t\t\t\t            const   { return _playerToMoveMethod; }\n    const size_t & playerModel(const size_t & player)\t        const   { return _playerModel[player]; }\n    const std::string & graphVizFilename()                      const   { return _graphVizFilename; }\n    const std::vector<size_t> & getOrderedMoveScripts()         const   { return _orderedMoveScripts; }\n\t\n    void setSearchMethod(const size_t & method)                         { _searchMethod = method; }\n    void setMaxPlayer(const size_t & player)\t\t\t\t\t        { _maxPlayer = player; }\n    void setMaxDepth(const size_t & depth)                              { _maxDepth = depth; }\n    \n    void setTimeLimit(const size_t & timeLimit)\t\t\t\t\t        { _timeLimit = timeLimit; }\n    void setMaxChildren(const size_t & children)                        { _maxChildren = children; }\n    void setMoveOrderingMethod(const size_t & method)                   { _moveOrdering = method; }\n    void setEvalMethod(const size_t & eval)\t\t\t\t\t\t        { _evalMethod = eval; }\n    void setSimScripts(const size_t & p1, const size_t & p2)\t\t    { _simScripts[0] = p1; _simScripts[1] = p2; }\n    void setPlayerToMoveMethod(const size_t & method)\t\t\t\t    { _playerToMoveMethod = method; }\n    void setGraphVizFilename(const std::string & filename)              { _graphVizFilename = filename; }\n    void addOrderedMoveScript(const size_t & script)                    { _orderedMoveScripts.push_back(script); }\n    void setPlayerModel(const size_t & player, const size_t & model)\t{ _playerModel[player] = model; }\t\n\n    std::vector<std::vector<std::string> > & getDescription()\n    {\n        if (_desc.size() == 0)\n        {\n            _desc.push_back(std::vector<std::string>());\n            _desc.push_back(std::vector<std::string>());\n\n            std::stringstream ss;\n\n            _desc[0].push_back(\"Player Type:\");\n            _desc[0].push_back(\"Time Limit:\");\n            _desc[0].push_back(\"Max Children:\");\n            _desc[0].push_back(\"Move Ordering:\");\n            _desc[0].push_back(\"Player To Move:\");\n            _desc[0].push_back(\"Opponent Model:\");\n\n            ss << \"AlphaBeta\";                                              _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << timeLimit() << \"ms\";                                      _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << maxChildren();                                            _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << MoveOrderMethod::getName(moveOrderingMethod());             _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << PlayerToMove::getName(playerToMoveMethod());                _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << PlayerModels::getName(playerModel((maxPlayer()+1)%2));   _desc[1].push_back(ss.str()); ss.str(std::string());\n        }\n        \n        return _desc;\n    }\n};\n"
  },
  {
    "path": "SparCraft/source/AlphaBetaSearchResults.hpp",
    "content": "#pragma once\n\n#include <vector>\n#include \"Action.h\"\n\nnamespace SparCraft\n{\nclass AlphaBetaSearchResults\n{\n\npublic:\n\n\tbool \t\t\t\tsolved,\t\t\t// whether ot not a solution was found\n\t\t\t\t\t\ttimedOut;\t\t// did the search time-out?\n\t\n\tunsigned long long \tnodesExpanded;\t// number of nodes expanded in the search\n\t\n\tdouble \t\t\t\ttimeElapsed,\t// time elapsed in milliseconds\n\t\t\t\t\t\tavgBranch;\t\t// avg branching factor\n\n    std::vector<Action>   bestMoves;\n\tScoreType\t\t\tabValue;\n\tunsigned long long  ttcuts;\n\tsize_t\t\t\t\tmaxDepthReached;\t\n\n\tsize_t\t\t\t\tttMoveOrders;\n\tsize_t\t\t\t\tttFoundButNoMove;\n\tsize_t\t\t\t\tttFoundNoCut;\n\tsize_t\t\t\t\tttFoundCheck;\n\tsize_t\t\t\t\tttFoundLessDepth;\n\tsize_t\t\t\t\tttSaveAttempts;\n\n    std::vector<std::vector<std::string> > _desc;    // 2-column description vector\n\t\n\tAlphaBetaSearchResults() \n\t\t: solved(false)\n\t\t, timedOut(false)\n\t\t, nodesExpanded(0)\n\t\t, timeElapsed(0)\n\t\t, avgBranch(0)\n\t\t, abValue(0)\n\t\t, ttcuts(0)\n\t\t, maxDepthReached(0)\n\t\t, ttMoveOrders(0)\n\t\t, ttFoundButNoMove(0)\n\t\t, ttFoundNoCut(0)\n\t\t, ttFoundCheck(0)\n\t\t, ttFoundLessDepth(0)\n\t\t, ttSaveAttempts(0)\n\t{\n\t}\n\n    std::vector<std::vector<std::string> > & getDescription()\n    {\n        _desc.clear();\n        _desc.push_back(std::vector<std::string>());\n        _desc.push_back(std::vector<std::string>());\n\n        std::stringstream ss;\n\n        _desc[0].push_back(\"Nodes Searched: \");\n        _desc[0].push_back(\"AB Value: \");\n        _desc[0].push_back(\"Max Depth: \");\n\n        ss << nodesExpanded;       _desc[1].push_back(ss.str()); ss.str(std::string());\n        ss << abValue;              _desc[1].push_back(ss.str()); ss.str(std::string());\n        ss << maxDepthReached;     _desc[1].push_back(ss.str()); ss.str(std::string());\n        \n        return _desc;\n    }\n};\n}"
  },
  {
    "path": "SparCraft/source/AnimationFrameData.cpp",
    "content": "#include \"AnimationFrameData.h\"\n\nusing namespace SparCraft;\n\nstd::vector<AttackFrameData> AnimationFrameData::attackFrameData;\n\nvoid AnimationFrameData::init()\n{\n    // allocate the vector according to UnitType size\n    attackFrameData = std::vector<AttackFrameData>(BWAPI::UnitTypes::allUnitTypes().size(), AttackFrameData(0,0));\n\n    // Protoss Units\n    attackFrameData[BWAPI::UnitTypes::Protoss_Probe.getID()]                = AttackFrameData(2, 2);\n    attackFrameData[BWAPI::UnitTypes::Protoss_Zealot.getID()]               = AttackFrameData(8, 7);\n    attackFrameData[BWAPI::UnitTypes::Protoss_Dragoon.getID()]              = AttackFrameData(7, 3);\n    attackFrameData[BWAPI::UnitTypes::Protoss_Dark_Templar.getID()]         = AttackFrameData(9, 9);\n    attackFrameData[BWAPI::UnitTypes::Protoss_Scout.getID()]                = AttackFrameData(2, 2);\n    attackFrameData[BWAPI::UnitTypes::Protoss_Corsair.getID()]              = AttackFrameData(8, 8);\n    attackFrameData[BWAPI::UnitTypes::Protoss_Arbiter.getID()]              = AttackFrameData(2, 2);\n    attackFrameData[BWAPI::UnitTypes::Protoss_Archon.getID()]               = AttackFrameData(1, 1);\n    attackFrameData[BWAPI::UnitTypes::Protoss_Photon_Cannon.getID()]        = AttackFrameData(1, 1);\n\n    // Terran Units\n    attackFrameData[BWAPI::UnitTypes::Terran_SCV.getID()]                   = AttackFrameData(2, 2);\n    attackFrameData[BWAPI::UnitTypes::Terran_Marine.getID()]                = AttackFrameData(8, 6);\n    attackFrameData[BWAPI::UnitTypes::Terran_Firebat.getID()]               = AttackFrameData(8, 8);\n    attackFrameData[BWAPI::UnitTypes::Terran_Ghost.getID()]                 = AttackFrameData(3, 2);\n    attackFrameData[BWAPI::UnitTypes::Terran_Vulture.getID()]               = AttackFrameData(1, 1);\n    attackFrameData[BWAPI::UnitTypes::Terran_Goliath.getID()]               = AttackFrameData(1, 1);\n    attackFrameData[BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode.getID()]  = AttackFrameData(1, 1);\n    attackFrameData[BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode.getID()] = AttackFrameData(1, 1);\n    attackFrameData[BWAPI::UnitTypes::Terran_Wraith.getID()]                = AttackFrameData(2, 2);\n    attackFrameData[BWAPI::UnitTypes::Terran_Battlecruiser.getID()]         = AttackFrameData(2, 2);\n    attackFrameData[BWAPI::UnitTypes::Terran_Valkyrie.getID()]              = AttackFrameData(40, 40);\n    attackFrameData[BWAPI::UnitTypes::Terran_Missile_Turret.getID()]        = AttackFrameData(1, 1);\n\n    // Zerg Units\n    attackFrameData[BWAPI::UnitTypes::Zerg_Drone.getID()]                   = AttackFrameData(2, 2);\n    attackFrameData[BWAPI::UnitTypes::Zerg_Zergling.getID()]                = AttackFrameData(5, 5);\n    attackFrameData[BWAPI::UnitTypes::Zerg_Hydralisk.getID()]               = AttackFrameData(3, 2);\n    attackFrameData[BWAPI::UnitTypes::Zerg_Lurker.getID()]                  = AttackFrameData(2, 2);\n    attackFrameData[BWAPI::UnitTypes::Zerg_Ultralisk.getID()]               = AttackFrameData(14, 14);\n    attackFrameData[BWAPI::UnitTypes::Zerg_Mutalisk.getID()]                = AttackFrameData(1, 1);\n    attackFrameData[BWAPI::UnitTypes::Zerg_Devourer.getID()]                = AttackFrameData(9, 9);\n    attackFrameData[BWAPI::UnitTypes::Zerg_Sunken_Colony.getID()]           = AttackFrameData(1, 1);\n    attackFrameData[BWAPI::UnitTypes::Zerg_Spore_Colony.getID()]            = AttackFrameData(1, 1);\n}\n\nconst AttackFrameData & AnimationFrameData::getAttackFrames(const BWAPI::UnitType & type)\n{\n    return attackFrameData[type.getID()];\n}"
  },
  {
    "path": "SparCraft/source/AnimationFrameData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace SparCraft\n{\n\ntypedef std::pair<TimeType,TimeType> AttackFrameData;\n\nclass AnimationFrameData\n{\n    static std::vector<AttackFrameData> attackFrameData;\n\npublic:\n\n    static void init();\n    static const AttackFrameData & getAttackFrames(const BWAPI::UnitType & type);\n};\n\n}"
  },
  {
    "path": "SparCraft/source/Array.hpp",
    "content": "#pragma once\n\nnamespace SparCraft\n{\ntemplate <class T, size_t elem>\nclass Array\n{\n\tsize_t\t_size;\n\tsize_t  _capacity;\n\tT\t\t_arr[elem];\n\npublic:\n\n\tArray<T, elem> ()\n\t\t: _size(0)\n\t\t, _capacity(elem)\n\t{\n\t}\n\n\tArray<T, elem> (const T & fill)\n\t\t: _size(0)\n\t\t, _capacity(elem)\n\t{\n\t\tstd::fill(_arr, _arr + elem, fill);\n\t}\n\n\tT & get(const size_t & index)\n\t{\n\t\treturn _arr[index];\n\t}\n\n\tconst T & get(const size_t & index) const\n\t{\n\t\treturn _arr[index];\n\t}\n\n\tT & operator [] (const size_t & index)\n\t{\n\t\treturn get(index);\n\t}\n\t\n\tconst T & operator [] (const size_t & index) const\n\t{\n\t\treturn get(index);\n\t}\n\n\tconst bool contains(const T & e) const\n\t{\n\t\tfor (size_t i(0); i<capacity(); ++i)\n\t\t{\n\t\t\tif (get(i) == e)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tconst size_t capacity() const\n\t{\n\t\treturn _capacity;\n\t}\n\n\tconst bool containsSize(const T & e) const\n\t{\n\t\tfor (size_t i(0); i<_size; ++i)\n\t\t{\n\t\t\tif (get(i) == e)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tvoid inc()\n\t{\n\t\t_size++;\n\t}\t\t\n\n\tvoid add(const T & e)\n\t{\n\t\tassert(_size < (capacity()-1));\n\t\tget(_size) = e;\n\t\t_size++;\n\t}\n\n\tvoid addUnique(const T & e)\n\t{\n\t\tif (!contains(e))\n\t\t{\n\t\t\tadd(e);\n\t\t}\n\t}\n\n\tconst T & back() const\n\t{\n\t\tassert(_size > 0);\n\t\treturn get(_size);\n\t}\n\n\tvoid clear()\n\t{\n\t\t_size = 0;\n\t}\n\n\tconst size_t & size() const\n\t{\n\t\treturn _size;\n\t}\n\n\tvoid fill(const T & e)\n\t{\n\t\tstd::fill(_arr, _arr + elem, e);\n\t}\n};\n\ntemplate <class T, size_t rows, size_t cols>\nclass Array2D\n{\n\tsize_t\t\t\t\t\t_rows;\n\tsize_t\t\t\t\t\t_cols;\n\n\tArray< Array<T, cols>, rows>\t_arr;\n\npublic:\n\n\tArray2D<T, rows, cols>()\n\t\t: _rows(rows)\n\t\t, _cols(cols)\n\t{\n\t}\n\n\tArray2D<T, rows, cols> & operator = (const Array2D<T, rows, cols> & rhs)\n\t{\n\t\tif (this == &rhs)\n\t\t{\n\t\t\treturn *this;\n\t\t}\n\n\t\tfor (size_t r(0); r<_rows; ++r)\n\t\t{\n\t\t\t_arr[r] = rhs._arr[r];\n\t\t}\n\n\t\treturn *this;\n\t}\n\n\tArray2D<T, rows, cols> (const Array2D<T, rows, cols> & rhs)\n\t\t: _rows(rhs._rows)\n\t\t, _cols(rhs._cols)\n\t\t, _arr(rhs._arr)\n\t{\n\t\t\n\t}\n\n\tconst size_t getRows() const\n\t{\n\t\treturn _arr.capacity();\n\t}\n\t\n\tArray<T, cols> & operator [] (const size_t & index)\n\t{\n\t\tassert(index < _rows);\n\t\treturn _arr[index];\n\t}\n\t\n\tconst Array<T, cols> & operator [] (const size_t & index) const\n\t{\n\t\tassert(index < _rows);\n\t\treturn _arr[index];\n\t}\n\n\tvoid fill(const T & e)\n\t{\n\t\tfor (size_t i(0); i<_rows; ++i)\n\t\t{\n\t\t\t_arr[i].fill(e);\n\t\t}\n\t}\n\n};\n}"
  },
  {
    "path": "SparCraft/source/BaseTypes.hpp",
    "content": "#pragma once\n\n#include \"Common.h\"\n\n\nnamespace SparCraft\n{\n\n    // type definitions for storing data\n    typedef \tint\t\t\t\t\tPositionType;\n    typedef \tint\t\t\t\t\tTimeType;\n    typedef\t\tshort\t\t\t\tHealthType;\n    typedef\t\tint\t\t\t\t\tScoreType;\n    typedef\t\tunsigned int\t\tHashType;\n    typedef     int                 UCTValue;\n\n    class StateEvalScore\n    {\n        ScoreType\t_val;\n        int\t\t\t_numMoves;\n\n    public:\n\n        StateEvalScore()\n            : _val(0)\n            ,_numMoves(0)\n        {\n        }\n\n        StateEvalScore(const ScoreType & val,const int & numMoves)\n            : _val(val)\n            ,_numMoves(numMoves)\n        {\n        }\n\n        const bool operator < (const StateEvalScore & rhs) const\n        {\n            if (_val < rhs._val)\n            {\n                return true;\n            }\n            else if (_val == rhs._val)\n            {\n                return _numMoves > rhs._numMoves;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        const bool operator > (const StateEvalScore & rhs) const\n        {\n            if (_val > rhs._val)\n            {\n                return true;\n            }\n            else if (_val == rhs._val)\n            {\n                return _numMoves < rhs._numMoves;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        const bool operator <= (const StateEvalScore & rhs) const\n        {\n            if (_val > rhs._val)\n            {\n                return true;\n            }\n            else if (_val == rhs._val)\n            {\n                return _numMoves >= rhs._numMoves;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        const bool operator >= (const StateEvalScore & rhs) const\n        {\n            if (_val > rhs._val)\n            {\n                return true;\n            }\n            else if (_val == rhs._val)\n            {\n                return _numMoves <= rhs._numMoves;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        const bool operator == (const StateEvalScore & rhs) const\n        {\n            return (_val == rhs._val) && (_numMoves == rhs._numMoves);\n        }\n\n        const ScoreType & val() const { return _val; }\n        const TimeType & numMoves() const { return _numMoves; }\n    };\n\n\n\n}\n\n"
  },
  {
    "path": "SparCraft/source/Common.cpp",
    "content": "#include \"Common.h\"\n\n// SEARCH PARAMETERS\nchar SPARCRAFT_LOGFILE[100] { \"sparcraft_error_log.txt\" };\n\nnamespace SparCraft\n{\n    namespace System\n    {\n        void FatalError(const std::string & errorMessage)\n        {\n            std::cerr << \"\\n\\n\\nSparCraft Fatal Error: \\n\\n\\n      \" << errorMessage << \"\\n\\n\";\n\n\t\t\t/*std::ofstream logStream;\n\t\t\tlogStream.open(SPARCRAFT_LOGFILE, std::ofstream::app);\n\t\t\tlogStream << \"\\n\\n\\nSparCraft Fatal Error: \\n\\n\\n      \" << errorMessage << \"\\n\\n\";\n\t\t\tlogStream.flush();\n\t\t\tlogStream.close();*/\n\n            throw(SPARCRAFT_FATAL_ERROR);\n        }\n        \n        void checkSupportedUnitType(const BWAPI::UnitType & type)\n        {\n            if (type == BWAPI::UnitTypes::None || type == BWAPI::UnitTypes::Unknown)\n            {\n                System::FatalError(\"Unknown unit type in experiment file, not supported\");\n            }\n\n            if (type == BWAPI::UnitTypes::Protoss_Corsair || \n                type == BWAPI::UnitTypes::Zerg_Devourer || \n                type == BWAPI::UnitTypes::Zerg_Scourge ||\n                type == BWAPI::UnitTypes::Terran_Valkyrie)\n            {\n                System::FatalError(\"Units with just air weapons currently not supported correctly: \" + type.getName());\n            }\n\n            if (type.isBuilding() && !(type == BWAPI::UnitTypes::Protoss_Photon_Cannon || type == BWAPI::UnitTypes::Zerg_Sunken_Colony || type == BWAPI::UnitTypes::Terran_Missile_Turret))\n            {\n                System::FatalError(\"Non-attacking buildings not currently supported: \" + type.getName());\n            }\n\n            if (type.isSpellcaster())\n            {\n                System::FatalError(\"Spell casting units not currently supported: \" + type.getName());\n            }\n\n             // Don't support units loading other units yet\n            if (type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine || \n                type == BWAPI::UnitTypes::Protoss_Carrier || \n                type == BWAPI::UnitTypes::Protoss_Interceptor || \n                type == BWAPI::UnitTypes::Protoss_Reaver ||\n                type == BWAPI::UnitTypes::Protoss_Scarab ||\n                type == BWAPI::UnitTypes::Zerg_Broodling)\n            {\n\n                System::FatalError(\"Units which have unit projectiles not supported: \" + type.getName());\n            }\n        }\n\n        bool isSupportedUnitType(const BWAPI::UnitType & type)\n        {\n            if (type == BWAPI::UnitTypes::None || type == BWAPI::UnitTypes::Unknown)\n            {\n                return false;\n            }\n\n            if (type == BWAPI::UnitTypes::Protoss_Corsair || \n                type == BWAPI::UnitTypes::Zerg_Devourer || \n                type == BWAPI::UnitTypes::Zerg_Scourge ||\n                type == BWAPI::UnitTypes::Terran_Valkyrie)\n            {\n                return false;\n            }\n\n            if (type.isBuilding() && !(type == BWAPI::UnitTypes::Protoss_Photon_Cannon || type == BWAPI::UnitTypes::Zerg_Sunken_Colony || type == BWAPI::UnitTypes::Terran_Missile_Turret))\n            {\n                return false;\n            }\n\n            if (type.isSpellcaster())\n            {\n                return false;\n            }\n\n            // Don't support units loading other units yet\n            if (type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine || \n                type == BWAPI::UnitTypes::Protoss_Carrier || \n                type == BWAPI::UnitTypes::Protoss_Interceptor || \n                type == BWAPI::UnitTypes::Protoss_Reaver ||\n                type == BWAPI::UnitTypes::Protoss_Scarab ||\n                type == BWAPI::UnitTypes::Zerg_Broodling)\n            {\n                return false;\n            }\n\n            return true;\n        }\n    }\n};\n"
  },
  {
    "path": "SparCraft/source/Common.h",
    "content": "#pragma once\n\n#include \"BWAPI.h\"\n#include \"BaseTypes.hpp\"\n#include <cassert>\n#include <vector>\n#include <stdio.h>\n#include <math.h>\n#include <fstream>\n#include <sstream>\n#include <map>\n#include <ios>\n#include <iostream>\n#include <cstdlib>\n#include \"Logger.h\"\n#include \"SparCraftAssert.h\"\n\nextern char SPARCRAFT_LOGFILE[100];\n\nnamespace SparCraft\n{\n\t// constants for search\n\tnamespace Constants\n\t{\n\t\t// number of players in the game\n\t\tconst size_t Num_Players\t\t\t\t= 2;\n\t\t\n\t\t// maximum number of units a player can have\n\t\tconst size_t Max_Units\t\t\t\t\t= 100;\n\n\t\t// max depth the search can ever handle\n\t\tconst size_t Max_Search_Depth\t\t\t= 50;\n\n\t\t// number of directions that units can move\n\t\tconst size_t Num_Directions\t\t\t\t= 4;\n\n\t\t// max number of ordered moves in a search depth\n\t\tconst size_t Max_Ordered_Moves\t\t\t= 10;\n\n\t\t// distance moved for a 'move' command\n\t\tconst size_t Move_Distance\t\t\t\t= 16;\n\n        // add between a move and attack as penalty\n        const TimeType Move_Penalty             = 4;\n\n        // add range to units because of bounding boxes\n        const PositionType Range_Addition       = 32;\n\n\t\t// maximum number of moves possible for any unit\n\t\tconst size_t Max_Moves\t\t\t\t\t= Max_Units + Num_Directions + 1;\n\t\tconst bool   Use_Unit_Bounding\t\t\t= false;\n\t\tconst size_t Pass_Move_Duration\t\t\t= 20;\n\t\tconst float  Min_Unit_DPF\t\t\t\t= 0.1f;\n\t\tconst HealthType Starting_Energy\t\t= 50;\n\n\t\t// whether to use transposition table in search\n\t\tconst bool   Use_Transposition_Table\t= true;\n\t\tconst size_t Transposition_Table_Size\t= 100000;\n\t\tconst size_t Transposition_Table_Scan\t= 10;\n\t\tconst size_t Num_Hashes\t\t\t\t\t= 2;\n        \n        // UCT options\n        const size_t Max_UCT_Children           = 10;\n\n\t\t// rng seeding options\n\t\tconst bool Seed_Hash_Time\t\t\t\t= false;\n\t\tconst bool Seed_Player_Random_Time\t\t= true;\n\n\t\t// directions of movement\n\t\tconst int Move_Dir[4][2] = {{-1,0}, {1,0}, {0,1}, {0,-1} };\n\t}\n\n    namespace System\n    {\n        const int SPARCRAFT_FATAL_ERROR = -1;\n\n        void FatalError(const std::string & errorMessage);\n        void checkSupportedUnitType(const BWAPI::UnitType & type);\n        bool isSupportedUnitType(const BWAPI::UnitType & type);\n    }\n};\n\n#include \"EnumData.h\""
  },
  {
    "path": "SparCraft/source/ConfigFileGenerator.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"SearchExperiment.h\"\n#include \"UCTSearch.h\"\n#include \"PlayerProperties.h\"\n#include \"UnitProperties.h\"\n\n// you shouldn't run this, I used it for my paper\nvoid generateExperimentFile(int searchTimer, int maxChildren, int numStates, int numUnits, bool sep)\n{\n    std::string display(\"Display true C:\\\\Users\\\\Dave\\\\Desktop\\\\sc2010\\\\StarCraft_Bot\\\\Visual_Studio_Projects\\\\SparCraft\\\\starcraft_images\\\\\");\n        \n    std::string stat = (sep ? \"sep\" : \"sym\");\n    std::stringstream folder; folder << \"exp\\\\exp_\" << numUnits << \"_\" << stat;\n    std::stringstream command; command << \"mkdir \" << folder.str();\n\n    // Creates the directory\n    system(\"mkdir exp\");\n    system(command.str().c_str());\n\n    std::stringstream states;\n    if (sep)\n    {\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon \"   << numUnits << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling \"     << numUnits << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon \"   << (numUnits/2) << \" Protoss_Zealot \" << (numUnits/2) << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon \"   << (numUnits/2) << \" Terran_Marine \" << (numUnits/2) << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Terran_Marine \"     << (numUnits/2) << \" Zerg_Zergling \" << (numUnits/2) << \"\\n\";\n    }\n    else\n    {\n        states << \"State StateSymmetric 100 128 128 Protoss_Dragoon \"   << numUnits << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Zerg_Zergling \"     << numUnits << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Protoss_Dragoon \"   << (numUnits/2) << \" Protoss_Zealot \" << (numUnits/2) << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Protoss_Dragoon \"   << (numUnits/2) << \" Terran_Marine \" << (numUnits/2) << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Terran_Marine \"     << (numUnits/2) << \" Zerg_Zergling \" << (numUnits/2) << \"\\n\";\n    }\n\n    std::stringstream exp1;\n    exp1 << \"Player 0 AlphaBeta \" << searchTimer << \" \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp1 << \"Player 0 AlphaBeta \" << searchTimer << \" \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp1 << \"Player 1 PortfolioGreedySearch 40 NOKDPS 1 0\\n\";\n    exp1 << \"ResultsFile c:\\\\users\\\\dave\\\\desktop\\\\results\\\\exp\\\\exp_\" << numUnits << \"_\" << stat << \"\\\\results_\" << numUnits << \"_ab_vs_portfolio_\" << stat << \" true\\n\";\n\n    std::stringstream exp2;\n    exp2 << \"Player 0 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp2 << \"Player 0 UCT \" << searchTimer << \" 1.5 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp2 << \"Player 1 PortfolioGreedySearch 40 NOKDPS 1 0\\n\";\n    exp2 << \"ResultsFile c:\\\\users\\\\dave\\\\desktop\\\\results\\\\exp\\\\exp_\" << numUnits << \"_\" << stat << \"\\\\results_\" << numUnits << \"_uct_vs_portfolio_\" << stat << \" true\\n\";\n\n    std::stringstream exp3;\n    exp3 << \"Player 0 AlphaBeta \" << searchTimer << \" \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp3 << \"Player 1 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp3 << \"Player 1 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp3 << \"ResultsFile c:\\\\users\\\\dave\\\\desktop\\\\results\\\\exp\\\\exp_\" << numUnits << \"_\" << stat << \"\\\\results_\" << numUnits << \"_ab_vs_uct_nok_\" << stat << \" true\\n\";\n\n    std::stringstream exp4;\n    exp4 << \"Player 0 AlphaBeta \" << searchTimer << \" \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp4 << \"Player 1 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp4 << \"Player 1 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp4 << \"ResultsFile c:\\\\users\\\\dave\\\\desktop\\\\results\\\\exp\\\\exp_\" << numUnits << \"_\" << stat << \"\\\\results_\" << numUnits << \"_ab_vs_uct_none_\" << stat << \" true\\n\";\n\n    std::stringstream exp5;\n    exp5 << \"Player 0 PortfolioGreedySearch 0 NOKDPS 1 0\\n\";\n    exp5 << \"Player 1 PortfolioGreedySearch 0 NOKDPS 2 0\\n\";\n    exp5 << \"Player 1 PortfolioGreedySearch 0 NOKDPS 3 0\\n\";\n    exp5 << \"ResultsFile c:\\\\users\\\\dave\\\\desktop\\\\results\\\\exp\\\\exp_\" << numUnits << \"_\" << stat << \"\\\\results_\" << numUnits << \"_p_vs_p_iter_\" << stat << \" true\\n\";\n    \n    std::stringstream exp6;\n    exp6 << \"Player 0 PortfolioGreedySearch 0 NOKDPS 1 0\\n\";\n    exp6 << \"Player 1 PortfolioGreedySearch 0 NOKDPS 1 1\\n\";\n    exp6 << \"Player 1 PortfolioGreedySearch 0 NOKDPS 1 2\\n\";\n    exp6 << \"ResultsFile c:\\\\users\\\\dave\\\\desktop\\\\results\\\\exp\\\\exp_\" << numUnits << \"_\" << stat << \"\\\\results_\" << numUnits << \"_p_vs_p_resp_\" << stat << \" true\\n\";\n     \n    std::stringstream exp7;\n    exp7 << \"Player 0 PortfolioGreedySearch 0 NOKDPS 1 0\\n\";\n    exp7 << \"Player 1 PortfolioGreedySearch 0 NOKDPS 1 1\\n\";\n    exp7 << \"Player 1 PortfolioGreedySearch 0 NOKDPS 1 2\\n\";\n    exp7 << \"ResultsFile c:\\\\users\\\\dave\\\\desktop\\\\results\\\\exp\\\\exp_\" << numUnits << \"_\" << stat << \"\\\\results_\" << numUnits << \"_p_vs_p_resp_\" << stat << \" true\\n\";\n\n    std::stringstream f1; f1 << folder.str() << \"\\\\exp_\" << numUnits << \"_ab_vs_portfolio_\"     << stat << \".txt\";\n    std::stringstream f2; f2 << folder.str() << \"\\\\exp_\" << numUnits << \"_uct_vs_portfolio_\"    << stat << \".txt\";\n    std::stringstream f3; f3 << folder.str() << \"\\\\exp_\" << numUnits << \"_ab_vs_uct_nok_\"       << stat << \".txt\";\n    std::stringstream f4; f4 << folder.str() << \"\\\\exp_\" << numUnits << \"_ab_vs_uct_none_\"      << stat << \".txt\";\n    std::stringstream f5; f5 << folder.str() << \"\\\\exp_\" << numUnits << \"_p_vs_p_iter_\"         << stat << \".txt\";\n    std::stringstream f6; f6 << folder.str() << \"\\\\exp_\" << numUnits << \"_p_vs_p_resp_\"         << stat << \".txt\";\n\n    std::ofstream fout1(f1.str().c_str()); fout1 << exp1.str(); fout1 << states.str(); fout1 << display; fout1.close();\n    std::ofstream fout2(f2.str().c_str()); fout2 << exp2.str(); fout2 << states.str(); fout2 << display; fout2.close();\n    std::ofstream fout3(f3.str().c_str()); fout3 << exp3.str(); fout3 << states.str(); fout3 << display; fout3.close();\n    std::ofstream fout4(f4.str().c_str()); fout4 << exp4.str(); fout4 << states.str(); fout4 << display; fout4.close();\n    std::ofstream fout5(f5.str().c_str()); fout5 << exp5.str(); fout5 << states.str(); fout5 << display; fout5.close();\n    std::ofstream fout6(f6.str().c_str()); fout6 << exp6.str(); fout6 << states.str(); fout6 << display; fout6.close();\n\n    std::stringstream batName; batName << folder.str() << \"\\\\runall_\" << numUnits << \"_\" << stat << \".bat\";\n    std::ofstream bat(batName.str().c_str());\n    bat << \"@echo off\\n\";\n    bat << \"cd C:\\\\Users\\\\Dave\\\\Desktop\\\\sc2010\\\\StarCraft_Bot\\\\Visual_Studio_Projects\\\\SparCraft\\\\VisualStudio\\\\Release\\n\";\n    bat << \"copy SparCraft.exe exp_\" << numUnits << \"_\" << stat << \".exe\\n\";\n    bat << \"TIMEOUT 3\\n\";\n    bat << \"start exp_\" << numUnits << \"_\" << stat << \".exe c:\\\\users\\\\dave\\\\desktop\\\\results\\\\\" << f1.str() << \"\\n\";\n    bat << \"start exp_\" << numUnits << \"_\" << stat << \".exe c:\\\\users\\\\dave\\\\desktop\\\\results\\\\\" << f2.str() << \"\\n\";\n    bat << \"start exp_\" << numUnits << \"_\" << stat << \".exe c:\\\\users\\\\dave\\\\desktop\\\\results\\\\\" << f3.str() << \"\\n\";\n    bat << \"start exp_\" << numUnits << \"_\" << stat << \".exe c:\\\\users\\\\dave\\\\desktop\\\\results\\\\\" << f4.str() << \"\\n\";\n    bat.close();\n\n    std::stringstream batName2; batName2 << folder.str() << \"\\\\runall_p_\" << numUnits << \"_\" << stat << \".bat\";\n    std::ofstream bat2(batName2.str().c_str());\n    bat2 << \"@echo off\\n\";\n    bat2 << \"cd C:\\\\Users\\\\Dave\\\\Desktop\\\\sc2010\\\\StarCraft_Bot\\\\Visual_Studio_Projects\\\\SparCraft\\\\VisualStudio\\\\Release\\n\";\n    bat2 << \"copy SparCraft.exe exp_p_\" << numUnits << \"_\" << stat << \".exe\\n\";\n    bat2 << \"TIMEOUT 3\\n\";\n    bat2 << \"start exp_p_\" << numUnits << \"_\" << stat << \".exe c:\\\\users\\\\dave\\\\desktop\\\\results\\\\\" << f5.str() << \"\\n\";\n    bat2 << \"start exp_p_\" << numUnits << \"_\" << stat << \".exe c:\\\\users\\\\dave\\\\desktop\\\\results\\\\\" << f6.str() << \"\\n\";\n    bat.close();\n}\n\nvoid generateStateConfig(int numUnits, bool sep)\n{\n    std::stringstream states;\n\n    if (sep)\n    {\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon \"   << numUnits << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling \"     << numUnits << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Protoss_Zealot \"     << numUnits << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Terran_Marine \"     << numUnits << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Terran_Vulture \"     << numUnits << \"\\n\";\n   }\n    else\n    {\n        states << \"State StateSymmetric 100 128 128 Protoss_Dragoon \"   << numUnits << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Zerg_Zergling \"     << numUnits << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Protoss_Zealot \"     << numUnits << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Terran_Marine \"     << numUnits << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Terran_Vulture \"     << numUnits << \"\\n\";\n    }\n\n    std::cout << states.str();\n}\n\n// you shouldn't run this, I used it for my paper\nvoid generateExperimentFileLinux(int searchTimer, int maxChildren, int numStates, int numUnits, bool sep)\n{\n    std::string display(\"Display false .\");\n        \n    std::string stat = (sep ? \"sep\" : \"sym\");\n    std::stringstream folder; folder << \"exp_linux_\" << numUnits << \"_\" << stat;\n    std::stringstream command; command << \"mkdir exp\\\\\" << folder.str();\n\n    // Creates the directory\n    system(\"mkdir exp\");\n    system(command.str().c_str());\n\n    std::stringstream states;\n    if (sep)\n    {\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon \"   << numUnits << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling \"     << numUnits << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon \"   << (numUnits/2) << \" Protoss_Zealot \" << (numUnits/2) << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon \"   << (numUnits/2) << \" Terran_Marine \" << (numUnits/2) << \"\\n\";\n        states << \"State SeparatedState 100 128 128 400 360 840 360 Terran_Marine \"     << (numUnits/2) << \" Zerg_Zergling \" << (numUnits/2) << \"\\n\";\n    }\n    else\n    {\n        states << \"State StateSymmetric 100 128 128 Protoss_Dragoon \"   << numUnits << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Zerg_Zergling \"     << numUnits << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Protoss_Dragoon \"   << (numUnits/2) << \" Protoss_Zealot \" << (numUnits/2) << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Protoss_Dragoon \"   << (numUnits/2) << \" Terran_Marine \" << (numUnits/2) << \"\\n\";\n        states << \"State StateSymmetric 100 128 128 Terran_Marine \"     << (numUnits/2) << \" Zerg_Zergling \" << (numUnits/2) << \"\\n\";\n    }\n\n    std::stringstream exp1;\n    exp1 << \"Player 0 AlphaBeta \" << searchTimer << \" \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp1 << \"Player 0 AlphaBeta \" << searchTimer << \" \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp1 << \"Player 1 PortfolioGreedySearch NOKDPS 1 0\\n\";\n    exp1 << \"ResultsFile /home/cdavid/SparCraft/linux/exp/\" << folder.str() << \"/results_\" << numUnits << \"_ab_vs_portfolio_\" << stat << \" true\\n\";\n\n    std::stringstream exp2;\n    exp2 << \"Player 0 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp2 << \"Player 0 UCT \" << searchTimer << \" 1.5 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp2 << \"Player 1 PortfolioGreedySearch NOKDPS 1 0\\n\";\n    exp2 << \"ResultsFile /home/cdavid/SparCraft/linux/exp/\" << folder.str() << \"/results_\" << numUnits << \"_uct_vs_portfolio_\" << stat << \" true\\n\";\n\n    std::stringstream exp3;\n    exp3 << \"Player 0 AlphaBeta \" << searchTimer << \" \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp3 << \"Player 1 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp3 << \"Player 1 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp3 << \"ResultsFile /home/cdavid/SparCraft/linux/exp/\" << folder.str() << \"/results_\" << numUnits << \"_ab_vs_uct_nok_\" << stat << \" true\\n\";\n\n    std::stringstream exp4;\n    exp4 << \"Player 0 AlphaBeta \" << searchTimer << \" \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp4 << \"Player 1 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate None\\n\";\n    exp4 << \"Player 1 UCT \" << searchTimer << \" 1.6 5000 \" << maxChildren << \" ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\\n\";\n    exp4 << \"ResultsFile /home/cdavid/SparCraft/linux/exp/\" << folder.str() << \"/results_\" << numUnits << \"_ab_vs_uct_none_\" << stat << \" true\\n\";\n\n    std::stringstream f1; f1 << \"exp/\" << folder.str() << \"/exp_linux_\" << numUnits << \"_ab_vs_portfolio_\"     << stat << \".txt\";\n    std::stringstream f2; f2 << \"exp/\" << folder.str() << \"/exp_linux_\" << numUnits << \"_uct_vs_portfolio_\"    << stat << \".txt\";\n    std::stringstream f3; f3 << \"exp/\" << folder.str() << \"/exp_linux_\" << numUnits << \"_ab_vs_uct_nok_\"       << stat << \".txt\";\n    std::stringstream f4; f4 << \"exp/\" << folder.str() << \"/exp_linux_\" << numUnits << \"_ab_vs_uct_none_\"      << stat << \".txt\";\n\n    std::ofstream fout1(f1.str().c_str()); fout1 << exp1.str(); fout1 << states.str(); fout1 << display; fout1.close();\n    std::ofstream fout2(f2.str().c_str()); fout2 << exp2.str(); fout2 << states.str(); fout2 << display; fout2.close();\n    std::ofstream fout3(f3.str().c_str()); fout3 << exp3.str(); fout3 << states.str(); fout3 << display; fout3.close();\n    std::ofstream fout4(f4.str().c_str()); fout4 << exp4.str(); fout4 << states.str(); fout4 << display; fout4.close();\n\n    std::stringstream batName; batName << \"exp\\\\\" << folder.str() << \"\\\\ssh_linuxbox_runall_\" << numUnits << \"_\" << stat << \".bat\";\n    std::ofstream bat(batName.str().c_str());\n    bat << \"start cmd /K plink cdavid@linuxbox /home/cdavid/SparCraft/linux/SparCraft /home/cdavid/SparCraft/linux/\" << f1.str() << \"\\n\";\n    bat << \"start cmd /K plink cdavid@linuxbox /home/cdavid/SparCraft/linux/SparCraft /home/cdavid/SparCraft/linux/\" << f2.str() << \"\\n\";\n    bat << \"start cmd /K plink cdavid@linuxbox /home/cdavid/SparCraft/linux/SparCraft /home/cdavid/SparCraft/linux/\" << f3.str() << \"\\n\";\n    bat << \"start cmd /K plink cdavid@linuxbox /home/cdavid/SparCraft/linux/SparCraft /home/cdavid/SparCraft/linux/\" << f4.str() << \"\\n\";\n    bat.close();\n}\n\nvoid generate()\n{\n    generateExperimentFileLinux(40, 20, 100, 8, true);\n    generateExperimentFileLinux(40, 20, 100, 16, true);\n    generateExperimentFileLinux(40, 20, 100, 32, true);\n    generateExperimentFileLinux(40, 20, 100, 50, true);\n    generateExperimentFileLinux(40, 20, 100, 8, false);\n    generateExperimentFileLinux(40, 20, 100, 16, false);\n    generateExperimentFileLinux(40, 20, 100, 32, false);\n    generateExperimentFileLinux(40, 20, 100, 50, false);\n    generateExperimentFile(40, 20, 100, 8, true);\n    generateExperimentFile(40, 20, 100, 16, true);\n    generateExperimentFile(40, 20, 100, 32, true);\n    generateExperimentFile(40, 20, 100, 50, true);\n    generateExperimentFile(40, 20, 100, 8, false);\n    generateExperimentFile(40, 20, 100, 16, false);\n    generateExperimentFile(40, 20, 100, 32, false);\n    generateExperimentFile(40, 20, 100, 50, false);\n\n    //for (int i=1; i<51; ++i)\n    //{\n    //    generateStateConfig(i, false);\n    //}\n}"
  },
  {
    "path": "SparCraft/source/EnumData.cpp",
    "content": "#include \"EnumData.h\"\n\nusing namespace SparCraft;\n\nvoid SparCraft::EnumDataInit()\n{\n    Players::init();\n    SearchMethods::init();\n    PlayerModels::init();\n    EvaluationMethods::init();\n    SearchNodeType::init();\n    MoveOrderMethod::init();\n    PlayerToMove::init();\n}"
  },
  {
    "path": "SparCraft/source/EnumData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace SparCraft\n{\n\ntemplate <class T>\nclass EnumData\n{\nprotected:\n\n    static std::string name;\n    static std::vector<std::string> names;\n    static std::map<std::string, int> nameMap;\n\npublic:\n\n    static const int size()\n    {\n        return T::Size;\n    }\n\n    static void setType(const std::string & s)\n    {\n        name = s;\n    }\n\n    static const std::string & getType()\n    {\n        return name;\n    }\n\n    static void setData(const int & ID, const std::string & s)\n    {\n        if (ID > size())\n        {\n            std::stringstream ss;\n            ss << ID;\n            System::FatalError(\"Unknown \" + getType() + \" ID: \" + ss.str());\n        }\n\n        names[ID] = s;\n        nameMap[s] = ID;\n    }\n\n    static const size_t getID(const std::string & s)\n    {\n        const std::map<std::string, int>::const_iterator it(nameMap.find(s));\n\n        if (it == nameMap.end())\n        {\n            System::FatalError(\"Unknown \" + getType() + \" String: \" + s);\n        }\n        \n        return it->second;\n    }\n\n    static const std::string & getName(const size_t & ID)\n    {\n        if (ID > (size_t)size())\n        {\n            std::stringstream ss;\n            ss << ID;\n            System::FatalError(\"Unknown \" + getType() + \" ID: \" + ss.str());\n        }\n\n        return names[ID];\n    }\n};\n\ntemplate <class T> std::string EnumData<T>::name;\ntemplate <class T> std::vector<std::string> EnumData<T>::names;\ntemplate <class T> std::map<std::string, int> EnumData<T>::nameMap;\n\nclass Players : public EnumData<Players>\n{\npublic:\n    enum { Player_One = 0, Player_Two = 1, Player_None = 2, Player_Both = 3, Size};\n    static void init()\n    {\n        setType(\"Players\");\n        names.resize(Size);\n        setData(Player_One,     \"Player One\");\n\t\tsetData(Player_Two,     \"Player Two\");\n\t\tsetData(Player_None,    \"Player None\");\n\t\tsetData(Player_Both,    \"Player Both\");\n    }\n};\n\nclass SearchMethods : public EnumData<SearchMethods>\n{\npublic:\n    enum { AlphaBeta, IDAlphaBeta, MiniMax, Size };\n    static void init()\n    {\n        setType(\"SearchMethod\");\n        names.resize(Size);\n        setData(AlphaBeta,      \"AlphaBeta\");\n        setData(IDAlphaBeta,    \"IDAlphaBeta\");\n        setData(MiniMax,        \"MiniMax\");\n    }\n};\n\nclass PlayerModels : public EnumData<PlayerModels>\n{\npublic:\n    enum { AlphaBeta, AttackClosest, Kiter, Random, AttackWeakest, AttackDPS, KiterDPS, NOKDPS, Kiter_NOKDPS, Cluster, PortfolioGreedySearch, UCT, None, Size };\n    static void init()\n    {\n        setType(\"PlayerModels\");\n        names.resize(Size);\n        setData(AlphaBeta,              \"AlphaBeta\");\n\t\tsetData(AttackClosest,          \"AttackClosest\");\n\t\tsetData(Kiter,                  \"Kiter\");\n\t\tsetData(Random,                 \"Random\");\n\t\tsetData(AttackWeakest,          \"AttackWeakest\");\n\t\tsetData(AttackDPS,              \"AttackDPS\");\n\t\tsetData(KiterDPS,               \"KiterDPS\");\n\t\tsetData(NOKDPS,                 \"NOKDPS\");\n        setData(Kiter_NOKDPS,           \"Kiter_NOKDPS\");\n        setData(Cluster,                \"Cluster\");\n        setData(PortfolioGreedySearch,  \"PortfolioGreedySearch\");\n        setData(UCT,                    \"UCT\");\n\t\tsetData(None,                   \"None\");\n    }\n};\n\nclass EvaluationMethods : public EnumData<EvaluationMethods>\n{\npublic:\n    enum { LTD, LTD2, Playout, Size };\n    static void init()\n    {\n        setType(\"EvaluationMethods\");\n        names.resize(Size);\n        setData(LTD,        \"LTD\");\n        setData(LTD2,       \"LTD2\");\n        setData(Playout,    \"Playout\");\n    }\n};\n\nclass SearchNodeType : public EnumData<SearchNodeType>\n{\npublic:\n    enum { Default, RootNode, SoloNode, FirstSimNode, SecondSimNode, Size };\n    static void init()\n    {\n        setType(\"SearchNodeType\");\n        names.resize(Size);\n        setData(Default,        \"Default\");\n        setData(RootNode,       \"RootNode\");\n        setData(SoloNode,       \"SoloNode\");\n        setData(FirstSimNode,   \"FirstSimNode\");\n        setData(SecondSimNode,  \"SecondSimNode\");\n    }\n};\n\nclass MoveOrderMethod : public EnumData<MoveOrderMethod>\n{\npublic:\n    enum { ScriptFirst, None, Size };\n    static void init()\n    {\n        setType(\"MoveOrderMethod\");\n        names.resize(Size);\n        setData(ScriptFirst,    \"ScriptFirst\");\n        setData(None,           \"None\");\n    }\n};\n\nclass PlayerToMove : public EnumData<PlayerToMove>\n{\npublic:\n    enum { Random, Alternate, Not_Alternate, Size };\n    static void init()\n    {\n        setType(\"PlayerToMove\");\n        names.resize(Size);\n        setData(Random,         \"Random\");\n        setData(Alternate,      \"Alternate\");\n        setData(Not_Alternate,  \"Not_Alternate\");\n    }\n};\n\nextern void EnumDataInit();\n\n}"
  },
  {
    "path": "SparCraft/source/Game.cpp",
    "content": "#include \"Game.h\"\n\nusing namespace SparCraft;\n\nGame::Game(const GameState & initialState, const size_t & limit)\n    : _numPlayers(0)\n    , state(initialState)\n    , _playerToMoveMethod(SparCraft::PlayerToMove::Alternate)\n    , rounds(0)\n    , moveLimit(limit)\n{\n\n}\n\nGame::Game(const GameState & initialState, PlayerPtr & p1, PlayerPtr & p2, const size_t & limit)\n    : _numPlayers(0)\n    , state(initialState)\n    , _playerToMoveMethod(SparCraft::PlayerToMove::Alternate)\n    , rounds(0)\n    , moveLimit(limit)\n{\n    // add the players\n    _players[Players::Player_One] = p1;\n    _players[Players::Player_Two] = p2;\n}\n\n// play the game until there is a winner\nvoid Game::play()\n{\n    scriptMoves[Players::Player_One] = std::vector<Action>(state.numUnits(Players::Player_One));\n    scriptMoves[Players::Player_Two] = std::vector<Action>(state.numUnits(Players::Player_Two));\n\n    t.start();\n\n    // play until there is no winner\n    while (!gameOver())\n    {\n        if (moveLimit && rounds >= moveLimit)\n        {\n            break;\n        }\n\n        playNextTurn();\n    }\n\n    gameTimeMS = t.getElapsedTimeInMilliSec();\n}\n\nvoid Game::playNextTurn()\n{\n    Timer frameTimer;\n    frameTimer.start();\n\n    scriptMoves[0].clear();\n    scriptMoves[1].clear();\n\n    // the player that will move next\n    const size_t playerToMove(getPlayerToMove());\n    PlayerPtr & toMove = _players[playerToMove];\n    PlayerPtr & enemy = _players[state.getEnemy(playerToMove)];\n\n    // generate the moves possible from this state\n    state.generateMoves(moves[toMove->ID()], toMove->ID());\n\n    // the tuple of moves he wishes to make\n    toMove->getMoves(state, moves[playerToMove], scriptMoves[playerToMove]);\n        \n    // if both players can move, generate the other player's moves\n    if (state.bothCanMove())\n    {\n        state.generateMoves(moves[enemy->ID()], enemy->ID());\n        enemy->getMoves(state, moves[enemy->ID()], scriptMoves[enemy->ID()]);\n\n        state.makeMoves(scriptMoves[enemy->ID()]);\n    }\n\n    // make the moves\n    state.makeMoves(scriptMoves[toMove->ID()]);\n\n    state.finishedMoving();\n    rounds++;\n}\n\n// play the game until there is a winner\nvoid Game::playIndividualScripts(UnitScriptData & scriptData)\n{\n    // array which will hold all the script moves for players\n    Array2D<std::vector<Action>, Constants::Num_Players, PlayerModels::Size> allScriptMoves;\n\n    scriptMoves[Players::Player_One] = std::vector<Action>(state.numUnits(Players::Player_One));\n    scriptMoves[Players::Player_Two] = std::vector<Action>(state.numUnits(Players::Player_Two));\n\n    t.start();\n\n    // play until there is no winner\n    while (!gameOver())\n    {\n        if (moveLimit && rounds > moveLimit)\n        {\n            break;\n        }\n\n        Timer frameTimer;\n        frameTimer.start();\n\n        // clear all script moves for both players\n        for (size_t p(0); p<Constants::Num_Players; p++)\n        {\n            for (size_t s(0); s<PlayerModels::Size; ++s)\n            {\n                allScriptMoves[p][s].clear();\n            }\n        }\n\n        // clear the moves we will actually be doing\n        scriptMoves[0].clear();\n        scriptMoves[1].clear();\n\n        // the playr that will move next\n        const size_t playerToMove(getPlayerToMove());\n        const size_t enemyPlayer(state.getEnemy(playerToMove));\n\n        // generate the moves possible from this state\n        state.generateMoves(moves[playerToMove], playerToMove);\n\n        // calculate the moves the unit would do given its script preferences\n        scriptData.calculateMoves(playerToMove, moves[playerToMove], state, scriptMoves[playerToMove]);\n\n        // if both players can move, generate the other player's moves\n        if (state.bothCanMove())\n        {\n            state.generateMoves(moves[enemyPlayer], enemyPlayer);\n\n            scriptData.calculateMoves(enemyPlayer, moves[enemyPlayer], state, scriptMoves[enemyPlayer]);\n\n            state.makeMoves(scriptMoves[enemyPlayer]);\n        }\n\n        // make the moves\n        state.makeMoves(scriptMoves[playerToMove]);\n        state.finishedMoving();\n        rounds++;\n    }\n\n    gameTimeMS = t.getElapsedTimeInMilliSec();\n}\n\nPlayerPtr Game::getPlayer(const size_t & player)\n{\n    return _players[player];\n}\n\nint Game::getRounds()\n{\n    return rounds;\n}\n\ndouble Game::getTime()\n{\n    return gameTimeMS;\n}\n\n// returns whether or not the game is over\nbool Game::gameOver() const\n{\n    return state.isTerminal(); \n}\n\nconst GameState & Game::getState() const\n{\n    return state;\n}\n\nGameState & Game::getState()\n{\n    return state;\n}\n\n// determine the player to move\nconst size_t Game::getPlayerToMove()\n{\n    const size_t whoCanMove(state.whoCanMove());\n\n    return (whoCanMove == Players::Player_Both) ? Players::Player_One : whoCanMove;\n}\n"
  },
  {
    "path": "SparCraft/source/Game.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"Player.h\"\n#include \"AllPlayers.h\"\n#include \"Action.h\"\n#include \"UnitScriptData.h\"\n#include <memory>\n#include \"Timer.h\"\n\nnamespace SparCraft\n{\n\t\ntypedef\tstd::shared_ptr<Player> PlayerPtr;\n\nclass UnitScriptData;\n\nclass Game\n{\nprotected:\n\tPlayerPtr\t\t\t_players[2];\n\tsize_t\t\t\t\t_numPlayers;\n\tsize_t\t\t\t\t_playerToMoveMethod;\n\tsize_t\t\t\t\trounds;\n\tTimer\t\t\t\tt;\n\tdouble\t\t\t\tgameTimeMS;\n\tsize_t\t\t\t\tmoveLimit;\n\n\tGameState state;\n\n\t// moves array to store moves in\n\tMoveArray moves[2];\n\tstd::vector<Action> scriptMoves[2];\n\n    \n\npublic:\n\t\n\t// game constructor\n\tGame(const GameState & initialState, PlayerPtr & p1, PlayerPtr & p2, const size_t & limit);\n    Game(const GameState & initialState, const size_t & limit);\n\n\tvoid            play();\n    void            playNextTurn();\n    void            playIndividualScripts(UnitScriptData & scriptsChosen);\n\tvoid            storeHistory(const bool & store);\n\tbool            gameOver() const;\n    \n\n\tScoreType       eval(const size_t & evalMethod) const;\n\n\tGameState &     getState();\n    const GameState &     getState() const;\n\tint             getRounds();\n\tdouble          getTime();\n\tconst size_t    getPlayerToMove();\n    PlayerPtr       getPlayer(const size_t & player);\n\n};\n\n\n\n}"
  },
  {
    "path": "SparCraft/source/GameState.cpp",
    "content": "#include \"GameState.h\"\n#include \"Player.h\"\n#include \"Game.h\"\n\nusing namespace SparCraft;\n\n#define TABS(N) for (int i(0); i<N; ++i) { fprintf(stderr, \"\\t\"); }\n\nclass UnitIndexCompare\n{\n    const GameState & state;\n    int player;\n\npublic:\n\n    UnitIndexCompare(const GameState & s, const int & p)\n        : state(s)\n        , player(p)\n    {\n\n    }\n\n\tconst bool operator() (const int & u1, const int & u2) const\n\t{\n        return state.getUnitDirect(player, u1) < state.getUnitDirect(player, u2);\n    }\n};\n\n// default constructor\nGameState::GameState()\n\t: _map(NULL)\n\t, _currentTime(0)\n\t, _maxUnits(Constants::Max_Units)\n    , _sameHPFrames(0)\n{\n\t_numUnits.fill(0);\n\t_prevNumUnits.fill(0);\n\t_numMovements.fill(0);\n    _prevHPSum.fill(0);\n\n    _units[0] = std::vector<Unit>(Constants::Max_Units, Unit());\n    _units[1] = std::vector<Unit>(Constants::Max_Units, Unit());\n    _unitIndex[0] = std::vector<int>(Constants::Max_Units, 0);\n    _unitIndex[1] = std::vector<int>(Constants::Max_Units, 0);\n\n\tfor (size_t u(0); u<_maxUnits; ++u)\n\t{\n        _unitIndex[0][u] = u;\n\t\t_unitIndex[1][u] = u;\n\t}\n}\n\n// construct state from a save file\nGameState::GameState(const std::string & filename)\n{\n    read(filename);\n}\n\n// call this whenever we are done with moves\nvoid GameState::finishedMoving()\n{\n\t// sort the unit vector based on time left to move\n\tsortUnits();\n\n\t// update the current time of the state\n\tupdateGameTime();\n\n    // calculate the hp sum of each player\n    int hpSum[2];\n    for (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n\t\thpSum[p] = 0;\n\n\t\tfor (size_t u(0); u<numUnits(p); ++u)\n\t\t{ \n            hpSum[p] += getUnit(p, u).currentHP();\n        }\n    }\n\n    // if the hp sums match the last hp sum\n    if (hpSum[0] == _prevHPSum[0] && hpSum[1] == _prevHPSum[1])\n    {\n        _sameHPFrames++;\n    }\n    else\n    {\n        _sameHPFrames = 0;\n    }\n\n    for (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n        _prevHPSum[p] = hpSum[p];\n    }\n}\n\nconst HashType GameState::calculateHash(const size_t & hashNum) const\n{\n\tHashType hash(0);\n\n\tfor (size_t p(0); p < Constants::Num_Players; ++p)\n\t{\n\t\tfor (size_t u(0); u < _numUnits[p]; ++u)\n\t\t{\n\t\t\thash ^= Hash::magicHash(getUnit(p,u).calculateHash(hashNum, _currentTime), p, u);\n\t\t}\n\t}\n\n\treturn hash;\n}\n\nvoid GameState::generateMoves(MoveArray & moves, const size_t & playerIndex) const\n{\n\tmoves.clear();\n\n    // which is the enemy player\n\tsize_t enemyPlayer  = getEnemy(playerIndex);\n\n    // make sure this player can move right now\n    const size_t canMove(whoCanMove());\n    if (canMove == enemyPlayer)\n    {\n        System::FatalError(\"GameState Error - Called generateMoves() for a player that cannot currently move\");\n    }\n\n\t// we are interested in all simultaneous moves\n\t// so return all units which can move at the same time as the first\n\tTimeType firstUnitMoveTime = getUnit(playerIndex, 0).firstTimeFree();\n\t\t\n\tfor (size_t unitIndex(0); unitIndex < _numUnits[playerIndex]; ++unitIndex)\n\t{\n\t\t// unit reference\n\t\tconst Unit & unit(getUnit(playerIndex,unitIndex));\n\t\t\t\n\t\t// if this unit can't move at the same time as the first\n\t\tif (unit.firstTimeFree() != firstUnitMoveTime)\n\t\t{\n\t\t\t// stop checking\n\t\t\tbreak;\n\t\t}\n\n\t\tif (unit.previousActionTime() == _currentTime && _currentTime != 0)\n\t\t{\n            System::FatalError(\"Previous Move Took 0 Time: \" + unit.previousAction().moveString());\n\t\t}\n\n\t\tmoves.addUnit();\n\n\t\t// generate attack moves\n\t\tif (unit.canAttackNow())\n\t\t{\n\t\t\tfor (size_t u(0); u<_numUnits[enemyPlayer]; ++u)\n\t\t\t{\n\t\t\t\tconst Unit & enemyUnit(getUnit(enemyPlayer, u));\n\t\t\t\tbool invisible = false;\n\t\t\t\tif (enemyUnit.type().hasPermanentCloak())\n\t\t\t\t{\n\t\t\t\t\tinvisible = true;\n\t\t\t\t\tfor (size_t detectorIndex(0); detectorIndex < _numUnits[playerIndex]; ++detectorIndex)\n\t\t\t\t\t{\n\t\t\t\t\t\t// unit reference\n\t\t\t\t\t\tconst Unit & detector(getUnit(playerIndex, detectorIndex));\n\t\t\t\t\t\tif (detector.type().isDetector() && detector.canSeeTarget(enemyUnit, _currentTime))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tinvisible = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!invisible && unit.canAttackTarget(enemyUnit, _currentTime) && enemyUnit.isAlive())\n\t\t\t\t{\n\t\t\t\t\tmoves.add(Action(unitIndex, playerIndex, ActionTypes::ATTACK, u));\n                    //moves.add(Action(unitIndex, playerIndex, ActionTypes::ATTACK, unit.ID()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (unit.canHealNow())\n\t\t{\n\t\t\tfor (size_t u(0); u<_numUnits[playerIndex]; ++u)\n\t\t\t{\n\t\t\t\t// units cannot heal themselves in broodwar\n\t\t\t\tif (u == unitIndex)\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst Unit & ourUnit(getUnit(playerIndex, u));\n\t\t\t\tif (unit.canHealTarget(ourUnit, _currentTime) && ourUnit.isAlive())\n\t\t\t\t{\n\t\t\t\t\tmoves.add(Action(unitIndex, playerIndex, ActionTypes::HEAL, u));\n                    //moves.add(Action(unitIndex, playerIndex, ActionTypes::HEAL, unit.ID()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// generate the wait move if it can't attack yet\n\t\telse\n\t\t{\n\t\t\tif (!unit.canHeal())\n\t\t\t{\n\t\t\t\tmoves.add(Action(unitIndex, playerIndex, ActionTypes::RELOAD, 0));\n\t\t\t}\n\t\t}\n\t\t\n\t\t// generate movement moves\n\t\tif (unit.isMobile())\n\t\t{\n            // In order to not move when we could be shooting, we want to move for the minimum of:\n            // 1) default move distance move time\n            // 2) time until unit can attack, or if it can attack, the next cooldown\n            double timeUntilAttack          = unit.nextAttackActionTime() - getTime();\n            timeUntilAttack                 = timeUntilAttack == 0 ? unit.attackCooldown() : timeUntilAttack;\n\n            // the default move duration\n            double defaultMoveDuration      = (double)Constants::Move_Distance / unit.speed();\n\n            // if we can currently attack\n\t\t\tdouble chosenTime = timeUntilAttack != 0 ? std::min(timeUntilAttack, defaultMoveDuration) : defaultMoveDuration;\n\n            // the chosen movement distance\n            PositionType moveDistance       = (PositionType)(chosenTime * unit.speed());\n\n            // DEBUG: If chosen move distance is ever 0, something is wrong\n            if (moveDistance == 0)\n            {\n                System::FatalError(\"Move Action with distance 0 generated. timeUntilAttack:\"+\n\t\t\t\t\tstd::to_string(timeUntilAttack)+\", speed:\"+std::to_string(unit.speed()));\n            }\n\n            // we are only generating moves in the cardinal direction specified in common.h\n\t\t\tfor (size_t d(0); d<Constants::Num_Directions; ++d)\n\t\t\t{\t\t\t\n                // the direction of this movement\n              \tPosition dir(Constants::Move_Dir[d][0], Constants::Move_Dir[d][1]);\n            \n                if (moveDistance == 0)\n                {\n                    printf(\"%lf %lf %lf\\n\", timeUntilAttack, defaultMoveDuration, chosenTime);\n                }\n\n                // the final destination position of the unit\n                Position dest = unit.pos() + Position(moveDistance*dir.x(), moveDistance*dir.y());\n\n                // if that poisition on the map is walkable\n                if (isWalkable(dest) || (unit.type().isFlyer() && isFlyable(dest)))\n\t\t\t\t{\n                    // add the move to the MoveArray\n\t\t\t\t\tmoves.add(Action(unitIndex, playerIndex, ActionTypes::MOVE, d, dest));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// if no moves were generated for this unit, it must be issued a 'PASS' move\n\t\tif (moves.numMoves(unitIndex) == 0)\n\t\t{\n\t\t\tmoves.add(Action(unitIndex, playerIndex, ActionTypes::PASS, 0));\n\t\t}\n\t}\n}\n\n\nvoid GameState::makeMoves(const std::vector<Action> & moves)\n{    \n    if (moves.size() > 0)\n    {\n        const size_t canMove(whoCanMove());\n        const size_t playerToMove(moves[0].player());\n        if (canMove == getEnemy(playerToMove))\n        {\n            System::FatalError(\"GameState Error - Called makeMove() for a player that cannot currently move\");\n        }\n    }\n    \n    for (size_t m(0); m<moves.size(); ++m)\n    {\n        performAction(moves[m]);\n    }\n}\n\nvoid GameState::performAction(const Action & move)\n{\n\tUnit & ourUnit\t\t= getUnit(move.player(), move.unit());\n\tsize_t player\t\t= ourUnit.player();\n\tsize_t enemyPlayer  = getEnemy(player);\n\n\tif (move.type() == ActionTypes::ATTACK)\n\t{\n\t\tUnit & enemyUnit(getUnit(enemyPlayer,move.index()));\n        //Unit & enemyUnit(getUnitByID(enemyPlayer ,move.index()));\n\t\t\t\n\t\t// attack the unit\n\t\tourUnit.attack(move, enemyUnit, _currentTime);\n\t\t\t\n\t\t// enemy unit takes damage if it is alive\n\t\tif (enemyUnit.isAlive())\n\t\t{\t\t\t\t\n\t\t\tenemyUnit.takeAttack(ourUnit);\n\n\t\t\t// check to see if enemy unit died\n\t\t\tif (!enemyUnit.isAlive())\n\t\t\t{\n\t\t\t\t// if it died, remove it\n\t\t\t\t_numUnits[enemyPlayer]--;\n\t\t\t}\n\t\t}\t\t\t\n\t}\n\telse if (move.type() == ActionTypes::MOVE)\n\t{\n\t\t_numMovements[player]++;\n\n\t\tourUnit.move(move, _currentTime);\n\t}\n\telse if (move.type() == ActionTypes::HEAL)\n\t{\n\t\tUnit & ourOtherUnit(getUnit(player,move.index()));\n\t\t\t\n\t\t// attack the unit\n\t\tourUnit.heal(move, ourOtherUnit, _currentTime);\n\t\t\t\n\t\tif (ourOtherUnit.isAlive())\n\t\t{\n\t\t\tourOtherUnit.takeHeal(ourUnit);\n\t\t}\n\t}\n\telse if (move.type() == ActionTypes::RELOAD)\n\t{\n\t\tourUnit.waitUntilAttack(move, _currentTime);\n\t}\n\telse if (move.type() == ActionTypes::PASS)\n\t{\n\t\tourUnit.pass(move, _currentTime);\n\t}\n}\n\nconst Unit & GameState::getUnitByID(const size_t & unitID) const\n{\n\tfor (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n\t\tfor (size_t u(0); u<numUnits(p); ++u)\n\t\t{\n\t\t\tif (getUnit(p, u).ID() == unitID)\n\t\t\t{\n\t\t\t\treturn getUnit(p, u);\n\t\t\t}\n\t\t}\n\t}\n\n\tSystem::FatalError(\"GameState Error: getUnitByID() Unit not found, id:\" + std::to_string(unitID));\n\treturn getUnit(0,0);\n}\n\nconst Unit & GameState::getUnitByID(const size_t & player, const size_t & unitID) const\n{\n\tfor (size_t u(0); u<numUnits(player); ++u)\n\t{\n\t\tif (getUnit(player, u).ID() == unitID)\n\t\t{\n\t\t\treturn getUnit(player, u);\n\t\t}\n\t}\n\n\tSystem::FatalError(\"GameState Error: getUnitByID() Unit not found, player:\"+std::to_string(player)+\" id:\" + std::to_string(unitID));\n\treturn getUnit(0,0);\n}\n\nUnit & GameState::getUnitByID(const size_t & player, const size_t & unitID) \n{\n\tfor (size_t u(0); u<numUnits(player); ++u)\n\t{\n\t\tif (getUnit(player, u).ID() == unitID)\n\t\t{\n\t\t\treturn getUnit(player, u);\n\t\t}\n\t}\n\n\tSystem::FatalError(\"GameState Error: getUnitByID() Unit not found, player:\" + std::to_string(player) + \" id:\" + std::to_string(unitID));\n\treturn getUnit(0,0);\n}\n\nconst bool GameState::isWalkable(const Position & pos) const\n{\n\tif (_map)\n\t{\n\t\treturn _map->isWalkable(pos);\n\t}\n\n\t// if there is no map, then return true\n\treturn true;\n}\n\nconst bool GameState::isFlyable(const Position & pos) const\n{\n\tif (_map)\n\t{\n\t\treturn _map->isFlyable(pos);\n\t}\n\n\t// if there is no map, then return true\n\treturn true;\n}\n\nconst size_t GameState::getEnemy(const size_t & player) const\n{\n\treturn (player + 1) % 2;\n}\n\nconst Unit & GameState::getClosestOurUnit(const size_t & player, const size_t & unitIndex)\n{\n\tconst Unit & myUnit(getUnit(player,unitIndex));\n\n\tsize_t minDist(1000000);\n\tsize_t minUnitInd(0);\n\n\tPosition currentPos = myUnit.currentPosition(_currentTime);\n\n\tfor (size_t u(0); u<_numUnits[player]; ++u)\n\t{\n\t\tif (u == unitIndex || getUnit(player, u).canHeal())\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\t//size_t distSq(myUnit.distSq(getUnit(enemyPlayer,u)));\n\t\tsize_t distSq(currentPos.getDistanceSq(getUnit(player, u).currentPosition(_currentTime)));\n\n\t\tif (distSq < minDist)\n\t\t{\n\t\t\tminDist = distSq;\n\t\t\tminUnitInd = u;\n\t\t}\n\t}\n\n\treturn getUnit(player, minUnitInd);\n}\n\nconst Unit & GameState::getClosestEnemyUnit(const size_t & player, const size_t & unitIndex, bool checkCloaked)\n{\n\tconst size_t enemyPlayer(getEnemy(player));\n\tconst Unit & myUnit(getUnit(player,unitIndex));\n\n\tPositionType minDist(1000000);\n\tsize_t minUnitInd(0);\n    size_t minUnitID(255);\n\n\tPosition currentPos = myUnit.currentPosition(_currentTime);\n\n\tfor (size_t u(0); u<_numUnits[enemyPlayer]; ++u)\n\t{\n        Unit & enemyUnit(getUnit(enemyPlayer, u));\n\t\tif (checkCloaked&& enemyUnit.type().hasPermanentCloak())\n\t\t{\n\t\t\tbool invisible = true;\n\t\t\tfor (size_t detectorIndex(0); detectorIndex < _numUnits[player]; ++detectorIndex)\n\t\t\t{\n\t\t\t\t// unit reference\n\t\t\t\tconst Unit & detector(getUnit(player, detectorIndex));\n\t\t\t\tif (detector.type().isDetector() && detector.canSeeTarget(enemyUnit, _currentTime))\n\t\t\t\t{\n\t\t\t\t\tinvisible = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (invisible)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n        PositionType distSq = myUnit.getDistanceSqToUnit(enemyUnit, _currentTime);\n\n\t\tif ((distSq < minDist))// || ((distSq == minDist) && (enemyUnit.ID() < minUnitID)))\n\t\t{\n\t\t\tminDist = distSq;\n\t\t\tminUnitInd = u;\n            minUnitID = enemyUnit.ID();\n\t\t}\n        else if ((distSq == minDist) && (enemyUnit.ID() < minUnitID))\n        {\n            minDist = distSq;\n\t\t\tminUnitInd = u;\n            minUnitID = enemyUnit.ID();\n        }\n\t}\n\n\treturn getUnit(enemyPlayer, minUnitInd);\n}\n\nconst bool GameState::checkFull(const size_t & player) const\n{\n    if (numUnits(player) >= Constants::Max_Units)\n    {\n        std::stringstream ss;\n        ss << \"GameState has too many units. Constants::Max_Units = \" << Constants::Max_Units;\n        System::FatalError(ss.str());\n        return false;\n    }\n\n    return false;\n}\n\n// Add a given unit to the state\n// This function will give the unit a unique unitID\nvoid GameState::addUnit(const Unit & u)\n{\n    checkFull(u.player());\n    System::checkSupportedUnitType(u.type());\n\n    // Calculate the unitID for this unit\n    // This will just be the current total number of units in the state\n    size_t unitID = _numUnits[Players::Player_One] + _numUnits[Players::Player_Two];\n\n    // Set the unit and it's unitID\n\tgetUnit(u.player(), _numUnits[u.player()]) = u;\n    getUnit(u.player(), _numUnits[u.player()]).setUnitID(unitID);\n\n    // Increment the number of units this player has\n\t_numUnits[u.player()]++;\n\t_prevNumUnits[u.player()]++;\n\n    // And do the clean-up\n\tfinishedMoving();\n\tcalculateStartingHealth();\n\n    if (!checkUniqueUnitIDs())\n    {\n        System::FatalError(\"GameState has non-unique Unit ID values\");\n    }\n}\n\n// Add a unit with given parameters to the state\n// This function will give the unit a unique unitID\nvoid GameState::addUnit(const BWAPI::UnitType type, const size_t playerID, const Position & pos)\n{\n    checkFull(playerID);\n    System::checkSupportedUnitType(type);\n\n    // Calculate the unitID for this unit\n    // This will just be the current total number of units in the state\n    size_t unitID = _numUnits[Players::Player_One] + _numUnits[Players::Player_Two];\n\n    // Set the unit and it's unitID\n\tgetUnit(playerID, _numUnits[playerID]) = Unit(type, playerID, pos);\n    getUnit(playerID, _numUnits[playerID]).setUnitID(unitID);\n\n    // Increment the number of units this player has\n\t_numUnits[playerID]++;\n\t_prevNumUnits[playerID]++;\n\n    // And do the clean-up\n\tfinishedMoving();\n\tcalculateStartingHealth();\n\n    if (!checkUniqueUnitIDs())\n    {\n        System::FatalError(\"GameState has non-unique Unit ID values\");\n    }\n}\n\n// Add a given unit to the state\n// This function will keep the unit ID assigned by player. Only use this for advanced / BWAPI states\nvoid GameState::addUnitWithID(const Unit & u)\n{\n    checkFull(u.player());\n    System::checkSupportedUnitType(u.type());\n\n    // Simply add the unit to the array\n\tgetUnit(u.player(), _numUnits[u.player()]) = u;\n\n    // Increment the number of units this player has\n\t_numUnits[u.player()]++;\n\t_prevNumUnits[u.player()]++;\n\n    // And do the clean-up\n\tfinishedMoving();\n\tcalculateStartingHealth();\n\n    if (!checkUniqueUnitIDs())\n    {\n        System::FatalError(\"GameState has non-unique Unit ID values\");\n    }\n}\n\nvoid GameState::sortUnits()\n{\n\t// sort the units based on time free\n\tfor (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n\t\tif (_prevNumUnits[p] <= 1)\n\t\t{\n\t\t\t_prevNumUnits[p] = _numUnits[p];\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/*for (int i=1; i<_prevNumUnits[p]; ++i)\n\t\t\t{\n\t\t\t\t// A[ i ] is added in the sorted sequence A[0, .. i-1]\n\t\t\t\t// save A[i] to make a hole at index iHole\n\t\t\t\t//Unit * item = _unitPtrs[p][i];\n                int itemIndex = _unitIndex[p][i];\n                Unit & itemUnit = getUnit(p, i);\n                int iHole = i;\n\t\t\t\t// keep moving the hole to next smaller index until A[iHole - 1] is <= item\n\t\t\t\t//while ((iHole > 0) && (*item < *(_unitPtrs[p][iHole - 1])))\n                while ((iHole > 0) && (itemUnit < getUnit(p, iHole-1)))\n\t\t\t\t{\n\t\t\t\t\t// move hole to next smaller index\n\t\t\t\t\t//_unitPtrs[p][iHole] = _unitPtrs[p][iHole - 1];\n                    _unitIndex[p][iHole] = _unitIndex[p][iHole - 1];\n\t\t\t\t\tiHole = iHole - 1;\n\t\t\t\t}\n\t\t\t\t// put item in the hole\n                _unitIndex[p][iHole] = itemIndex;\n\t\t\t\t//_unitPtrs[p][iHole] = item;\n\t\t\t}*/\n\t\n\t\t\t\n\t\t\t//_unitPtrs[p].sort(_prevNumUnits[p], UnitPtrCompare());\n            std::sort(&_unitIndex[p][0], &_unitIndex[p][0] + _prevNumUnits[p], UnitIndexCompare(*this, p));\n\t\t\t_prevNumUnits[p] = _numUnits[p];\n\t\t}\n\t}\t\n}\n\nUnit & GameState::getUnit(const size_t & player, const size_t & unitIndex)\n{\n    return _units[player][_unitIndex[player][unitIndex]];\n}\n\nconst Unit & GameState::getUnit(const size_t & player, const size_t & unitIndex) const\n{\n    return _units[player][_unitIndex[player][unitIndex]];\n}\n\nconst size_t GameState::closestEnemyUnitDistance(const Unit & unit) const\n{\n\tsize_t enemyPlayer(getEnemy(unit.player()));\n\n\tsize_t closestDist(0);\n\n\tfor (size_t u(0); u<numUnits(enemyPlayer); ++u)\n\t{\n        size_t dist(unit.getDistanceSqToUnit(getUnit(enemyPlayer, u), _currentTime));\n\n\t\tif (dist > closestDist)\n\t\t{\n\t\t\tclosestDist = dist;\n\t\t}\n\t}\n\n\treturn closestDist;\n}\n\nconst bool GameState::playerDead(const size_t & player) const\n{\n\tif (numUnits(player) <= 0)\n\t{\n\t\treturn true;\n\t}\n\n\tfor (size_t u(0); u<numUnits(player); ++u)\n\t{\n\t\tif (getUnit(player, u).damage() > 0)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nconst size_t GameState::whoCanMove() const\n{\n\tTimeType p1Time(getUnit(0,0).firstTimeFree());\n\tTimeType p2Time(getUnit(1,0).firstTimeFree());\n\n\t// if player one is to move first\n\tif (p1Time < p2Time)\n\t{\n\t\treturn Players::Player_One;\n\t}\n\t// if player two is to move first\n\telse if (p1Time > p2Time)\n\t{\n\t\treturn Players::Player_Two;\n\t}\n\telse\n\t{\n\t\treturn Players::Player_Both;\n\t}\n}\n\nconst bool GameState::checkUniqueUnitIDs() const\n{\n    std::set<size_t> unitIDs;\n\n    for (size_t p(0); p<Constants::Num_Players; ++p)\n    {\n        for (size_t u(0); u<numUnits(p); ++u)\n        {\n            size_t unitID(getUnit(p, u).ID());\n            if (unitIDs.find(unitID) != unitIDs.end())\n            {\n                return false;\n            }\n            else\n            {\n                unitIDs.insert(unitID);\n            }\n        }\n    }\n\n    return true;\n}\n\nvoid GameState::updateGameTime()\n{\n\tconst size_t who(whoCanMove());\n\n\t// if the first player is to move, set the time to his time\n\tif (who == Players::Player_One)\n\t{\n\t\t_currentTime = getUnit(Players::Player_One, 0).firstTimeFree();\n\t}\n\t// otherwise it is player two or both, so it's equal to player two's time\n\telse\n\t{\n\t\t_currentTime = getUnit(Players::Player_Two, 0).firstTimeFree();\n\t}\n}\n\nconst StateEvalScore GameState::eval(const size_t & player, const size_t & evalMethod, const size_t p1Script, const size_t p2Script) const\n{\n\tStateEvalScore score;\n\tconst size_t enemyPlayer(getEnemy(player));\n\n\t// if both players are dead, return 0\n\tif (playerDead(enemyPlayer) && playerDead(player))\n\t{\n\t\treturn StateEvalScore(0, 0);\n\t}\n\n\tStateEvalScore simEval;\n\n\tif (evalMethod == SparCraft::EvaluationMethods::LTD)\n\t{\n\t\tscore = StateEvalScore(evalLTD(player), 0);\n\t}\n\telse if (evalMethod == SparCraft::EvaluationMethods::LTD2)\n\t{\n\t\tscore = StateEvalScore(evalLTD2(player), 0);\n\t}\n\telse if (evalMethod == SparCraft::EvaluationMethods::Playout)\n\t{\n\t\tscore = evalSim(player, p1Script, p2Script);\n\t}\n\n\tif (score.val() == 0)\n\t{\n\t\treturn score;\n\t}\n\n\tScoreType winBonus(0);\n\n\tif (playerDead(enemyPlayer) && !playerDead(player))\n\t{\n\t\twinBonus = 100000;\n\t}\n\telse if (playerDead(player) && !playerDead(enemyPlayer))\n\t{\n\t\twinBonus = -100000;\n\t}\n\n\treturn StateEvalScore(score.val() + winBonus, score.numMoves());\n}\n\n// evaluate the state for _playerToMove\nconst ScoreType GameState::evalLTD(const size_t & player) const\n{\n\tconst size_t enemyPlayer(getEnemy(player));\n\t\n\treturn LTD(player) - LTD(enemyPlayer);\n}\n\n// evaluate the state for _playerToMove\nconst ScoreType GameState::evalLTD2(const size_t & player) const\n{\n\tconst size_t enemyPlayer(getEnemy(player));\n\n\treturn LTD2(player) - LTD2(enemyPlayer);\n}\n\nconst StateEvalScore GameState::evalSim(const size_t & player, const size_t & p1Script, const size_t & p2Script) const\n{\n\tconst size_t p1Model = (p1Script == PlayerModels::Random) ? PlayerModels::NOKDPS : p1Script;\n\tconst size_t p2Model = (p2Script == PlayerModels::Random) ? PlayerModels::NOKDPS : p2Script;\n\n\tPlayerPtr p1(AllPlayers::getPlayerPtr(Players::Player_One, p1Model));\n\tPlayerPtr p2(AllPlayers::getPlayerPtr(Players::Player_Two, p2Model));\n\n\tGame game(*this, p1, p2, 200);\n\n\tgame.play();\n\n\tScoreType evalReturn = game.getState().evalLTD2(player);\n\n\treturn StateEvalScore(evalReturn, game.getState().getNumMovements(player));\n}\n\nvoid GameState::calculateStartingHealth()\n{\n\tfor (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n\t\tfloat totalHP(0);\n\t\tfloat totalSQRT(0);\n\n\t\tfor (size_t u(0); u<_numUnits[p]; ++u)\n\t\t{\n\t\t\ttotalHP += getUnit(p, u).maxHP() * getUnit(p, u).dpf();\n\t\t\ttotalSQRT += sqrtf(getUnit(p,u).maxHP()) * getUnit(p, u).dpf();;\n\t\t}\n\n\t\t_totalLTD[p] = totalHP;\n\t\t_totalSumSQRT[p] = totalSQRT;\n\t}\n}\n\nconst ScoreType\tGameState::LTD2(const size_t & player) const\n{\n\tif (numUnits(player) == 0)\n\t{\n\t\treturn 0;\n\t}\n\n\tfloat sum(0);\n\n\tfor (size_t u(0); u<numUnits(player); ++u)\n\t{\n\t\tconst Unit & unit(getUnit(player, u));\n\n\t\tsum += sqrtf(unit.currentHP()) * unit.dpf();\n\t}\n\n\tScoreType ret = (ScoreType)(1000 * sum / _totalSumSQRT[player]);\n\n\treturn ret;\n}\n\nconst ScoreType GameState::LTD(const size_t & player) const\n{\n\tif (numUnits(player) == 0)\n\t{\n\t\treturn 0;\n\t}\n\n\tfloat sum(0);\n\n\tfor (size_t u(0); u<numUnits(player); ++u)\n\t{\n\t\tconst Unit & unit(getUnit(player, u));\n\n\t\tsum += unit.currentHP() * unit.dpf();\n\t}\n\n\treturn (ScoreType)(1000 * sum / _totalLTD[player]);\n}\n\nvoid GameState::setMap(Map * map)\n{\n\t_map = map;\n\n    // check to see if all units are on walkable tiles\n    for (size_t p(0); p<Constants::Num_Players; ++p)\n    {\n        for (size_t u(0); u<numUnits(p); ++u)\n        {\n            const Position & pos(getUnit(p, u).pos());\n\n            if (!isWalkable(pos))\n            {\n                std::stringstream ss;\n                ss << \"Unit initial position on non-walkable map tile: \" << getUnit(p, u).name() << \" (\" << pos.x() << \",\" << pos.y() << \")\";\n                System::FatalError(ss.str());\n            }\n        }\n    }\n}\n\nconst size_t GameState::numUnits(const size_t & player) const\n{\n\treturn _numUnits[player];\n}\n\nconst size_t GameState::prevNumUnits(const size_t & player) const\n{\n\treturn _prevNumUnits[player];\n}\n\nconst Unit & GameState::getUnitDirect(const size_t & player, const size_t & unit) const\n{\n\treturn _units[player][unit];\n}\n\nconst bool GameState::bothCanMove() const\n{\n\treturn getUnit(0, 0).firstTimeFree() == getUnit(1, 0).firstTimeFree();\n}\n\nvoid GameState::setTime(const TimeType & time)\n{\n\t_currentTime = time;\n}\n\nconst int & GameState::getNumMovements(const size_t & player) const\n{\n\treturn _numMovements[player];\n}\n\nconst TimeType GameState::getTime() const\n{\n\treturn _currentTime;\n}\n\nconst float & GameState::getTotalLTD(const size_t & player) const\n{\n\treturn _totalLTD[player];\n}\n\nconst float & GameState::getTotalLTD2(const size_t & player)\tconst\n{\n\treturn _totalSumSQRT[player];\n}\n\nvoid GameState::setTotalLTD(const float & p1, const float & p2)\n{\n\t_totalLTD[Players::Player_One] = p1;\n\t_totalLTD[Players::Player_Two] = p2;\n}\n\n// detect if there is a deadlock, such that no team can possibly win\nconst bool GameState::isTerminal() const\n{\n    // if someone is dead, then nobody can move\n    if (playerDead(Players::Player_One) || playerDead(Players::Player_Two))\n    {\n        return true;\n    }\n\n    if (_sameHPFrames > 200)\n    {\n        return true;\n    }\n\n\tfor (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n\t\tfor (size_t u(0); u<numUnits(p); ++u)\n\t\t{\n\t\t\t// if any unit on any team is a mobile attacker\n\t\t\tif (getUnit(p, u).isMobile() && !getUnit(p, u).canHeal())\n\t\t\t{\n\t\t\t\t// there is no deadlock, so return false\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\t// at this point we know everyone must be immobile, so check for attack deadlock\n\tfor (size_t u1(0); u1<numUnits(Players::Player_One); ++u1)\n\t{\n\t\tconst Unit & unit1(getUnit(Players::Player_One, u1));\n\n\t\tfor (size_t u2(0); u2<numUnits(Players::Player_Two); ++u2)\n\t\t{\n\t\t\tconst Unit & unit2(getUnit(Players::Player_Two, u2));\n\n\t\t\t// if anyone can attack anyone else\n\t\t\tif (unit1.canAttackTarget(unit2, _currentTime) || unit2.canAttackTarget(unit1, _currentTime))\n\t\t\t{\n\t\t\t\t// then there is no deadlock\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// if everyone is immobile and nobody can attack, then there is a deadlock\n\treturn true;\n}\n\nvoid GameState::setTotalLTD2(const float & p1, const float & p2)\n{\n\t_totalSumSQRT[Players::Player_One] = p1;\n\t_totalSumSQRT[Players::Player_Two] = p2;\n}\n\nMap * GameState::getMap() const\n{\n\treturn _map;\n}\n\nconst size_t GameState::numNeutralUnits() const\n{\n\treturn _neutralUnits.size();\n}\n\nconst Unit & GameState::getNeutralUnit(const size_t & u) const\n{\n\treturn _neutralUnits[u];\n}\n\nvoid GameState::addNeutralUnit(const Unit & unit)\n{\n\t_neutralUnits.add(unit);\n}\n\n// print the state in a neat way\nvoid GameState::print(int indent) const\n{\n\tTABS(indent);\n\tstd::cout << calculateHash(0) << \"\\n\";\n\tfprintf(stderr, \"State - Time: %d\\n\", _currentTime);\n\n\tfor (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n\t\tfor (size_t u(0); u<_numUnits[p]; ++u)\n\t\t{\n\t\t\tconst Unit & unit(getUnit(p, u));\n\n\t\t\tTABS(indent);\n\t\t\tfprintf(stderr, \"  P%d %5d %5d    (%3d, %3d)     %s\\n\", unit.player(), unit.currentHP(), unit.firstTimeFree(), unit.x(), unit.y(), unit.name().c_str());\n\t\t}\n\t}\n\tfprintf(stderr, \"\\n\\n\");\n}\n\nstd::string GameState::toString() const\n{\n\n\tstd::stringstream ss;\n\n\tss << calculateHash(0) << \"\\n\";\n\tss << \"Time: \" << _currentTime << std::endl;\n\n\tfor (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n\t\tfor (size_t u(0); u<_numUnits[p]; ++u)\n\t\t{\n\t\t\tconst Unit & unit(getUnit(p, u));\n\n\t\t\tss << \"  P\" << (int)unit.player() << \" \" << unit.currentHP() << \" (\" << unit.x() << \", \" << unit.y() << \") \" << unit.name() << std::endl;\n\t\t}\n\t}\n\tss << std::endl;\n\n\treturn ss.str();\n}\n\nstd::string GameState::toStringCompact() const\n{\n\tstd::stringstream ss;\n\n\tfor (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n        std::map<BWAPI::UnitType, size_t> typeCount;\n\n\t\tfor (size_t u(0); u<_numUnits[p]; ++u)\n\t\t{\n\t\t\tconst Unit & unit(getUnit(p, u));\n\n            if (typeCount.find(unit.type()) != std::end(typeCount))\n            {\n                typeCount[unit.type()]++;\n            }\n            else\n            {\n                typeCount[unit.type()] = 1;\n            }\n\t\t}\n\n        for (auto & kv : typeCount)\n        {\n            const BWAPI::UnitType & type = kv.first;\n            const size_t count = kv.second;\n\n            ss << \"P\" << (int)p << \" \" << count << \" \" << type.getName() << \"\\n\";\n        }\n\t}\n\n\treturn ss.str();\n}\n\nvoid GameState::write(const std::string & filename) const\n{\n    std::ofstream fout (filename.c_str(), std::ios::out | std::ios::binary); \n    fout.write((char *)this, sizeof(*this)); \n    fout.close();\n}\n\nvoid GameState::read(const std::string & filename)\n{\n    std::ifstream fin (filename.c_str(), std::ios::in | std::ios::binary);\n    fin.read((char *)this, sizeof(*this));\n    fin.close();\n}\n"
  },
  {
    "path": "SparCraft/source/GameState.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include <algorithm>\n#include \"MoveArray.h\"\n#include \"Hash.h\"\n#include \"Map.hpp\"\n#include \"Unit.h\"\n#include \"GraphViz.hpp\"\n#include \"Array.hpp\"\n#include \"Logger.h\"\n#include <memory>\n\ntypedef std::shared_ptr<SparCraft::Map> MapPtr;\n\nnamespace SparCraft\n{\nclass GameState \n{\n    Map *                                                           _map;               \n\n    std::vector<Unit> _units[Constants::Num_Players];\n    std::vector<int>  _unitIndex[Constants::Num_Players];\n\n    Array2D<Unit, Constants::Num_Players, Constants::Max_Units>     _units2;             \n    Array2D<int, Constants::Num_Players, Constants::Max_Units>      _unitIndex2;        \n    Array<Unit, 1>                                                  _neutralUnits;\n\n    Array<size_t, Constants::Num_Players>                    _numUnits;\n    Array<size_t, Constants::Num_Players>                    _prevNumUnits;\n\n    Array<float, Constants::Num_Players>                            _totalLTD;\n    Array<float, Constants::Num_Players>                            _totalSumSQRT;\n\n    Array<int, Constants::Num_Players>                              _numMovements;\n    Array<int, Constants::Num_Players>                              _prevHPSum;\n\t\n    TimeType                                                        _currentTime;\n    size_t                                                          _maxUnits;\n    TimeType                                                        _sameHPFrames;\n\n    // checks to see if the unit array is full before adding a unit to the state\n    const bool              checkFull(const size_t & player)                                        const;\n    const bool              checkUniqueUnitIDs()                                                    const;\n\n    void                    performAction(const Action & theMove);\n\npublic:\n\n    GameState();\n    GameState(const std::string & filename);\n\n\t// misc functions\n    void                    finishedMoving();\n    void                    updateGameTime();\n    const bool              playerDead(const size_t & player)                                       const;\n    const bool              isTerminal()                                                            const;\n\n    // unit data functions\n    const size_t            numUnits(const size_t & player)                                         const;\n    const size_t            prevNumUnits(const size_t & player)                                     const;\n    const size_t            numNeutralUnits()                                                       const;\n    const size_t            closestEnemyUnitDistance(const Unit & unit)                             const;\n\n    // Unit functions\n    void                    sortUnits();\n    void                    addUnit(const Unit & u);\n    void                    addUnit(const BWAPI::UnitType unitType, const size_t playerID, const Position & pos);\n    void                    addUnitWithID(const Unit & u);\n    void                    addNeutralUnit(const Unit & unit);\n    const Unit &            getUnit(const size_t & player, const size_t & unitIndex)         const;\n    const Unit &            getUnitByID(const size_t & unitID)                                      const;\n          Unit &            getUnit(const size_t & player, const size_t & unitIndex);\n    const Unit &            getUnitByID(const size_t & player, const size_t & unitID)               const;\n          Unit &            getUnitByID(const size_t & player, const size_t & unitID);\n    const Unit &            getClosestEnemyUnit(const size_t & player, const size_t & unitIndex, bool checkCloaked=false);\n    const Unit &            getClosestOurUnit(const size_t & player, const size_t & unitIndex);\n    const Unit &            getUnitDirect(const size_t & player, const size_t & unit)               const;\n    const Unit &            getNeutralUnit(const size_t & u)                                        const;\n    \n    // game time functions\n    void                    setTime(const TimeType & time);\n    const TimeType          getTime()                                                               const;\n\n    // evaluation functions\n    const StateEvalScore    eval(   const size_t & player, const size_t & evalMethod, \n                                    const size_t p1Script = PlayerModels::NOKDPS,\n                                    const size_t p2Script = PlayerModels::NOKDPS)                   const;\n    const ScoreType         evalLTD(const size_t & player)                                        const;\n    const ScoreType         evalLTD2(const size_t & player)                                       const;\n    const ScoreType         LTD(const size_t & player)                                            const;\n    const ScoreType         LTD2(const size_t & player)                                           const;\n    const StateEvalScore    evalSim(const size_t & player, const size_t & p1, const size_t & p2)    const;\n    const size_t            getEnemy(const size_t & player)                                         const;\n\n    // unit hitpoint calculations, needed for LTD2 evaluation\n    void                    calculateStartingHealth();\n    void                    setTotalLTD(const float & p1, const float & p2);\n    void                    setTotalLTD2(const float & p1, const float & p2);\n    const float &           getTotalLTD(const size_t & player)                                    const;\n    const float &           getTotalLTD2(const size_t & player)                                   const;\n\n    // move related functions\n    void                    generateMoves(MoveArray & moves, const size_t & playerIndex)            const;\n    void                    makeMoves(const std::vector<Action> & moves);\n    const int &             getNumMovements(const size_t & player)                                  const;\n    const size_t            whoCanMove()                                                            const;\n    const bool              bothCanMove()                                                           const;\n\t\t  \n    // map-related functions\n    void                    setMap(Map * map);\n    Map *                   getMap()                                                                const;\n    const bool              isWalkable(const Position & pos)                                        const;\n    const bool              isFlyable(const Position & pos)                                         const;\n\n    // hashing functions\n    const HashType          calculateHash(const size_t & hashNum)                                   const;\n\n    // state i/o functions\n    void                    print(int indent = 0) const;\n\tstd::string             toString() const;\n    std::string             toStringCompact() const;\n    void                    write(const std::string & filename)                                     const;\n    void                    read(const std::string & filename);\n};\n\n}\n\n"
  },
  {
    "path": "SparCraft/source/GraphViz.hpp",
    "content": "#pragma once\n\n#include <iostream>\n\nnamespace SparCraft\n{\nnamespace GraphViz\n{\n\tclass Property\n\t{\n\tpublic:\n\t\tstd::string prop;\n\t\tstd::string value;\n\t\tProperty(std::string p, std::string val) : prop(p), value(val) { }\t\n\t\tvoid print(std::ofstream & out) { out << prop << \"=\\\"\" << value << \"\\\", \"; }\n\t};\n\n\tclass Node\n\t{\t\n\tpublic:\n\t\tstd::vector<Property> props;\n\t\tstd::string name;\n\t\tNode(std::string n) : name(n) {}\n\t\tNode() {}\n\t\n\t\tvoid set(std::string p, std::string v) { props.push_back(Property(p,v)); }\n\t\tvoid print(std::ofstream & out)\n\t\t{\n\t\t\tout << name << \" [\";\n\t\t\tfor (size_t p(0); p<props.size(); ++p) { props[p].print(out); }\n\t\t\tout << \"]\\n\";\n\t\t}\n\t};\n\n\tclass Edge\n\t{\n\tpublic:\n\t\tstd::pair<std::string, std::string> nodes;\n\t\tstd::vector<Property> props;\n\n\t\tEdge(std::string n1, std::string n2) : nodes(n1, n2) {}\n\t\tEdge(Node & n1, Node & n2) : nodes(n1.name, n2.name) {}\n\t\tvoid set(std::string p, std::string v) { props.push_back(Property(p,v)); }\n\t\tvoid print(std::ofstream & out)\n\t\t{\n\t\t\tout << nodes.first << \" -> \" << nodes.second << \" [\";\n\t\t\tfor (size_t p(0); p<props.size(); ++p) { props[p].print(out); }\n\t\t\tout << \"]\\n\";\n\t\t}\n\t};\n\n\tclass Graph\n\t{\n\t\tstd::vector<Node> nodes;\n\t\tstd::vector<Edge> edges;\n\t\tstd::vector<Property> props;\n\t\tstd::string name;\n\n\tpublic:\n\n\t\tGraph(std::string n) : name(n) {}\n\t\tvoid set(std::string p, std::string v) { props.push_back(Property(p,v)); }\n\t\tvoid addNode(Node & n) { nodes.push_back(n); }\n\t\tvoid addEdge(Edge & e) { edges.push_back(e); }\n\n        void print(std::ofstream & out)\n\t\t{\n\t\t\tout << \"digraph \" << name << \" {\\n\";\n\t\t\tfor (size_t p(0); p<props.size(); ++p) { out << props[p].prop << \"=\\\"\" << props[p].value << \"\\\"\\n\"; }\n\t\t\tfor (size_t n(0); n<nodes.size(); ++n) { nodes[n].print(out); }\n\t\t\tfor (size_t e(0); e<edges.size(); ++e) { edges[e].print(out); }\n\t\t    out << \"}\\n\";\n\t\t}\n\n\t};\n\n\t/*\n\tvoid example()\n\t{\n\t\t// construct a graph, give it a name and some properties\n\t\tGraphViz::Graph G(\"g\");\n\t\t                G.set(\"bgcolor\", \"#000000\");\n\n\t\t// construct some nodes with unique identifiers then give them some properties\n\t\tGraphViz::Node  n1(\"n1\");\n\t\t                n1.set(\"fontcolor\", \"#ffffff\");\n\t\t\t\t\t\tn1.set(\"style\", \"filled\");\n\t\t\t\t\t\tn1.set(\"fillcolor\", \"#ff0000\");\n\t\t\t\t\t\tn1.set(\"label\", \"Node 1\");\n\t\t\t\t\t\tn1.set(\"shape\", \"box\");\n\t\t\t\t\t\tn1.set(\"color\", \"white\");\n\n\t\tGraphViz::Node  n2(\"n2\");\n\t\t                n2.set(\"fontcolor\", \"#ff00ff\");\n\t\t\t\t\t\tn2.set(\"style\", \"filled\");\n\t\t\t\t\t\tn2.set(\"fillcolor\", \"#ffffff\");\n\t\t\t\t\t\tn2.set(\"label\", \"Node 2\");\n\n\t\t// construct an edge, either on unique identifier or node object\n\t\tGraphViz::Edge  e1(n1, n2);\n                        e1.set(\"label\", \"Edge 1\");\n\t\t\t\t\t\te1.set(\"color\", \"white\");\n\n\t\t// add the elements to the graph, this can happen at any time in any order\n\t\tG.addNode(n1);\n\t\tG.addNode(n2);\n\t\tG.addEdge(e1);\n\n\t\t// print out the graph\n\t\tG.print();\n\n\t\t// to use this output you need to have GraphViz installed\n\t\t// to run the above example, pipe the output to test.txt then run\n\t\t//     dot < test.txt -Tpng > test.png\n\t}*/\n}\n}"
  },
  {
    "path": "SparCraft/source/Hash.cpp",
    "content": "#include \"Hash.h\"\n\nusing namespace SparCraft;\n\nnamespace SparCraft\n{\n\tnamespace Hash\n\t{\n\t\tHashType\t\tunitIndexHash[Constants::Num_Players][Constants::Max_Units];\n\t\tHashValues\t\tvalues[Constants::Num_Hashes];\n\t}\n}\n\nconst HashType Hash::HashValues::positionHash(const size_t & player, const PositionType & x, const PositionType & y) const\n{\n\t// return hash32shift(unitPositionHash[player] ^ ((x << 16) + y))\n\treturn hash32shift(hash32shift(unitPositionHash[player] ^ x) ^ y);\n}\n\nHash::HashValues::HashValues(int seed)\n{\n\tRandomInt rand(std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), Constants::Seed_Hash_Time ? 0 : seed);\n\n\tfor (size_t p(0); p<Constants::Num_Players; ++p)\n\t{\n\t\t\t\t\n\t\tfor (size_t u(0); u<Constants::Max_Units; ++u)\n\t\t{\n\t\t\tunitIndexHash[p][u] = rand.nextInt();\n\t\t}\n\n\t\tunitPositionHash[p]\t\t= rand.nextInt();\n\t\ttimeCanAttackHash[p]\t= rand.nextInt();\n\t\ttimeCanMoveHash[p]\t\t= rand.nextInt();\n\t\tunitTypeHash[p]\t\t\t= rand.nextInt();\n\t\tcurrentHPHash[p]\t\t= rand.nextInt();\n\t}\n}\n\nconst HashType Hash::HashValues::getAttackHash (const size_t & player, const size_t & value) const\t\t\n{ \n\treturn hash32shift(timeCanAttackHash[player] ^ value); \n}\n\n\nconst HashType Hash::HashValues::getMoveHash\t\t(const size_t & player, const size_t & value) const\t\t{ return hash32shift(timeCanMoveHash[player] ^ value); }\nconst HashType Hash::HashValues::getUnitTypeHash\t(const size_t & player, const size_t & value) const\t\t{ return hash32shift(unitTypeHash[player] ^ value); }\nconst HashType Hash::HashValues::getCurrentHPHash\t(const size_t & player, const size_t & value) const\t\t{ return hash32shift(currentHPHash[player] ^ value); }\n\n//Robert Jenkins' 32 bit integer hash function\nconst size_t Hash::jenkinsHash( size_t a)\n{\n\ta = (a+0x7ed55d16) + (a<<12);\n\ta = (a^0xc761c23c) ^ (a>>19);\n\ta = (a+0x165667b1) + (a<<5);\n\ta = (a+0xd3a2646c) ^ (a<<9);\n\ta = (a+0xfd7046c5) + (a<<3);\n\ta = (a^0xb55a4f09) ^ (a>>16);\n\treturn a;\n}\n\nvoid Hash::initHash()\n{\n\tvalues[0] = HashValues(0);\n\tvalues[1] = HashValues(1);\n}\n\nint Hash::hash32shift(int key)\n{\n\tkey = ~key + (key << 15); // key = (key << 15) - key - 1;\n\tkey = key ^ (key >> 12);\n\tkey = key + (key << 2);\n\tkey = key ^ (key >> 4);\n\tkey = key * 2057; // key = (key + (key << 3)) + (key << 11);\n\tkey = key ^ (key >> 16);\n\treturn key;\n}\n\nconst int Hash::jenkinsHashCombine(const HashType & hash, const int val)\n{\n\treturn hash32shift(hash ^ (HashType)val);\n}\n\nconst size_t Hash::magicHash(const HashType & hash, const size_t & player, const size_t & index)\n{\n\treturn hash32shift(hash ^ unitIndexHash[player][index]);\n}\n"
  },
  {
    "path": "SparCraft/source/Hash.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include <ctime>\n#include \"Random.hpp\"\n\nnamespace SparCraft\n{\nnamespace Hash\n{\n\ttypedef std::vector<HashType> HashVec;\n\n\tclass HashValues\n\t{\n\t\tHashType\tunitPositionHash[Constants::Num_Players];\n\t\tHashType\ttimeCanAttackHash[Constants::Num_Players];\n\t\tHashType\ttimeCanMoveHash[Constants::Num_Players];\n\t\tHashType\tunitTypeHash[Constants::Num_Players];\n\t\tHashType\tcurrentHPHash[Constants::Num_Players];\n\n\tpublic:\n\n\t\tHashValues(int seed = 0);\n\t\t\n\t\tconst HashType getAttackHash\t\t(const size_t & player, const size_t & value) const;\n\t\tconst HashType getMoveHash\t\t\t(const size_t & player, const size_t & value) const;\n\t\tconst HashType getUnitTypeHash\t\t(const size_t & player, const size_t & value) const;\n\t\tconst HashType getCurrentHPHash\t\t(const size_t & player, const size_t & value) const;\n\t\tconst HashType positionHash\t\t\t(const size_t & player, const PositionType & x, const PositionType & y) const;\n\t};\n\n\t// some data storage\n\textern HashType\t\t\tunitIndexHash[Constants::Num_Players][Constants::Max_Units];\n\textern HashValues\t\tvalues[Constants::Num_Hashes];\n\t\n\t// good hashing functions\n\tvoid\t\t\tinitHash();\n\tint\t\t\t\thash32shift(int key);\n\tconst size_t\tjenkinsHash( size_t a);\n\tconst size_t\tmagicHash(const HashType & hash, const size_t & player, const size_t & index);\n\n\tconst int jenkinsHashCombine(const HashType & hash, const int val);\n};\n}"
  },
  {
    "path": "SparCraft/source/Logger.cpp",
    "content": "#include \"Logger.h\"\n\nusing namespace SparCraft;\n\nLogger::Logger() \n    : totalCharsLogged(0)\n{\n\t\n}\n\nLogger & Logger::Instance() \n{\n\tstatic Logger instance;\n\treturn instance;\n}\n\nvoid Logger::clearLogFile(const std::string & logFile)\n{\n\n}\n\nvoid Logger::log(const std::string & logFile, std::string & msg)\n{\n    std::ofstream logStream;\n\tlogStream.open(logFile.c_str(), std::ofstream::app);\n\tlogStream << msg;\n    logStream.flush();\n    logStream.close();\n}\n"
  },
  {
    "path": "SparCraft/source/Logger.h",
    "content": "#pragma once\n\n#include <string>\n#include <iostream>\n#include <fstream>\n\nnamespace SparCraft\n{\n\nclass Logger \n{\n    size_t totalCharsLogged;\n\n\tLogger();\n\npublic:\n\n\tstatic Logger &\tInstance();\n\tvoid log(const std::string & logFile, std::string & msg);\n\tvoid clearLogFile(const std::string & logFile);\n};\n}"
  },
  {
    "path": "SparCraft/source/Map.hpp",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Array.hpp\"\n#include \"Unit.h\"\n\nnamespace SparCraft\n{\n\ntypedef std::vector< std::vector<bool> > bvv;\n\nclass Map\n{\n\tsize_t\t\t\t\t\t_walkTileWidth;\n\tsize_t\t\t\t\t\t_walkTileHeight;\n\tsize_t\t\t\t\t\t_buildTileWidth;\n\tsize_t\t\t\t\t\t_buildTileHeight;\n\tbvv\t\t\t\t\t\t_mapData;\t            // true if walk tile [x][y] is walkable\n\n\tbvv\t\t\t\t\t\t_unitData;\t            // true if unit on build tile [x][y]\n\tbvv\t\t\t\t\t\t_buildingData;          // true if building on build tile [x][y]\n\n\tconst Position getWalkPosition(const Position & pixelPosition) const\n\t{\n\t\treturn Position(pixelPosition.x() / 8, pixelPosition.y() / 8);\n\t}\n\n    void resetVectors()\n    {\n        _mapData =          bvv(_walkTileWidth,  std::vector<bool>(_walkTileHeight,  true));\n\t\t_unitData =         bvv(_buildTileWidth, std::vector<bool>(_buildTileHeight, false));\n\t\t_buildingData =     bvv(_buildTileWidth, std::vector<bool>(_buildTileHeight, false));\n    }\n\npublic:\n\n\tMap() \n        : _walkTileWidth(0)\n\t\t, _walkTileHeight(0)\n\t\t, _buildTileWidth(0)\n\t\t, _buildTileHeight(0)\n    {\n    }\n\n    // constructor which sets a completely walkable map\n    Map(const size_t & bottomRightBuildTileX, const size_t & bottomRightBuildTileY)\n        : _walkTileWidth(bottomRightBuildTileX * 4)\n\t\t, _walkTileHeight(bottomRightBuildTileY * 4)\n\t\t, _buildTileWidth(bottomRightBuildTileX)\n\t\t, _buildTileHeight(bottomRightBuildTileY)\n    {\n        resetVectors();\n    }\n\n\tMap(BWAPI::GameWrapper & game) \n        : _walkTileWidth(game->mapWidth() * 4)\n\t\t, _walkTileHeight(game->mapHeight() * 4)\n\t\t, _buildTileWidth(game->mapWidth())\n\t\t, _buildTileHeight(game->mapHeight())\n\t{\n\t\tresetVectors();\n\n\t\tfor (size_t x(0); x<_walkTileWidth; ++x)\n\t\t{\n\t\t\tfor (size_t y(0); y<_walkTileHeight; ++y)\n\t\t\t{\n\t\t\t\tsetMapData(x, y, game->isWalkable(x, y));\n\t\t\t}\n\t\t}\n\t}\n\t\n    const size_t getPixelWidth() const\n    {\n        return getWalkTileWidth() * 4;\n    }\n\n    const size_t getPixelHeight() const\n    {\n        return getWalkTileHeight() * 4;\n    }\n\n\tconst size_t & getWalkTileWidth() const\n\t{\n\t\treturn _walkTileWidth;\n\t}\n\n\tconst size_t & getWalkTileHeight() const\n\t{\n\t\treturn _walkTileHeight;\n\t}\n\n\tconst size_t & getBuildTileWidth() const\n\t{\n\t\treturn _buildTileWidth;\n\t}\n\n\tconst size_t & getBuildTileHeight() const\n\t{\n\t\treturn _buildTileHeight;\n\t}\n\n\tconst bool isWalkable(const SparCraft::Position & pixelPosition) const\n\t{\n\t\tconst Position & wp(getWalkPosition(pixelPosition));\n\n\t\treturn\tisWalkable(wp.x(), wp.y());\n\t}\n    \n    const bool isFlyable(const SparCraft::Position & pixelPosition) const\n\t{\n\t\tconst Position & wp(getWalkPosition(pixelPosition));\n\n\t\treturn isFlyable(wp.x(), wp.y());\n\t}\n\n\tconst bool isWalkable(const size_t & walkTileX, const size_t & walkTileY) const\n\t{\n\t\treturn\twalkTileX >= 0 && walkTileX < (PositionType)getWalkTileWidth() && \n\t\t\t\twalkTileY >= 0 && walkTileY < (PositionType)getWalkTileHeight() &&\n\t\t\t\tgetMapData(walkTileX, walkTileY);\n\t}\n\n    const bool isFlyable(const size_t & walkTileX, const size_t & walkTileY) const\n\t{\n\t\treturn\twalkTileX >= 0 && walkTileX < (PositionType)getWalkTileWidth() && \n\t\t\t\twalkTileY >= 0 && walkTileY < (PositionType)getWalkTileHeight();\n\t}\n\n\tconst bool getMapData(const size_t & walkTileX, const size_t & walkTileY) const\n\t{\n\t\treturn _mapData[walkTileX][walkTileY];\n\t}\n\n\tconst bool getUnitData(const size_t & buildTileX, const size_t & buildTileY) const\n\t{\n\t\treturn _unitData[buildTileX][buildTileY];\n\t}\n\n\tvoid setMapData(const size_t & walkTileX, const size_t & walkTileY, const bool val)\n\t{\n\t\t_mapData[walkTileX][walkTileY] = val;\n\t}\n\n\tvoid setUnitData(BWAPI::GameWrapper & game)\n\t{\n\t\t_unitData = bvv(getBuildTileWidth(), std::vector<bool>(getBuildTileHeight(), true));\n\n\t\tfor (BWAPI::UnitInterface * unit : game->getAllUnits())\n\t\t{\n\t\t\tif (!unit->getType().isBuilding())\n\t\t\t{\n\t\t\t\taddUnit(unit);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst bool canBuildHere(BWAPI::TilePosition pos)\n\t{\n\t\treturn _unitData[pos.x][pos.y] && _buildingData[pos.x][pos.y];\n\t}\n\n\tvoid setBuildingData(BWAPI::GameWrapper & game)\n\t{\n\t\t_buildingData = bvv(getBuildTileWidth(), std::vector<bool>(getBuildTileHeight(), true));\n\n\t\tfor (BWAPI::UnitInterface * unit : game->getAllUnits())\n\t\t{\n\t\t\tif (unit->getType().isBuilding())\n\t\t\t{\n\t\t\t\taddUnit(unit);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid addUnit(BWAPI::Unit & unit)\n\t{\n        \n\t\tif (unit->getType().isBuilding())\n\t\t{\n\t\t\tint tx = unit->getPosition().x / TILE_SIZE;\n\t\t\tint ty = unit->getPosition().y / TILE_SIZE;\n\t\t\tint sx = unit->getType().tileWidth(); \n\t\t\tint sy = unit->getType().tileHeight();\n\t\t\tfor(int x = tx; x < tx + sx && x < (int)getBuildTileWidth(); ++x)\n\t\t\t{\n\t\t\t\tfor(int y = ty; y < ty + sy && y < (int)getBuildTileHeight(); ++y)\n\t\t\t\t{\n\t\t\t\t\t_buildingData[x][y] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tint startX = (unit->getPosition().x - unit->getType().dimensionLeft()) / TILE_SIZE;\n\t\t\tint endX   = (unit->getPosition().x + unit->getType().dimensionRight() + TILE_SIZE - 1) / TILE_SIZE; // Division - round up\n\t\t\tint startY = (unit->getPosition().y - unit->getType().dimensionUp()) / TILE_SIZE;\n\t\t\tint endY   = (unit->getPosition().y + unit->getType().dimensionDown() + TILE_SIZE - 1) / TILE_SIZE;\n\t\t\tfor (int x = startX; x < endX && x < (int)getBuildTileWidth(); ++x)\n\t\t\t{\n\t\t\t\tfor (int y = startY; y < endY && y < (int)getBuildTileHeight(); ++y)\n\t\t\t\t{\n\t\t\t\t\t_unitData[x][y] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tunsigned int * getRGBATexture()\n\t{\n\t\tunsigned int * data = new unsigned int[getWalkTileWidth() * getWalkTileHeight()];\n\t\tfor (size_t x(0); x<getWalkTileWidth(); ++x)\n\t\t{\n\t\t\tfor (size_t y(0); y<getWalkTileHeight(); ++y)\n\t\t\t{\n\t\t\t\tif (!isWalkable(x, y))\n\t\t\t\t{\n\t\t\t\t\tdata[y*getWalkTileWidth() + x] = 0xffffffff;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tdata[y*getWalkTileWidth() + x] = 0x00000000;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tvoid write(const std::string & filename)\n\t{\n\t\tstd::ofstream fout(filename.c_str());\n\t\tfout << getWalkTileWidth() << \"\\n\" << getWalkTileHeight() << \"\\n\";\n\n\t\tfor (size_t y(0); y<getWalkTileHeight(); ++y)\n\t\t{\n\t\t\tfor (size_t x(0); x<getWalkTileWidth(); ++x)\n\t\t\t{\n\t\t\t\tfout << (isWalkable(x, y) ? 1 : 0);\n\t\t\t}\n\n\t\t\tfout << \"\\n\";\n\t\t}\n\n\t\tfout.close();\n\t}\n\n\tvoid load(const std::string & filename)\n\t{\n\t\tstd::ifstream fin(filename.c_str());\n\t\tstd::string line;\n\t\t\n\t\tgetline(fin, line);\n\t\t_walkTileWidth = atoi(line.c_str());\n\n\t\tgetline(fin, line);\n\t\t_walkTileHeight = atoi(line.c_str());\n\n        _buildTileWidth = _walkTileWidth/4;\n        _buildTileHeight = _walkTileHeight/4;\n\n\t\tresetVectors();\n\n\t\tfor (size_t y(0); y<getWalkTileHeight(); ++y)\n\t\t{\n\t\t\tgetline(fin, line);\n\n\t\t\tfor (size_t x(0); x<getWalkTileWidth(); ++x)\n\t\t\t{\n\t\t\t\t_mapData[x][y] = line[x] == '1' ? true : false;\n\t\t\t}\n\t\t}\n\n\t\tfin.close();\n\t}\n};\n}"
  },
  {
    "path": "SparCraft/source/MoveArray.cpp",
    "content": "#include \"MoveArray.h\"\n\nusing namespace SparCraft;\n\nMoveArray::MoveArray(const size_t maxUnits) \n\t: _numUnits(0)\n\t, _maxUnits(Constants::Max_Units)\n    , _hasMoreMoves(true)\n{\n    //_currentMovesVec.reserve(Constants::Max_Units);\n\t_numMoves.fill(0);\n    _currentMovesIndex.fill(0);\n}\n    \nvoid MoveArray::clear() \n{\n    // only clear things if they need to be cleared\n    if (_numUnits == 0)\n    {\n        return;\n    }\n\n\t_numUnits = 0;\n\t_numMoves.fill(0);\n    resetMoveIterator();\n}\n\n// shuffle the MOVE unit actions to prevent bias in experiments\n// this function assumes that all MOVE actions are contiguous in the moves array\n// this should be the case unless you change the move generation ordering\nvoid MoveArray::shuffleMoveActions()\n{\n    // for each unit\n    for (size_t u(0); u<numUnits(); ++u)\n    {\n        int moveEnd(-1);\n        int moveBegin(-1);\n\n        // reverse through the list of actions for this unit\n        for (int a(numMoves(u)-1); a >= 0; --a)\n        {\n            size_t moveType(getMove(u, a).type());\n\n            // mark the end of the move actions\n            if (moveEnd == -1 && (moveType == ActionTypes::MOVE))\n            {\n                moveEnd = a;\n            }\n            // mark the beginning of the MOVE unit actions\n            else if ((moveEnd != -1) && (moveBegin == -1) && (moveType != ActionTypes::MOVE))\n            {\n                moveBegin = a;\n            }\n            else if (moveBegin != -1)\n            {\n                break;\n            }\n        }\n\n        // if we found the end but didn't find the beginning\n        if (moveEnd != -1 && moveBegin == -1)\n        {\n            // then the move actions begin at the beginning of the array\n            moveBegin = 0;\n        }\n\n        // shuffle the movement actions for this unit\n        if (moveEnd != -1 && moveBegin != -1 && moveEnd != moveBegin)\n        {\n            std::random_shuffle(&_moves[u][moveBegin], &_moves[u][moveEnd]);\n            resetMoveIterator();\n        }\n    }\n}\n\n// returns a given move from a unit\nconst Action & MoveArray::getMove(const size_t & unit, const size_t & move) const\n{\n    assert(_moves[unit][(size_t)move].unit() != 255);\n\n    return _moves[unit][(size_t)move];\n}\n\nvoid MoveArray::printCurrentMoveIndex()\n{\n    for (size_t u(0); u<_numUnits; ++u)\n    {\n        std::cout << _currentMovesIndex[u] << \" \";\n    }\n\n    std::cout << std::endl;\n}\n\nvoid MoveArray::incrementMove(const size_t & unit)\n{\n    // increment the index for this unit\n    _currentMovesIndex[unit] = (_currentMovesIndex[unit] + 1) % _numMoves[unit];\n\n    // if the value rolled over, we need to do the carry calculation\n    if (_currentMovesIndex[unit] == 0)\n    {\n        // the next unit index\n        size_t nextUnit = unit + 1;\n\n        // if we have space left to increment, do it\n        if (nextUnit < _numUnits)\n        {\n            incrementMove(nextUnit);\n        }\n        // otherwise we have no more moves\n        else\n        {\n            // stop\n            _hasMoreMoves = false;\n        }\n    }\n\n    _currentMoves[unit] = _moves[unit][_currentMovesIndex[unit]];\n    //_currentMovesVec[unit] = _moves[unit][_currentMovesIndex[unit]];\n}\n\nconst bool MoveArray::hasMoreMoves() const\n{\n    return _hasMoreMoves;\n}\n\nvoid MoveArray::resetMoveIterator()\n{\n    _hasMoreMoves = true;\n    _currentMovesIndex.fill(0);\n\n    for (size_t u(0); u<numUnits(); ++u)\n    {\n        _currentMoves[u] = _moves[u][_currentMovesIndex[u]];\n        //_currentMovesVec[u] = _moves[u][_currentMovesIndex[u]];\n    }\n}\n\nvoid MoveArray::getNextMoveVec(std::vector<Action> & moves)\n{\n    moves.assign(&_currentMoves[0], &_currentMoves[_numUnits]);\n    //moves = _currentMovesVec;\n    incrementMove(0);\n}\n\nconst size_t MoveArray::maxUnits() const\n{\n\treturn _moves.getRows();\n}\n\n// adds a Move to the unit specified\nvoid MoveArray::add(const Action & move)\n{\n\t_moves[move.unit()][_numMoves[move.unit()]] = move;\n\t_numMoves[move.unit()]++;\n\n    _currentMovesIndex[_numUnits-1] = 0;\n    _currentMoves[_numUnits-1] = _moves[move.unit()][0];\n    //_currentMovesVec.push_back(_moves[move.unit()][0]);\n    //resetMoveIterator();\n}\n\t\nbool MoveArray::validateMoves()\n{\n\tfor (size_t u(0); u<numUnits(); ++u)\n\t{\n\t\tfor (size_t m(0); m<numMoves(u); ++m)\n\t\t{\n\t\t\tconst Action & move(getMove(u, m));\n\n\t\t\tif (move.unit() > 200)\n\t\t\t{\n\t\t\t\tprintf(\"Unit Move Incorrect! Something will be wrong\\n\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\t\t\n\treturn true;\n}\n\nconst size_t MoveArray::getUnitID(const size_t & unit) const\n{\n\treturn getMove(unit, 0).unit();\n}\n\nconst size_t MoveArray::getPlayerID(const size_t & unit) const\n{\n\treturn getMove(unit, 0).player();\n}\n\nvoid MoveArray::addUnit() \t\t\t\t\t\t\t\t\t\t\t{ _numUnits++; }\n\nconst size_t & MoveArray::numUnits()\t\t\t\t\t\tconst\t{ return _numUnits; }\nconst size_t & MoveArray::numUnitsInTuple()\t\t\t\tconst\t{ return numUnits(); }\nconst size_t & MoveArray::numMoves(const size_t & unit)\tconst\t{ return _numMoves[unit]; }"
  },
  {
    "path": "SparCraft/source/MoveArray.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Array.hpp\"\n#include \"Unit.h\"\n#include \"Action.h\"\n\nnamespace SparCraft\n{\nclass MoveArray\n{\n\t// the array which contains all the moves\n\tArray2D<Action, Constants::Max_Units, Constants::Max_Moves> _moves;\n\n\t// how many moves each unit has\n\tArray<size_t, Constants::Max_Units>                         _numMoves;\n\n    // the current move array, used for the 'iterator'\n    //std::vector<Action> _currentMoves;\n    //std::vector<Action>                                             _currentMovesVec;\n    Array<Action, Constants::Max_Units>                         _currentMoves;\n    Array<size_t, Constants::Max_Units>                         _currentMovesIndex;\n\n\t// the number of units that have moves;\n\tsize_t                                                      _numUnits;\n\tsize_t                                                              _maxUnits;\n    bool                                                                _hasMoreMoves;\n\npublic:\n\n\tMoveArray(const size_t maxUnits = 0);\n\n\tvoid clear();\n\n\t// returns a given move from a unit\n\tconst Action & getMove(const size_t & unit, const size_t & move) const;\n\n    void printCurrentMoveIndex();\n\n    void incrementMove(const size_t & unit);\n\n    const bool hasMoreMoves() const;\n\n    void resetMoveIterator();\n\n    void getNextMoveVec(std::vector<Action> & moves);\n\n\tconst size_t maxUnits() const;\n\n\t// adds a Move to the unit specified\n\tvoid add(const Action & move);\n\t\n\tbool validateMoves();\n\n\tconst size_t getUnitID(const size_t & unit) const;\n\n\tconst size_t getPlayerID(const size_t & unit) const;\n\n\tvoid addUnit();\n\n    void shuffleMoveActions();\n\n\tconst size_t & numUnits()\t\t\t\t\t\tconst;\n\tconst size_t & numUnitsInTuple()\t\t\t\tconst;\n\tconst size_t & numMoves(const size_t & unit)\tconst;\n};\n}"
  },
  {
    "path": "SparCraft/source/MoveSet.hpp",
    "content": "#pragma once\n\n#include <stdio.h>\n#include \"Common.h\"\n\n///////////////////////////////////////////////////////////////////////////////\n//\n// BitSet\n//\n///////////////////////////////////////////////////////////////////////////////\n\n#ifdef WIN32\n\t#include <intrin.h>\n\t#pragma intrinsic(__ll_lshift)\n\t#pragma intrinsic(__ll_rshift)\n\t#define __lz(a) countLeadingZeros(a)\n\t#define __tz(a) countTrailingZeros(a)\n\t#define __ONE 1ull\n\t#define __ZERO 0ull\n\t#define __LSHIFT64(VAL, N) __ll_lshift(VAL, N)\n\t#define __RSHIFT64(VAL, N) __ll_rshift(VAL, N)\n#else\n\t#define __lz(a) __builtin_clzll(a)\n\t#define __tz(a) __builtin_ctzll(a)\n\t#define __ONE 1LLU\n\t#define __ZERO 0LLU\n\t#define __LSHIFT64(VAL, N) VAL << N\n\t#define __RSHIFT64(VAL, N) VAL >> N\n#endif\n\n#define LBIT(N) (__LSHIFT64(__ONE, (63-N)))\n#define RBIT(N) (__LSHIFT64(__ONE, N))\n#define SINGLE_BIT(N) RBIT(N)\n\n//#define REVERSE_ACTION_ITERATOR\n\nclass BitSet {\n\n\tunsigned long long set;\t\t\t\t\t\t\t// 64 bit unsigned int to represent set\n\npublic:\n\n\tBitSet() : set(0) {}\t\t\t\t\t\t\t// default constructor sets to zero\n\tBitSet(long long unsigned s) : set(s) {}\t\t// constructor which takes a uint64\n\n\t// pops the next action (bit from the right)\n\tint popAction()\n\t{\t\n\t\t#ifdef REVERSE_ACTION_ITERATOR\n\t\t\t// get the number of trailing zeros\n\t\t\tint nextAction = 63 - __lz(set);\n\t\t#else\n\t\t\t// get the number of trailing zeros\n\t\t\tint nextAction = __tz(set);\n\t\t#endif\n\t\t\n\t\t// set that bit to a zero\n\t\tsubtract(nextAction);\n\n\t\treturn (Action)nextAction;\n\t}\n\t\n\t// peeks at the next action\n\tint nextAction()\n\t{\t\n\t\t#ifdef REVERSE_ACTION_ITERATOR\n\t\t\t// get the number of trailing zeros\n\t\t\tint nextAction = 63 - __lz(set);\n\t\t#else\n\t\t\t// get the number of trailing zeros\n\t\t\tint nextAction = __tz(set);\n\t\t#endif\n\n\t\treturn nextAction;\n\t}\n\n\tint  \t\toperator [] \t(const int bit) \tconst\t{ return set & SINGLE_BIT(bit) ? 1 : 0; }\t// get the bit at i\n\tBitSet \t\toperator +  \t(const int bit) \tconst\t{ return BitSet(set | SINGLE_BIT(bit)); }\t// member addition\n\tBitSet \t\toperator -  \t(const int bit) \tconst\t{ return BitSet(set & ~SINGLE_BIT(bit)); }\t// member subtraction\n\tBitSet \t\toperator |  \t(const BitSet & a) \tconst\t{ return BitSet(set | a.set); }\t\t\t\t// set union\n\tBitSet \t\toperator +  \t(const BitSet & a)\tconst \t{ return BitSet(set | a.set); }\t\t\t\t// set union\n\tBitSet \t\toperator -  \t(const BitSet & a)\tconst \t{ return BitSet(set & ~a.set); }\t\t\t// set subtraction\n\tBitSet \t\toperator &  \t(const BitSet & a)\tconst \t{ return BitSet(set & a.set); }\t\t\t\t// set intersection\n\tBitSet \t\toperator ~  \t()\t\t\t\t\tconst \t{ return BitSet(~set); }\t\t\t\t\t// set negation\n\n\tbool \t\tisEmpty\t\t\t() \t\t\t\t\tconst\t{ return set == __ZERO; }\t\t\t\t\t// the set is all zeros\n\tbool \t\tcontains\t\t(const BitSet a) \tconst\t{ return (set & a.set) == a.set; }\t\t\t// completely contain another set\n\tbool\t\tcontains\t\t(const int bit) \tconst\t{ return (set & SINGLE_BIT(bit)) != __ZERO;}// contains a bit set to 1\n\tbool\t\tcontainsAny \t(const BitSet a)\tconst\t{ return (set & ~a.set) != set; }\t\t\t// does set contain any of\n\tbool\t\tcontainsNone \t(const BitSet a)\tconst\t{ return (set & ~a.set) == set; }\t\t\t// does set contain none of \n\tbool \t\tisSubsetOf\t\t(const BitSet a) \tconst\t{ return (a.set & set) == set; }\t\t\t// is a subset of another set\n\tint \t\tgetBit\t\t\t(const int bit)\t\tconst\t{ return (set & SINGLE_BIT(bit)) ? 1 : 0; }\t// identical to contains\n\tvoid \t\tadd\t\t\t\t(const int bit) \t\t\t{ set |= SINGLE_BIT(bit); }\t\t\t\t\t// sets a bit to 1\n\tvoid \t\tadd\t\t\t\t(const BitSet a)\t\t\t{ set |= a.set; }\t\t\t\t\t\t\t// sets all of input set to 1\n\tvoid\t\tsubtract\t\t(const int bit)\t\t\t\t{ set &= ~SINGLE_BIT(bit); }\t\t\t\t// set bit to zero\n\tvoid \t\tsubtract\t\t(const BitSet a)\t\t\t{ set &= ~a.set; }\t\t\t\t\t\t\t// sets all of input set to 0\n\t\n\tint countTrailingZeros(unsigned long long s) const\n\t{\t\n\t\tint zeros = 0;\n\t\t\n\t\twhile (!(s & __ONE))\n\t\t{\n\t\t\ts = __RSHIFT64(s,1);\n\t\t\t++zeros;\n\t\t}\n\t\t\n\t\treturn zeros;\n\t}\n\t\n\tint countLeadingZeros(unsigned long long s) const\n\t{\t\n\t\tint zeros = 0;\n\t\tunsigned long long __L_ONE = __LSHIFT64(__ONE, 63);\n\t\t\n\t\twhile (!(s & __L_ONE))\n\t\t{\n\t\t\ts = __LSHIFT64(s,1);\n\t\t\t++zeros;\n\t\t}\n\t\t\n\t\treturn zeros;\n\t}\n\t\n\tint numActions() const\n\t{\n\t\tBitSet t(set);\n\t\tint count(0);\n\t\t\n\t\twhile (!t.isEmpty())\n\t\t{\n\t\t\tt.popAction();\n\t\t\t++count;\n\t\t}\n\t\t\n\t\treturn count;\n\t}\n\t\n\tint randomAction() const\n\t{\n        BitSet s(set);\n        int num = s.numActions();\n        if (num == 1)\n        {\n            return s.popAction();\n        }\n        \n        int r = (rand() % (s.numActions() - 1));\n        \n        Action a = s.popAction();\n        \n        for (int i=0; i<r; i++)\n        {\n            a = s.popAction();\n        }\n        \n\t    return a;\n\t}\n\n\tvoid print() const\n\t{\n\t\t// print the bits from left to right\n\t\tprintf(\"%ull\\n\", set);\n\t\tfor (int i=0; i<64; ++i) { \tprintf(\"%d\", (63-i)%10); }\n\t\tprintf(\"\\n\");\n\t\tfor (int i=0; i<64; ++i) { \tprintf(\"%d\", (set & (__LSHIFT64(__ONE, (63 - i))) ? 1 : 0)); }\n\t\tprintf(\"\\n\");\n\t}\n};\n\ntypedef BitSet MoveSet;\n"
  },
  {
    "path": "SparCraft/source/Player.cpp",
    "content": "#include \"Player.h\"\n\nusing namespace SparCraft;\n\n\nvoid Player::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n\t// not implemented\n}\n\nconst size_t Player::ID() \n{ \n\treturn _playerID; \n}\n\nvoid Player::setID(const size_t & playerID)\n{\n\t_playerID = playerID;\n}\n"
  },
  {
    "path": "SparCraft/source/Player.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"MoveArray.h\"\n#include \"Unit.h\"\n#include <memory>\n\nnamespace SparCraft\n{\n \nclass GameState;\n\nclass Player \n{\nprotected:\n    size_t _playerID;\npublic:\n    virtual void\t\tgetMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n    const size_t        ID();\n    void                setID(const size_t & playerid);\n    virtual size_t      getType() { return PlayerModels::None; }\n};\n\nclass CompareUnitDPSThreat\n{\n    const bool operator() (Unit * u1, Unit * u2) const\n    {\n        double u1Threat = ((double)u1->damage()/(double)u1->attackCooldown()) / u1->currentHP();\n        double u2Threat = ((double)u2->damage()/(double)u2->attackCooldown()) / u2->currentHP();\n\n        return u1Threat > u2Threat;\n    }\n};\n\ntypedef\tstd::shared_ptr<Player> PlayerPtr; \n\n}"
  },
  {
    "path": "SparCraft/source/PlayerProperties.cpp",
    "content": "#include \"PlayerProperties.h\"\n#include \"WeaponProperties.h\"\n\nusing namespace SparCraft;\n\nPlayerProperties PlayerProperties::props[2];\n\nPlayerProperties::PlayerProperties()\n{\n\tReset();\n}\n\nPlayerProperties::PlayerProperties(const BWAPI::Player & player) \n{ \n\tCapture(player); \n}\n\nPlayerProperties & PlayerProperties::Get(const size_t & playerID)\n{ \n    return props[playerID]; \n}\n\nvoid PlayerProperties::Reset()\n{\n\tfor(int i(0); i<NUM_UPGRADES; ++i)\n\t{\n\t\tupgradeLevel[i] = 0;\n\t}\n\n\tfor(int i(0); i<NUM_TECHS; ++i)\n\t{\n\t\thasResearched[i] = false;\n\t}\n}\n\nvoid PlayerProperties::SetUpgradeLevel(BWAPI::UpgradeType upgrade, int level)\n{\n\tassert(upgrade != BWAPI::UpgradeTypes::None);\n\tassert(upgrade != BWAPI::UpgradeTypes::Unknown);\n\tassert(level >= 0 && level <= upgrade.maxRepeats());\n\tupgradeLevel[upgrade.getID()] = level;\n}\n\nvoid PlayerProperties::SetResearched(BWAPI::TechType tech, bool researched)\n{\n\tassert(tech != BWAPI::TechTypes::None); \n\tassert(tech != BWAPI::TechTypes::Unknown); \n\thasResearched[tech.getID()] = researched;\n}\n\nvoid PlayerProperties::Capture(const BWAPI::Player & player)\n{\n\tfor(int i(0); i<NUM_UPGRADES; ++i)\n\t{\n\t\tupgradeLevel[i] = player->getUpgradeLevel(i);\n\t}\n\n\tfor(int i(0); i<NUM_TECHS; ++i)\n\t{\n\t\thasResearched[i] = player->hasResearched(i);\n\t}\n}\n\nint PlayerProperties::GetUpgradeLevel(BWAPI::UpgradeType upgrade) const \n{ \n    return upgradeLevel[upgrade.getID()]; \n}\n\nbool PlayerProperties::HasUpgrade(BWAPI::UpgradeType upgrade) const \n{ \n    return upgradeLevel[upgrade.getID()] > 0; \n}\n\nbool PlayerProperties::HasResearched(BWAPI::TechType tech) const \n{ \n    return hasResearched[tech.getID()]; \n}\n\nPlayerWeapon::PlayerWeapon(const PlayerProperties * player, BWAPI::WeaponType type) \n    : player(player)\n    , type(type) \n{\n}\n\nint\tPlayerWeapon::GetDamageBase() const\t\t\t\t\t\t\t\t\t\t\n{ \n    return SparCraft::WeaponProperties::Get(type).GetDamageBase(*player); \n}\n\nfloat PlayerWeapon::GetDamageMultiplier(BWAPI::UnitSizeType targetSize) const\t\n{ \n    return SparCraft::WeaponProperties::Get(type).GetDamageMultiplier(targetSize); \n}\n\nint\tPlayerWeapon::GetCooldown() const\t\t\t\t\t\t\t\t\t\t\t\n{ \n    return SparCraft::WeaponProperties::Get(type).GetCooldown(*player); \n}\n\nint\tPlayerWeapon::GetMaxRange() const\n{ \n    return SparCraft::WeaponProperties::Get(type).GetMaxRange(*player); \n}"
  },
  {
    "path": "SparCraft/source/PlayerProperties.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace SparCraft\n{\n\t\nclass PlayerProperties\n{\n\tenum        { NUM_UPGRADES\t= 63, NUM_TECHS\t= 47 };\n\n\tint\t\t\tupgradeLevel[NUM_UPGRADES];\n\tbool\t\thasResearched[NUM_TECHS];\n\n    static      PlayerProperties    props[2];\n\npublic:\n\t\t\t\tPlayerProperties();\n\t\t\t\tPlayerProperties(const BWAPI::Player & player);\n\n\tint\t\t\tGetUpgradeLevel(BWAPI::UpgradeType upgrade) const;\n\tbool\t\tHasUpgrade(BWAPI::UpgradeType upgrade) const;\n\tbool\t\tHasResearched(BWAPI::TechType tech) const;\n\n\tvoid\t\tReset();\n\tvoid\t\tSetUpgradeLevel(BWAPI::UpgradeType upgrade, int level);\n\tvoid\t\tSetResearched(BWAPI::TechType tech, bool researched);\n\tvoid\t\tCapture(const BWAPI::Player & player);\n\n    static      PlayerProperties & Get(const size_t & playerID);\n};\n\nclass PlayerWeapon\n{\n\tconst PlayerProperties *\t\tplayer;\n\tBWAPI::WeaponType\ttype;\n\npublic:\n\t\t\tPlayerWeapon(const PlayerProperties * player, BWAPI::WeaponType type);\n\n\tint\t\tGetDamageBase() const;\n\tfloat\tGetDamageMultiplier(BWAPI::UnitSizeType targetSize) const;\n\tint\t\tGetCooldown() const;\n\tint\t\tGetMaxRange() const;\n};\n}\n"
  },
  {
    "path": "SparCraft/source/Player_AlphaBeta.cpp",
    "content": "#include \"Player_AlphaBeta.h\"\n\nusing namespace SparCraft;\n\nPlayer_AlphaBeta::Player_AlphaBeta (const size_t & playerID) \n{\n\t_playerID = playerID;\n}\n\nPlayer_AlphaBeta::Player_AlphaBeta (const size_t & playerID, const AlphaBetaSearchParameters & params, TTPtr table)\n{\n\t_playerID = playerID;\n\t_params = params;\n\tTT = table;\n\n    alphaBeta = new AlphaBetaSearch(_params, TT);\n}\n\nPlayer_AlphaBeta::~Player_AlphaBeta()\n{\n    delete alphaBeta;\n}\n\nAlphaBetaSearchResults & Player_AlphaBeta::results()\n{\n\treturn alphaBeta->getResults();\n}\n\nAlphaBetaSearchParameters & Player_AlphaBeta::getParams()\n{\n\treturn _params;\n}\n\nvoid Player_AlphaBeta::setParameters(AlphaBetaSearchParameters & p)\n{\n\t_params = p;\n}\n\nvoid Player_AlphaBeta::setTranspositionTable(TTPtr table)\n{\n\tTT = table;\n}\n\nvoid Player_AlphaBeta::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n\talphaBeta->doSearch(state);\n    moveVec.assign(alphaBeta->getResults().bestMoves.begin(), alphaBeta->getResults().bestMoves.end());\n}\n"
  },
  {
    "path": "SparCraft/source/Player_AlphaBeta.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n\n#include \"TranspositionTable.h\"\n#include \"AlphaBetaSearch.h\"\n#include \"AlphaBetaSearchParameters.hpp\"\n#include \"AlphaBetaSearchResults.hpp\"\n\nnamespace SparCraft\n{\n   \nclass AlphaBetaSearch;\n/*----------------------------------------------------------------------\n | Alpha Beta Player\n |----------------------------------------------------------------------\n | Runs Alpha Beta search given a set of search parameters\n `----------------------------------------------------------------------*/\nclass Player_AlphaBeta : public Player\n{\n\tAlphaBetaSearch * alphaBeta;\n\tTTPtr TT;\n\tAlphaBetaSearchParameters _params;\npublic:\n\tPlayer_AlphaBeta (const size_t & playerID);\n\tPlayer_AlphaBeta (const size_t & playerID, const AlphaBetaSearchParameters & params, TTPtr table);\n    virtual ~Player_AlphaBeta();\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tvoid setParameters(AlphaBetaSearchParameters & p);\n\tAlphaBetaSearchParameters & getParams();\n\tvoid setTranspositionTable(TTPtr table);\n\tAlphaBetaSearchResults & results();\n\tsize_t getType() { return PlayerModels::AlphaBeta; }\n};\n\n}\n"
  },
  {
    "path": "SparCraft/source/Player_AttackClosest.cpp",
    "content": "#include \"Player_AttackClosest.h\"\n\nusing namespace SparCraft;\n\nPlayer_AttackClosest::Player_AttackClosest(const size_t & playerID)\n{\n    _playerID = playerID;\n}\n\nvoid Player_AttackClosest::getMoves(GameState & state,const MoveArray & moves,std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n    for (size_t u(0); u<moves.numUnits(); ++u)\n    {\n        bool foundAction(false);\n        size_t actionMoveIndex(0);\n        size_t closestMoveIndex(0);\n        unsigned long long actionDistance(std::numeric_limits<unsigned long long>::max());\n        unsigned long long closestMoveDist(std::numeric_limits<unsigned long long>::max());\n\n        const Unit & ourUnit(state.getUnit(_playerID,u));\n        const Unit & closestUnit(ourUnit.canHeal() ? state.getClosestOurUnit(_playerID,u) : state.getClosestEnemyUnit(_playerID,u));\n\n        for (size_t m(0); m<moves.numMoves(u); ++m)\n        {\n            const Action move(moves.getMove(u,m));\n\n            if (move.type() == ActionTypes::ATTACK)\n            {\n                const Unit & target(state.getUnit(state.getEnemy(move.player()),move.index()));\n                size_t dist(ourUnit.getDistanceSqToUnit(target,state.getTime()));\n\n                if (dist < actionDistance)\n                {\n                    actionDistance = dist;\n                    actionMoveIndex = m;\n                    foundAction = true;\n                }\n            }\n            if (move.type() == ActionTypes::HEAL)\n            {\n                const Unit & target(state.getUnit(move.player(),move.index()));\n                size_t dist(ourUnit.getDistanceSqToUnit(target,state.getTime()));\n\n                if (dist < actionDistance)\n                {\n                    actionDistance = dist;\n                    actionMoveIndex = m;\n                    foundAction = true;\n                }\n            }\n            else if (move.type() == ActionTypes::RELOAD)\n            {\n                if (ourUnit.canAttackTarget(closestUnit,state.getTime()))\n                {\n                    closestMoveIndex = m;\n                    break;\n                }\n            }\n            else if (move.type() == ActionTypes::MOVE)\n            {\n                Position ourDest(ourUnit.x() + Constants::Move_Dir[move.index()][0],\n                    ourUnit.y() + Constants::Move_Dir[move.index()][1]);\n                size_t dist(closestUnit.getDistanceSqToPosition(ourDest,state.getTime()));\n\n                if (dist < closestMoveDist)\n                {\n                    closestMoveDist = dist;\n                    closestMoveIndex = m;\n                }\n            }\n        }\n\n        size_t bestMoveIndex(foundAction ? actionMoveIndex : closestMoveIndex);\n\n        moveVec.push_back(moves.getMove(u,bestMoveIndex));\n    }\n}\n"
  },
  {
    "path": "SparCraft/source/Player_AttackClosest.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n\nnamespace SparCraft\n{\n    class Player_AttackClosest;\n}\n\n/*----------------------------------------------------------------------\n | Attack Closest Player\n |----------------------------------------------------------------------\n | Chooses an action with following priority:\n | 1) If it can attack, ATTACK closest enemy unit\n | 2) If it cannot attack:\n |    a) If it is in range to attack an enemy, WAIT until can shoot again\n |    b) If it is not in range of enemy, MOVE towards closest\n `----------------------------------------------------------------------*/\nclass SparCraft::Player_AttackClosest : public SparCraft::Player\n{\npublic:\n\tPlayer_AttackClosest (const size_t & playerID);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tsize_t getType() { return PlayerModels::AttackClosest; }\n};"
  },
  {
    "path": "SparCraft/source/Player_AttackDPS.cpp",
    "content": "#include \"Player_AttackDPS.h\"\n\nusing namespace SparCraft;\n\nPlayer_AttackDPS::Player_AttackDPS (const size_t & playerID) \n{\n\t_playerID = playerID;\n}\n\nvoid Player_AttackDPS::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n\tfor (size_t u(0); u<moves.numUnits(); ++u)\n\t{\n\t\tbool foundAction\t\t\t\t\t\t(false);\n\t\tsize_t actionMoveIndex\t\t\t\t\t(0);\n\t\tsize_t closestMoveIndex\t\t\t\t\t(0);\n\t\tdouble actionHighestDPS\t\t\t\t\t(0);\n\t\tunsigned long long closestMoveDist\t\t(std::numeric_limits<unsigned long long>::max());\n\t\t\n\t\tconst Unit & ourUnit\t\t\t\t\t(state.getUnit(_playerID, u));\n\t\tconst Unit & closestUnit\t\t\t\t(ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u));\n\n\t\tfor (size_t m(0); m<moves.numMoves(u); ++m)\n\t\t{\n\t\t\tconst Action move\t\t\t\t\t\t(moves.getMove(u, m));\n\t\t\t\t\n\t\t\tif (move.type() == ActionTypes::ATTACK)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(state.getEnemy(move.player()), move.index()));\n\t\t\t\tdouble dpsHPValue =\t\t\t\t(target.dpf() / target.currentHP());\n\n\t\t\t\tif (dpsHPValue > actionHighestDPS)\n\t\t\t\t{\n\t\t\t\t\tactionHighestDPS = dpsHPValue;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (move.type() == ActionTypes::HEAL)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(move.player(), move.index()));\n\t\t\t\tdouble dpsHPValue =\t\t\t\t(target.dpf() / target.currentHP());\n\n\t\t\t\tif (dpsHPValue > actionHighestDPS)\n\t\t\t\t{\n\t\t\t\t\tactionHighestDPS = dpsHPValue;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::RELOAD)\n\t\t\t{\n\t\t\t\tif (ourUnit.canAttackTarget(closestUnit, state.getTime()))\n\t\t\t\t{\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::MOVE)\n\t\t\t{\n\t\t\t\tPosition ourDest\t\t\t\t(ourUnit.x() + Constants::Move_Dir[move.index()][0], \n\t\t\t\t\t\t\t\t\t\t\t\t ourUnit.y() + Constants::Move_Dir[move.index()][1]);\n\t\t\t\tsize_t dist\t\t\t\t\t\t(closestUnit.getDistanceSqToPosition(ourDest, state.getTime()));\n\n\t\t\t\tif (dist < closestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tclosestMoveDist = dist;\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsize_t bestMoveIndex(foundAction ? actionMoveIndex : closestMoveIndex);\n\t\t\t\n\t\tmoveVec.push_back(moves.getMove(u, bestMoveIndex));\n\t}\n}\n"
  },
  {
    "path": "SparCraft/source/Player_AttackDPS.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n\nnamespace SparCraft\n{\n/*----------------------------------------------------------------------\n | Attack HighestDPS Player\n |----------------------------------------------------------------------\n | Chooses an action with following priority:\n | 1) If it can attack, ATTACK highest DPS/HP enemy unit in range\n | 2) If it cannot attack:\n |    a) If it is in range to attack an enemy, WAIT until attack\n |    b) If it is not in range of enemy, MOVE towards closest\n `----------------------------------------------------------------------*/\nclass Player_AttackDPS : public Player\n{\npublic:\n\tPlayer_AttackDPS (const size_t & playerID);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tsize_t getType() { return PlayerModels::AttackDPS; }\n};\n}"
  },
  {
    "path": "SparCraft/source/Player_AttackWeakest.cpp",
    "content": "#include \"Player_AttackWeakest.h\"\n\nusing namespace SparCraft;\n\nPlayer_AttackWeakest::Player_AttackWeakest (const size_t & playerID) \n{\n\t_playerID = playerID;\n}\n\nvoid Player_AttackWeakest::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n\tfor (size_t u(0); u<moves.numUnits(); ++u)\n\t{\n\t\tbool foundAction\t\t\t\t\t\t(false);\n\t\tsize_t actionMoveIndex\t\t\t\t\t(0);\n\t\tsize_t closestMoveIndex\t\t\t\t\t(0);\n\t\tsize_t actionLowestHP\t\t\t\t\t(1000000);\n\t\tunsigned long long closestMoveDist\t\t(std::numeric_limits<unsigned long long>::max());\n\t\t\n\t\tconst Unit & ourUnit\t\t\t\t(state.getUnit(_playerID, u));\n\t\tconst Unit & closestUnit\t\t\t(ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u));\n\n\t\tfor (size_t m(0); m<moves.numMoves(u); ++m)\n\t\t{\n\t\t\tconst Action move\t\t\t\t\t\t(moves.getMove(u, m));\n\t\t\t\t\n\t\t\tif (move.type() == ActionTypes::ATTACK)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(state.getEnemy(move.player()), move.index()));\n\n\t\t\t\tif ((size_t)target.currentHP() < actionLowestHP)\n\t\t\t\t{\n\t\t\t\t\tactionLowestHP = target.currentHP();\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::HEAL)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(move.player(), move.index()));\n\n\t\t\t\tif ((size_t)target.currentHP() < actionLowestHP)\n\t\t\t\t{\n\t\t\t\t\tactionLowestHP = target.currentHP();\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::RELOAD)\n\t\t\t{\n\t\t\t\tif (ourUnit.canAttackTarget(closestUnit, state.getTime()))\n\t\t\t\t{\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::MOVE)\n\t\t\t{\n\t\t\t\tPosition ourDest\t\t\t\t(ourUnit.x() + Constants::Move_Dir[move.index()][0], \n\t\t\t\t\t\t\t\t\t\t\t\t ourUnit.y() + Constants::Move_Dir[move.index()][1]);\n\t\t\t\tsize_t dist\t\t\t\t\t\t(closestUnit.getDistanceSqToPosition(ourDest, state.getTime()));\n\n\t\t\t\tif (dist < closestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tclosestMoveDist = dist;\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsize_t bestMoveIndex(foundAction ? actionMoveIndex : closestMoveIndex);\n\t\t\t\n\t\tmoveVec.push_back(moves.getMove(u, bestMoveIndex));\n\t}\n}\n"
  },
  {
    "path": "SparCraft/source/Player_AttackWeakest.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n\nnamespace SparCraft\n{\n\n/*----------------------------------------------------------------------\n | Attack Weakest Player\n |----------------------------------------------------------------------\n | Chooses an action with following priority:\n | 1) If it can attack, ATTACK least hp enemy unit\n | 2) If it cannot attack:\n |    a) If it is in range to attack an enemy, WAIT\n |    b) If it is not in range of enemy, MOVE towards closest\n `----------------------------------------------------------------------*/\nclass Player_AttackWeakest : public Player\n{\npublic:\n\tPlayer_AttackWeakest (const size_t & playerID);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tsize_t getType() { return PlayerModels::AttackWeakest; }\n};\n}"
  },
  {
    "path": "SparCraft/source/Player_Cluster.cpp",
    "content": "#include \"Player_Cluster.h\"\n\nusing namespace SparCraft;\n\nPlayer_Cluster::Player_Cluster (const size_t & playerID) \n{\n\t_playerID = playerID;\n}\n\nvoid Player_Cluster::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n\tsize_t enemy(state.getEnemy(_playerID));\n\n    // compute the centroid of our unit cluster\n    Position avgPos(0,0);\n    for (size_t u(0); u<state.numUnits(_playerID); ++u)\n    {\n        avgPos.addPosition(state.getUnit(_playerID, u).pos());\n    }\n\n    avgPos.scalePosition(1.0f / state.numUnits(_playerID));\n\n\tfor (size_t u(0); u<moves.numUnits(); ++u)\n\t{\n\t\tbool foundMoveAction\t\t\t\t\t(false);\n\t\tdouble actionHighestDPS\t\t\t\t\t(0);\n\t\tsize_t closestMoveIndex\t\t\t\t\t(0);\n\t\tunsigned long long closestMoveDist\t\t(std::numeric_limits<unsigned long long>::max());\n\t\t\n\t\tconst Unit & ourUnit\t\t\t\t(state.getUnit(_playerID, u));\n\t\t\n\t\tfor (size_t m(0); m<moves.numMoves(u); ++m)\n\t\t{\n\t\t\tconst Action move\t\t\t\t\t\t(moves.getMove(u, m));\n\t\t\t\t\n\t\t\tif (move.type() == ActionTypes::MOVE)\n\t\t\t{\n\t\t\t\tPosition ourDest\t\t\t\t(ourUnit.x() + Constants::Move_Dir[move.index()][0], \n\t\t\t\t\t\t\t\t\t\t\t\t ourUnit.y() + Constants::Move_Dir[move.index()][1]);\n                size_t dist\t\t\t\t\t\t(avgPos.getDistanceSq(ourDest));\n\n\t\t\t\tif (dist < closestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tclosestMoveDist = dist;\n\t\t\t\t\tclosestMoveIndex = m;\n                    foundMoveAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsize_t bestMoveIndex(foundMoveAction ? closestMoveIndex : 0);\n        \t\t\t\n\t\tmoveVec.push_back(moves.getMove(u, bestMoveIndex));\n\t}\n}\n"
  },
  {
    "path": "SparCraft/source/Player_Cluster.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n\nnamespace SparCraft\n{\n/*----------------------------------------------------------------------\n | Attack HighestDPS Player No Overkill\n |----------------------------------------------------------------------\n | Chooses an action with following priority:\n | 1) If it can attack, ATTACK highest DPS/HP enemy unit to overkill\n | 2) If it cannot attack:\n |    a) If it is in range to attack an enemy, WAIT until attack\n |    b) If it is not in range of enemy, MOVE towards closest\n `----------------------------------------------------------------------*/\nclass Player_Cluster : public Player\n{\npublic:\n\tPlayer_Cluster (const size_t & playerID);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tsize_t getType() { return PlayerModels::Cluster; }\n};\n}"
  },
  {
    "path": "SparCraft/source/Player_Kiter.cpp",
    "content": "#include \"Player_Kiter.h\"\n\nusing namespace SparCraft;\n\nPlayer_Kiter::Player_Kiter (const size_t & playerID) \n{\n\t_playerID = playerID;\n}\n\nvoid Player_Kiter::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n\tfor (size_t u(0); u<moves.numUnits(); ++u)\n\t{\n\t\tbool foundAction\t\t\t\t\t\t(false);\n\t\tsize_t actionMoveIndex\t\t\t\t\t(0);\n\t\tsize_t furthestMoveIndex\t\t\t\t(0);\n\t\tsize_t furthestMoveDist\t\t\t\t\t(0);\n\t\tsize_t closestMoveIndex\t\t\t\t\t(0);\n\t\tint actionDistance\t\t\t\t\t\t(std::numeric_limits<int>::max());\n\t\tunsigned long long closestMoveDist\t\t(std::numeric_limits<unsigned long long>::max());\n\n\t\tconst Unit & ourUnit\t\t\t\t\t(state.getUnit(_playerID, u));\n\t\tconst Unit & closestUnit\t\t\t\t(ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u));\n\n\t\tfor (size_t m(0); m<moves.numMoves(u); ++m)\n\t\t{\n\t\t\tconst Action move\t\t\t\t\t\t(moves.getMove(u, m));\n\t\t\t\t\n\t\t\tif (move.type() == ActionTypes::ATTACK)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(state.getEnemy(move.player()), move.index()));\n\t\t\t\tPositionType dist\t\t\t\t(ourUnit.getDistanceSqToUnit(target, state.getTime()));\n\n\t\t\t\tif (dist < actionDistance)\n\t\t\t\t{\n\t\t\t\t\tactionDistance = dist;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::HEAL)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(move.player(), move.index()));\n\t\t\t\tPositionType dist\t\t\t\t(ourUnit.getDistanceSqToUnit(target, state.getTime()));\n\n\t\t\t\tif (dist < actionDistance)\n\t\t\t\t{\n\t\t\t\t\tactionDistance = dist;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::MOVE)\n\t\t\t{\n\t\t\t\tPosition ourDest\t\t\t\t(ourUnit.x() + Constants::Move_Dir[move.index()][0], \n\t\t\t\t\t\t\t\t\t\t\t\t ourUnit.y() + Constants::Move_Dir[move.index()][1]);\n\t\t\t\tsize_t dist\t\t\t\t\t\t(closestUnit.getDistanceSqToPosition(ourDest, state.getTime()));\n\n\t\t\t\tif (dist > furthestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tfurthestMoveDist = dist;\n\t\t\t\t\tfurthestMoveIndex = m;\n\t\t\t\t}\n\n\t\t\t\tif (dist < closestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tclosestMoveDist = dist;\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// the move we will be returning\n\t\tsize_t bestMoveIndex(0);\n\n\t\t// if we have an attack move we will use that one\n\t\tif (foundAction)\n\t\t{\n\t\t\tbestMoveIndex = actionMoveIndex;\n\t\t}\n\t\t// otherwise use the closest move to the opponent\n\t\telse\n\t\t{\n\t\t\t// if we are in attack range of the unit, back up\n\t\t\tif (ourUnit.canAttackTarget(closestUnit, state.getTime()))\n\t\t\t{\n\t\t\t\tbestMoveIndex = furthestMoveIndex;\n\t\t\t}\n\t\t\t// otherwise get back into the fight\n\t\t\telse\n\t\t\t{\n\t\t\t\tbestMoveIndex = closestMoveIndex;\n\t\t\t}\n\t\t}\n\t\t\t\n\t\tmoveVec.push_back(moves.getMove(u, bestMoveIndex));\n\t}\n}\n"
  },
  {
    "path": "SparCraft/source/Player_Kiter.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n\nnamespace SparCraft\n{\n/*----------------------------------------------------------------------\n | Kiter Player\n |----------------------------------------------------------------------\n | Chooses an action with following priority:\n | 1) If it can attack, ATTACK closest enemy unit\n | 2) If it cannot attack:\n |    a) If it is in range to attack an enemy, move away from closest\n |    b) If it is not in range of enemy, MOVE towards closest\n `----------------------------------------------------------------------*/\nclass Player_Kiter : public Player\n{\npublic:\n\tPlayer_Kiter (const size_t & playerID);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tsize_t getType() { return PlayerModels::Kiter; }\n};\n}"
  },
  {
    "path": "SparCraft/source/Player_KiterDPS.cpp",
    "content": "#include \"Player_KiterDPS.h\"\n\nusing namespace SparCraft;\n\nPlayer_KiterDPS::Player_KiterDPS (const size_t & playerID) \n{\n\t_playerID = playerID;\n}\n\nvoid Player_KiterDPS::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n\tfor (size_t u(0); u<moves.numUnits(); ++u)\n\t{\n\t\tbool foundAction\t\t\t\t\t(false);\n\t\tsize_t actionMoveIndex\t\t\t\t\t(0);\n\t\tsize_t furthestMoveIndex\t\t\t\t(0);\n\t\tsize_t furthestMoveDist\t\t\t\t\t(0);\n\t\tsize_t closestMoveIndex\t\t\t\t\t(0);\n\t\tdouble actionHighestDPS\t\t\t\t\t(0);\n\t\tunsigned long long closestMoveDist\t\t(std::numeric_limits<unsigned long long>::max());\n\n\t\tconst Unit & ourUnit\t\t\t\t\t(state.getUnit(_playerID, u));\n\t\tconst Unit & closestUnit\t\t\t\t(ourUnit.canHeal() ? \n                                                state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u));\n\n\t\tfor (size_t m(0); m<moves.numMoves(u); ++m)\n\t\t{\n\t\t\tconst Action move\t\t\t\t\t\t(moves.getMove(u, m));\n\t\t\t\t\n\t\t\tif (move.type() == ActionTypes::ATTACK)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(state.getEnemy(move.player()), move.index()));\n\t\t\t\tdouble dpsHPValue \t\t\t\t(target.dpf() / target.currentHP());\n\n\t\t\t\tif (dpsHPValue > actionHighestDPS)\n\t\t\t\t{\n\t\t\t\t\tactionHighestDPS = dpsHPValue;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::HEAL)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(move.player(), move.index()));\n\t\t\t\tdouble dpsHPValue \t\t\t\t(target.dpf() / target.currentHP());\n\n\t\t\t\tif (dpsHPValue > actionHighestDPS)\n\t\t\t\t{\n\t\t\t\t\tactionHighestDPS = dpsHPValue;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::MOVE)\n\t\t\t{\n\t\t\t\tPosition ourDest\t\t\t\t(ourUnit.x() + Constants::Move_Dir[move.index()][0], \n\t\t\t\t\t\t\t\t\t\t\t\t ourUnit.y() + Constants::Move_Dir[move.index()][1]);\n\t\t\t\tsize_t dist\t\t\t\t\t\t(closestUnit.getDistanceSqToPosition(ourDest, state.getTime()));\n\n\t\t\t\tif (dist > furthestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tfurthestMoveDist = dist;\n\t\t\t\t\tfurthestMoveIndex = m;\n\t\t\t\t}\n\n\t\t\t\tif (dist < closestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tclosestMoveDist = dist;\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// the move we will be returning\n\t\tsize_t bestMoveIndex(0);\n\n\t\t// if we have an attack move we will use that one\n\t\tif (foundAction)\n\t\t{\n\t\t\tbestMoveIndex = actionMoveIndex;\n\t\t}\n\t\t// otherwise use the closest move to the opponent\n\t\telse\n\t\t{\n\t\t\t// if we are in attack range of the unit, back up\n\t\t\tif (ourUnit.canAttackTarget(closestUnit, state.getTime()))\n\t\t\t{\n\t\t\t\tbestMoveIndex = furthestMoveIndex;\n\t\t\t}\n\t\t\t// otherwise get back into the fight\n\t\t\telse\n\t\t\t{\n\t\t\t\tbestMoveIndex = closestMoveIndex;\n\t\t\t}\n\t\t}\n\t\t\n\t\tmoveVec.push_back(moves.getMove(u, bestMoveIndex));\n\t}\n}\n"
  },
  {
    "path": "SparCraft/source/Player_KiterDPS.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n\nnamespace SparCraft\n{\n/*----------------------------------------------------------------------\n | Kiter DPS Player\n |----------------------------------------------------------------------\n | Chooses an action with following priority:\n | 1) If it can attack, ATTACK highest DPS/HP enemy unit in range\n | 2) If it cannot attack:\n |    a) If it is in range to attack an enemy, move away from closest one\n |    b) If it is not in range of enemy, MOVE towards closest one\n `----------------------------------------------------------------------*/\nclass Player_KiterDPS : public Player\n{\npublic:\n\tPlayer_KiterDPS (const size_t & playerID);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tsize_t getType() { return PlayerModels::KiterDPS; }\n};\n}"
  },
  {
    "path": "SparCraft/source/Player_Kiter_NOKDPS.cpp",
    "content": "#include \"Player_Kiter_NOKDPS.h\"\n\nusing namespace SparCraft;\n\nPlayer_Kiter_NOKDPS::Player_Kiter_NOKDPS (const size_t & playerID) \n{\n\t_playerID = playerID;\n}\n\nvoid Player_Kiter_NOKDPS::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n\tsize_t enemy(state.getEnemy(_playerID));\n\n\tArray<int, Constants::Max_Units> hpRemaining;\n\n\tfor (size_t u(0); u<state.numUnits(enemy); ++u)\n\t{\n\t\thpRemaining[u] = state.getUnit(enemy,u).currentHP();\n\t}\n\n\tfor (size_t u(0); u<moves.numUnits(); ++u)\n\t{\n\t\tbool foundAction\t\t\t\t\t(false);\n\t\tsize_t actionMoveIndex\t\t\t\t\t(0);\n        size_t furthestMoveIndex\t\t\t\t(0);\n\t\tsize_t furthestMoveDist\t\t\t\t\t(0);\n\t\tdouble actionHighestDPS\t\t\t\t\t(0);\n\t\tsize_t closestMoveIndex\t\t\t\t\t(0);\n\t\tunsigned long long closestMoveDist\t\t(std::numeric_limits<unsigned long long>::max());\n\t\t\n\t\tconst Unit & ourUnit\t\t\t\t(state.getUnit(_playerID, u));\n\t\tconst Unit & closestUnit\t\t\t(ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u));\n\n\t\tfor (size_t m(0); m<moves.numMoves(u); ++m)\n\t\t{\n\t\t\tconst Action move\t\t\t\t\t\t(moves.getMove(u, m));\n\t\t\t\t\n\t\t\tif ((move.type() == ActionTypes::ATTACK) && (hpRemaining[move.index()] > 0))\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(state.getEnemy(move.player()), move.index()));\n\t\t\t\tdouble dpsHPValue =\t\t\t\t(target.dpf() / hpRemaining[move.index()]);\n\n\t\t\t\tif (dpsHPValue > actionHighestDPS)\n\t\t\t\t{\n\t\t\t\t\tactionHighestDPS = dpsHPValue;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\n                if (move.index() >= state.numUnits(enemy))\n                {\n                    int e = enemy;\n                    int pl = _playerID;\n                    printf(\"wtf\\n\");\n                }\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::HEAL)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(move.player(), move.index()));\n\t\t\t\tdouble dpsHPValue =\t\t\t\t(target.dpf() / hpRemaining[move.index()]);\n\n\t\t\t\tif (dpsHPValue > actionHighestDPS)\n\t\t\t\t{\n\t\t\t\t\tactionHighestDPS = dpsHPValue;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::RELOAD)\n\t\t\t{\n\t\t\t\tif (ourUnit.canAttackTarget(closestUnit, state.getTime()))\n\t\t\t\t{\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::MOVE)\n\t\t\t{\n\t\t\t\tPosition ourDest\t\t\t\t(ourUnit.x() + Constants::Move_Dir[move.index()][0], \n\t\t\t\t\t\t\t\t\t\t\t\t ourUnit.y() + Constants::Move_Dir[move.index()][1]);\n\t\t\t\tsize_t dist\t\t\t\t\t\t(closestUnit.getDistanceSqToPosition(ourDest, state.getTime()));\n\n                if (dist > furthestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tfurthestMoveDist = dist;\n\t\t\t\t\tfurthestMoveIndex = m;\n\t\t\t\t}\n\n\t\t\t\tif (dist < closestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tclosestMoveDist = dist;\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsize_t bestMoveIndex(0);\n        // if we have an attack move we will use that one\n\t\tif (foundAction)\n\t\t{\n\t\t\tbestMoveIndex = actionMoveIndex;\n\t\t}\n\t\t// otherwise use the closest move to the opponent\n\t\telse\n\t\t{\n\t\t\t// if we are in attack range of the unit, back up\n\t\t\tif (ourUnit.canAttackTarget(closestUnit, state.getTime()))\n\t\t\t{\n\t\t\t\tbestMoveIndex = furthestMoveIndex;\n\t\t\t}\n\t\t\t// otherwise get back into the fight\n\t\t\telse\n\t\t\t{\n\t\t\t\tbestMoveIndex = closestMoveIndex;\n\t\t\t}\n\t\t}\n\n\t\tAction theMove(moves.getMove(u, actionMoveIndex));\n\t\tif (theMove.type() == ActionTypes::ATTACK)\n\t\t{\n\t\t\thpRemaining[theMove.index()] -= state.getUnit(_playerID, theMove.unit()).damage();\n\t\t}\n\t\t\t\n\t\tmoveVec.push_back(moves.getMove(u, bestMoveIndex));\n\t}\n}\n"
  },
  {
    "path": "SparCraft/source/Player_Kiter_NOKDPS.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n\nnamespace SparCraft\n{\n/*----------------------------------------------------------------------\n | Attack HighestDPS Player No Overkill\n |----------------------------------------------------------------------\n | Chooses an action with following priority:\n | 1) If it can attack, ATTACK highest DPS/HP enemy unit to overkill\n | 2) If it cannot attack:\n |    a) If it is in range to attack an enemy, WAIT until attack\n |    b) If it is not in range of enemy, MOVE towards closest\n `----------------------------------------------------------------------*/\nclass Player_Kiter_NOKDPS : public Player\n{\npublic:\n\tPlayer_Kiter_NOKDPS (const size_t & playerID);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tsize_t getType() { return PlayerModels::Kiter_NOKDPS; }\n};\n}"
  },
  {
    "path": "SparCraft/source/Player_NOKDPS.cpp",
    "content": "#include \"Player_NOKDPS.h\"\n\nusing namespace SparCraft;\n\nPlayer_NOKDPS::Player_NOKDPS (const size_t & playerID) \n{\n\t_playerID = playerID;\n}\n\nvoid Player_NOKDPS::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n\tsize_t enemy(state.getEnemy(_playerID));\n\n\tArray<int, Constants::Max_Units> hpRemaining;\n\n\tfor (size_t u(0); u<state.numUnits(enemy); ++u)\n\t{\n\t\thpRemaining[u] = state.getUnit(enemy,u).currentHP();\n\t}\n\n\tfor (size_t u(0); u<moves.numUnits(); ++u)\n\t{\n\t\tbool foundAction\t\t\t\t\t\t(false);\n\t\tsize_t actionMoveIndex\t\t\t\t\t(0);\n\t\tdouble actionHighestDPS\t\t\t\t\t(0);\n\t\tsize_t closestMoveIndex\t\t\t\t\t(0);\n\t\tunsigned long long closestMoveDist\t\t(std::numeric_limits<unsigned long long>::max());\n\t\t\n\t\tconst Unit & ourUnit\t\t\t\t(state.getUnit(_playerID, u));\n\t\tconst Unit & closestUnit(ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : ourUnit.type().isDetector() ? state.getClosestEnemyUnit(_playerID, u, false):state.getClosestEnemyUnit(_playerID, u, true));\n\t\t\n\t\tfor (size_t m(0); m<moves.numMoves(u); ++m)\n\t\t{\n\t\t\tconst Action move\t\t\t\t\t\t(moves.getMove(u, m));\n\t\t\t\t\n\t\t\tif ((move.type() == ActionTypes::ATTACK) && (hpRemaining[move.index()] > 0))\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(state.getEnemy(move.player()), move.index()));\n\t\t\t\tdouble dpsHPValue =\t\t\t\t(target.dpf() / hpRemaining[move.index()]);\n\n\t\t\t\tif (dpsHPValue > actionHighestDPS)\n\t\t\t\t{\n\t\t\t\t\tactionHighestDPS = dpsHPValue;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\n                if (move.index() >= state.numUnits(enemy))\n                {\n                    int e = enemy;\n                    int pl = _playerID;\n                    printf(\"wtf\\n\");\n                }\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::HEAL)\n\t\t\t{\n\t\t\t\tconst Unit & target\t\t\t\t(state.getUnit(move.player(), move.index()));\n\t\t\t\tdouble dpsHPValue =\t\t\t\t(target.dpf() / hpRemaining[move.index()]);\n\n\t\t\t\tif (dpsHPValue > actionHighestDPS)\n\t\t\t\t{\n\t\t\t\t\tactionHighestDPS = dpsHPValue;\n\t\t\t\t\tactionMoveIndex = m;\n\t\t\t\t\tfoundAction = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::RELOAD)\n\t\t\t{\n\t\t\t\tif (ourUnit.canAttackTarget(closestUnit, state.getTime()))\n\t\t\t\t{\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (move.type() == ActionTypes::MOVE)\n\t\t\t{\n\t\t\t\tPosition ourDest\t\t\t\t(ourUnit.x() + Constants::Move_Dir[move.index()][0], \n\t\t\t\t\t\t\t\t\t\t\t\t ourUnit.y() + Constants::Move_Dir[move.index()][1]);\n\t\t\t\tsize_t dist\t\t\t\t\t\t(closestUnit.getDistanceSqToPosition(ourDest, state.getTime()));\n\n\t\t\t\tif (dist < closestMoveDist)\n\t\t\t\t{\n\t\t\t\t\tclosestMoveDist = dist;\n\t\t\t\t\tclosestMoveIndex = m;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsize_t bestMoveIndex(foundAction ? actionMoveIndex : closestMoveIndex);\n\n\t\tAction theMove(moves.getMove(u, actionMoveIndex));\n\t\tif (theMove.type() == ActionTypes::ATTACK)\n\t\t{\n\t\t\thpRemaining[theMove.index()] -= state.getUnit(_playerID, theMove.unit()).damage();\n\t\t}\n\t\t\t\n\t\tmoveVec.push_back(moves.getMove(u, bestMoveIndex));\n\t}\n}\n"
  },
  {
    "path": "SparCraft/source/Player_NOKDPS.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n\nnamespace SparCraft\n{\n/*----------------------------------------------------------------------\n | Attack HighestDPS Player No Overkill\n |----------------------------------------------------------------------\n | Chooses an action with following priority:\n | 1) If it can attack, ATTACK highest DPS/HP enemy unit to overkill\n | 2) If it cannot attack:\n |    a) If it is in range to attack an enemy, WAIT until attack\n |    b) If it is not in range of enemy, MOVE towards closest\n `----------------------------------------------------------------------*/\nclass Player_NOKDPS : public Player\n{\npublic:\n\tPlayer_NOKDPS (const size_t & playerID);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tsize_t getType() { return PlayerModels::NOKDPS; }\n};\n}"
  },
  {
    "path": "SparCraft/source/Player_PortfolioGreedySearch.cpp",
    "content": "#include \"Player_PortfolioGreedySearch.h\"\n\nusing namespace SparCraft;\n\nPlayer_PortfolioGreedySearch::Player_PortfolioGreedySearch (const size_t & playerID) \n{\n\t_playerID = playerID;\n\t_iterations = 1;\n    _responses = 0;\n\t_seed = PlayerModels::NOKDPS;\n}\n\nPlayer_PortfolioGreedySearch::Player_PortfolioGreedySearch (const size_t & playerID, const size_t & seed, const size_t & iter, const size_t & responses, const size_t & timeLimit)\n{\n\t_playerID = playerID;\n\t_iterations = iter;\n    _responses = responses;\n\t_seed = seed;\n    _timeLimit = timeLimit;\n}\n\nvoid Player_PortfolioGreedySearch::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n\tPortfolioGreedySearch pgs(_playerID, _seed, _iterations, _responses, _timeLimit);\n\n\tmoveVec = pgs.search(_playerID, state);\n}\n"
  },
  {
    "path": "SparCraft/source/Player_PortfolioGreedySearch.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n#include \"PortfolioGreedySearch.h\"\n\nnamespace SparCraft\n{\nclass Player_PortfolioGreedySearch : public Player\n{\n\tsize_t _seed;\n\tsize_t _iterations;\n    size_t _responses;\n    size_t _timeLimit;\npublic:\n\tPlayer_PortfolioGreedySearch (const size_t & playerID);\n    Player_PortfolioGreedySearch (const size_t & playerID, const size_t & seed, const size_t & iter, const size_t & responses, const size_t & timeLimit);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n    size_t getType() { return PlayerModels::PortfolioGreedySearch; }\n};\n}"
  },
  {
    "path": "SparCraft/source/Player_Random.cpp",
    "content": "#include \"Player_Random.h\"\n\nusing namespace SparCraft;\n\nPlayer_Random::Player_Random (const size_t & playerID)\n\t: rand(0, std::numeric_limits<int>::max(), Constants::Seed_Player_Random_Time ? static_cast<unsigned int>(std::time(0)) : 0)\n{\n\t_playerID = playerID;\n}\n\nvoid Player_Random::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n\tfor (size_t u(0); u<moves.numUnits(); u++)\n\t{\n\t\tmoveVec.push_back(moves.getMove(u, rand.nextInt() % moves.numMoves(u)));\n\t}\n}\n"
  },
  {
    "path": "SparCraft/source/Player_Random.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n#include \"Random.hpp\"\n\n\nnamespace SparCraft\n{\n/*----------------------------------------------------------------------\n | Random Player\n |----------------------------------------------------------------------\n | Chooses a random legal move per unit and implements it\n `----------------------------------------------------------------------*/\nclass Player_Random : public Player\n{\n\tRandomInt rand;\npublic:\n\tPlayer_Random (const size_t & playerID);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n\tsize_t getType() { return PlayerModels::Random; }\n};\n}"
  },
  {
    "path": "SparCraft/source/Player_UCT.cpp",
    "content": "#include \"Player_UCT.h\"\n\nusing namespace SparCraft;\n\nPlayer_UCT::Player_UCT (const size_t & playerID, const UCTSearchParameters & params) \n{\n\t_playerID = playerID;\n    _params = params;\n}\n\nvoid Player_UCT::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec)\n{\n    moveVec.clear();\n    \n    UCTSearch uct(_params);\n\n    uct.doSearch(state, moveVec);\n    _prevResults = uct.getResults();\n}\n\nUCTSearchParameters & Player_UCT::getParams()\n{\n    return _params;\n}\n\nUCTSearchResults & Player_UCT::getResults()\n{\n    return _prevResults;\n}"
  },
  {
    "path": "SparCraft/source/Player_UCT.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Player.h\"\n#include \"AllPlayers.h\"\n#include \"UCTSearch.h\"\n#include \"UCTMemoryPool.hpp\"\n\nnamespace SparCraft\n{\nclass Player_UCT : public Player\n{\n    UCTSearchParameters     _params;\n    UCTSearchResults        _prevResults;\npublic:\n    Player_UCT (const size_t & playerID, const UCTSearchParameters & params);\n\tvoid getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec);\n    size_t getType() { return PlayerModels::UCT; }\n    UCTSearchParameters & getParams();\n    UCTSearchResults & getResults();\n};\n}"
  },
  {
    "path": "SparCraft/source/PortfolioGreedySearch.cpp",
    "content": "#include \"PortfolioGreedySearch.h\"\n\nusing namespace SparCraft;\n\nPortfolioGreedySearch::PortfolioGreedySearch(const size_t & player, const size_t & enemyScript, const size_t & iter, const size_t & responses, const size_t & timeLimit)\n\t: _player(player)\n\t, _enemyScript(enemyScript)\n\t, _iterations(iter)\n    , _responses(responses)\n    , _totalEvals(0)\n    , _timeLimit(timeLimit)\n{\n\t_playerScriptPortfolio.push_back(PlayerModels::NOKDPS);\n\t_playerScriptPortfolio.push_back(PlayerModels::KiterDPS);\n}\n\nstd::vector<Action> PortfolioGreedySearch::search(const size_t & player, const GameState & state)\n{\n    Timer t;\n    t.start();\n\n    const size_t enemyPlayer(state.getEnemy(player));\n\n    // calculate the seed scripts for each player\n    // they will be used to seed the initial root search\n    size_t seedScript = calculateInitialSeed(player, state);\n    size_t enemySeedScript = calculateInitialSeed(enemyPlayer, state);\n\n    // set up the root script data\n    UnitScriptData originalScriptData;\n    setAllScripts(player, state, originalScriptData, seedScript);\n    setAllScripts(enemyPlayer, state, originalScriptData, enemySeedScript);\n\n    double ms = t.getElapsedTimeInMilliSec();\n    //printf(\"\\nFirst Part %lf ms\\n\", ms);\n\n    // do the initial root portfolio search for our player\n    UnitScriptData currentScriptData(originalScriptData);\n    doPortfolioSearch(player, state, currentScriptData);\n\n    // iterate as many times as required\n    for (size_t i(0); i<_responses; ++i)\n    {\n        // do the portfolio search to improve the enemy's scripts\n        doPortfolioSearch(enemyPlayer, state, currentScriptData);\n\n        // then do portfolio search again for us to improve vs. enemy's update\n        doPortfolioSearch(player, state, currentScriptData);\n    }\n\n    // convert the script vector into a move vector and return it\n\tMoveArray moves;\n\tstate.generateMoves(moves, player);\n    std::vector<Action> moveVec;\n    GameState copy(state);\n    currentScriptData.calculateMoves(player, moves, copy, moveVec);\n\n    _totalEvals = 0;\n\n    return moveVec;\n}\n\nvoid PortfolioGreedySearch::doPortfolioSearch(const size_t & player, const GameState & state, UnitScriptData & currentScriptData)\n{\n    Timer t;\n    t.start();\n\n    // the enemy of this player\n    const size_t enemyPlayer(state.getEnemy(player));\n    \n    for (size_t i(0); i<_iterations; ++i)\n    {\n        // set up data for best scripts\n        size_t          bestScriptVec[Constants::Max_Units];\n\t    StateEvalScore  bestScoreVec[Constants::Max_Units];\n\n        // for each unit that can move\n        for (size_t unitIndex(0); unitIndex<state.numUnits(player); ++unitIndex)\n        {\n            if (_timeLimit > 0 && t.getElapsedTimeInMilliSec() > _timeLimit)\n            {\n                break;\n            }\n\n            const Unit & unit(state.getUnit(player, unitIndex));\n\n            // iterate over each script move that it can execute\n            for (size_t sIndex(0); sIndex<_playerScriptPortfolio.size(); ++sIndex)\n            {\n                // set the current script for this unit\n                currentScriptData.setUnitScript(unit, _playerScriptPortfolio[sIndex]);\n\n                // evaluate the current state given a playout with these unit scripts\n                StateEvalScore score = eval(player, state, currentScriptData);\n\n                // if we have a better score, set it\n                if (sIndex == 0 || score > bestScoreVec[unitIndex])\n                {\n                    bestScriptVec[unitIndex] = _playerScriptPortfolio[sIndex];\n                    bestScoreVec[unitIndex]  = score;\n                }\n            }\n\n            // set the current vector to the best move for use in future simulations\n            currentScriptData.setUnitScript(unit, bestScriptVec[unitIndex]);\n        }\n    }   \n}\n\nsize_t PortfolioGreedySearch::calculateInitialSeed(const size_t & player, const GameState & state)\n{\n    size_t bestScript;\n    StateEvalScore bestScriptScore;\n    const size_t enemyPlayer(state.getEnemy(player));\n    \n    // try each script in the portfolio for each unit as an initial seed\n    for (size_t sIndex(0); sIndex<_playerScriptPortfolio.size(); ++sIndex)\n    {\n        UnitScriptData currentScriptData;\n    \n        // set the player's chosen script initially to the seed choice\n        for (size_t unitIndex(0); unitIndex < state.numUnits(player); ++unitIndex)\n        {\n            currentScriptData.setUnitScript(state.getUnit(player, unitIndex), _playerScriptPortfolio[sIndex]);\n        }\n\n        // set the enemy units script choice to NOKDPS\n        for (size_t unitIndex(0); unitIndex < state.numUnits(enemyPlayer); ++unitIndex)\n        {\n            currentScriptData.setUnitScript(state.getUnit(enemyPlayer, unitIndex), _enemyScript);\n        }\n\n        // evaluate the current state given a playout with these unit scripts\n        StateEvalScore score = eval(player, state, currentScriptData);\n\n        if (sIndex == 0 || score > bestScriptScore)\n        {\n            bestScriptScore = score;\n            bestScript = _playerScriptPortfolio[sIndex];\n        }\n    }\n\n    return bestScript;\n}\n\nStateEvalScore PortfolioGreedySearch::eval(const size_t & player, const GameState & state, UnitScriptData & playerScriptsChosen)\n{\n    const size_t enemyPlayer(state.getEnemy(player));\n\n\tGame g(state, 100);\n\n    g.playIndividualScripts(playerScriptsChosen);\n\n    _totalEvals++;\n\n\treturn g.getState().eval(player, SparCraft::EvaluationMethods::LTD2);\n}\n\nvoid  PortfolioGreedySearch::setAllScripts(const size_t & player, const GameState & state, UnitScriptData & data, const size_t & script)\n{\n    for (size_t unitIndex(0); unitIndex < state.numUnits(player); ++unitIndex)\n    {\n        data.setUnitScript(state.getUnit(player, unitIndex), script);\n    }\n}\n\n/*\nstd::vector<Action> PortfolioGreedySparCraft::search(const size_t & player, const GameState & state)\n{\n    const size_t enemyPlayer(state.getEnemy(player));\n\tGameState initialState(state);\n\tMoveArray moves;\n\tstate.generateMoves(moves, player);\n\n    size_t seedScript = calculateInitialSeed(player, state);\n\n    UnitScriptData currentScriptData;\n    \n    // set the player's chosen script initially to the seed choice\n    for (size_t unitIndex(0); unitIndex < state.numUnits(player); ++unitIndex)\n    {\n        currentScriptData.setUnitScript(state.getUnit(player, unitIndex), seedScript);\n    }\n\n    // set the enemy units script choice to the seed as well\n    for (size_t unitIndex(0); unitIndex < state.numUnits(enemyPlayer); ++unitIndex)\n    {\n        currentScriptData.setUnitScript(state.getUnit(enemyPlayer, unitIndex), _enemyScript);\n    }\n\t\n    std::vector<size_t> bestScriptVec(moves.numUnits(), seedScript);\n\tstd::vector<StateEvalScore> bestScoreVec(moves.numUnits());\n\n    // the current script vector we will be working with\n    std::vector<size_t> currentScriptVec(moves.numUnits(), seedScript);\n\n    // for each unit that can move\n    for (size_t unitIndex(0); unitIndex<moves.numUnits(); ++unitIndex)\n    {\n        const Unit & unit(state.getUnit(player, unitIndex));\n\n        // iterate over each script move that it can execute\n        for (size_t sIndex(0); sIndex<_playerScriptPortfolio.size(); ++sIndex)\n        {\n            // set the current script for this unit\n            currentScriptData.setUnitScript(unit, _playerScriptPortfolio[sIndex]);\n\n            // evaluate the current state given a playout with these unit scripts\n            StateEvalScore score = evalAfterMoves(player, state, currentScriptData);\n\n            // if we have a better score, set it\n            if (sIndex == 0 || score > bestScoreVec[unitIndex])\n            {\n                bestScriptVec[unitIndex] = _playerScriptPortfolio[sIndex];\n                bestScoreVec[unitIndex]  = score;\n            }\n        }\n\n        // set the current vector to the best move for use in future simulations\n        currentScriptData.setUnitScript(unit, bestScriptVec[unitIndex]);\n    }\n\t\n    std::vector<Action> moveVec;\n    currentScriptData.calculateMoves(player, moves, GameState(state), moveVec);\n    return moveVec;\n}*/"
  },
  {
    "path": "SparCraft/source/PortfolioGreedySearch.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"Player.h\"\n#include \"Game.h\"\n#include \"Action.h\"\n#include \"UnitScriptData.h\"\n#include <memory>\n\nnamespace SparCraft\n{\n\t\ntypedef\tstd::shared_ptr<Player> PlayerPtr;\n\nclass PortfolioGreedySearch\n{\nprotected:\n\t\n    const size_t\t\t\t\t_player;\n    const size_t\t\t\t\t_enemyScript;\n    const size_t\t\t\t\t_iterations;\n    const size_t                _responses;\n    std::vector<size_t>\t\t\t_playerScriptPortfolio;\n    size_t                      _totalEvals;\n    size_t                      _timeLimit;\n\n    void                        doPortfolioSearch(const size_t & player,const GameState & state,UnitScriptData & currentData);\n    std::vector<Action>     getMoveVec(const size_t & player,const GameState & state,const std::vector<size_t> & playerScripts);\n    StateEvalScore              eval(const size_t & player,const GameState & state,UnitScriptData & playerScriptsChosen);\n    size_t                      calculateInitialSeed(const size_t & player,const GameState & state);\n    void                        setAllScripts(const size_t & player,const GameState & state,UnitScriptData & data,const size_t & script);\n\npublic:\n\n    PortfolioGreedySearch(const size_t & player, const size_t & enemyScript, const size_t & iter, const size_t & responses, const size_t & timeLimit);\n    std::vector<Action> search(const size_t & player, const GameState & state);\n};\n\n}"
  },
  {
    "path": "SparCraft/source/Position.hpp",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include <math.h>\n#include <sstream>\n\nnamespace SparCraft\n{\nclass Position\n{\n\t// x,y location will be used for Units in a 'grid'\n\tPositionType\t\t_x, \n\t\t\t\t\t\t_y;\n\npublic:\n\t\n\tPosition()\n\t\t: _x(0)\n\t\t, _y(0)\n\t{\n\t}\n\n\tPosition(const PositionType & x, const PositionType & y)\n\t\t: _x(x)\n\t\t, _y(y)\n\t{\n\t}\n\n    Position(const BWAPI::Position & p)\n        : _x(p.x)\n        , _y(p.y)\n    {\n\n    }\n\n\tconst bool operator < (const Position & rhs) const\n\t{\n        return (x() < rhs.x()) || ((x() == rhs.x()) && y() < rhs.y());\n\t}\n\n    const bool operator == (const Position & rhs) const\n    {\n        return x() == rhs.x() && y() == rhs.y();\n    }\n\n\tconst Position operator + (const Position & rhs) const\n\t{\n\t\treturn Position(x() + rhs.x(), y() + rhs.y());\n\t}\n\n\tconst Position operator - (const Position & rhs) const\n\t{\n\t\treturn Position(x() - rhs.x(), y() - rhs.y());\n\t}\n\n\tconst Position scale(const float & f) const\n\t{\n\t\treturn Position((PositionType)(f * x()), (PositionType)(f * y()));\n\t}\n\n    void scalePosition(const float & f)\n    {\n        _x = (PositionType)(f * _x);\n        _y = (PositionType)(f * _y);\n    }\n\n    void addPosition(const Position & rhs)\n    {\n        _x += rhs.x();\n        _y += rhs.y();\n    }\n\n    void subtractPosition(const Position & rhs)\n    {\n        _x -= rhs.x();\n        _y -= rhs.y();\n    }\n\t\n\tvoid moveTo(const Position & pos)\n\t{\n\t\t_x = pos.x();\n\t\t_y = pos.y();\n\t}\n\n\tvoid addPosition(const PositionType & x, const PositionType & y)\n\t{\n\t\t_x += x;\n\t\t_y += y;\n\t}\n\n\tvoid moveTo(const PositionType & x, const PositionType & y)\n\t{\n\t\t_x = x;\n\t\t_y = y;\n\t}\n\n\tconst PositionType x() const\n\t{\n\t\treturn _x;\n\t}\n\n\tconst PositionType y() const\n\t{\n\t\treturn _y;\n\t}\n\n\tconst Position flipX() const\n\t{\n\t\treturn Position(-_x,_y);\n\t}\n\n\tconst Position flipY() const\n\t{\n\t\treturn Position(_y,_x);\n\t}\n\n    const float Q_rsqrt( float number ) const\n    {\n        long i;\n        float x2, y;\n        const float threehalfs = 1.5F;\n \n        x2 = number * 0.5F;\n        y  = number;\n        i  = * ( long * ) &y;                       // evil floating point bit level hacking\n        i  = 0x5f3759df - ( i >> 1 );               \n        y  = * ( float * ) &i;\n        y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration\n//      y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed\n \n        return y;\n    }\n\n\tconst Position flip() const\n\t{\n\t\treturn Position(-_x, -_y);\n\t}\n\n    inline const PositionType getDistance(const Position & p) const\t\n\t{\n        PositionType dX = x() - p.x();\n        PositionType dY = y() - p.y();\n\n        if (dX == 0)\n        {\n            return abs(dY);\n        }\n        else if (dY == 0)\n        {\n            return abs(dX);\n        }\n        else\n        {\n            return (PositionType)sqrt((float)(dX*dX - dY*dY));\n        }\n\t}\n\n\tinline const PositionType getDistanceSq(const Position & p) const\t\n\t{\n        return (x()-p.x())*(x()-p.x()) + (y()-p.y())*(y()-p.y());\n\t}\n\n\tvoid print() const\n\t{\n\t\tprintf(\"Position = (%d, %d)\\n\", _x, _y);\n\t}\n\n    const std::string getString() const\n    {\n        std::stringstream ss;\n        ss << \"(\" << x() << \", \" << y() << \")\";\n        return ss.str();\n    }\n\n};\n}"
  },
  {
    "path": "SparCraft/source/Random.hpp",
    "content": "#pragma once\n\n#include <ctime>\n#include <limits>\n\nnamespace SparCraft\n{\n\tclass RandomInt;\n}\n\t\nclass SparCraft::RandomInt\n{\n\tint _seed;\n    int _min;\n    int _max;\n\npublic:\n\n\tRandomInt(int min, int max, int seed)\n        : _seed(seed)\n        , _min(min)\n        , _max(max)\n\t{\n\t\tsrand(seed);\n\t}\n\n\tint nextInt()\n\t{\n\t\treturn ( rand() % (_max-_min) ) + _min;\n\t}\n};\n"
  },
  {
    "path": "SparCraft/source/SparCraft.cpp",
    "content": "#include \"SparCraft.h\"\n\nnamespace SparCraft\n{\n    void init()\n    {\n        // Initialize Data for Attack Frame Animations\n        SparCraft::AnimationFrameData::init();\n\n        // Initialize Random Data for State Hashing\n        SparCraft::Hash::initHash();\n\n        // Initialize Weapon and Unit Property Data\n        SparCraft::WeaponProperties::Init();\n\t    SparCraft::UnitProperties::Init();\n    \n        // Initialize EnumData Class Types\n        SparCraft::EnumDataInit();\n    }\n}"
  },
  {
    "path": "SparCraft/source/SparCraft.h",
    "content": "#pragma once\n\n#ifndef WIN32\n#define APIENTRY\n#define APIENTRYP\n#endif\n\n#include \"Common.h\"\n#include \"PlayerProperties.h\"\n#include \"UnitProperties.h\"\n#include \"Player.h\"\n#include \"AllPlayers.h\"\n#include \"Game.h\"\n#include \"GameState.h\"\n#include \"AnimationFrameData.h\"\n\nnamespace SparCraft\n{\n    void init();\n}\n"
  },
  {
    "path": "SparCraft/source/SparCraftAssert.cpp",
    "content": "#include \"SparCraftAssert.h\"\n#include \"SparCraftException.h\"\n\n#include <cstring>\n\nusing namespace SparCraft;\n\nnamespace SparCraft\n{\nnamespace Assert\n{\n    const std::string currentDateTime() \n    {\n        time_t     now = time(0);\n        struct tm  tstruct;\n        char       buf[80];\n        tstruct = *localtime(&now);\n        strftime(buf, sizeof(buf), \"%Y-%m-%d_%X\", &tstruct);\n\n        for (size_t i(0); i < strlen(buf); ++i)\n        {\n            if (buf[i] == ':')\n            {\n                buf[i] = '-';\n            }\n        }\n\n        return buf;\n    }\n\n    void ReportFailure(const GameState * state, const char * condition, const char * file, int line, const char * msg, ...)\n    {\n        std::cerr << \"Assertion thrown!\\n\";\n\n        char messageBuffer[4096] = \"\";\n        if (msg != NULL)\n        {\n            va_list args;\n            va_start(args, msg);\n            vsprintf(messageBuffer, msg, args);\n            va_end(args);\n        }\n\n        std::stringstream ss;\n        ss                                      << std::endl;\n        ss << \"!Assert:   \" << condition        << std::endl;\n        ss << \"File:      \" << file             << std::endl;\n        ss << \"Message:   \" << messageBuffer    << std::endl;\n        ss << \"Line:      \" << line             << std::endl;\n        \n        #if !defined(EMSCRIPTEN)\n            std::cerr << ss.str();  \n            throw SparCraftException(ss.str(), state);\n        #else\n            printf(\"C++ AI: AI Exception Thrown:\\n %s\\n\", ss.str().c_str());\n            throw SparCraftException(ss.str());\n        #endif\n    }\n}\n}\n\n"
  },
  {
    "path": "SparCraft/source/SparCraftAssert.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include <cstdarg>\n\n#include <ctime>\n\nnamespace SparCraft\n{\n\nclass GameState;\nnamespace Assert\n{\n    const std::string currentDateTime();\n    void ReportFailure(const GameState * state, const char * condition, const char * file, int line, const char * msg, ...);\n}\n}\n\n#define SPARCRAFT_ASSERT_ENABLE\n\n#ifdef SPARCRAFT_ASSERT_ENABLE\n\n    #define SPARCRAFT_ASSERT(cond, msg, ...) \\\n        do \\\n        { \\\n            if (!(cond)) \\\n            { \\\n                SparCraft::Assert::ReportFailure(nullptr, #cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \\\n            } \\\n        } while(0)\n\n    #define SPARCRAFT_ASSERT_STATE(cond, state, filename, msg, ...) \\\n        do \\\n        { \\\n            if (!(cond)) \\\n            { \\\n                SparCraft::Assert::ReportFailure(&state, #cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \\\n            } \\\n        } while(0)\n\n#else\n    #define SPARCRAFT_ASSERT(cond, msg, ...) \n    #define SPARCRAFT_ASSERT_STATE(cond, state, filename, msg, ...) \n#endif\n"
  },
  {
    "path": "SparCraft/source/SparCraftException.cpp",
    "content": "#include \"SparCraftException.h\"\n\nusing namespace SparCraft;\n\nSparCraftException::SparCraftException(std::string ss) \n    : _s(ss) \n    , _hasState(false)\n{\n}\n\nSparCraftException::SparCraftException(std::string ss, const GameState * state) \n    : _s(ss) \n    , _hasState(false)\n{\n    if (state != nullptr)\n    {\n        _state = *state;\n        _hasState = true;\n    }\n}\n\nSparCraftException::~SparCraftException() throw () \n{\n} \n\nconst char* SparCraftException::what() const throw() \n{ \n    return _s.c_str(); \n}\n\nbool SparCraftException::hasState() const \n{ \n    return _hasState; \n}\n\nconst GameState & SparCraftException::getState() const \n{ \n    return _state; \n}"
  },
  {
    "path": "SparCraft/source/SparCraftException.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n\nnamespace SparCraft\n{\nclass SparCraftException : public std::exception\n{\n    std::string _s;\n    GameState _state;\n    bool _hasState;\n\npublic :\n\n    SparCraftException(std::string ss, const GameState * state);\n    SparCraftException(std::string ss);\n\n    ~SparCraftException() throw ();\n    const char* what() const throw();\n    bool hasState() const;\n    const GameState & getState() const;\n}; \n}\n"
  },
  {
    "path": "SparCraft/source/Timer.cpp",
    "content": "#include \"Timer.h\"\n\nusing namespace SparCraft;\n\nTimer::Timer()\n{\n\t#ifdef WIN32\n\t\tQueryPerformanceFrequency(&frequency);\n\t\tstartCount.QuadPart = 0;\n\t\tendCount.QuadPart = 0;\n\t#else\n\t\tstartCount.tv_sec = startCount.tv_usec = 0;\n\t\tendCount.tv_sec = endCount.tv_usec = 0;\n\t#endif\n\n\tstopped = 0;\n\tstartTimeInMicroSec = 0;\n\tendTimeInMicroSec = 0;\n\t\t\n\tstart();\n}\n\t\nTimer::~Timer() {}                                 // default destructor\n\nvoid Timer::start()\n{\n\tstopped = 0; // reset stop flag\n\t\t\n\t#ifdef WIN32\n\t\tQueryPerformanceCounter(&startCount);\n\t#else\n\t\tgettimeofday(&startCount, NULL);\n\t#endif\n}\n\t\nvoid Timer::stop()\n{\n\tstopped = 1; // set timer stopped flag\n\n\t#ifdef WIN32\n\t\tQueryPerformanceCounter(&endCount);\n\t#else\n\t\tgettimeofday(&endCount, NULL);\n\t#endif\n}\n\t\ndouble Timer::getElapsedTimeInMicroSec()\n{\n\t#ifdef WIN32\n\t\tif(!stopped)\n\t\t\tQueryPerformanceCounter(&endCount);\n\n\t\tstartTimeInMicroSec = startCount.QuadPart * (1000000.0 / frequency.QuadPart);\n\t\tendTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart);\n\t#else\n\t\tif(!stopped)\n\t\t\tgettimeofday(&endCount, NULL);\n\n\t\tstartTimeInMicroSec = (startCount.tv_sec * 1000000.0) + startCount.tv_usec;\n\t\tendTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec;\n\t#endif\n\n\treturn endTimeInMicroSec - startTimeInMicroSec;\n}\n\t \ndouble Timer::getElapsedTimeInMilliSec()\n{\n\treturn this->getElapsedTimeInMicroSec() * 0.001;\n}\n\ndouble Timer::getElapsedTimeInSec()\n{\n\treturn this->getElapsedTimeInMicroSec() * 0.000001;\n}\n\ndouble Timer::getElapsedTime()\n{\n\treturn this->getElapsedTimeInSec();\n}"
  },
  {
    "path": "SparCraft/source/Timer.h",
    "content": "//////////////////////////////////////////////////////////////////////////////\n// Timer.h\n// =======\n// High Resolution Timer.\n// This timer is able to measure the elapsed time with 1 micro-second accuracy\n// in both Windows, Linux and Unix system \n//\n//  AUTHOR: Song Ho Ahn (song.ahn@gmail.com)\n// CREATED: 2003-01-13\n// UPDATED: 2006-01-13\n//\n// Copyright (c) 2003 Song Ho Ahn\n//////////////////////////////////////////////////////////////////////////////\n// Modified by: David Churchill (dave.churchill@gmail.com)\n// For academic use (2011)\n//////////////////////////////////////////////////////////////////////////////\n\n#pragma once\n\n#ifdef WIN32   // Windows system specific\n\t#include <windows.h>\n#else          // Unix based system specific\n\t#include <sys/time.h>\n#endif\n\n#include \"Common.h\"\n\nnamespace SparCraft\n{\nclass Timer\n{\n \tdouble startTimeInMicroSec;                 // starting time in micro-second\n    double endTimeInMicroSec;                   // ending time in micro-second\n    int    stopped;                             // stop flag \n\t#ifdef WIN32\n\t\tLARGE_INTEGER frequency;                    // ticks per second\n\t\tLARGE_INTEGER startCount;                   //\n\t\tLARGE_INTEGER endCount;                     //\n\t#else\n\t\ttimeval startCount;                         //\n\t\ttimeval endCount;                           //\n\t#endif\n\npublic:\n\n\tTimer();\n\t\n    ~Timer();\n\n    void start();\n\t\n    void stop();\n\t\n    double getElapsedTimeInMicroSec();\n\tdouble getElapsedTimeInMilliSec();\n\tdouble getElapsedTimeInSec();\n\tdouble getElapsedTime();\n};\n}"
  },
  {
    "path": "SparCraft/source/TranspositionTable.cpp",
    "content": "#include \"TranspositionTable.h\"\n\nusing namespace SparCraft;\n\nTTEntry::TTEntry()\n\t: _hash2(0)\n\t, _depth(0)\n\t, _type(TTEntry::NONE)\n{\n\n}\n\nTTEntry::TTEntry(const HashType & hash2, const StateEvalScore & score, const size_t & depth, const int & type, \n\t\t\t\tconst size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove)\n\t: _hash2(hash2)\n\t, _score(score)\n\t, _depth(depth)\n\t, _type(type)\n{\n\t_bestMoves[firstPlayer] = TTBestMove(bestFirstMove, bestSecondMove);\n}\n\nconst bool TTEntry::hashMatches(const HashType & hash2) const\n{\n\treturn hash2 == _hash2;\n}\n\nconst bool TTEntry::isValid() const\n{\n\treturn _type != TTEntry::NONE;\n}\n\nconst HashType & TTEntry::getHash()\t\t\t\t\t\t\t\tconst { return _hash2; }\nconst StateEvalScore & TTEntry::getScore()\t\t\t\t\t\tconst { return _score; }\nconst size_t & TTEntry::getDepth()\t\t\t\t\t\t\t\tconst { return _depth; }\nconst int & TTEntry::getType()\t\t\t\t\t\t\t\t\tconst { return _type;  }\nconst TTBestMove & TTEntry::getBestMove(const size_t & player)\tconst { return _bestMoves[player];  }\nvoid TTEntry::setBestMove(const size_t &firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove)\n{\n\t_bestMoves[firstPlayer] = TTBestMove(bestFirstMove, bestSecondMove);\n}\n\nTranspositionTable::TranspositionTable () \n\t: TT(Constants::Transposition_Table_Size, TTEntry())\n\t, size(Constants::Transposition_Table_Size)\n    , collisions(0)\n    , lookups(0)\n    , found(0)\n    , notFound(0)\n\t, saves(0)\n\t, minIndex(0)\n\t, maxIndex(0)\n\t, saveOverwriteSelf(0)\n\t, saveOverwriteOther(0)\n\t, saveEmpty(0)\n{\n}\n\t\nconst TTEntry & TranspositionTable::operator [] (const size_t & hash) const\n{\n\treturn TT[getIndex(hash)];\n}\n\nconst TTEntry & TranspositionTable::get(const size_t & hash) const\n{\n\treturn TT[getIndex(hash)];\n}\n        \nconst size_t TranspositionTable::getSaveIndex(const size_t & index, const HashType & hash2, const size_t & depth) const\n{\n\tsize_t worstDepth(1000);\n\tsize_t worstDepthIndex(index);\n\n\t// scan ahead to find the best spot to store this entryw\n\tfor (size_t i(index); (i<(index+Constants::Transposition_Table_Scan)) && (i <TT.size()); ++i)\n\t{\n\t\t// if this index holds worse data about the current state, use it to overwrite\n\t\tif (TT[i].getHash() == hash2 && TT[i].getDepth() < depth)\n\t\t{\n\t\t\treturn i;\n\t\t}\n\t\telse if (TT[i].getHash() == hash2 && TT[i].getDepth() > depth)\n\t\t{\n\t\t\tprintf(\"We shouldn't get here\\n\");\n\t\t}\n\t\t// otherwise if this entry is empty, use it\n\t\telse if (!TT[i].isValid())\n\t\t{\n\t\t\treturn i;\n\t\t}\n\t\t// otherwise if the hashes don't match, check to see how old the data is\n\t\telse if (TT[i].getHash() != hash2)\n\t\t{\n\t\t\tif (TT[i].getDepth() < worstDepth)\n\t\t\t{\n\t\t\t\tworstDepth = TT[i].getDepth();\n\t\t\t\tworstDepthIndex = i;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn worstDepthIndex;\n}\n\nvoid TranspositionTable::save(\tconst HashType & hash1, const HashType & hash2, const StateEvalScore & value, const size_t & depth, const int & type,\n\t\t\tconst size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove)\n{\n\tsize_t indexToSave = getSaveIndex(getIndex(hash1), hash2, depth);\n\tTTEntry existing = TT[indexToSave];\n\n\tif (existing.isValid())\n\t{\n\t\tif (existing.getHash() == hash2)\n\t\t{\n\t\t\tsaveOverwriteSelf++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsaveOverwriteOther++;\n\t\t}\n\t}\n\telse\n\t{\n\t\tsaveEmpty++;\n\t}\n\n\tsaves++;\n\t\n\tTT[indexToSave] = TTEntry(hash2, value, depth, type, firstPlayer, bestFirstMove, bestSecondMove);\n}\n\nTTEntry * TranspositionTable::lookupScan(const HashType & hash1, const HashType & hash2)\n{\n\tlookups++;\n\tsize_t index = getIndex(hash1);\n\n\t// scan to see if this exists anywhere in the next few entries\n\tfor (size_t i(index); (i<(index+Constants::Transposition_Table_Scan)) && (i <TT.size()); ++i)\n\t{\n\t\tTTEntry * entry = lookup(i, hash2);\n\n\t\t// if it does, return it\n\t\tif (entry)\n\t\t{\n\t\t\tfound++;\n\t\t\treturn entry;\n\t\t}\n\t}\n\n\t// otherwise return null\n\tnotFound++;\n\treturn NULL;\n}\n\n// look up a value in the transposition table, return NULL if not found or collision\nTTEntry * TranspositionTable::lookup(const size_t & index, const HashType & hash2)\n{\n\tif (index < minIndex) minIndex = index;\n\tif (index > maxIndex) maxIndex = index;\n\t\n\tTTEntry tte = TT[index];\n\n\t// if there is a valid entry at that location\n\tif (TT[index].isValid())\n\t{\n\t\t// test for matching secondary hash\n\t\tif (TT[index].hashMatches(hash2))\n\t\t{\n\t\t\tfound++;\n\t\t\treturn &TT[index];\n\t\t}\n\t\t// if no match it is a collision\n\t\telse\n\t\t{\n\t\t\t//collisions++;\n\t\t\treturn NULL;\n\t\t}\n\t}\n\telse\n\t{\n\t\t//notFound++;\n\t\treturn NULL;\n\t}\n}\n\t\nconst size_t & TranspositionTable::getSize()\t\tconst { return size; }\nconst size_t & TranspositionTable::numFound()\t\tconst { return found; }\t\nconst size_t & TranspositionTable::numNotFound()\tconst { return notFound; }\nconst size_t & TranspositionTable::numCollisions()\tconst { return collisions; }\nconst size_t & TranspositionTable::numSaves()\t\tconst { return saves; }\nconst size_t & TranspositionTable::numLookups()\t\tconst { return lookups; }\n\nconst size_t TranspositionTable::getUsage() const\n{\n\tsize_t sum(0);\n\tfor (size_t i(0); i<TT.size(); ++i)\n\t{\n\t\tif (TT[i].isValid())\n\t\t{\n\t\t\tsum++;\n\t\t}\n\t}\n\n\treturn sum;\n}\n\nvoid TranspositionTable::print()\n{\n\tstd::cout << \"TT stats: \" << lookups << \" lookups, \" << found << \" found, \" << notFound << \" not found, \" << collisions << \" collions. \" << minIndex << \" min, \" << maxIndex << \" max.\\n\";\n}"
  },
  {
    "path": "SparCraft/source/TranspositionTable.h",
    "content": "#pragma once\n\n#include <vector>\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"Action.h\"\n#include \"AlphaBetaMove.h\"\n#include <memory>\n\nnamespace SparCraft\n{\n\nclass TTEntry\n{\t\npublic:\n\n\tenum { NONE, UPPER, LOWER, ACCURATE };\n\nprivate:\n\n\tHashType\t\t\t_hash2;\n\tStateEvalScore\t\t_score;\n\tsize_t\t\t\t\t_depth;\n\tTTBestMove\t\t\t_bestMoves[2];\n\tint\t\t\t\t\t_type;\n\npublic:\n\n\tTTEntry();\n\tTTEntry(const HashType & hash2, const StateEvalScore & score, const size_t & depth, const int & type, \n\t\t\tconst size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove);\n\n\tconst bool hashMatches(const HashType & hash2) const;\n\n\tconst bool isValid() const;\n\n\tconst HashType & getHash()\t\t\t\t\t\t\t\t\tconst;\n\tconst StateEvalScore & getScore()\t\t\t\t\t\t\tconst;\n\tconst size_t & getDepth()\t\t\t\t\t\t\t\t\tconst;\n\tconst int & getType()\t\t\t\t\t\t\t\t\t\tconst;\n\tconst TTBestMove & getBestMove(const size_t & player)\t\tconst;\n\tvoid setBestMove(const size_t &firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove);\n\n\tvoid print() const\n\t{\n\t\tprintf (\"%d, %d, %d, %d\\n\", (int) _hash2, (int) _score.val(), (int) _depth, (int) _type);\n\t}\n};\n\n\nclass TTLookupValue\n{\n\tbool\t\t_found;\t\t// did we find a value?\n\tbool\t\t_cut;\t\t// should we produce a cut?\n\tTTEntry *\t_entry;\t\t// the entry we found\n\npublic:\n\n\tTTLookupValue()\n\t\t: _found(false)\n\t\t, _cut(false)\n\t\t, _entry(NULL)\n\t{\n\t}\n\n\tTTLookupValue(const bool found, const bool cut, TTEntry * entry)\n\t\t: _found(found)\n\t\t, _cut(cut)\n\t\t, _entry(entry)\n\t{\n\t\t\n\t}\n\n\tconst bool found() const\t{ return _found; }\n\tconst bool cut() const\t\t{ return _cut; }\n\tTTEntry * entry() const\t\t{ return _entry; }\n};\n\nclass TranspositionTable \n{\n\t//Array<TTEntry, Constants::Transposition_Table_Size>\tTT;\n\t//TTEntry TT[Constants::Transposition_Table_Size];\n\tstd::vector<TTEntry> TT;\n\n\tsize_t\t\t\tsize;\n\n\tsize_t\t\t\tminIndex,\n\t\t\t\t\tmaxIndex;\n\n\tconst size_t getIndex(const HashType & hash1) const\n\t{\n\t\treturn hash1 % size; \n\t}\n\npublic:\n\n\tsize_t\t\t\tcollisions,\n\t\t\t\t\tlookups, \n\t\t\t\t\tfound, \n\t\t\t\t\tnotFound,\n\t\t\t\t\tsaves,\n\t\t\t\t\tsaveOverwriteSelf,\n\t\t\t\t\tsaveOverwriteOther,\n\t\t\t\t\tsaveEmpty;\n\n\tTranspositionTable ();\n\t\n\tconst TTEntry & operator [] (const size_t & hash) const;\n\n\tconst TTEntry & get(const size_t & hash) const;\n        \n\tvoid save(const HashType & hash1, const TTEntry & entry) ;\n\n\tvoid save(\tconst HashType & hash1, const HashType & hash2, const StateEvalScore & value, const size_t & depth, const int & type,\n\t\t\t\tconst size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove);\n\n\tTTEntry * lookup(const size_t & index, const HashType & hash2);\n\tTTEntry * lookupScan(const HashType & hash1, const HashType & hash2);\n\t\n\tconst size_t & getSize()\t\tconst;\n\tconst size_t & numFound()\t\tconst;\t\n\tconst size_t & numNotFound()\tconst;\n\tconst size_t & numCollisions()\tconst;\n\tconst size_t & numSaves()\t\tconst;\n\tconst size_t & numLookups()\t\tconst;\n\n\tconst size_t getUsage() const;\n\n\tconst size_t getSaveIndex(const size_t & index, const HashType & hash2, const size_t & depth) const;\n\n\tvoid print();\n};\n\ntypedef\tstd::shared_ptr<TranspositionTable> TTPtr;\n}"
  },
  {
    "path": "SparCraft/source/TutorialCode.cpp",
    "content": "#include \"SparCraft.h\"\n\nusing namespace SparCraft;\n\n// IMPORTANT:\n// Consult BaseTypes.hpp for all important variable typedefs\n// Consult Common.h for all important constant and enum values \n\nUnit getSampleUnit()\n{\n    // Unit has several constructors\n    // You will typically only be using this one to construct a 'starting' unit\n\n    // Unit(const BWAPI::UnitType unitType, const IDType & playerID, const Position & pos)\n\n    // The BWAPI::UnitType of the unit to be added\n    BWAPI::UnitType marine = BWAPI::UnitTypes::Terran_Marine;\n\n    // The player to add this unit to, specified by an IDType\n    IDType player = Players::Player_One;\n\n    // A Position, measured in Pixel coordinates\n    Position p(0,0);\n\n    // Simple unit constructor\n    Unit marineAtOrigin(marine, player, p);\n    \n    return marineAtOrigin;\n}\n\nGameState getSampleState()\n{\n    // GameState only has a default constructor, you must add units to it manually\n    GameState state;\n\n    // The recommended way of adding a unit to a state is to just construct a unit and add it with:\n    state.addUnit(getSampleUnit());\n\n    // Or it can be added to the state via unit construction parameters\n    state.addUnit(BWAPI::UnitTypes::Terran_Marine, Players::Player_One, Position(10,10));\n    state.addUnit(BWAPI::UnitTypes::Protoss_Dragoon, Players::Player_Two, Position(40,40));\n\n    // Units added with those 2 functions will be given a unique unitID inside GameState\n    // If you require setting your own unique unitID for a unit, for example when translating a BWAPI::Broodwar state to GameState\n\n    // Construct the unit\n    Unit u(BWAPI::UnitTypes::Terran_Marine, Players::Player_One, Position(0,0));\n\n    // Set the unitID\n    u.setUnitID(5);\n\n    // Add it to the state and tell it not to change the unitID.\n    // If a state contains two units with the same ID, an error will occur\n    state.addUnitWithID(u);\n\n    return state;\n}\n\nMap getSampleMap()\n{\n    // Maps are used to constrain the movement of Units on a battlefield\n\n    // There are 3 resolution scales at which positions operate in StarCraft maps\n    // Pixel Resolution = 1x1 pixel = StarCraft smallest movement resolution\n    // WalkTile Resolution = 8x8 pixels = StarCraft 'walkable' resolution\n    // BuildTile Resolution = 32x32 pixels, or 4x4 WalkTiles = StarCraft \"map size\" resolution\n\n    // Example: A Map of size 32*32 BuildTiles has size 128*128 WalkTiles or 1024*1024 pixels\n    \n    // The Map object constructor takes in size coordinates in BWAPI BuildTile resolution    \n    Map smallMap(32, 32);\n\n    // We can set the walkable values of WalkTile resolution via\n    // void setMapData(const size_t & buildTileX, const size_t & buildTileY, const bool val)\n    smallMap.setMapData(21, 98, false);\n\n    // The default map sets all tiles to walkable, with an upper-left boundary of (0,0) and a lower-right boundary of (x,y)\n    // We can query whether or not a unit can walk at a given position \n    bool canWalkHere = smallMap.isWalkable(Position(100, 30));\n\n    // You can also construct a Map from a BWAPI::Game object, if you are using this code from within a bot\n    // Map gameMap(BWAPI::BroodWar)\n\n    // Once constructed, maps can be saved or loaded to files\n    // A sample map (Destination) is provided under the sample_experiment directory\n    // smallMap.load(\"mapname.txt\");\n\n    // We can set the Map of a GameState via a pointer to the map, as Map objects can be quite large:\n    GameState state(getSampleState());\n    state.setMap(&smallMap);\n\n    return smallMap;\n}\n\n// When dealing with players, use a shared pointer, it's safer\n// PlayerPtr is a boost::shared_pointer wrapper for Player *\n\nPlayerPtr getSamplePlayer(const IDType playerID)\n{\n    // Player is the base class for all Player objects\n    //\n    // Scripted players all have the same constructor which is just the player ID which will be using this script\n    // It is imoprtant to set that player ID correctly, as that player will only be generating and returning moves for that player\n\n    PlayerPtr attackClosest(new Player_AttackClosest(playerID));\n\n    return attackClosest;\n}\n\nstd::vector<Action> getSamplePlayerActionsFromState()\n{\n    // get our sample player\n    IDType currentPlayerID = Players::Player_One;\n    PlayerPtr myPlayer = getSamplePlayer(currentPlayerID);\n\n    // Construct a blank vector of Actions, which are individual unit moves\n    std::vector<Action> move;\n\n    // Get a state\n    GameState state = getSampleState();\n\n    // Construct a MoveArray. This structure will hold all the legal moves for each unit possible for this state\n    MoveArray moveArray;\n\n    // Generate the moves possible by currentPlayer from state into moveArray\n    state.generateMoves(moveArray, currentPlayerID);\n\n    // Call getMoves with these arguments\n    myPlayer->getMoves(state, moveArray, move);\n    \n    return move;\n}\n\nvoid runSampleGame()\n{\n    // running a game is quite simple, you just need 2 players and an initial state\n    GameState initialState = getSampleState();\n\n    // get the players\n    PlayerPtr p1 = getSamplePlayer(Players::Player_One);\n    PlayerPtr p2 = getSamplePlayer(Players::Player_Two);\n\n    // enter a maximum move limit for the game to go on for\n    int moveLimit = 1000;\n\n    // contruct the game\n    Game g(initialState, p1, p2, moveLimit);\n\n    // play the game\n    g.play();\n\n    // you can access the resulting game state after g has been played via getState\n    GameState finalState = g.getState();\n\n    // you can now evaluate the state however you wish. let's use an LTD2 evaluation from the point of view of player one\n    StateEvalScore score = finalState.eval(Players::Player_One, EvaluationMethods::LTD2);\n\n    // StateEvalScore has two components, a numerical score and a number of Movement actions performed by each player\n    // with this evaluation, positive val means win, negative means loss, 0 means tie\n    if (score.val() > 0)\n    {\n        std::cout << \"Player One Wins!\\n\";\n    }\n    else if (score.val() < 0)\n    {\n        std::cout << \"Player Two Wins!\\n\";\n    }\n    else\n    {\n        std::cout << \"Game is a draw!\\n\";\n    }\n}"
  },
  {
    "path": "SparCraft/source/UCTMemoryPool.hpp",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"UCTNode.h\"\n\nnamespace SparCraft\n{\n    class UCTMemoryPool;\n}\n\nclass SparCraft::UCTMemoryPool\n{\t\n    std::vector< std::vector<UCTNode> > _pool;\n\n    const size_t    _poolSize;\n    const size_t    _maxChildren;\n    \n    size_t    _currentIndex;\n\npublic:\n\n\tUCTMemoryPool(const size_t & poolSize, const size_t & maxChildren)\n        : _pool             (poolSize, std::vector<UCTNode>())\n        , _poolSize         (poolSize)\n        , _maxChildren      (maxChildren)\n        , _currentIndex     (0)\n    {\n        for (size_t s(0); s<poolSize; ++s)\n        {\n            _pool[s].reserve(maxChildren);\n        }\n    }\n\n    std::vector<UCTNode> * alloc()\n    {\n        std::vector<UCTNode> & ret(_pool[_currentIndex]);\n        if (ret.size() > 0)\n        {\n            ret.clear();\n        }\n\n        _currentIndex = (_currentIndex + 1) % _poolSize;\n        return &ret;\n    }\n\n    void clearPool()\n    {\n        for (size_t i(0); i<_poolSize; ++i)\n        {\n            _pool[i].clear();\n        }\n\n        _currentIndex = 0;\n    }\n};\n"
  },
  {
    "path": "SparCraft/source/UCTNode.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Action.h\"\n\nnamespace SparCraft\n{\n\n\nclass UCTNode\n{\n    // uct stat counting variables\n    size_t                      _numVisits;         // total visits to this node\n    double                      _numWins;           // wins from this node\n    double                      _uctVal;            // previous computed UCT value\n            \n    // game specific variables\n    size_t                      _player;            // the player who made a move to generate this node\n    size_t                      _nodeType;\n    std::vector<Action>     _move;              // the ove that generated this node\n\n    // holds children\n    std::vector<UCTNode>        _children;\n\n    // nodes for traversing the tree\n    UCTNode *                   _parent;\n    \npublic:\n\n    UCTNode ()\n        : _numVisits            (0)\n        , _numWins              (0)\n        , _uctVal               (0)\n        , _player               (Players::Player_None)\n        , _nodeType             (SearchNodeType::Default)\n        , _parent               (NULL)\n    {\n\n    }\n\n    UCTNode (UCTNode * parent, const size_t player, const size_t nodeType, const std::vector<Action> & move, const size_t & maxChildren, std::vector<UCTNode> * fromPool = NULL)\n        : _numVisits            (0)\n        , _numWins              (0)\n        , _uctVal               (0)\n        , _player               (player)\n        , _nodeType             (nodeType)\n        , _move                 (move)\n        , _parent               (parent)\n    {\n        _children.reserve(maxChildren);\n    }\n\n    const size_t    numVisits()                 const           { return _numVisits; }\n    const double    numWins()                   const           { return _numWins; }\n    const size_t    numChildren()               const           { return _children.size(); }\n    const double    getUCTVal()                 const           { return _uctVal; }\n    const bool      hasChildren()               const           { return numChildren() > 0; }\n    const size_t    getNodeType()               const           { return _nodeType; }\n    const size_t    getPlayer()                 const           { return _player; }\n\n    UCTNode *       getParent()                 const           { return _parent; }\n    UCTNode &       getChild(const size_t & c)                  { return _children[c]; }\n\n    void            setUCTVal(double val)                       { _uctVal = val; }\n    void            incVisits()                                 { _numVisits++; }\n    void            addWins(double val)                         { _numWins += val; }\n\n    std::vector<UCTNode> & getChildren()                        { return _children; }\n\n    const std::vector<Action> & getMove() const\n    {\n        return _move;\n    }\n\n    void setMove(const std::vector<Action> & move)\n    {\n        _move = move;\n    }\n\n    void addChild(UCTNode * parent, const size_t player, const size_t nodeType, const std::vector<Action> & move, const size_t & maxChildren, std::vector<UCTNode> * fromPool = NULL)\n    {\n        _children.push_back(UCTNode(parent, player, nodeType, move, maxChildren));\n    }\n\n    UCTNode & mostVisitedChild() \n    {\n        UCTNode * mostVisitedChild = NULL;\n        size_t mostVisits = 0;\n\n       for (size_t c(0); c < numChildren(); ++c)\n       {\n           UCTNode & child = getChild(c);\n\n           if (!mostVisitedChild || (child.numVisits() > mostVisits))\n           {\n               mostVisitedChild = &child;\n               mostVisits = child.numVisits();\n           }\n       }\n\n       return *mostVisitedChild;\n    }\n\n    UCTNode & bestUCTValueChild(const bool maxPlayer, const UCTSearchParameters & params) \n    {\n        UCTNode * bestChild = NULL;\n        double bestVal = maxPlayer ? std::numeric_limits<double>::min() : std::numeric_limits<double>::max();\n\n        for (size_t c(0); c < numChildren(); ++c)\n        {\n            UCTNode & child = getChild(c);\n       \n            double winRate      = (double)child.numWins() / (double)child.numVisits();\n            double uctVal       = params.cValue() * sqrt( log( (double)numVisits() ) / ( child.numVisits() ) );\n\t\t\tdouble currentVal   = maxPlayer ? (winRate + uctVal) : (winRate - uctVal);\n\n            if (maxPlayer)\n            {\n                if (currentVal > bestVal)\n                {\n                    bestVal             = currentVal;\n\t\t\t        bestChild           = &child;\n                }\n            }\n            else if (currentVal < bestVal)\n            {\n                bestVal             = currentVal;\n\t\t        bestChild           = &child;\n            }\n        }\n\n        return *bestChild;\n    }\n};\n}"
  },
  {
    "path": "SparCraft/source/UCTSearch.cpp",
    "content": "#include \"UCTSearch.h\"\n\nusing namespace SparCraft;\n\nUCTSearch::UCTSearch(const UCTSearchParameters & params) \n\t: _params(params)\n    , _memoryPool(NULL)\n{\n    for (size_t p(0); p<Constants::Num_Players; ++p)\n    {\n        // set ordered move script player objects\n        for (size_t s(0); s<_params.getOrderedMoveScripts().size(); ++s)\n        {\n            _allScripts[p].push_back(AllPlayers::getPlayerPtr(p, _params.getOrderedMoveScripts()[s]));\n        }\n\n        // set player model objects\n        if (_params.playerModel(p) != PlayerModels::None)\n        {\n            _playerModels[p] = AllPlayers::getPlayerPtr(p, _params.playerModel(p));\n        }\n    }\n}\n\nvoid UCTSearch::setMemoryPool(UCTMemoryPool * pool)\n{\n    _memoryPool = pool;\n}\n\nvoid UCTSearch::doSearch(GameState & initialState, std::vector<Action> & move)\n{\n    Timer t;\n    t.start();\n\n    _rootNode = UCTNode(NULL, Players::Player_None, SearchNodeType::RootNode, _actionVec, _params.maxChildren(), _memoryPool ? _memoryPool->alloc() : NULL);\n\n    // do the required number of traversals\n    for (size_t traversals(0); traversals < _params.maxTraversals(); ++traversals)\n    {\n        GameState state(initialState);\n        traverse(_rootNode, state);\n\n        if (traversals && (traversals % 5 == 0))\n        {\n            if (_params.timeLimit() && (t.getElapsedTimeInMilliSec() >= _params.timeLimit()))\n            {\n                break;\n            }\n        }\n\n        _results.traversals++;\n\n        //printSubTree(_rootNode, initialState, \"__uct.txt\");\n        //system(\"\\\"C:\\\\Program Files (x86)\\\\Graphviz2.30\\\\bin\\\\dot.exe\\\" < __uct.txt -Tpng > uct.png\");\n    }\n\n    // choose the move to return\n    if (_params.rootMoveSelectionMethod() == UCTMoveSelect::HighestValue)\n    {\n        move = _rootNode.bestUCTValueChild(true, _params).getMove();\n    }\n    else if (_params.rootMoveSelectionMethod() == UCTMoveSelect::MostVisited)\n    {\n        move = _rootNode.mostVisitedChild().getMove();\n    }\n\n    if (_params.graphVizFilename().length() > 0)\n    {\n        //printSubTree(_rootNode, initialState, _params.graphVizFilename());\n        //system(\"\\\"C:\\\\Program Files (x86)\\\\Graphviz2.30\\\\bin\\\\dot.exe\\\" < __uct.txt -Tpng > uct.png\");\n    }\n\n    double ms = t.getElapsedTimeInMilliSec();\n    _results.timeElapsed = ms;\n    //printf(\"Search took %lf ms\\n\", ms);\n    //printf(\"Hello\\n\");\n}\n\nconst bool UCTSearch::searchTimeOut()\n{\n\treturn (_params.timeLimit() && (_searchTimer.getElapsedTimeInMilliSec() >= _params.timeLimit()));\n}\n\nconst bool UCTSearch::terminalState(GameState & state, const size_t & depth) const\n{\n\treturn (depth <= 0 || state.isTerminal());\n}\n\nvoid UCTSearch::generateOrderedMoves(GameState & state, MoveArray & moves, const size_t & playerToMove)\n{\n\t_orderedMoves.clear();\n\n\t// if we are using opponent modeling, get the move and then return, we don't want to put any more moves in\n    if (_params.playerModel(playerToMove) != PlayerModels::None)\n\t{\n        // put the vector into the ordered moves array\n        _orderedMoves.add(std::vector<Action>());\n\n        // generate the moves into that vector\n\t\t_playerModels[playerToMove]->getMoves(state, moves, _orderedMoves[0]);\n\t\t\n\t\treturn;\n\t}\n\n\t// if we are using script move ordering, insert the script moves we want\n    if (_params.moveOrderingMethod() == MoveOrderMethod::ScriptFirst)\n    {\n        for (size_t s(0); s<_params.getOrderedMoveScripts().size(); s++)\n\t    {\n            std::vector<Action> moveVec;\n\t\t    _allScripts[playerToMove][s]->getMoves(state, moves, moveVec);\n\t\t    _orderedMoves.add(moveVec);\n\t    }\n    }\n\t\n}\nconst size_t UCTSearch::getChildNodeType(UCTNode & parent, const GameState & prevState) const\n{\n    if (!prevState.bothCanMove())\n    {\n        return SearchNodeType::SoloNode;\n    }\n    else\n    {\n        if (parent.getNodeType() == SearchNodeType::RootNode)\n        {\n            return SearchNodeType::FirstSimNode;\n        }\n        else if (parent.getNodeType() == SearchNodeType::SoloNode)\n        {\n            return SearchNodeType::FirstSimNode;\n        }\n        else if (parent.getNodeType() == SearchNodeType::SecondSimNode)\n        {\n            return SearchNodeType::FirstSimNode;\n        }\n        else if (parent.getNodeType() == SearchNodeType::FirstSimNode)\n        {\n            return SearchNodeType::SecondSimNode;\n        }\n    }\n\n    return SearchNodeType::Default;\n}\n\nconst bool UCTSearch::getNextMove(size_t playerToMove, MoveArray & moves, const size_t & moveNumber, std::vector<Action> & actionVec)\n{\n    if (moveNumber > _params.maxChildren())\n    {\n        return false;\n    }\n\n    // if this move is beyond the first, check to see if we are only using a single move\n    if (moveNumber == 1)\n    {\n        // if we are player modeling, we should have only generated the first move\n        if (_params.playerModel(playerToMove) != PlayerModels::None)\n\t    {\n            // so return false\n\t\t    return false;\n\t    }\n    }\n\n    actionVec.clear();\n\n\t// if this move should be from the ordered list, return it from the list\n\tif (moveNumber < _orderedMoves.size())\n\t{\n        actionVec.assign(_orderedMoves[moveNumber].begin(), _orderedMoves[moveNumber].end());\n        return true;\n\t}\n\t// otherwise return the next move vector starting from the beginning\n\telse\n\t{\n        if (moves.hasMoreMoves())\n        {\n            moves.getNextMoveVec(actionVec);\n            return true;\n        }\n        else\n        {\n            return false;\n        }\n\t}\n}\n\nconst size_t UCTSearch::getPlayerToMove(UCTNode & node, const GameState & state) const\n{\n\tconst size_t whoCanMove(state.whoCanMove());\n\n\t// if both players can move\n\tif (whoCanMove == Players::Player_Both)\n\t{\n        // pick the first move based on our policy\n\t\tconst size_t policy(_params.playerToMoveMethod());\n\t\tconst size_t maxPlayer(_params.maxPlayer());\n\n        // the max player always chooses at the root\n        if (isRoot(node))\n        {\n            return maxPlayer;\n        }\n\n        // the type of node this is\n        const size_t nodeType = node.getNodeType();\n\n        // the 2nd player in a sim move is always the enemy of the first\n        if (nodeType == SearchNodeType::FirstSimNode)\n        {\n            return state.getEnemy(node.getPlayer());\n        }\n        // otherwise use our policy to see who goes first in a sim move state\n        else\n        {\n\t\t    if (policy == SparCraft::PlayerToMove::Alternate)\n\t\t    {\n\t\t\t    return state.getEnemy(node.getPlayer());\n\t\t    }\n\t\t    else if (policy == SparCraft::PlayerToMove::Not_Alternate)\n\t\t    {\n\t\t\t    return node.getPlayer();\n\t\t    }\n\t\t    else if (policy == SparCraft::PlayerToMove::Random)\n\t\t    {\n\t\t\t    return rand() % 2;\n\t\t    }\n\n            // we should never get to this state\n\t\t    System::FatalError(\"UCT Error: Nobody can move for some reason\");\n\t\t    return Players::Player_None;\n        }\n\t}\n\telse\n\t{\n\t\treturn whoCanMove;\n\t}\n}\n\nUCTNode & UCTSearch::UCTNodeSelect(UCTNode & parent)\n{\n    UCTNode *   bestNode    = NULL;\n    bool        maxPlayer   = isRoot(parent) || (parent.getChild(0).getPlayer() == _params.maxPlayer());\n    double      bestVal     = maxPlayer ? std::numeric_limits<double>::min() : std::numeric_limits<double>::max();\n         \n    // loop through each child to find the best node\n    for (size_t c(0); c < parent.numChildren(); ++c)\n    {\n        UCTNode & child = parent.getChild(c);\n\n\t\tdouble currentVal(0);\n\t\n        // if we have visited this node already, get its UCT value\n\t\tif (child.numVisits() > 0)\n\t\t{\n\t\t\tdouble winRate    = (double)child.numWins() / (double)child.numVisits();\n            double uctVal     = _params.cValue() * sqrt( log( (double)parent.numVisits() ) / ( child.numVisits() ) );\n\t\t\tcurrentVal        = maxPlayer ? (winRate + uctVal) : (winRate - uctVal);\n            \n            child.setUCTVal(currentVal);\n\t\t}\n\t\telse\n\t\t{\n            // if we haven't visited it yet, return it and visit immediately\n\t\t\treturn child;\n\t\t}\n\n        // choose the best node depending on max or min player\n        if (maxPlayer)\n        {\n            if (currentVal > bestVal)\n            {\n                bestVal             = currentVal;\n\t\t\t    bestNode            = &child;\n            }\n        }\n        else if (currentVal < bestVal)\n        {\n            bestVal             = currentVal;\n\t\t\tbestNode            = &child;\n        }\n\t}\n\n    return *bestNode;\n}\n\nvoid UCTSearch::updateState(UCTNode & node, GameState & state, bool isLeaf)\n{\n    // if it's the first sim move with children, or the root node\n    if ((node.getNodeType() != SearchNodeType::FirstSimNode) || isLeaf)\n    {\n        // if this is a second sim node\n        if (node.getNodeType() == SearchNodeType::SecondSimNode)\n        {\n            // make the parent's moves on the state because they haven't been done yet\n            state.makeMoves(node.getParent()->getMove());\n        }\n\n        // do the current node moves and call finished moving\n        state.makeMoves(node.getMove());\n        state.finishedMoving();\n    }\n}\n\nStateEvalScore UCTSearch::traverse(UCTNode & node, GameState & currentState)\n{\n    StateEvalScore playoutVal;\n\n    _results.totalVisits++;\n\n    // if we haven't visited this node yet, do a playout\n    if (node.numVisits() == 0)\n    {\n        // update the status of the current state with this node's moves\n        //updateState(node, currentState, !node.hasChildren());\n        updateState(node, currentState, true);\n\n        // do the playout\n        playoutVal = currentState.eval(_params.maxPlayer(), _params.evalMethod(), _params.simScript(Players::Player_One), _params.simScript(Players::Player_Two));\n\n        _results.nodesVisited++;\n    }\n    // otherwise we have seen this node before\n    else\n    {\n        // update the state for a non-leaf node\n        updateState(node, currentState, false);\n\n        if (currentState.isTerminal())\n        {\n            playoutVal = currentState.eval(_params.maxPlayer(), EvaluationMethods::LTD2);\n        }\n        else\n        {\n            // if the children haven't been generated yet\n            if (!node.hasChildren())\n            {\n                generateChildren(node, currentState);\n            }\n\n            UCTNode & next = UCTNodeSelect(node);\n            playoutVal = traverse(next, currentState);\n        }\n    }\n\n    node.incVisits();\n    \n    if (playoutVal.val() > 0)\n    {\n        node.addWins(1);\n    }\n    else if (playoutVal.val() == 0)\n    {\n        node.addWins(0.5);\n    }\n\n    return playoutVal;\n}\n\n// generate the children of state 'node'\n// state is the GameState after node's moves have been performed\nvoid UCTSearch::generateChildren(UCTNode & node, GameState & state)\n{\n    // figure out who is next to move in the game\n    const size_t playerToMove(getPlayerToMove(node, state));\n\n    // generate all the moves possible from this state\n\tstate.generateMoves(_moveArray, playerToMove);\n    _moveArray.shuffleMoveActions();\n\n    // generate the 'ordered moves' for move ordering\n    generateOrderedMoves(state, _moveArray, playerToMove);\n\n    // for each child of this state, add a child to the current node\n    for (size_t child(0); (child < _params.maxChildren()) && getNextMove(playerToMove, _moveArray, child, _actionVec); ++child)\n    {\n        // add the child to the tree\n        node.addChild(&node, playerToMove, getChildNodeType(node, state), _actionVec, _params.maxChildren(), _memoryPool ? _memoryPool->alloc() : NULL);\n        _results.nodesCreated++;\n    }\n}\n\nStateEvalScore UCTSearch::performPlayout(GameState & state)\n{\n    GameState copy(state);\n    copy.finishedMoving();\n\n    return copy.eval(_params.maxPlayer(), _params.evalMethod(), _params.simScript(Players::Player_One), _params.simScript(Players::Player_Two));\n}\n\nconst bool UCTSearch::isRoot(UCTNode & node) const\n{\n    return &node == &_rootNode;\n}\n\nvoid UCTSearch::printSubTree(UCTNode & node, GameState s, std::string filename)\n{\n    std::ofstream out(filename.c_str());\n\n    GraphViz::Graph G(\"g\");\n    G.set(\"bgcolor\", \"#ffffff\");\n\n    printSubTreeGraphViz(node, G, s);\n\n    G.print(out);\n}\n\nvoid UCTSearch::printSubTreeGraphViz(UCTNode & node, GraphViz::Graph & g, GameState state)\n{\n    if (node.getNodeType() == SearchNodeType::FirstSimNode && node.hasChildren())\n    {\n        // don't make any moves if it is a first simnode\n    }\n    else\n    {\n        if (node.getNodeType() == SearchNodeType::SecondSimNode)\n        {\n            state.makeMoves(node.getParent()->getMove());\n        }\n\n        state.makeMoves(node.getMove());\n        state.finishedMoving();\n    }\n\n    std::stringstream label;\n    std::stringstream move;\n\n    for (size_t a(0); a<node.getMove().size(); ++a)\n    {\n        move << node.getMove()[a].moveString() << \"\\\\n\";\n    }\n\n    if (node.getMove().size() == 0)\n    {\n        move << \"root\";\n    }\n\n    std::string firstSim = SearchNodeType::getName(node.getNodeType());\n\n    Unit p1 = state.getUnit(0,0);\n    Unit p2 = state.getUnit(1,0);\n\n    label   << move.str() \n            << \"\\\\nVal: \"       << node.getUCTVal() \n            << \"\\\\nWins: \"      << node.numWins() \n            << \"\\\\nVisits: \"    << node.numVisits() \n            << \"\\\\nChildren: \"  << node.numChildren() \n            << \"\\\\n\"            << firstSim\n            << \"\\\\nPtr: \"       << &node\n            << \"\\\\n---------------\"\n            << \"\\\\nFrame: \" << state.getTime()\n            << \"\\\\nHP: \" << p1.currentHP() << \"  \" << p2.currentHP()\n            << \"\\\\nAtk: \" << p1.nextAttackActionTime() << \"  \" << p2.nextAttackActionTime()\n            << \"\\\\nMove: \" << p1.nextMoveActionTime() << \"  \" << p2.nextMoveActionTime()\n            << \"\\\\nPrev: \" << p1.previousActionTime() << \"  \" << p2.previousActionTime();\n    \n    std::string fillcolor       (\"#aaaaaa\");\n\n    if (node.getPlayer() == Players::Player_One)\n    {\n        fillcolor = \"#ff0000\";\n    }\n    else if (node.getPlayer() == Players::Player_Two)\n    {\n        fillcolor = \"#00ff00\";\n    }\n    \n    GraphViz::Node n(getNodeIDString(node));\n    n.set(\"label\",      label.str());\n    n.set(\"fillcolor\",  fillcolor);\n    n.set(\"color\",      \"#000000\");\n    n.set(\"fontcolor\",  \"#000000\");\n    n.set(\"style\",      \"filled,bold\");\n    n.set(\"shape\",      \"box\");\n    g.addNode(n);\n\n    // recurse for each child\n    for (size_t c(0); c<node.numChildren(); ++c)\n    {\n        UCTNode & child = node.getChild(c);\n        if (child.numVisits() > 0)\n        {\n            GraphViz::Edge edge(getNodeIDString(node), getNodeIDString(child));\n            g.addEdge(edge);\n            printSubTreeGraphViz(child, g, state);\n        }\n    }\n}\n \nstd::string UCTSearch::getNodeIDString(UCTNode & node)\n{\n    std::stringstream ss;\n    ss << (unsigned long long)&node;\n    return ss.str();\n}\n\nUCTSearchResults & UCTSearch::getResults()\n{\n    return _results;\n}"
  },
  {
    "path": "SparCraft/source/UCTSearch.h",
    "content": "#pragma once\n\n#include <limits>\n\n#include \"Timer.h\"\n#include \"GameState.h\"\n#include \"Action.h\"\n#include \"GraphViz.hpp\"\n#include \"Array.hpp\"\n#include \"MoveArray.h\"\n#include \"UCTSearchParameters.hpp\"\n#include \"UCTSearchResults.hpp\"\n#include \"Player.h\"\n#include \"AllPlayers.h\"\n#include \"UCTNode.h\"\n#include \"GraphViz.hpp\"\n#include \"UCTMemoryPool.hpp\"\n#include <memory>\n\nnamespace SparCraft\n{\n\nclass Game;\nclass Player;\n\nclass UCTSearch\n{\n\tUCTSearchParameters \t_params;\n    UCTSearchResults        _results;\n\tTimer\t\t            _searchTimer;\n    UCTNode                 _rootNode;\n    UCTMemoryPool *         _memoryPool;\n\n    GameState               _currentState;\n\n\t// we will use these as variables to save stack allocation every time\n    std::vector<Action>                 _actionVec;\n\tMoveArray                               _moveArray;\n\tArray<std::vector<Action>,\n\t\t Constants::Max_Ordered_Moves>      _orderedMoves;\n\n    std::vector<PlayerPtr>\t\t\t\t\t_allScripts[Constants::Num_Players];\n    PlayerPtr                               _playerModels[Constants::Num_Players];\n\npublic:\n\n\tUCTSearch(const UCTSearchParameters & params);\n\n    \n    // UCT-specific functions\n    UCTNode &       UCTNodeSelect(UCTNode & parent);\n    StateEvalScore  traverse(UCTNode & node, GameState & currentState);\n\tvoid            uct(GameState & state, size_t depth, const size_t lastPlayerToMove, std::vector<Action> * firstSimMove);\n\n\tvoid            doSearch(GameState & initialState, std::vector<Action> & move);\n    \n    // Move and Child generation functions\n    void            generateChildren(UCTNode & node, GameState & state);\n\tvoid            generateOrderedMoves(GameState & state, MoveArray & moves, const size_t & playerToMove);\n    void            makeMove(UCTNode & node, GameState & state);\n\tconst bool      getNextMove(size_t playerToMove, MoveArray & moves, const size_t & moveNumber, std::vector<Action> & actionVec);\n\n    // Utility functions\n\tconst size_t    getPlayerToMove(UCTNode & node, const GameState & state) const;\n    const size_t    getChildNodeType(UCTNode & parent, const GameState & prevState) const;\n\tconst bool      searchTimeOut();\n\tconst bool      isRoot(UCTNode & node) const;\n\tconst bool      terminalState(GameState & state, const size_t & depth) const;\n    const bool      isFirstSimMove(UCTNode & node, GameState & state);\n    const bool      isSecondSimMove(UCTNode & node, GameState & state);\n    StateEvalScore  performPlayout(GameState & state);\n    void            updateState(UCTNode & node, GameState & state, bool isLeaf);\n    void            setMemoryPool(UCTMemoryPool * pool);\n    UCTSearchResults & getResults();\n\n    // graph printing functions\n    void            printSubTree(UCTNode & node, GameState state, std::string filename);\n    void            printSubTreeGraphViz(UCTNode & node, GraphViz::Graph & g, GameState state);\n    std::string     getNodeIDString(UCTNode & node);\n};\n}"
  },
  {
    "path": "SparCraft/source/UCTSearchParameters.hpp",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace SparCraft\n{\n    class UCTSearchParameters;\n\n    namespace UCTMoveSelect\n    {\n        enum { HighestValue, MostVisited };\n    }\n}\n\nclass SparCraft::UCTSearchParameters\n{\t\t\t\t\t\t\t\t\t\t\t        // DEFAULT\t\t\t\tDESCRIPTION\n    size_t\t\t    _maxPlayer;\t\t\t\t\t    // Player_One\t\t\tThe player who will make maximizing moves\n    size_t          _rootMoveSelection;             // MostVisited          Which node to pick from the root\n\n\tsize_t\t\t    _timeLimit;\t\t\t\t\t    // 0\t\t\t\t\tSearch time limit. 0 means no time limit\n    double          _cValue;                        // 1                    C constant for UCT formula\n    size_t          _maxTraversals;                 // 100                  Max number of UCT traversals to make\n    size_t          _maxChildren;                   // 10                   Max children at each node\n    size_t          _moveOrdering;                  // ScriptFirst          Move ordering method for child generation\n\tsize_t\t\t    _evalMethod;\t\t\t\t    // LTD\t\t\t\tEvaluation function type\n    size_t          _simScripts[2];                 // NOKDPS               Policy to use for playouts\n\tsize_t\t\t    _playerToMoveMethod;\t\t    // Alternate\t\t\tThe player to move policy\n\tsize_t\t\t    _playerModel[2];                // None                 Player model to use for each player\n\n    std::string     _graphVizFilename;              // \"\"                   File name to output graph viz file\n\n    std::vector<size_t> _orderedMoveScripts;\n\n    std::vector<std::vector<std::string> > _desc;    // 2-column description vector\n\npublic:\n\n\t// default constructor\n\tUCTSearchParameters() \n\t    : _maxPlayer            (Players::Player_One)\n        , _rootMoveSelection    (UCTMoveSelect::MostVisited)\n\t    , _timeLimit            (0)\n        , _cValue               (1)\n        , _maxTraversals        (100)\n        , _maxChildren          (10)\n        , _moveOrdering         (MoveOrderMethod::ScriptFirst)\n        , _evalMethod           (SparCraft::EvaluationMethods::Playout)\n\t    , _playerToMoveMethod   (SparCraft::PlayerToMove::Alternate)\n    {\n\t    setPlayerModel(Players::Player_One, PlayerModels::None);\n\t    setPlayerModel(Players::Player_Two, PlayerModels::None);\n        setSimScripts(PlayerModels::NOKDPS, PlayerModels::NOKDPS);\n    }\n\n    const size_t & maxPlayer()\t\t\t\t\t\t\t        const   { return _maxPlayer; }\n    const size_t & timeLimit()\t\t\t\t\t\t\t        const   { return _timeLimit; }\n    const double & cValue()\t\t\t\t\t\t\t            const   { return _cValue; }\n    const size_t & maxTraversals()\t\t\t\t\t\t        const   { return _maxTraversals; }\n    const size_t & maxChildren()                                const   { return _maxChildren; }\n    const size_t & moveOrderingMethod()                         const   { return _moveOrdering; }\n    const size_t & evalMethod()\t\t\t\t\t\t            const   { return _evalMethod; }\n    const size_t & simScript(const size_t & player)             const   { return _simScripts[player]; }\n    const size_t & playerToMoveMethod()\t\t\t\t            const   { return _playerToMoveMethod; }\n    const size_t & playerModel(const size_t & player)\t        const   { return _playerModel[player]; }\n    const size_t & rootMoveSelectionMethod()                    const   { return _rootMoveSelection; }\n    const std::string & graphVizFilename()                      const   { return _graphVizFilename; }\n    const std::vector<size_t> & getOrderedMoveScripts()         const   { return _orderedMoveScripts; }\n\t\n    void setMaxPlayer(const size_t & player)\t\t\t\t\t        { _maxPlayer = player; }\n    void setTimeLimit(const size_t & timeLimit)\t\t\t\t\t        { _timeLimit = timeLimit; }  \n    void setCValue(const double & c)\t\t\t\t\t                { _cValue = c; }\n    void setMaxTraversals(const size_t & traversals)                    { _maxTraversals = traversals; }\n    void setMaxChildren(const size_t & children)                        { _maxChildren = children; }\n    void setMoveOrderingMethod(const size_t & method)                   { _moveOrdering = method; }\n    void setEvalMethod(const size_t & eval)\t\t\t\t\t\t        { _evalMethod = eval; }\n    void setPlayerToMoveMethod(const size_t & method)\t\t\t\t    { _playerToMoveMethod = method; }\n    void setSimScripts(const size_t & p1, const size_t & p2)\t\t    { _simScripts[0] = p1; _simScripts[1] = p2; }\n    void setRootMoveSelectionMethod(const size_t & method)              { _rootMoveSelection = method; }\n    void setGraphVizFilename(const std::string & filename)              { _graphVizFilename = filename; }\n    void addOrderedMoveScript(const size_t & script)                    { _orderedMoveScripts.push_back(script); }\n    void setPlayerModel(const size_t & player, const size_t & model)\t{ _playerModel[player] = model; }\t\n\n    std::vector<std::vector<std::string> > & getDescription()\n    {\n        if (_desc.size() == 0)\n        {\n            _desc.push_back(std::vector<std::string>());\n            _desc.push_back(std::vector<std::string>());\n\n            std::stringstream ss;\n\n            _desc[0].push_back(\"Player Type:\");\n            _desc[0].push_back(\"Time Limit:\");\n            _desc[0].push_back(\"C Value:\");\n            _desc[0].push_back(\"Max Traversals:\");\n            _desc[0].push_back(\"Max Children:\");\n            _desc[0].push_back(\"Move Ordering:\");\n            _desc[0].push_back(\"Player To Move:\");\n            _desc[0].push_back(\"Opponent Model:\");\n\n            ss << \"UCT\";                                                _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << timeLimit() << \"ms\";                                  _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << cValue();                                             _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << maxTraversals();                                      _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << maxChildren();                                        _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << MoveOrderMethod::getName(moveOrderingMethod());         _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << PlayerToMove::getName(playerToMoveMethod());            _desc[1].push_back(ss.str()); ss.str(std::string());\n            ss << PlayerModels::getName(playerModel((maxPlayer()+1)%2));  _desc[1].push_back(ss.str()); ss.str(std::string());\n        }\n        \n        return _desc;\n    }\n};\n"
  },
  {
    "path": "SparCraft/source/UCTSearchResults.hpp",
    "content": "#pragma once\n\n#include <vector>\n#include \"Action.h\"\n\nnamespace SparCraft\n{\nclass UCTSearchResults\n{\n\npublic:\n\n\tunsigned long long          nodesExpanded;\t// number of nodes expanded in the search\n\tdouble                      timeElapsed;\t// time elapsed in milliseconds\n\n    int                         traversals;\n    int                         traverseCalls;\n    int                         nodesVisited;\n    int                         totalVisits;\n    int                         nodesCreated;\n\n    std::vector<Action>     bestMoves;\n\tScoreType                   abValue;\n\t\n    std::vector<std::vector<std::string> > _desc;    // 2-column description vector\n\n\tUCTSearchResults() \n\t\t: nodesExpanded         (0)\n\t\t, timeElapsed           (0)\n        , traversals            (0)\n        , traverseCalls         (0)\n        , nodesVisited          (0)\n        , totalVisits           (0)\n        , nodesCreated          (0)\n\t\t, abValue               (0)\n\t{\n\t}\n\n    std::vector<std::vector<std::string> > & getDescription()\n    {\n        _desc.clear();\n        _desc.push_back(std::vector<std::string>());\n        _desc.push_back(std::vector<std::string>());\n\n        std::stringstream ss;\n\n        _desc[0].push_back(\"Traversals: \");\n        _desc[0].push_back(\"Nodes Visited: \");\n        _desc[0].push_back(\"Total Visits: \");\n        _desc[0].push_back(\"Nodes Created: \");\n\n        ss << traversals;       _desc[1].push_back(ss.str()); ss.str(std::string());\n        ss << nodesVisited;     _desc[1].push_back(ss.str()); ss.str(std::string());\n        ss << totalVisits;      _desc[1].push_back(ss.str()); ss.str(std::string());\n        ss << nodesCreated;     _desc[1].push_back(ss.str()); ss.str(std::string());\n        \n        return _desc;\n    }\n};\n}"
  },
  {
    "path": "SparCraft/source/Unit.cpp",
    "content": "#include \"Unit.h\"\n\nusing namespace SparCraft;\n\nUnit::Unit()\n    : _unitType             (BWAPI::UnitTypes::None)\n    , _range                (0)\n    , _unitID               (255)\n    , _playerID             (255)\n    , _currentHP            (0)\n    , _currentEnergy        (0)\n    , _timeCanMove          (0)\n    , _timeCanAttack        (0)\n    , _previousActionTime   (0)\n    , _prevCurrentPosTime   (0)\n{\n    \n}\n\n// test constructor for setting all variables of a unit\nUnit::Unit(const BWAPI::UnitType unitType, const Position & pos, const size_t & unitID, const size_t & playerID, \n           const HealthType & hp, const HealthType & energy, const TimeType & tm, const TimeType & ta) \n    : _unitType             (unitType)\n    , _range                (PlayerWeapon(&PlayerProperties::Get(playerID), unitType.groundWeapon()).GetMaxRange() + Constants::Range_Addition)\n    , _position             (pos)\n    , _unitID               (unitID)\n    , _playerID             (playerID)\n    , _currentHP            (hp)\n    , _currentEnergy        (energy)\n    , _timeCanMove          (tm)\n    , _timeCanAttack        (ta)\n    , _previousActionTime   (0)\n    , _prevCurrentPosTime   (0)\n    , _previousPosition     (pos)\n    , _prevCurrentPos       (pos)\n{\n    System::checkSupportedUnitType(unitType);\n}\n\n// constructor for units to construct basic units, sets some things automatically\nUnit::Unit(const BWAPI::UnitType unitType, const size_t & playerID, const Position & pos) \n    : _unitType             (unitType)\n    , _range                (PlayerWeapon(&PlayerProperties::Get(playerID), unitType.groundWeapon()).GetMaxRange() + Constants::Range_Addition)\n    , _position             (pos)\n    , _unitID               (0)\n    , _playerID             (playerID)\n    , _currentHP            (maxHP())\n    , _currentEnergy        (unitType == BWAPI::UnitTypes::Terran_Medic ? Constants::Starting_Energy : 0)\n    , _timeCanMove          (0)\n    , _timeCanAttack        (0)\n    , _previousActionTime   (0)\n    , _prevCurrentPosTime   (0)\n    , _previousPosition     (pos)\n    , _prevCurrentPos       (pos)\n{\n    System::checkSupportedUnitType(unitType);\n}\n\n// Less than operator, used for sorting the GameState unit array.\n// Units are sorted in this order:\n//\t\t1) alive < dead\n//\t\t2) firstTimeFree()\n//\t\t3) currentHP()\n//\t\t4) pos()\nconst bool Unit::operator < (const Unit & rhs) const\n{\n    if (!isAlive())\n    {\n        return false;\n    }\n    else if (!rhs.isAlive())\n    {\n        return true;\n    }\n\n    if (firstTimeFree() == rhs.firstTimeFree())\n    {\n        return ID() < rhs.ID();\n    }\n    else\n    {\n        return firstTimeFree() < rhs.firstTimeFree();\n    }\n\n    /*if (firstTimeFree() == rhs.firstTimeFree())\n    {\n        if (currentHP() == rhs.currentHP())\n        {\n            return pos() < rhs.pos();\n        }\n        else\n        {\n            return currentHP() < rhs.currentHP();\n        }\n    }\n    else\n    {\n        return firstTimeFree() < rhs.firstTimeFree();\n    }*/\n}\n\n// compares a unit based on unit id\nconst bool Unit::equalsID(const Unit & rhs) const\n{ \n    return _unitID == rhs._unitID; \n}\n// returns whether or not this unit can see a given unit at a given time\nbool Unit::canSeeTarget(const Unit & unit, const TimeType & gameTime) const\n{\n\n\t// range of this unit attacking\n\tPositionType r = type().sightRange();\n\n\t// return whether the target unit is in range\n\treturn (r * r) >= getDistanceSqToUnit(unit, gameTime);\n}\n\n// returns whether or not this unit can attack a given unit at a given time\nconst bool Unit::canAttackTarget(const Unit & unit, const TimeType & gameTime) const\n{\n    BWAPI::WeaponType weapon = unit.type().isFlyer() ? type().airWeapon() : type().groundWeapon();\n\n    if (weapon.damageAmount() == 0)\n    {\n        return false;\n    }\n\n    // range of this unit attacking\n    PositionType r = range();\n\n    // return whether the target unit is in range\n    return (r * r) >= getDistanceSqToUnit(unit, gameTime);\n}\n\nconst bool Unit::canHealTarget(const Unit & unit, const TimeType & gameTime) const\n{\n    // if the unit can't heal or the target unit is not on the same team\n    if (!canHeal() || !unit.isOrganic() || !(unit.player() == player()) || (unit.currentHP() == unit.maxHP()))\n    {\n        // then it can't heal the target\n        return false;\n    }\n\n    // range of this unit attacking\n    PositionType r = healRange();\n\n    // return whether the target unit is in range\n    return (r * r) >= getDistanceSqToUnit(unit, gameTime);\n}\n\nconst Position & Unit::position() const\n{\n    return _position;\n}\n\n// take an attack, subtract the hp\nvoid Unit::takeAttack(const Unit & attacker)\n{\n    PlayerWeapon    weapon(attacker.getWeapon(*this));\n    HealthType      damage(weapon.GetDamageBase());\n\n    // calculate the damage based on armor and damage types\n    damage = std::max((int)((damage-getArmor()) * weapon.GetDamageMultiplier(getSize())), 2);\n    \n    // special case where units attack multiple times\n    if (attacker.type() == BWAPI::UnitTypes::Protoss_Zealot || attacker.type() == BWAPI::UnitTypes::Terran_Firebat)\n    {\n        damage *= 2;\n    }\n\n    //std::cout << type().getName() << \" took \" << (int)attacker.player() << \" \" << damage << \"\\n\";\n\n    updateCurrentHP(_currentHP - damage);\n}\n\nvoid Unit::takeHeal(const Unit & healer)\n{\n    updateCurrentHP(_currentHP + healer.healAmount());\n}\n\n// returns whether or not this unit is alive\nconst bool Unit::isAlive() const\n{\n    return _currentHP > 0;\n}\n\n// attack a unit, set the times accordingly\nvoid Unit::attack(const Action & move, const Unit & target, const TimeType & gameTime)\n{\n    // if this is a repeat attack\n    if (_previousAction.type() == ActionTypes::ATTACK || _previousAction.type() == ActionTypes::RELOAD)\n    {\n        // add the repeat attack animation duration\n        // can't attack again until attack cooldown is up\n        updateMoveActionTime      (gameTime + attackRepeatFrameTime());\n        updateAttackActionTime    (gameTime + attackCooldown());\n    }\n    // if there previous action was a MOVE action, add the move penalty\n    else if (_previousAction.type() == ActionTypes::MOVE)\n    {\n        updateMoveActionTime      (gameTime + attackInitFrameTime() + 2);\n        updateAttackActionTime    (gameTime + attackCooldown() + Constants::Move_Penalty);\n    }\n    else\n    {\n        // add the initial attack animation duration\n        updateMoveActionTime      (gameTime + attackInitFrameTime() + 2);\n        updateAttackActionTime    (gameTime + attackCooldown());\n    }\n\n    // if the unit is not mobile, set its next move time to its next attack time\n    if (!isMobile())\n    {\n        updateMoveActionTime(_timeCanAttack);\n    }\n\n    setPreviousAction(move, gameTime);\n}\n\n// attack a unit, set the times accordingly\nvoid Unit::heal(const Action & move, const Unit & target, const TimeType & gameTime)\n{\n    _currentEnergy -= healCost();\n\n    // can't attack again until attack cooldown is up\n    updateAttackActionTime        (gameTime + healCooldown());\n    updateMoveActionTime          (gameTime + healCooldown());\n\n    if (currentEnergy() < healCost())\n    {\n        updateAttackActionTime(1000000);\n    }\n\n    setPreviousAction(move, gameTime);\n}\n\n// unit update for moving based on a given Move\nvoid Unit::move(const Action & move, const TimeType & gameTime) \n{\n    _previousPosition = pos();\n\n    // get the distance to the move action destination\n    PositionType dist = move.pos().getDistance(pos());\n    \n    // how long will this move take?\n    TimeType moveDuration = (TimeType)((double)dist / speed());\n\n    // update the next time we can move, make sure a move always takes 1 time step\n    updateMoveActionTime(gameTime + std::max(moveDuration, 1));\n\n    // assume we need 4 frames to turn around after moving\n    updateAttackActionTime(std::max(nextAttackActionTime(), nextMoveActionTime()));\n\n    // update the position\n    //_position.addPosition(dist * dir.x(), dist * dir.y());\n    _position.moveTo(move.pos());\n\n    setPreviousAction(move, gameTime);\n}\n\n// unit is commanded to wait until his attack cooldown is up\nvoid Unit::waitUntilAttack(const Action & move, const TimeType & gameTime)\n{\n    // do nothing until we can attack again\n    updateMoveActionTime(_timeCanAttack);\n    setPreviousAction(move, gameTime);\n}\n\nvoid Unit::pass(const Action & move, const TimeType & gameTime)\n{\n    updateMoveActionTime(gameTime + Constants::Pass_Move_Duration);\n    updateAttackActionTime(gameTime + Constants::Pass_Move_Duration);\n    setPreviousAction(move, gameTime);\n}\n\nconst PositionType Unit::getDistanceSqToUnit(const Unit & u, const TimeType & gameTime) const \n{ \n    return getDistanceSqToPosition(u.currentPosition(gameTime), gameTime); \n}\n\nconst PositionType Unit::getDistanceSqToPosition(const Position & p, const TimeType & gameTime) const\t\n{ \n    return currentPosition(gameTime).getDistanceSq(p);\n}\n\n// returns current position based on game time\nconst Position & Unit::currentPosition(const TimeType & gameTime) const\n{\n    // if the previous move was MOVE, then we need to calculate where the unit is now\n    if (_previousAction.type() == ActionTypes::MOVE)\n    {\n        // if gameTime is equal to previous move time then we haven't moved yet\n        if (gameTime == _previousActionTime)\n        {\n            return _previousPosition;\n        }\n        // else if game time is >= time we can move, then we have arrived at the destination\n        else if (gameTime >= _timeCanMove)\n        {\n            return _position;\n        }\n        // otherwise we are still moving, so calculate the current position\n        else if (gameTime == _prevCurrentPosTime)\n        {\n            return _prevCurrentPos;\n        }\n        else\n        {\n            TimeType moveDuration = _timeCanMove - _previousActionTime;\n            float moveTimeRatio = (float)(gameTime - _previousActionTime) / moveDuration;\n            _prevCurrentPosTime = gameTime;\n\n            // calculate the new current position\n            _prevCurrentPos = _position;\n            _prevCurrentPos.subtractPosition(_previousPosition);\n            _prevCurrentPos.scalePosition(moveTimeRatio);\n            _prevCurrentPos.addPosition(_previousPosition);\n\n            //_prevCurrentPos = _previousPosition + (_position - _previousPosition).scale(moveTimeRatio);\n            return _prevCurrentPos;\n        }\n    }\n    // if it wasn't a MOVE, then we just return the Unit position\n    else\n    {\n        return _position;\n    }\n}\n\nvoid Unit::setPreviousPosition(const TimeType & gameTime)\n{\n    TimeType moveDuration = _timeCanMove - _previousActionTime;\n    float moveTimeRatio = (float)(gameTime - _previousActionTime) / moveDuration;\n    _prevCurrentPosTime = gameTime;\n    _prevCurrentPos = _previousPosition + (_position - _previousPosition).scale(moveTimeRatio);\n}\n\n// returns the damage a unit does\nconst HealthType Unit::damage() const\t\n{ \n    return _unitType == BWAPI::UnitTypes::Protoss_Zealot ? \n        2 * (HealthType)_unitType.groundWeapon().damageAmount() : \n    (HealthType)_unitType.groundWeapon().damageAmount(); \n}\n\nconst HealthType Unit::healAmount() const\n{\n    return canHeal() ? 6 : 0;\n}\n\nvoid Unit::print() const \n{ \n    printf(\"%s %5d [%5d %5d] (%5d, %5d)\\n\", _unitType.getName().c_str(), currentHP(), nextAttackActionTime(), nextMoveActionTime(), x(), y()); \n}\n\nvoid Unit::updateCurrentHP(const HealthType & newHP) \n{ \n    _currentHP = std::min(maxHP(), newHP); \n}\n\nvoid Unit::updateAttackActionTime(const TimeType & newTime)\n{ \n    _timeCanAttack = newTime; \n}\n\nvoid Unit::updateMoveActionTime(const TimeType & newTime)\n{ \n    _timeCanMove = newTime; \n} \n\nvoid Unit::setCooldown(TimeType attack, TimeType move)\n{ \n    _timeCanAttack = attack; _timeCanMove = move; \n}\n\nvoid Unit::setUnitID(const size_t & id)\n{ \n    _unitID = id; \n}\n\nvoid Unit::setPreviousAction(const Action & m, const TimeType & previousMoveTime) \n{\t\n    // if it was an attack move, store the unitID of the opponent unit\n    _previousAction = m;\n    _previousActionTime = previousMoveTime; \n}\n\nconst bool Unit::canAttackNow() const\n{ \n    return !canHeal() && _timeCanAttack <= _timeCanMove; \n}\n\nconst bool Unit::canMoveNow() const\n{ \n    return isMobile() && _timeCanMove <= _timeCanAttack; \n}\n\nconst bool Unit::canHealNow() const\n{ \n    return canHeal() && (currentEnergy() >= healCost()) && (_timeCanAttack <= _timeCanMove); \n}\n\nconst bool Unit::canKite() const\n{ \n    return _timeCanMove < _timeCanAttack; \n}\n\nconst bool Unit::isMobile() const\n{ \n    return _unitType.canMove(); \n}\n\nconst bool Unit::canHeal() const\n{ \n    return _unitType == BWAPI::UnitTypes::Terran_Medic; \n}\n\nconst bool Unit::isOrganic() const\n{ \n    return _unitType.isOrganic(); \n}\n\nconst size_t Unit::ID() const\t\n{ \n    return _unitID; \n}\n\nconst size_t Unit::player() const\n{ \n    return _playerID; \n}\n\nconst Position & Unit::pos() const\n{ \n    return _position; \n}\n\nconst PositionType Unit::x() const \n{ \n    return _position.x(); \n}\n\nconst PositionType Unit::y() const \n{ \n    return _position.y(); \n}\n\nconst PositionType Unit::range() const \n{ \n    return _range; \n}\n\nconst PositionType Unit::healRange() const\n{ \n    return canHeal() ? 96 : 0; \n}\n\nconst HealthType Unit::maxHP() const \n{ \n    return (HealthType)_unitType.maxHitPoints() + (HealthType)_unitType.maxShields(); \n}\n\nconst HealthType Unit::currentHP() const \n{ \n    return (HealthType)_currentHP; \n}\n\nconst HealthType Unit::currentEnergy() const \n{ \n    return (HealthType)_currentEnergy; \n}\n\nconst HealthType Unit::maxEnergy() const\n{ \n    return (HealthType)_unitType.maxEnergy(); \n}\n\nconst HealthType Unit::healCost() const\t\n{ \n    return 3; \n}\n\nconst float Unit::dpf() const \n{ \n    return (float)std::max(Constants::Min_Unit_DPF, (float)damage() / ((float)attackCooldown() + 1)); \n}\n\nconst TimeType Unit::moveCooldown() const \n{ \n    return (TimeType)((double)Constants::Move_Distance / _unitType.topSpeed()); \n}\n\nconst TimeType Unit::attackCooldown() const \n{ \n    return (TimeType)_unitType.groundWeapon().damageCooldown(); \n}\n\nconst TimeType Unit::healCooldown() const \n{ \n    return (TimeType)8; \n}\n\nconst TimeType Unit::nextAttackActionTime() const \n{ \n    return _timeCanAttack; \n}\n\nconst TimeType Unit::nextMoveActionTime() const\t\n{ \n    return _timeCanMove; \n}\n\nconst TimeType Unit::previousActionTime() const\t\n{ \n    return _previousActionTime; \n}\n\nconst TimeType Unit::firstTimeFree() const\t\n{ \n    return _timeCanAttack <= _timeCanMove ? _timeCanAttack : _timeCanMove; \n}\n\nconst TimeType Unit::attackInitFrameTime() const\t\n{ \n    return AnimationFrameData::getAttackFrames(_unitType).first; \n}\n\nconst TimeType Unit::attackRepeatFrameTime() const\t\n{\n    return AnimationFrameData::getAttackFrames(_unitType).second; \n}\n\nconst int Unit::typeID() const\t\n{ \n    return _unitType.getID(); \n}\n\nconst double Unit::speed() const \n{ \n    return _unitType.topSpeed(); \n}\n\nconst BWAPI::UnitType Unit::type() const \n{ \n    return _unitType; \n}\n\nconst Action & Unit::previousAction() const \n{ \n    return _previousAction; \n}\n\nconst BWAPI::UnitSizeType Unit::getSize() const\n{\n    return _unitType.size();\n}\n\nconst PlayerWeapon Unit::getWeapon(const Unit & target) const\n{\n    return PlayerWeapon(&PlayerProperties::Get(player()), target.type().isFlyer() ? _unitType.airWeapon() : _unitType.groundWeapon());\n}\n\nconst HealthType Unit::getArmor() const\n{\n    return UnitProperties::Get(type()).GetArmor(PlayerProperties::Get(player())); \n}\n\nconst BWAPI::WeaponType Unit::getWeapon(BWAPI::UnitType target) const\n{\n    return target.isFlyer() ? _unitType.airWeapon() : _unitType.groundWeapon();\n}\n\nconst std::string Unit::name() const \n{ \n    std::string n(_unitType.getName());\n    std::replace(n.begin(), n.end(), ' ', '_');\n    return n;\n}\n\n// calculates the hash of this unit based on a given game time\nconst HashType Unit::calculateHash(const size_t & hashNum, const TimeType & gameTime) const\n{\n    Position currentPos = currentPosition(gameTime);\n\n    return\t  Hash::values[hashNum].positionHash(_playerID, currentPos.x(), currentPos.y()) \n            ^ Hash::values[hashNum].getAttackHash(_playerID, nextAttackActionTime() - gameTime) \n            ^ Hash::values[hashNum].getMoveHash(_playerID, nextMoveActionTime() - gameTime)\n            ^ Hash::values[hashNum].getCurrentHPHash(_playerID, currentHP())\n            ^ Hash::values[hashNum].getUnitTypeHash(_playerID, typeID());\n}\n\n// calculates the hash of this unit based on a given game time, and prints debug info\nvoid Unit::debugHash(const size_t & hashNum, const TimeType & gameTime) const\n{\n    std::cout << \" Pos   \" << Hash::values[hashNum].positionHash(_playerID, position().x(), position().y());\n    std::cout << \" Att   \" << Hash::values[hashNum].getAttackHash(_playerID, nextAttackActionTime() - gameTime);\n    std::cout << \" Mov   \" << Hash::values[hashNum].getMoveHash(_playerID, nextMoveActionTime() - gameTime);\n    std::cout << \" HP    \" << Hash::values[hashNum].getCurrentHPHash(_playerID, currentHP());\n    std::cout << \" Typ   \" << Hash::values[hashNum].getUnitTypeHash(_playerID, typeID()) << \"\\n\";;\n\n    HashType hash = Hash::values[hashNum].positionHash(_playerID, position().x(), position().y()); std::cout << hash << \"\\n\";\n    hash ^= Hash::values[hashNum].getAttackHash(_playerID, nextAttackActionTime() - gameTime) ; std::cout << hash << \"\\n\";\n    hash ^= Hash::values[hashNum].getMoveHash(_playerID, nextMoveActionTime() - gameTime); std::cout << hash << \"\\n\";\n    hash ^= Hash::values[hashNum].getCurrentHPHash(_playerID, currentHP()); std::cout << hash << \"\\n\";\n    hash ^= Hash::values[hashNum].getUnitTypeHash(_playerID, typeID()); std::cout << hash << \"\\n\";\n}\n\nconst std::string Unit::debugString() const\n{\n    std::stringstream ss;\n\n    ss << \"Unit Type:           \" << type().getName()                               << \"\\n\";\n    ss << \"Unit ID:             \" << (int)ID()                                      << \"\\n\";\n    ss << \"Player:              \" << (int)player()                                  << \"\\n\";\n    ss << \"Range:               \" << range()                                        << \"\\n\";\n    ss << \"Position:            \" << \"(\" << _position.x() << \",\" << _position.y()   << \")\\n\";\n    ss << \"Current HP:          \" << currentHP()                                    << \"\\n\";\n    ss << \"Next Move Time:      \" << nextMoveActionTime()                           << \"\\n\";\n    ss << \"Next Attack Time:    \" << nextAttackActionTime()                         << \"\\n\";\n    ss << \"Previous Action:     \" << previousAction().debugString()                 << \"\\n\";\n    ss << \"Previous Pos Time:   \" << _prevCurrentPosTime                            << \"\\n\";\n    ss << \"Previous Pos:        \" << \"(\" << _prevCurrentPos.x() << \",\" << _prevCurrentPos.y()   << \")\\n\";\n\n    return ss.str();\n}"
  },
  {
    "path": "SparCraft/source/Unit.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\n#include \"Action.h\"\n#include \"Position.hpp\"\n#include \"Hash.h\"\n#include \"PlayerProperties.h\"\n#include \"UnitProperties.h\"\n#include \"AnimationFrameData.h\"\n#include <iostream>\n\nnamespace SparCraft\n{\n\nclass Action;\n\nclass Unit \n{\n    BWAPI::UnitType     _unitType;\t\t\t\t// the BWAPI unit type that we are mimicing\n    PositionType        _range;\n\t\n\tPosition            _position;\t\t\t\t// current location in a possibly infinite space\n\t\n\tsize_t              _unitID;\t\t\t\t// unique unit ID to the state it's contained in\n    size_t              _playerID;\t\t\t\t// the player who controls the unit\n\t\n\tHealthType          _currentHP;\t\t\t\t// current HP of the unit\n\tHealthType          _currentEnergy;\n\n\tTimeType            _timeCanMove;\t\t\t// time the unit can next move\n\tTimeType            _timeCanAttack;\t\t\t// time the unit can next attack\n\n\tAction              _previousAction;\t\t// the previous action that the unit performed\n\tTimeType            _previousActionTime;\t// the time the previous move was performed\n\tPosition            _previousPosition;\n\n    mutable TimeType    _prevCurrentPosTime;\n    mutable Position    _prevCurrentPos;\n\npublic:\n\n\tUnit();\n\tUnit(const BWAPI::UnitType unitType, const size_t & playerID, const Position & pos);\n\tUnit(const BWAPI::UnitType unitType, const Position & pos, const size_t & unitID, const size_t & playerID, \n\t\t const HealthType & hp, const HealthType & energy, const TimeType & tm, const TimeType & ta);\n\n\tconst bool operator < (const Unit & rhs) const;\n\n    // action functions\n\tvoid                    setPreviousAction(const Action & m, const TimeType & previousMoveTime);\n\tvoid                    updateAttackActionTime(const TimeType & newTime);\n\tvoid                    updateMoveActionTime(const TimeType & newTime);\n\tvoid                    attack(const Action & move, const Unit & target, const TimeType & gameTime);\n\tvoid                    heal(const Action & move, const Unit & target, const TimeType & gameTime);\n\tvoid                    move(const Action & move, const TimeType & gameTime) ;\n\tvoid                    waitUntilAttack(const Action & move, const TimeType & gameTime);\n\tvoid                    pass(const Action & move, const TimeType & gameTime);\n\tvoid                    takeAttack(const Unit & attacker);\n\tvoid                    takeHeal(const Unit & healer);\n\n\t// conditional functions\n\tconst bool\t\t\t    isMobile()                  const;\n\tconst bool\t\t\t    isOrganic()                 const;\n\tconst bool              isAlive()                   const;\n\tconst bool\t\t\t    canAttackNow()              const;\n\tconst bool\t\t\t    canMoveNow()                const;\n\tconst bool\t\t\t    canHealNow()                const;\n\tconst bool\t\t\t    canKite()                   const;\n\tconst bool\t\t\t    canHeal()                   const;\n\tconst bool              equalsID(const Unit & rhs)  const;\n\tbool\t\t\t\t\tcanSeeTarget(const Unit & unit, const TimeType & gameTime) const;\n\tconst bool              canAttackTarget(const Unit & unit, const TimeType & gameTime) const;\n\tconst bool              canHealTarget(const Unit & unit, const TimeType & gameTime) const;\n\n    // id related\n\tvoid                    setUnitID(const size_t & id);\n\tconst size_t\t\t    ID()                        const;\n\tconst size_t\t\t    player()                    const;\n\n    // position related functions\n\tconst Position &        position()                  const;\n\tconst Position &        pos()                       const;\n\tconst PositionType      x()                         const;\n\tconst PositionType      y()                         const;\n\tconst PositionType      range()                     const;\n\tconst PositionType      healRange()                 const;\n\tconst PositionType      getDistanceSqToUnit(const Unit & u, const TimeType & gameTime) const;\n\tconst PositionType      getDistanceSqToPosition(const Position & p, const TimeType & gameTime) const;\n    const Position &        currentPosition(const TimeType & gameTime) const;\n    void                    setPreviousPosition(const TimeType & gameTime);\n\n    // health and damage related functions\n\tconst HealthType        damage()                    const;\n\tconst HealthType        healAmount()                const;\n\tconst HealthType\t    maxHP()                     const;\n\tconst HealthType\t    currentHP()                 const;\n\tconst HealthType\t    currentEnergy()             const;\n\tconst HealthType\t    maxEnergy()                 const;\n\tconst HealthType\t    healCost()                  const;\n    const HealthType        getArmor()                  const;\n\tconst float\t\t\t    dpf()                       const;\n\tvoid                    updateCurrentHP(const HealthType & newHP);\n    const BWAPI::UnitSizeType getSize()                 const;\n    const BWAPI::WeaponType getWeapon(BWAPI::UnitType target) const;\n    const HealthType        getDamageTo(const Unit & unit) const;\n    const PlayerWeapon      getWeapon(const Unit & target) const;\n\n    // time and cooldown related functions\n\tconst TimeType\t\t    moveCooldown()              const;\n\tconst TimeType\t\t    attackCooldown()            const;\n\tconst TimeType\t\t    healCooldown()              const;\n\tconst TimeType\t\t    nextAttackActionTime()      const;\n\tconst TimeType\t\t    nextMoveActionTime()        const;\n\tconst TimeType\t\t    previousActionTime()        const;\n\tconst TimeType\t\t    firstTimeFree()             const;\n\tconst TimeType \t\t    attackInitFrameTime()       const;\n\tconst TimeType \t\t    attackRepeatFrameTime()     const;\n\tvoid                    setCooldown(TimeType attack, TimeType move);\n\n    // other functions\n\tconst int\t\t\t    typeID()                    const;\n\tconst double\t\t    speed()                     const;\n\tconst BWAPI::UnitType   type()                      const;\n\tconst Action &\t        previousAction()            const;\n\tconst std::string       name()                      const;\n\tvoid                    print()                     const;\n    const std::string       debugString()               const;\n\n\t// hash functions\n\tconst HashType          calculateHash(const size_t & hashNum, const TimeType & gameTime) const;\n\tvoid                    debugHash(const size_t & hashNum, const TimeType & gameTime) const;\n};\n\nclass UnitPtrCompare\n{\npublic:\n\tconst bool operator() (Unit * u1, Unit * u2) const\n\t{\n\t\treturn *u1 < *u2;\n\t}\n};\n}"
  },
  {
    "path": "SparCraft/source/UnitAction.hpp",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Position.hpp\"\n\nnamespace SparCraft\n{\n\nnamespace UnitActionTypes\n{\n\tenum {NONE, ATTACK, RELOAD, MOVE, PASS, HEAL};\n};\n\nclass UnitAction \n{\n\npublic:\n\n\tIDType\t\t\t_unit,\n\t\t\t\t\t_player,\n\t\t\t\t\t_moveType,\n\t\t\t\t\t_moveIndex;\n\n    Position        _p;\n\n\tUnitAction()\n\t\t: _unit(255)\n\t\t, _player(255)\n\t\t, _moveType(UnitActionTypes::NONE)\n\t\t, _moveIndex(255)\n\t{\n\n\t}\n\n    UnitAction( const IDType & unitIndex, const IDType & player, const IDType & type, const IDType & moveIndex, const Position & dest)\n        : _unit(unitIndex)\n        , _player(player)\n        , _moveType(type)\n        , _moveIndex(moveIndex)\n        , _p(dest)\n    {\n        \n    }\n\n\tUnitAction( const IDType & unitIndex, const IDType & player, const IDType & type, const IDType & moveIndex)\n\t\t: _unit(unitIndex)\n\t\t, _player(player)\n\t\t, _moveType(type)\n\t\t, _moveIndex(moveIndex)\n\t{\n\t\t\n\t}\n\n\tconst bool operator == (const UnitAction & rhs)\n\t{\n\t\treturn _unit == rhs._unit && _player == rhs._player && _moveType == rhs._moveType && _moveIndex == rhs._moveIndex && _p == rhs._p;\n\t}\n\n\tconst IDType & unit()\tconst\t{ return _unit; }\n\tconst IDType & player() const\t{ return _player; }\n\tconst IDType & type()\tconst\t{ return _moveType; }\n\tconst IDType & index()\tconst\t{ return _moveIndex; }\n    const Position & pos()  const   { return _p; }\n\n\tconst std::string moveString() const\n\t{\n\t\tif (_moveType == UnitActionTypes::ATTACK) \n\t\t{\n\t\t\treturn \"ATTACK\";\n\t\t}\n\t\telse if (_moveType == UnitActionTypes::MOVE)\n\t\t{\n\t\t\treturn \"MOVE\";\n\t\t}\n\t\telse if (_moveType == UnitActionTypes::RELOAD)\n\t\t{\n\t\t\treturn \"RELOAD\";\n\t\t}\n\t\telse if (_moveType == UnitActionTypes::PASS)\n\t\t{\n\t\t\treturn \"PASS\";\n\t\t}\n\t\telse if (_moveType == UnitActionTypes::HEAL)\n\t\t{\n\t\t\treturn \"HEAL\";\n\t\t}\n\n\t\treturn \"NONE\";\n\t}\n\n\tconst Position getDir() const\n\t{\n\t\treturn Position(Constants::Move_Dir[_moveIndex][0], Constants::Move_Dir[_moveIndex][1]);\n\t}\n\n    const std::string debugString() const\n    {\n        std::stringstream ss;\n        ss << moveString() << \": (\" << (int)unit() << \",\" << (int)player() << \",\" << (int)type() << \",\" << (int)index() << \")  \" << \"(\" << pos().x() << \",\" << pos().y()   << \")\";\n        return ss.str();\n    }\n};\n\n\nclass AlphaBetaMove\n{\n\tstd::vector<UnitAction> _move;\n\tbool _isValid;\n\npublic:\n\n\tAlphaBetaMove()\n        : _isValid(false)\n\t{\n\t}\n\n\tAlphaBetaMove(const std::vector<UnitAction> & move, const bool & isValid)\n\t\t: _move(move)\n\t\t, _isValid(isValid)\n\t{\n\t}\n\n\tconst bool isValid() const { return _isValid; }\n\tconst std::vector<UnitAction> & moveVec() const { return _move; }\n};\n\nclass TTBestMove\n{\n\tAlphaBetaMove _firstMove;\n\tAlphaBetaMove _secondMove;\n\npublic:\n\n\tTTBestMove()\n\t{\n\t}\n\n\tTTBestMove(const AlphaBetaMove & first, const AlphaBetaMove & second)\n\t\t: _firstMove(first)\n\t\t, _secondMove(second)\n\t{\n\t}\n\n\tconst AlphaBetaMove & firstMove() const\t\t{ return _firstMove; }\n\tconst AlphaBetaMove & secondMove() const\t{ return _secondMove; }\n};\n\n\nclass AlphaBetaValue\n{\t\n\tStateEvalScore\t_score;\n\tAlphaBetaMove\t_move;\n\npublic:\n\n\tAlphaBetaValue()\n\t{\n\t}\n\n\tAlphaBetaValue(const StateEvalScore & score, const AlphaBetaMove & abMove)\n\t\t: _score(score)\n\t\t, _move(abMove)\n\t{\n\t}\n\n\tconst StateEvalScore & score() const { return _score; }\n\tconst AlphaBetaMove & abMove() const { return _move; }\n};\n}"
  },
  {
    "path": "SparCraft/source/UnitProperties.cpp",
    "content": "#include \"UnitProperties.h\"\n\nusing namespace SparCraft;\nusing namespace BWAPI::UpgradeTypes;\n\nUnitProperties UnitProperties::props[256];\n\nUnitProperties::UnitProperties() : \n\tcapacityUpgrade(BWAPI::UpgradeTypes::None),\n\tmaxEnergyUpgrade(BWAPI::UpgradeTypes::None),\n\tsightUpgrade(BWAPI::UpgradeTypes::None),\n\textraArmorUpgrade(BWAPI::UpgradeTypes::None),\n\tspeedUpgrade(BWAPI::UpgradeTypes::None)\n{\n\tcapacity[0]\t\t= capacity[1]\t\t= 0;\n}\n\nvoid UnitProperties::SetType(BWAPI::UnitType type)\n{\n\tthis->type\t\t= type;\n\tmaxEnergy[0]\t= maxEnergy[1]\t\t= type.maxEnergy();\n\tsightRange[0]\t= sightRange[1]\t\t= type.sightRange() << pixelShift;\n\textraArmor[0]\t= extraArmor[1]\t\t= 0;\n\tspeed[0]\t\t= speed[1]\t\t\t= static_cast<int>((1 << pixelShift) * type.topSpeed());\n}\n\nvoid UnitProperties::SetSpeedUpgrade(BWAPI::UpgradeType upgrade, double rate)\n{\n\tspeedUpgrade\t\t\t\t= upgrade;\n\tspeed[1]\t\t\t\t\t= static_cast<int>((1 << pixelShift) * rate);\n}\n\nvoid UnitProperties::SetCapacityUpgrade(BWAPI::UpgradeType upgrade, int capacity0, int capacity1)\n{\n\tcapacityUpgrade\t\t\t\t= upgrade;\n\tcapacity[0]\t\t\t\t\t= capacity0;\n\tcapacity[1]\t\t\t\t\t= capacity1;\n}\n\nvoid UnitProperties::SetEnergyUpgrade(BWAPI::UpgradeType upgrade)\n{\n\tmaxEnergyUpgrade\t\t\t= upgrade;\n\tmaxEnergy[1]\t\t\t\t= 250;\n}\n\nvoid UnitProperties::SetSightUpgrade(BWAPI::UpgradeType upgrade, int range)\n{\n\tsightUpgrade\t\t\t\t= upgrade;\n\tsightRange[1]\t\t\t\t= (range << 5) << pixelShift;\n}\n\nvoid UnitProperties::SetExtraArmorUpgrade(BWAPI::UpgradeType upgrade, int amount)\n{\n\textraArmorUpgrade\t\t\t= upgrade;\n\textraArmor[1]\t\t\t\t= amount;\n}\n\nusing namespace BWAPI::UnitTypes;\n\nvoid UnitProperties::Init()\n{\n\tfor (const BWAPI::UnitType & type : BWAPI::UnitTypes::allUnitTypes())\n\t{\n\t\tprops[type.getID()].SetType(type);\n\t}\n\n\tconst double standardSpeed(Terran_SCV.topSpeed());\n\n\tprops[BWAPI::UnitTypes::Terran_Ghost.getID()            ].SetEnergyUpgrade(Moebius_Reactor);\n\tprops[BWAPI::UnitTypes::Terran_Ghost.getID()            ].SetSightUpgrade(Ocular_Implants, 11);\n\n\tprops[BWAPI::UnitTypes::Terran_Medic.getID()            ].SetEnergyUpgrade(Caduceus_Reactor);\n\n\tprops[BWAPI::UnitTypes::Terran_Vulture.getID()          ].SetSpeedUpgrade(Ion_Thrusters,            standardSpeed * 1.881);\n\n\tprops[BWAPI::UnitTypes::Terran_Wraith.getID()           ].SetEnergyUpgrade(Apollo_Reactor);\n\n\tprops[BWAPI::UnitTypes::Terran_Battlecruiser.getID()    ].SetEnergyUpgrade(Colossus_Reactor);\n\tprops[BWAPI::UnitTypes::Terran_Science_Vessel.getID()   ].SetEnergyUpgrade(Titan_Reactor);\n\n\n\n\tprops[BWAPI::UnitTypes::Zerg_Zergling.getID()       ].SetSpeedUpgrade(Metabolic_Boost,\t\t\t    standardSpeed * 1.615);\n\n\tprops[BWAPI::UnitTypes::Zerg_Hydralisk.getID()      ].SetSpeedUpgrade(Muscular_Augments,\t\t    standardSpeed * 1.105);\n\n\tprops[BWAPI::UnitTypes::Zerg_Ultralisk.getID()      ].SetExtraArmorUpgrade(Chitinous_Plating,\t    2);\n\tprops[BWAPI::UnitTypes::Zerg_Ultralisk.getID()      ].SetSpeedUpgrade(Anabolic_Synthesis,\t\t    standardSpeed * 1.556);\n\n\tprops[BWAPI::UnitTypes::Zerg_Defiler.getID()        ].SetEnergyUpgrade(Metasynaptic_Node);\n\n\tprops[BWAPI::UnitTypes::Zerg_Overlord.getID()       ].SetSightUpgrade(Antennae,\t\t\t\t\t    11);\n\tprops[BWAPI::UnitTypes::Zerg_Overlord.getID()       ].SetSpeedUpgrade(Pneumatized_Carapace,\t\t    Protoss_Carrier.topSpeed());\n\n\tprops[BWAPI::UnitTypes::Zerg_Queen.getID()          ].SetEnergyUpgrade(Gamete_Meiosis);\n\n\n\n\tprops[BWAPI::UnitTypes::Protoss_Zealot.getID()      ].SetSpeedUpgrade(Leg_Enhancements,\t\t\t    standardSpeed * 1.167);\n\n\tprops[BWAPI::UnitTypes::Protoss_High_Templar.getID()].SetEnergyUpgrade(Khaydarin_Amulet);\n\n\tprops[BWAPI::UnitTypes::Protoss_Reaver.getID()      ].SetCapacityUpgrade(Reaver_Capacity,\t\t    5, 10);\n\n\tprops[BWAPI::UnitTypes::Protoss_Dark_Archon.getID() ].SetEnergyUpgrade(Argus_Talisman);\n\n\tprops[BWAPI::UnitTypes::Protoss_Observer.getID()    ].SetSightUpgrade(Sensor_Array,\t\t\t\t    11);\n\tprops[BWAPI::UnitTypes::Protoss_Observer.getID()    ].SetSpeedUpgrade(Gravitic_Boosters,\t\t    Protoss_Corsair.topSpeed());\n\n\tprops[BWAPI::UnitTypes::Protoss_Shuttle.getID()     ].SetSpeedUpgrade(Gravitic_Drive,\t\t\t    Protoss_Corsair.topSpeed());\n\n\tprops[BWAPI::UnitTypes::Protoss_Scout.getID()       ].SetSightUpgrade(Apial_Sensors,\t\t\t    10);\n\tprops[BWAPI::UnitTypes::Protoss_Scout.getID()       ].SetSpeedUpgrade(Gravitic_Thrusters,\t\t    Protoss_Corsair.topSpeed());\n\n\tprops[BWAPI::UnitTypes::Protoss_Corsair.getID()     ].SetEnergyUpgrade(Argus_Jewel);\n\n    props[BWAPI::UnitTypes::Protoss_Carrier.getID()     ].SetCapacityUpgrade(Carrier_Capacity,\t\t    4, 8);\n\n\tprops[BWAPI::UnitTypes::Protoss_Arbiter.getID()     ].SetEnergyUpgrade(Khaydarin_Core);\n}"
  },
  {
    "path": "SparCraft/source/UnitProperties.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"PlayerProperties.h\"\n#include \"WeaponProperties.h\"\n\nnamespace SparCraft\n{\nclass WeaponProperties;\nclass PlayerProperties;\n\nclass UnitProperties\n{\n\tstatic UnitProperties\t\tprops[256];\n\n\tBWAPI::UnitType\t\t\t\ttype;\n\n\tBWAPI::UpgradeType\t\t\tcapacityUpgrade;\n\tBWAPI::UpgradeType\t\t\textraArmorUpgrade;\n\tBWAPI::UpgradeType\t\t\tmaxEnergyUpgrade;\n\tBWAPI::UpgradeType\t\t\tsightUpgrade;\n\tBWAPI::UpgradeType\t\t\tspeedUpgrade;\n\n\tint\t\t\t\t\t\t\tcapacity[2];\n\tint\t\t\t\t\t\t\textraArmor[2];\n\tint\t\t\t\t\t\t\tmaxEnergy[2];\n\tint\t\t\t\t\t\t\tsightRange[2];\n\tint\t\t\t\t\t\t\tspeed[2];\n\n\tvoid\t\t\t\t\t\tSetCapacityUpgrade(BWAPI::UpgradeType upgrade, int capacity0, int capacity1);\n\tvoid\t\t\t\t\t\tSetEnergyUpgrade(BWAPI::UpgradeType upgrade);\n\tvoid\t\t\t\t\t\tSetExtraArmorUpgrade(BWAPI::UpgradeType upgrade, int amount);\n\tvoid\t\t\t\t\t\tSetSightUpgrade(BWAPI::UpgradeType upgrade, int range);\n\tvoid\t\t\t\t\t\tSetSpeedUpgrade(BWAPI::UpgradeType upgrade, double rate);\n\tvoid\t\t\t\t\t\tSetType(BWAPI::UnitType type);\n\npublic:\n\t\t\t\t\t\t\t\tUnitProperties();\n\n\tint\t\t\t\t\t\t\tGetArmor(const PlayerProperties & player) const\t\t{ return type.armor() + player.GetUpgradeLevel(type.armorUpgrade()) + extraArmor[player.GetUpgradeLevel(extraArmorUpgrade)]; }\n\tint\t\t\t\t\t\t\tGetCapacity(const PlayerProperties & player) const\t{ return capacity[player.GetUpgradeLevel(capacityUpgrade)]; }\n\tint\t\t\t\t\t\t\tGetMaxEnergy(const PlayerProperties & player) const\t{ return maxEnergy[player.GetUpgradeLevel(maxEnergyUpgrade)]; }\n\tint\t\t\t\t\t\t\tGetSight(const PlayerProperties & player) const\t\t{ return sightRange[player.GetUpgradeLevel(sightUpgrade)]; }\n\tint\t\t\t\t\t\t\tGetSpeed(const PlayerProperties & player) const\t\t{ return speed[player.GetUpgradeLevel(speedUpgrade)]; }\n\n\tconst WeaponProperties &\t\t\tGetGroundWeapon() const\t\t\t\t\t\t{ return WeaponProperties::Get(type.groundWeapon()); }\n\tconst WeaponProperties &\t\t\tGetAirWeapon() const\t\t\t\t\t\t{ return WeaponProperties::Get(type.airWeapon()); }\n\n\tstatic const UnitProperties &\tGet(BWAPI::UnitType type)\t\t\t\t\t{ return props[type.getID()]; }\n\tstatic void\t\t\t\t\tInit();\n};\n}"
  },
  {
    "path": "SparCraft/source/UnitScriptData.cpp",
    "content": "#include \"UnitScriptData.h\"\n\nusing namespace SparCraft;\n\nUnitScriptData::UnitScriptData() \n{\n}\n\nstd::vector<Action> & UnitScriptData::getMoves(const size_t & player, const size_t & actualScript)\n{\n    return _allScriptMoves[player][actualScript];\n}\n\nAction & UnitScriptData::getMove(const size_t & player, const size_t & unitIndex, const size_t & actualScript)\n{\n    return _allScriptMoves[player][actualScript][unitIndex];\n}\n\nvoid UnitScriptData::calculateMoves(const size_t & player, MoveArray & moves, GameState & state, std::vector<Action> & moveVec)\n{\n    // generate all script moves for this player at this state and store them in allScriptMoves\n    for (size_t scriptIndex(0); scriptIndex<_scriptVec[player].size(); ++scriptIndex)\n    {\n        // get the associated player pointer\n        const PlayerPtr & pp = getPlayerPtr(player, scriptIndex);\n\n        // get the actual script we are working with\n        const size_t actualScript = getScript(player, scriptIndex);\n\n        // generate the moves inside the appropriate vector\n        getMoves(player, actualScript).clear();\n        pp->getMoves(state, moves, getMoves(player, actualScript));\n    }\n\n    // for each unit the player has to move, populate the move vector with the appropriate script move\n    for (size_t unitIndex(0); unitIndex < moves.numUnits(); ++unitIndex)\n    {\n        // the unit from the state\n        const Unit & unit = state.getUnit(player, unitIndex);\n\n        // the move it would choose to do based on its associated script preference\n        Action unitMove = getMove(player, unitIndex, getUnitScript(unit));\n\n        // put the unit into the move vector\n        moveVec.push_back(unitMove);\n    }\n}\n\nconst size_t & UnitScriptData::getUnitScript(const size_t & player, const int & id) const\n{\n    return (*_unitScriptMap[player].find(id)).second;\n}\n    \nconst size_t & UnitScriptData::getUnitScript(const Unit & unit) const\n{\n    return getUnitScript(unit.player(), unit.ID());\n}\n\nconst size_t & UnitScriptData::getScript(const size_t & player, const size_t & index)\n{\n    return _scriptVec[player][index];\n}\n\nconst PlayerPtr & UnitScriptData::getPlayerPtr(const size_t & player, const size_t & index)\n{\n    return _playerPtrVec[player][index];\n}\n\nconst size_t UnitScriptData::getNumScripts(const size_t & player) const\n{\n    return _scriptSet[player].size();\n}\n\nvoid UnitScriptData::setUnitScript(const size_t & player, const int & id, const size_t & script)\n{\n    if (_scriptSet[player].find(script) == _scriptSet[player].end())\n    {\n        _scriptSet[player].insert(script);\n        _scriptVec[player].push_back(script);\n        _playerPtrVec[player].push_back(PlayerPtr(AllPlayers::getPlayerPtr(player, script)));\n    }\n        \n    _unitScriptMap[player][id] = script;\n}\n\nvoid UnitScriptData::setUnitScript(const Unit & unit, const size_t & script)\n{\n    setUnitScript(unit.player(), unit.ID(), script);\n}"
  },
  {
    "path": "SparCraft/source/UnitScriptData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameState.h\"\n#include \"Player.h\"\n#include \"AllPlayers.h\"\n#include \"Action.h\"\n#include <memory>\n#include <set>\n\nnamespace SparCraft\n{\n\t\ntypedef\tstd::shared_ptr<Player> PlayerPtr;\n\n\nclass UnitScriptData\n{\n    // map from UnitID to PlayerModel\n    std::map<int, size_t>   _unitScriptMap[2];\n    std::set<size_t>        _scriptSet[2];\n    std::vector<size_t>     _scriptVec[2];\n    std::vector<PlayerPtr>  _playerPtrVec[2];\n    \n   \n    std::vector<Action>       _allScriptMoves[2][PlayerModels::Size];\n\n    std::vector<Action> & getMoves(const size_t & player, const size_t & actualScript);\n\n    Action & getMove(const size_t & player, const size_t & unitIndex, const size_t & actualScript);\n\npublic:\n\n    UnitScriptData();\n\n    void calculateMoves(const size_t & player, MoveArray & moves, GameState & state, std::vector<Action> & moveVec);\n    void setUnitScript(const size_t & player, const int & id, const size_t & script);\n    void setUnitScript(const Unit & unit, const size_t & script);\n\n    const size_t &      getUnitScript(const size_t & player, const int & id) const;\n    const size_t &      getUnitScript(const Unit & unit) const;\n    const size_t &      getScript(const size_t & player, const size_t & index);\n    const PlayerPtr &   getPlayerPtr(const size_t & player, const size_t & index);\n    const size_t        getNumScripts(const size_t & player) const;\n};\n}"
  },
  {
    "path": "SparCraft/source/UnitType.hpp",
    "content": "#pragma once\n\n#include \"Location.hpp\"\n\nclass Unit \n{\n\tint\t\t_damage,\n\t\t\t_maxHP,\n\t\t\t_currentHP,\n\t\t\t_range,\n\t\t\t_moveCooldown,\n\t\t\t_weaponCooldown,\n\t\t\t_lastMove,\n\t\t\t_lastAttack;\n\npublic:\n\n\tUnit()\n\t\t : _damage(0)\n\t\t , _maxHP(0)\n\t\t , _currentHP(0)\n\t\t , _range(0)\n\t\t , _moveCooldown(0)\n\t\t , _weaponCooldown(0)\n\t\t , _lastMove(-1)\n\t\t , _lastAttack(-1)\n\t{\n\n\t}\n\n\tUnit(const int & damage, const int & maxHP, const int & currentHP, \n\t\t const int & range, const int & moveCooldown, const int & weaponCooldown) \n\t\t : _damage(damage)\n\t\t , _maxHP(maxHP)\n\t\t , _currentHP(currentHP)\n\t\t , _range(range)\n\t\t , _moveCooldown(moveCooldown)\n\t\t , _weaponCooldown(weaponCooldown)\n\t\t , _lastMove(-1)\n\t\t , _lastAttack(-1)\n\t{\n\n\t}\n\n\tconst int damage()\t\t\tconst { return _damage; }\n\tconst int maxHP()\t\t\tconst { return _maxHP; }\n\tconst int currentHP()\t\tconst { return _currentHP; }\n\tconst int range()\t\t\tconst { return _range; }\n\tconst int moveCooldown()\tconst { return _moveCooldown; }\n\tconst int weaponCooldown()\tconst { return _weaponCooldown; }\n\tconst int lastMove()\t\tconst { return _lastMove; }\n\tconst int lastAttack()\t\tconst { return _lastAttack; }\n};\n"
  },
  {
    "path": "SparCraft/source/WeaponProperties.cpp",
    "content": "#include \"WeaponProperties.h\"\n\nusing namespace SparCraft;\nusing namespace BWAPI::UpgradeTypes;\n\n\nnamespace SparCraft\n{\n\tconst int pixelShift(10);\n\tconst float damageMultipliers[7][6] = \n\t{ \n\t\t{0,  0,   0,    0,    0,  0}, \n\t\t{0,  .5f, .75f, 1,    0,  0}, \n\t\t{0,  1,   .5f,  .25,  0,  0},\n\t\t{0,  1,   1,    1,    0,  0},\n\t\t{0,  1,   1,    1,    0,  0},\n\t\t{0,  0,   0,    0,    0,  0}, \n\t\t{0,  0,   0,    0,    0,  0}\n\t};\n\n\tWeaponProperties WeaponProperties::props[256];\n}\n\nWeaponProperties::WeaponProperties() :\n    rangeUpgrade(BWAPI::UpgradeTypes::None),\n    speedUpgrade(BWAPI::UpgradeTypes::None)\n{\n\n}\n\nvoid WeaponProperties::SetType(BWAPI::WeaponType type)\n{\n\tthis->type\t\t= type;\n\tcooldown[0]\t\t= type.damageCooldown();\n    cooldown[1]\t\t= type.damageCooldown();\n\tmaxRange[0]\t\t= type.maxRange();\n    maxRange[1]\t\t= type.maxRange();\n}\n\nvoid WeaponProperties::SetRangeUpgrade(BWAPI::UpgradeType upgrade, int maxRange)\n{\n\trangeUpgrade\t\t= upgrade;\n\tthis->maxRange[1]\t= (maxRange << 5);\n}\n\nvoid WeaponProperties::SetSpeedUpgrade(BWAPI::UpgradeType upgrade, int cooldown)\n{\n\tspeedUpgrade\t\t= upgrade;\n\tthis->cooldown[1]\t= cooldown;\n}\n\nusing namespace BWAPI::WeaponTypes;\n\nvoid WeaponProperties::Init()\n{\n    for (const BWAPI::WeaponType & type : BWAPI::WeaponTypes::allWeaponTypes())\n\t{\n\t\tprops[type.getID()].SetType(type);\n\t}\n\n\tprops[Gauss_Rifle.getID()\t\t\t].SetRangeUpgrade(U_238_Shells,\t\t\t5);\t// Terran Marine ground/air attack\n\n\tprops[Hellfire_Missile_Pack.getID()\t].SetRangeUpgrade(Charon_Boosters,\t\t8);\t// Terran Goliath air attack\n\n\tprops[Claws.getID()\t\t\t\t\t].SetSpeedUpgrade(Adrenal_Glands,\t\t6);\t// Zerg Zergling ground attack\n\n\tprops[Needle_Spines.getID()\t\t\t].SetRangeUpgrade(Grooved_Spines,\t\t5); // Zerg Hydralisk ground/air attack\n\n\tprops[Phase_Disruptor.getID()\t\t].SetRangeUpgrade(Singularity_Charge,\t6);\t// Protoss Dragoon ground/air attack\n}\n\nint WeaponProperties::GetDamageBase(const PlayerProperties & player) const \n{ \n    return type.damageAmount() + player.GetUpgradeLevel(type.upgradeType()) * type.damageFactor(); \n}\n\nfloat WeaponProperties::GetDamageMultiplier(BWAPI::UnitSizeType targetSize) const \n{ \n    return damageMultipliers[type.damageType().getID()][targetSize.getID()]; \n}\n\nint WeaponProperties::GetCooldown(const PlayerProperties & player) const \n{ \n    return cooldown[player.GetUpgradeLevel(speedUpgrade)]; \n}\n\nint WeaponProperties::GetMaxRange(const PlayerProperties & player) const \n{ \n    return maxRange[player.GetUpgradeLevel(rangeUpgrade)];\n}\n\nconst WeaponProperties & WeaponProperties::Get(BWAPI::WeaponType type) \n{ \n    return props[type.getID()]; \n}"
  },
  {
    "path": "SparCraft/source/WeaponProperties.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"PlayerProperties.h\"\n\nnamespace SparCraft\n{\n    \nclass PlayerProperties;\n\nextern const int\t\t\t\tpixelShift;\nextern const float\t\t\t\tdamageMultipliers[7][6];\n\nclass WeaponProperties\n{\n\tstatic WeaponProperties\t\tprops[256];\n\n\tBWAPI::WeaponType\t\t\ttype;\n\n\tBWAPI::UpgradeType\t\t\trangeUpgrade;\n\tBWAPI::UpgradeType\t\t\tspeedUpgrade;\n\n\tint\t\t\t\t\t\t\tcooldown[2];\n\tint\t\t\t\t\t\t\tmaxRange[2];\n\n\tvoid\t\t\t\t\t\tSetRangeUpgrade(BWAPI::UpgradeType upgrade, int maxRange);\n\tvoid\t\t\t\t\t\tSetSpeedUpgrade(BWAPI::UpgradeType upgrade, int cooldown);\n\tvoid\t\t\t\t\t\tSetType(BWAPI::WeaponType type);\npublic:\n\t\t\t\t\t\t\t\tWeaponProperties();\n\n\tint\t\t\t\t\t\t\tGetDamageBase(const PlayerProperties & player) const;\n\tfloat\t\t\t\t\t\tGetDamageMultiplier(BWAPI::UnitSizeType targetSize) const;\n\tint\t\t\t\t\t\t\tGetCooldown(const PlayerProperties & player) const;\n\tint\t\t\t\t\t\t\tGetMaxRange(const PlayerProperties & player) const;\n\n\tstatic const WeaponProperties &\tGet(BWAPI::WeaponType type);\n\tstatic void\t\t\t\t\tInit();\n};\n}\n"
  },
  {
    "path": "SparCraft/source/glext/glext.h",
    "content": "#ifndef __glext_h_\n#define __glext_h_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n** License Applicability. Except to the extent portions of this file are\n** made subject to an alternative license as permitted in the SGI Free\n** Software License B, Version 1.1 (the \"License\"), the contents of this\n** file are subject only to the provisions of the License. You may not use\n** this file except in compliance with the License. You may obtain a copy\n** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600\n** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:\n** \n** http://oss.sgi.com/projects/FreeB\n** \n** Note that, as provided in the License, the Software is distributed on an\n** \"AS IS\" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS\n** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND\n** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A\n** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.\n** \n** Original Code. The Original Code is: OpenGL Sample Implementation,\n** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,\n** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc.\n** Copyright in any portions created by third parties is as indicated\n** elsewhere herein. All Rights Reserved.\n** \n** Additional Notice Provisions: This software was created using the\n** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has\n** not been independently verified as being compliant with the OpenGL(R)\n** version 1.2.1 Specification.\n*/\n\n#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)\n#define WIN32_LEAN_AND_MEAN 1\n#include <windows.h>\n#endif\n\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\n#ifndef GLAPI\n#define GLAPI extern\n#endif\n\n/*************************************************************/\n\n/* Header file version number, required by OpenGL ABI for Linux */\n/* glext.h last updated 2005/06/20 */\n/* Current version at http://oss.sgi.com/projects/ogl-sample/registry/ */\n#define GL_GLEXT_VERSION 29\n\n#ifndef GL_VERSION_1_2\n#define GL_UNSIGNED_BYTE_3_3_2            0x8032\n#define GL_UNSIGNED_SHORT_4_4_4_4         0x8033\n#define GL_UNSIGNED_SHORT_5_5_5_1         0x8034\n#define GL_UNSIGNED_INT_8_8_8_8           0x8035\n#define GL_UNSIGNED_INT_10_10_10_2        0x8036\n#define GL_RESCALE_NORMAL                 0x803A\n#define GL_TEXTURE_BINDING_3D             0x806A\n#define GL_PACK_SKIP_IMAGES               0x806B\n#define GL_PACK_IMAGE_HEIGHT              0x806C\n#define GL_UNPACK_SKIP_IMAGES             0x806D\n#define GL_UNPACK_IMAGE_HEIGHT            0x806E\n#define GL_TEXTURE_3D                     0x806F\n#define GL_PROXY_TEXTURE_3D               0x8070\n#define GL_TEXTURE_DEPTH                  0x8071\n#define GL_TEXTURE_WRAP_R                 0x8072\n#define GL_MAX_3D_TEXTURE_SIZE            0x8073\n#define GL_UNSIGNED_BYTE_2_3_3_REV        0x8362\n#define GL_UNSIGNED_SHORT_5_6_5           0x8363\n#define GL_UNSIGNED_SHORT_5_6_5_REV       0x8364\n#define GL_UNSIGNED_SHORT_4_4_4_4_REV     0x8365\n#define GL_UNSIGNED_SHORT_1_5_5_5_REV     0x8366\n#define GL_UNSIGNED_INT_8_8_8_8_REV       0x8367\n#define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368\n#define GL_BGR                            0x80E0\n#define GL_BGRA                           0x80E1\n#define GL_MAX_ELEMENTS_VERTICES          0x80E8\n#define GL_MAX_ELEMENTS_INDICES           0x80E9\n#define GL_CLAMP_TO_EDGE                  0x812F\n#define GL_TEXTURE_MIN_LOD                0x813A\n#define GL_TEXTURE_MAX_LOD                0x813B\n#define GL_TEXTURE_BASE_LEVEL             0x813C\n#define GL_TEXTURE_MAX_LEVEL              0x813D\n#define GL_LIGHT_MODEL_COLOR_CONTROL      0x81F8\n#define GL_SINGLE_COLOR                   0x81F9\n#define GL_SEPARATE_SPECULAR_COLOR        0x81FA\n#define GL_SMOOTH_POINT_SIZE_RANGE        0x0B12\n#define GL_SMOOTH_POINT_SIZE_GRANULARITY  0x0B13\n#define GL_SMOOTH_LINE_WIDTH_RANGE        0x0B22\n#define GL_SMOOTH_LINE_WIDTH_GRANULARITY  0x0B23\n#define GL_ALIASED_POINT_SIZE_RANGE       0x846D\n#define GL_ALIASED_LINE_WIDTH_RANGE       0x846E\n#endif\n\n#ifndef GL_ARB_imaging\n#define GL_CONSTANT_COLOR                 0x8001\n#define GL_ONE_MINUS_CONSTANT_COLOR       0x8002\n#define GL_CONSTANT_ALPHA                 0x8003\n#define GL_ONE_MINUS_CONSTANT_ALPHA       0x8004\n#define GL_BLEND_COLOR                    0x8005\n#define GL_FUNC_ADD                       0x8006\n#define GL_MIN                            0x8007\n#define GL_MAX                            0x8008\n#define GL_BLEND_EQUATION                 0x8009\n#define GL_FUNC_SUBTRACT                  0x800A\n#define GL_FUNC_REVERSE_SUBTRACT          0x800B\n#define GL_CONVOLUTION_1D                 0x8010\n#define GL_CONVOLUTION_2D                 0x8011\n#define GL_SEPARABLE_2D                   0x8012\n#define GL_CONVOLUTION_BORDER_MODE        0x8013\n#define GL_CONVOLUTION_FILTER_SCALE       0x8014\n#define GL_CONVOLUTION_FILTER_BIAS        0x8015\n#define GL_REDUCE                         0x8016\n#define GL_CONVOLUTION_FORMAT             0x8017\n#define GL_CONVOLUTION_WIDTH              0x8018\n#define GL_CONVOLUTION_HEIGHT             0x8019\n#define GL_MAX_CONVOLUTION_WIDTH          0x801A\n#define GL_MAX_CONVOLUTION_HEIGHT         0x801B\n#define GL_POST_CONVOLUTION_RED_SCALE     0x801C\n#define GL_POST_CONVOLUTION_GREEN_SCALE   0x801D\n#define GL_POST_CONVOLUTION_BLUE_SCALE    0x801E\n#define GL_POST_CONVOLUTION_ALPHA_SCALE   0x801F\n#define GL_POST_CONVOLUTION_RED_BIAS      0x8020\n#define GL_POST_CONVOLUTION_GREEN_BIAS    0x8021\n#define GL_POST_CONVOLUTION_BLUE_BIAS     0x8022\n#define GL_POST_CONVOLUTION_ALPHA_BIAS    0x8023\n#define GL_HISTOGRAM                      0x8024\n#define GL_PROXY_HISTOGRAM                0x8025\n#define GL_HISTOGRAM_WIDTH                0x8026\n#define GL_HISTOGRAM_FORMAT               0x8027\n#define GL_HISTOGRAM_RED_SIZE             0x8028\n#define GL_HISTOGRAM_GREEN_SIZE           0x8029\n#define GL_HISTOGRAM_BLUE_SIZE            0x802A\n#define GL_HISTOGRAM_ALPHA_SIZE           0x802B\n#define GL_HISTOGRAM_LUMINANCE_SIZE       0x802C\n#define GL_HISTOGRAM_SINK                 0x802D\n#define GL_MINMAX                         0x802E\n#define GL_MINMAX_FORMAT                  0x802F\n#define GL_MINMAX_SINK                    0x8030\n#define GL_TABLE_TOO_LARGE                0x8031\n#define GL_COLOR_MATRIX                   0x80B1\n#define GL_COLOR_MATRIX_STACK_DEPTH       0x80B2\n#define GL_MAX_COLOR_MATRIX_STACK_DEPTH   0x80B3\n#define GL_POST_COLOR_MATRIX_RED_SCALE    0x80B4\n#define GL_POST_COLOR_MATRIX_GREEN_SCALE  0x80B5\n#define GL_POST_COLOR_MATRIX_BLUE_SCALE   0x80B6\n#define GL_POST_COLOR_MATRIX_ALPHA_SCALE  0x80B7\n#define GL_POST_COLOR_MATRIX_RED_BIAS     0x80B8\n#define GL_POST_COLOR_MATRIX_GREEN_BIAS   0x80B9\n#define GL_POST_COLOR_MATRIX_BLUE_BIAS    0x80BA\n#define GL_POST_COLOR_MATRIX_ALPHA_BIAS   0x80BB\n#define GL_COLOR_TABLE                    0x80D0\n#define GL_POST_CONVOLUTION_COLOR_TABLE   0x80D1\n#define GL_POST_COLOR_MATRIX_COLOR_TABLE  0x80D2\n#define GL_PROXY_COLOR_TABLE              0x80D3\n#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4\n#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5\n#define GL_COLOR_TABLE_SCALE              0x80D6\n#define GL_COLOR_TABLE_BIAS               0x80D7\n#define GL_COLOR_TABLE_FORMAT             0x80D8\n#define GL_COLOR_TABLE_WIDTH              0x80D9\n#define GL_COLOR_TABLE_RED_SIZE           0x80DA\n#define GL_COLOR_TABLE_GREEN_SIZE         0x80DB\n#define GL_COLOR_TABLE_BLUE_SIZE          0x80DC\n#define GL_COLOR_TABLE_ALPHA_SIZE         0x80DD\n#define GL_COLOR_TABLE_LUMINANCE_SIZE     0x80DE\n#define GL_COLOR_TABLE_INTENSITY_SIZE     0x80DF\n#define GL_CONSTANT_BORDER                0x8151\n#define GL_REPLICATE_BORDER               0x8153\n#define GL_CONVOLUTION_BORDER_COLOR       0x8154\n#endif\n\n#ifndef GL_VERSION_1_3\n#define GL_TEXTURE0                       0x84C0\n#define GL_TEXTURE1                       0x84C1\n#define GL_TEXTURE2                       0x84C2\n#define GL_TEXTURE3                       0x84C3\n#define GL_TEXTURE4                       0x84C4\n#define GL_TEXTURE5                       0x84C5\n#define GL_TEXTURE6                       0x84C6\n#define GL_TEXTURE7                       0x84C7\n#define GL_TEXTURE8                       0x84C8\n#define GL_TEXTURE9                       0x84C9\n#define GL_TEXTURE10                      0x84CA\n#define GL_TEXTURE11                      0x84CB\n#define GL_TEXTURE12                      0x84CC\n#define GL_TEXTURE13                      0x84CD\n#define GL_TEXTURE14                      0x84CE\n#define GL_TEXTURE15                      0x84CF\n#define GL_TEXTURE16                      0x84D0\n#define GL_TEXTURE17                      0x84D1\n#define GL_TEXTURE18                      0x84D2\n#define GL_TEXTURE19                      0x84D3\n#define GL_TEXTURE20                      0x84D4\n#define GL_TEXTURE21                      0x84D5\n#define GL_TEXTURE22                      0x84D6\n#define GL_TEXTURE23                      0x84D7\n#define GL_TEXTURE24                      0x84D8\n#define GL_TEXTURE25                      0x84D9\n#define GL_TEXTURE26                      0x84DA\n#define GL_TEXTURE27                      0x84DB\n#define GL_TEXTURE28                      0x84DC\n#define GL_TEXTURE29                      0x84DD\n#define GL_TEXTURE30                      0x84DE\n#define GL_TEXTURE31                      0x84DF\n#define GL_ACTIVE_TEXTURE                 0x84E0\n#define GL_CLIENT_ACTIVE_TEXTURE          0x84E1\n#define GL_MAX_TEXTURE_UNITS              0x84E2\n#define GL_TRANSPOSE_MODELVIEW_MATRIX     0x84E3\n#define GL_TRANSPOSE_PROJECTION_MATRIX    0x84E4\n#define GL_TRANSPOSE_TEXTURE_MATRIX       0x84E5\n#define GL_TRANSPOSE_COLOR_MATRIX         0x84E6\n#define GL_MULTISAMPLE                    0x809D\n#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE            0x809F\n#define GL_SAMPLE_COVERAGE                0x80A0\n#define GL_SAMPLE_BUFFERS                 0x80A8\n#define GL_SAMPLES                        0x80A9\n#define GL_SAMPLE_COVERAGE_VALUE          0x80AA\n#define GL_SAMPLE_COVERAGE_INVERT         0x80AB\n#define GL_MULTISAMPLE_BIT                0x20000000\n#define GL_NORMAL_MAP                     0x8511\n#define GL_REFLECTION_MAP                 0x8512\n#define GL_TEXTURE_CUBE_MAP               0x8513\n#define GL_TEXTURE_BINDING_CUBE_MAP       0x8514\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_X    0x8515\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X    0x8516\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y    0x8517\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y    0x8518\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z    0x8519\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z    0x851A\n#define GL_PROXY_TEXTURE_CUBE_MAP         0x851B\n#define GL_MAX_CUBE_MAP_TEXTURE_SIZE      0x851C\n#define GL_COMPRESSED_ALPHA               0x84E9\n#define GL_COMPRESSED_LUMINANCE           0x84EA\n#define GL_COMPRESSED_LUMINANCE_ALPHA     0x84EB\n#define GL_COMPRESSED_INTENSITY           0x84EC\n#define GL_COMPRESSED_RGB                 0x84ED\n#define GL_COMPRESSED_RGBA                0x84EE\n#define GL_TEXTURE_COMPRESSION_HINT       0x84EF\n#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE  0x86A0\n#define GL_TEXTURE_COMPRESSED             0x86A1\n#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2\n#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3\n#define GL_CLAMP_TO_BORDER                0x812D\n#define GL_COMBINE                        0x8570\n#define GL_COMBINE_RGB                    0x8571\n#define GL_COMBINE_ALPHA                  0x8572\n#define GL_SOURCE0_RGB                    0x8580\n#define GL_SOURCE1_RGB                    0x8581\n#define GL_SOURCE2_RGB                    0x8582\n#define GL_SOURCE0_ALPHA                  0x8588\n#define GL_SOURCE1_ALPHA                  0x8589\n#define GL_SOURCE2_ALPHA                  0x858A\n#define GL_OPERAND0_RGB                   0x8590\n#define GL_OPERAND1_RGB                   0x8591\n#define GL_OPERAND2_RGB                   0x8592\n#define GL_OPERAND0_ALPHA                 0x8598\n#define GL_OPERAND1_ALPHA                 0x8599\n#define GL_OPERAND2_ALPHA                 0x859A\n#define GL_RGB_SCALE                      0x8573\n#define GL_ADD_SIGNED                     0x8574\n#define GL_INTERPOLATE                    0x8575\n#define GL_SUBTRACT                       0x84E7\n#define GL_CONSTANT                       0x8576\n#define GL_PRIMARY_COLOR                  0x8577\n#define GL_PREVIOUS                       0x8578\n#define GL_DOT3_RGB                       0x86AE\n#define GL_DOT3_RGBA                      0x86AF\n#endif\n\n#ifndef GL_VERSION_1_4\n#define GL_BLEND_DST_RGB                  0x80C8\n#define GL_BLEND_SRC_RGB                  0x80C9\n#define GL_BLEND_DST_ALPHA                0x80CA\n#define GL_BLEND_SRC_ALPHA                0x80CB\n#define GL_POINT_SIZE_MIN                 0x8126\n#define GL_POINT_SIZE_MAX                 0x8127\n#define GL_POINT_FADE_THRESHOLD_SIZE      0x8128\n#define GL_POINT_DISTANCE_ATTENUATION     0x8129\n#define GL_GENERATE_MIPMAP                0x8191\n#define GL_GENERATE_MIPMAP_HINT           0x8192\n#define GL_DEPTH_COMPONENT16              0x81A5\n#define GL_DEPTH_COMPONENT24              0x81A6\n#define GL_DEPTH_COMPONENT32              0x81A7\n#define GL_MIRRORED_REPEAT                0x8370\n#define GL_FOG_COORDINATE_SOURCE          0x8450\n#define GL_FOG_COORDINATE                 0x8451\n#define GL_FRAGMENT_DEPTH                 0x8452\n#define GL_CURRENT_FOG_COORDINATE         0x8453\n#define GL_FOG_COORDINATE_ARRAY_TYPE      0x8454\n#define GL_FOG_COORDINATE_ARRAY_STRIDE    0x8455\n#define GL_FOG_COORDINATE_ARRAY_POINTER   0x8456\n#define GL_FOG_COORDINATE_ARRAY           0x8457\n#define GL_COLOR_SUM                      0x8458\n#define GL_CURRENT_SECONDARY_COLOR        0x8459\n#define GL_SECONDARY_COLOR_ARRAY_SIZE     0x845A\n#define GL_SECONDARY_COLOR_ARRAY_TYPE     0x845B\n#define GL_SECONDARY_COLOR_ARRAY_STRIDE   0x845C\n#define GL_SECONDARY_COLOR_ARRAY_POINTER  0x845D\n#define GL_SECONDARY_COLOR_ARRAY          0x845E\n#define GL_MAX_TEXTURE_LOD_BIAS           0x84FD\n#define GL_TEXTURE_FILTER_CONTROL         0x8500\n#define GL_TEXTURE_LOD_BIAS               0x8501\n#define GL_INCR_WRAP                      0x8507\n#define GL_DECR_WRAP                      0x8508\n#define GL_TEXTURE_DEPTH_SIZE             0x884A\n#define GL_DEPTH_TEXTURE_MODE             0x884B\n#define GL_TEXTURE_COMPARE_MODE           0x884C\n#define GL_TEXTURE_COMPARE_FUNC           0x884D\n#define GL_COMPARE_R_TO_TEXTURE           0x884E\n#endif\n\n#ifndef GL_VERSION_1_5\n#define GL_BUFFER_SIZE                    0x8764\n#define GL_BUFFER_USAGE                   0x8765\n#define GL_QUERY_COUNTER_BITS             0x8864\n#define GL_CURRENT_QUERY                  0x8865\n#define GL_QUERY_RESULT                   0x8866\n#define GL_QUERY_RESULT_AVAILABLE         0x8867\n#define GL_ARRAY_BUFFER                   0x8892\n#define GL_ELEMENT_ARRAY_BUFFER           0x8893\n#define GL_ARRAY_BUFFER_BINDING           0x8894\n#define GL_ELEMENT_ARRAY_BUFFER_BINDING   0x8895\n#define GL_VERTEX_ARRAY_BUFFER_BINDING    0x8896\n#define GL_NORMAL_ARRAY_BUFFER_BINDING    0x8897\n#define GL_COLOR_ARRAY_BUFFER_BINDING     0x8898\n#define GL_INDEX_ARRAY_BUFFER_BINDING     0x8899\n#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A\n#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B\n#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C\n#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D\n#define GL_WEIGHT_ARRAY_BUFFER_BINDING    0x889E\n#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F\n#define GL_READ_ONLY                      0x88B8\n#define GL_WRITE_ONLY                     0x88B9\n#define GL_READ_WRITE                     0x88BA\n#define GL_BUFFER_ACCESS                  0x88BB\n#define GL_BUFFER_MAPPED                  0x88BC\n#define GL_BUFFER_MAP_POINTER             0x88BD\n#define GL_STREAM_DRAW                    0x88E0\n#define GL_STREAM_READ                    0x88E1\n#define GL_STREAM_COPY                    0x88E2\n#define GL_STATIC_DRAW                    0x88E4\n#define GL_STATIC_READ                    0x88E5\n#define GL_STATIC_COPY                    0x88E6\n#define GL_DYNAMIC_DRAW                   0x88E8\n#define GL_DYNAMIC_READ                   0x88E9\n#define GL_DYNAMIC_COPY                   0x88EA\n#define GL_SAMPLES_PASSED                 0x8914\n#define GL_FOG_COORD_SRC                  GL_FOG_COORDINATE_SOURCE\n#define GL_FOG_COORD                      GL_FOG_COORDINATE\n#define GL_CURRENT_FOG_COORD              GL_CURRENT_FOG_COORDINATE\n#define GL_FOG_COORD_ARRAY_TYPE           GL_FOG_COORDINATE_ARRAY_TYPE\n#define GL_FOG_COORD_ARRAY_STRIDE         GL_FOG_COORDINATE_ARRAY_STRIDE\n#define GL_FOG_COORD_ARRAY_POINTER        GL_FOG_COORDINATE_ARRAY_POINTER\n#define GL_FOG_COORD_ARRAY                GL_FOG_COORDINATE_ARRAY\n#define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING\n#define GL_SRC0_RGB                       GL_SOURCE0_RGB\n#define GL_SRC1_RGB                       GL_SOURCE1_RGB\n#define GL_SRC2_RGB                       GL_SOURCE2_RGB\n#define GL_SRC0_ALPHA                     GL_SOURCE0_ALPHA\n#define GL_SRC1_ALPHA                     GL_SOURCE1_ALPHA\n#define GL_SRC2_ALPHA                     GL_SOURCE2_ALPHA\n#endif\n\n#ifndef GL_VERSION_2_0\n#define GL_BLEND_EQUATION_RGB             GL_BLEND_EQUATION\n#define GL_VERTEX_ATTRIB_ARRAY_ENABLED    0x8622\n#define GL_VERTEX_ATTRIB_ARRAY_SIZE       0x8623\n#define GL_VERTEX_ATTRIB_ARRAY_STRIDE     0x8624\n#define GL_VERTEX_ATTRIB_ARRAY_TYPE       0x8625\n#define GL_CURRENT_VERTEX_ATTRIB          0x8626\n#define GL_VERTEX_PROGRAM_POINT_SIZE      0x8642\n#define GL_VERTEX_PROGRAM_TWO_SIDE        0x8643\n#define GL_VERTEX_ATTRIB_ARRAY_POINTER    0x8645\n#define GL_STENCIL_BACK_FUNC              0x8800\n#define GL_STENCIL_BACK_FAIL              0x8801\n#define GL_STENCIL_BACK_PASS_DEPTH_FAIL   0x8802\n#define GL_STENCIL_BACK_PASS_DEPTH_PASS   0x8803\n#define GL_MAX_DRAW_BUFFERS               0x8824\n#define GL_DRAW_BUFFER0                   0x8825\n#define GL_DRAW_BUFFER1                   0x8826\n#define GL_DRAW_BUFFER2                   0x8827\n#define GL_DRAW_BUFFER3                   0x8828\n#define GL_DRAW_BUFFER4                   0x8829\n#define GL_DRAW_BUFFER5                   0x882A\n#define GL_DRAW_BUFFER6                   0x882B\n#define GL_DRAW_BUFFER7                   0x882C\n#define GL_DRAW_BUFFER8                   0x882D\n#define GL_DRAW_BUFFER9                   0x882E\n#define GL_DRAW_BUFFER10                  0x882F\n#define GL_DRAW_BUFFER11                  0x8830\n#define GL_DRAW_BUFFER12                  0x8831\n#define GL_DRAW_BUFFER13                  0x8832\n#define GL_DRAW_BUFFER14                  0x8833\n#define GL_DRAW_BUFFER15                  0x8834\n#define GL_BLEND_EQUATION_ALPHA           0x883D\n#define GL_POINT_SPRITE                   0x8861\n#define GL_COORD_REPLACE                  0x8862\n#define GL_MAX_VERTEX_ATTRIBS             0x8869\n#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A\n#define GL_MAX_TEXTURE_COORDS             0x8871\n#define GL_MAX_TEXTURE_IMAGE_UNITS        0x8872\n#define GL_FRAGMENT_SHADER                0x8B30\n#define GL_VERTEX_SHADER                  0x8B31\n#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49\n#define GL_MAX_VERTEX_UNIFORM_COMPONENTS  0x8B4A\n#define GL_MAX_VARYING_FLOATS             0x8B4B\n#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C\n#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D\n#define GL_SHADER_TYPE                    0x8B4F\n#define GL_FLOAT_VEC2                     0x8B50\n#define GL_FLOAT_VEC3                     0x8B51\n#define GL_FLOAT_VEC4                     0x8B52\n#define GL_INT_VEC2                       0x8B53\n#define GL_INT_VEC3                       0x8B54\n#define GL_INT_VEC4                       0x8B55\n#define GL_BOOL                           0x8B56\n#define GL_BOOL_VEC2                      0x8B57\n#define GL_BOOL_VEC3                      0x8B58\n#define GL_BOOL_VEC4                      0x8B59\n#define GL_FLOAT_MAT2                     0x8B5A\n#define GL_FLOAT_MAT3                     0x8B5B\n#define GL_FLOAT_MAT4                     0x8B5C\n#define GL_SAMPLER_1D                     0x8B5D\n#define GL_SAMPLER_2D                     0x8B5E\n#define GL_SAMPLER_3D                     0x8B5F\n#define GL_SAMPLER_CUBE                   0x8B60\n#define GL_SAMPLER_1D_SHADOW              0x8B61\n#define GL_SAMPLER_2D_SHADOW              0x8B62\n#define GL_DELETE_STATUS                  0x8B80\n#define GL_COMPILE_STATUS                 0x8B81\n#define GL_LINK_STATUS                    0x8B82\n#define GL_VALIDATE_STATUS                0x8B83\n#define GL_INFO_LOG_LENGTH                0x8B84\n#define GL_ATTACHED_SHADERS               0x8B85\n#define GL_ACTIVE_UNIFORMS                0x8B86\n#define GL_ACTIVE_UNIFORM_MAX_LENGTH      0x8B87\n#define GL_SHADER_SOURCE_LENGTH           0x8B88\n#define GL_ACTIVE_ATTRIBUTES              0x8B89\n#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH    0x8B8A\n#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B\n#define GL_SHADING_LANGUAGE_VERSION       0x8B8C\n#define GL_CURRENT_PROGRAM                0x8B8D\n#define GL_POINT_SPRITE_COORD_ORIGIN      0x8CA0\n#define GL_LOWER_LEFT                     0x8CA1\n#define GL_UPPER_LEFT                     0x8CA2\n#define GL_STENCIL_BACK_REF               0x8CA3\n#define GL_STENCIL_BACK_VALUE_MASK        0x8CA4\n#define GL_STENCIL_BACK_WRITEMASK         0x8CA5\n#endif\n\n#ifndef GL_ARB_multitexture\n#define GL_TEXTURE0_ARB                   0x84C0\n#define GL_TEXTURE1_ARB                   0x84C1\n#define GL_TEXTURE2_ARB                   0x84C2\n#define GL_TEXTURE3_ARB                   0x84C3\n#define GL_TEXTURE4_ARB                   0x84C4\n#define GL_TEXTURE5_ARB                   0x84C5\n#define GL_TEXTURE6_ARB                   0x84C6\n#define GL_TEXTURE7_ARB                   0x84C7\n#define GL_TEXTURE8_ARB                   0x84C8\n#define GL_TEXTURE9_ARB                   0x84C9\n#define GL_TEXTURE10_ARB                  0x84CA\n#define GL_TEXTURE11_ARB                  0x84CB\n#define GL_TEXTURE12_ARB                  0x84CC\n#define GL_TEXTURE13_ARB                  0x84CD\n#define GL_TEXTURE14_ARB                  0x84CE\n#define GL_TEXTURE15_ARB                  0x84CF\n#define GL_TEXTURE16_ARB                  0x84D0\n#define GL_TEXTURE17_ARB                  0x84D1\n#define GL_TEXTURE18_ARB                  0x84D2\n#define GL_TEXTURE19_ARB                  0x84D3\n#define GL_TEXTURE20_ARB                  0x84D4\n#define GL_TEXTURE21_ARB                  0x84D5\n#define GL_TEXTURE22_ARB                  0x84D6\n#define GL_TEXTURE23_ARB                  0x84D7\n#define GL_TEXTURE24_ARB                  0x84D8\n#define GL_TEXTURE25_ARB                  0x84D9\n#define GL_TEXTURE26_ARB                  0x84DA\n#define GL_TEXTURE27_ARB                  0x84DB\n#define GL_TEXTURE28_ARB                  0x84DC\n#define GL_TEXTURE29_ARB                  0x84DD\n#define GL_TEXTURE30_ARB                  0x84DE\n#define GL_TEXTURE31_ARB                  0x84DF\n#define GL_ACTIVE_TEXTURE_ARB             0x84E0\n#define GL_CLIENT_ACTIVE_TEXTURE_ARB      0x84E1\n#define GL_MAX_TEXTURE_UNITS_ARB          0x84E2\n#endif\n\n#ifndef GL_ARB_transpose_matrix\n#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3\n#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4\n#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB   0x84E5\n#define GL_TRANSPOSE_COLOR_MATRIX_ARB     0x84E6\n#endif\n\n#ifndef GL_ARB_multisample\n#define GL_MULTISAMPLE_ARB                0x809D\n#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB   0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE_ARB        0x809F\n#define GL_SAMPLE_COVERAGE_ARB            0x80A0\n#define GL_SAMPLE_BUFFERS_ARB             0x80A8\n#define GL_SAMPLES_ARB                    0x80A9\n#define GL_SAMPLE_COVERAGE_VALUE_ARB      0x80AA\n#define GL_SAMPLE_COVERAGE_INVERT_ARB     0x80AB\n#define GL_MULTISAMPLE_BIT_ARB            0x20000000\n#endif\n\n#ifndef GL_ARB_texture_env_add\n#endif\n\n#ifndef GL_ARB_texture_cube_map\n#define GL_NORMAL_MAP_ARB                 0x8511\n#define GL_REFLECTION_MAP_ARB             0x8512\n#define GL_TEXTURE_CUBE_MAP_ARB           0x8513\n#define GL_TEXTURE_BINDING_CUBE_MAP_ARB   0x8514\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A\n#define GL_PROXY_TEXTURE_CUBE_MAP_ARB     0x851B\n#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB  0x851C\n#endif\n\n#ifndef GL_ARB_texture_compression\n#define GL_COMPRESSED_ALPHA_ARB           0x84E9\n#define GL_COMPRESSED_LUMINANCE_ARB       0x84EA\n#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB\n#define GL_COMPRESSED_INTENSITY_ARB       0x84EC\n#define GL_COMPRESSED_RGB_ARB             0x84ED\n#define GL_COMPRESSED_RGBA_ARB            0x84EE\n#define GL_TEXTURE_COMPRESSION_HINT_ARB   0x84EF\n#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0\n#define GL_TEXTURE_COMPRESSED_ARB         0x86A1\n#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2\n#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3\n#endif\n\n#ifndef GL_ARB_texture_border_clamp\n#define GL_CLAMP_TO_BORDER_ARB            0x812D\n#endif\n\n#ifndef GL_ARB_point_parameters\n#define GL_POINT_SIZE_MIN_ARB             0x8126\n#define GL_POINT_SIZE_MAX_ARB             0x8127\n#define GL_POINT_FADE_THRESHOLD_SIZE_ARB  0x8128\n#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129\n#endif\n\n#ifndef GL_ARB_vertex_blend\n#define GL_MAX_VERTEX_UNITS_ARB           0x86A4\n#define GL_ACTIVE_VERTEX_UNITS_ARB        0x86A5\n#define GL_WEIGHT_SUM_UNITY_ARB           0x86A6\n#define GL_VERTEX_BLEND_ARB               0x86A7\n#define GL_CURRENT_WEIGHT_ARB             0x86A8\n#define GL_WEIGHT_ARRAY_TYPE_ARB          0x86A9\n#define GL_WEIGHT_ARRAY_STRIDE_ARB        0x86AA\n#define GL_WEIGHT_ARRAY_SIZE_ARB          0x86AB\n#define GL_WEIGHT_ARRAY_POINTER_ARB       0x86AC\n#define GL_WEIGHT_ARRAY_ARB               0x86AD\n#define GL_MODELVIEW0_ARB                 0x1700\n#define GL_MODELVIEW1_ARB                 0x850A\n#define GL_MODELVIEW2_ARB                 0x8722\n#define GL_MODELVIEW3_ARB                 0x8723\n#define GL_MODELVIEW4_ARB                 0x8724\n#define GL_MODELVIEW5_ARB                 0x8725\n#define GL_MODELVIEW6_ARB                 0x8726\n#define GL_MODELVIEW7_ARB                 0x8727\n#define GL_MODELVIEW8_ARB                 0x8728\n#define GL_MODELVIEW9_ARB                 0x8729\n#define GL_MODELVIEW10_ARB                0x872A\n#define GL_MODELVIEW11_ARB                0x872B\n#define GL_MODELVIEW12_ARB                0x872C\n#define GL_MODELVIEW13_ARB                0x872D\n#define GL_MODELVIEW14_ARB                0x872E\n#define GL_MODELVIEW15_ARB                0x872F\n#define GL_MODELVIEW16_ARB                0x8730\n#define GL_MODELVIEW17_ARB                0x8731\n#define GL_MODELVIEW18_ARB                0x8732\n#define GL_MODELVIEW19_ARB                0x8733\n#define GL_MODELVIEW20_ARB                0x8734\n#define GL_MODELVIEW21_ARB                0x8735\n#define GL_MODELVIEW22_ARB                0x8736\n#define GL_MODELVIEW23_ARB                0x8737\n#define GL_MODELVIEW24_ARB                0x8738\n#define GL_MODELVIEW25_ARB                0x8739\n#define GL_MODELVIEW26_ARB                0x873A\n#define GL_MODELVIEW27_ARB                0x873B\n#define GL_MODELVIEW28_ARB                0x873C\n#define GL_MODELVIEW29_ARB                0x873D\n#define GL_MODELVIEW30_ARB                0x873E\n#define GL_MODELVIEW31_ARB                0x873F\n#endif\n\n#ifndef GL_ARB_matrix_palette\n#define GL_MATRIX_PALETTE_ARB             0x8840\n#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841\n#define GL_MAX_PALETTE_MATRICES_ARB       0x8842\n#define GL_CURRENT_PALETTE_MATRIX_ARB     0x8843\n#define GL_MATRIX_INDEX_ARRAY_ARB         0x8844\n#define GL_CURRENT_MATRIX_INDEX_ARB       0x8845\n#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB    0x8846\n#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB    0x8847\n#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB  0x8848\n#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849\n#endif\n\n#ifndef GL_ARB_texture_env_combine\n#define GL_COMBINE_ARB                    0x8570\n#define GL_COMBINE_RGB_ARB                0x8571\n#define GL_COMBINE_ALPHA_ARB              0x8572\n#define GL_SOURCE0_RGB_ARB                0x8580\n#define GL_SOURCE1_RGB_ARB                0x8581\n#define GL_SOURCE2_RGB_ARB                0x8582\n#define GL_SOURCE0_ALPHA_ARB              0x8588\n#define GL_SOURCE1_ALPHA_ARB              0x8589\n#define GL_SOURCE2_ALPHA_ARB              0x858A\n#define GL_OPERAND0_RGB_ARB               0x8590\n#define GL_OPERAND1_RGB_ARB               0x8591\n#define GL_OPERAND2_RGB_ARB               0x8592\n#define GL_OPERAND0_ALPHA_ARB             0x8598\n#define GL_OPERAND1_ALPHA_ARB             0x8599\n#define GL_OPERAND2_ALPHA_ARB             0x859A\n#define GL_RGB_SCALE_ARB                  0x8573\n#define GL_ADD_SIGNED_ARB                 0x8574\n#define GL_INTERPOLATE_ARB                0x8575\n#define GL_SUBTRACT_ARB                   0x84E7\n#define GL_CONSTANT_ARB                   0x8576\n#define GL_PRIMARY_COLOR_ARB              0x8577\n#define GL_PREVIOUS_ARB                   0x8578\n#endif\n\n#ifndef GL_ARB_texture_env_crossbar\n#endif\n\n#ifndef GL_ARB_texture_env_dot3\n#define GL_DOT3_RGB_ARB                   0x86AE\n#define GL_DOT3_RGBA_ARB                  0x86AF\n#endif\n\n#ifndef GL_ARB_texture_mirrored_repeat\n#define GL_MIRRORED_REPEAT_ARB            0x8370\n#endif\n\n#ifndef GL_ARB_depth_texture\n#define GL_DEPTH_COMPONENT16_ARB          0x81A5\n#define GL_DEPTH_COMPONENT24_ARB          0x81A6\n#define GL_DEPTH_COMPONENT32_ARB          0x81A7\n#define GL_TEXTURE_DEPTH_SIZE_ARB         0x884A\n#define GL_DEPTH_TEXTURE_MODE_ARB         0x884B\n#endif\n\n#ifndef GL_ARB_shadow\n#define GL_TEXTURE_COMPARE_MODE_ARB       0x884C\n#define GL_TEXTURE_COMPARE_FUNC_ARB       0x884D\n#define GL_COMPARE_R_TO_TEXTURE_ARB       0x884E\n#endif\n\n#ifndef GL_ARB_shadow_ambient\n#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF\n#endif\n\n#ifndef GL_ARB_window_pos\n#endif\n\n#ifndef GL_ARB_vertex_program\n#define GL_COLOR_SUM_ARB                  0x8458\n#define GL_VERTEX_PROGRAM_ARB             0x8620\n#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622\n#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB   0x8623\n#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624\n#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB   0x8625\n#define GL_CURRENT_VERTEX_ATTRIB_ARB      0x8626\n#define GL_PROGRAM_LENGTH_ARB             0x8627\n#define GL_PROGRAM_STRING_ARB             0x8628\n#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E\n#define GL_MAX_PROGRAM_MATRICES_ARB       0x862F\n#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640\n#define GL_CURRENT_MATRIX_ARB             0x8641\n#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB  0x8642\n#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB    0x8643\n#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645\n#define GL_PROGRAM_ERROR_POSITION_ARB     0x864B\n#define GL_PROGRAM_BINDING_ARB            0x8677\n#define GL_MAX_VERTEX_ATTRIBS_ARB         0x8869\n#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A\n#define GL_PROGRAM_ERROR_STRING_ARB       0x8874\n#define GL_PROGRAM_FORMAT_ASCII_ARB       0x8875\n#define GL_PROGRAM_FORMAT_ARB             0x8876\n#define GL_PROGRAM_INSTRUCTIONS_ARB       0x88A0\n#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB   0x88A1\n#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2\n#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3\n#define GL_PROGRAM_TEMPORARIES_ARB        0x88A4\n#define GL_MAX_PROGRAM_TEMPORARIES_ARB    0x88A5\n#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6\n#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7\n#define GL_PROGRAM_PARAMETERS_ARB         0x88A8\n#define GL_MAX_PROGRAM_PARAMETERS_ARB     0x88A9\n#define GL_PROGRAM_NATIVE_PARAMETERS_ARB  0x88AA\n#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB\n#define GL_PROGRAM_ATTRIBS_ARB            0x88AC\n#define GL_MAX_PROGRAM_ATTRIBS_ARB        0x88AD\n#define GL_PROGRAM_NATIVE_ATTRIBS_ARB     0x88AE\n#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF\n#define GL_PROGRAM_ADDRESS_REGISTERS_ARB  0x88B0\n#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1\n#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2\n#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3\n#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4\n#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5\n#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6\n#define GL_TRANSPOSE_CURRENT_MATRIX_ARB   0x88B7\n#define GL_MATRIX0_ARB                    0x88C0\n#define GL_MATRIX1_ARB                    0x88C1\n#define GL_MATRIX2_ARB                    0x88C2\n#define GL_MATRIX3_ARB                    0x88C3\n#define GL_MATRIX4_ARB                    0x88C4\n#define GL_MATRIX5_ARB                    0x88C5\n#define GL_MATRIX6_ARB                    0x88C6\n#define GL_MATRIX7_ARB                    0x88C7\n#define GL_MATRIX8_ARB                    0x88C8\n#define GL_MATRIX9_ARB                    0x88C9\n#define GL_MATRIX10_ARB                   0x88CA\n#define GL_MATRIX11_ARB                   0x88CB\n#define GL_MATRIX12_ARB                   0x88CC\n#define GL_MATRIX13_ARB                   0x88CD\n#define GL_MATRIX14_ARB                   0x88CE\n#define GL_MATRIX15_ARB                   0x88CF\n#define GL_MATRIX16_ARB                   0x88D0\n#define GL_MATRIX17_ARB                   0x88D1\n#define GL_MATRIX18_ARB                   0x88D2\n#define GL_MATRIX19_ARB                   0x88D3\n#define GL_MATRIX20_ARB                   0x88D4\n#define GL_MATRIX21_ARB                   0x88D5\n#define GL_MATRIX22_ARB                   0x88D6\n#define GL_MATRIX23_ARB                   0x88D7\n#define GL_MATRIX24_ARB                   0x88D8\n#define GL_MATRIX25_ARB                   0x88D9\n#define GL_MATRIX26_ARB                   0x88DA\n#define GL_MATRIX27_ARB                   0x88DB\n#define GL_MATRIX28_ARB                   0x88DC\n#define GL_MATRIX29_ARB                   0x88DD\n#define GL_MATRIX30_ARB                   0x88DE\n#define GL_MATRIX31_ARB                   0x88DF\n#endif\n\n#ifndef GL_ARB_fragment_program\n#define GL_FRAGMENT_PROGRAM_ARB           0x8804\n#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB   0x8805\n#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB   0x8806\n#define GL_PROGRAM_TEX_INDIRECTIONS_ARB   0x8807\n#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808\n#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809\n#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A\n#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B\n#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C\n#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D\n#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E\n#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F\n#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810\n#define GL_MAX_TEXTURE_COORDS_ARB         0x8871\n#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB    0x8872\n#endif\n\n#ifndef GL_ARB_vertex_buffer_object\n#define GL_BUFFER_SIZE_ARB                0x8764\n#define GL_BUFFER_USAGE_ARB               0x8765\n#define GL_ARRAY_BUFFER_ARB               0x8892\n#define GL_ELEMENT_ARRAY_BUFFER_ARB       0x8893\n#define GL_ARRAY_BUFFER_BINDING_ARB       0x8894\n#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895\n#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896\n#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897\n#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898\n#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899\n#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A\n#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B\n#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C\n#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D\n#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E\n#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F\n#define GL_READ_ONLY_ARB                  0x88B8\n#define GL_WRITE_ONLY_ARB                 0x88B9\n#define GL_READ_WRITE_ARB                 0x88BA\n#define GL_BUFFER_ACCESS_ARB              0x88BB\n#define GL_BUFFER_MAPPED_ARB              0x88BC\n#define GL_BUFFER_MAP_POINTER_ARB         0x88BD\n#define GL_STREAM_DRAW_ARB                0x88E0\n#define GL_STREAM_READ_ARB                0x88E1\n#define GL_STREAM_COPY_ARB                0x88E2\n#define GL_STATIC_DRAW_ARB                0x88E4\n#define GL_STATIC_READ_ARB                0x88E5\n#define GL_STATIC_COPY_ARB                0x88E6\n#define GL_DYNAMIC_DRAW_ARB               0x88E8\n#define GL_DYNAMIC_READ_ARB               0x88E9\n#define GL_DYNAMIC_COPY_ARB               0x88EA\n#endif\n\n#ifndef GL_ARB_occlusion_query\n#define GL_QUERY_COUNTER_BITS_ARB         0x8864\n#define GL_CURRENT_QUERY_ARB              0x8865\n#define GL_QUERY_RESULT_ARB               0x8866\n#define GL_QUERY_RESULT_AVAILABLE_ARB     0x8867\n#define GL_SAMPLES_PASSED_ARB             0x8914\n#endif\n\n#ifndef GL_ARB_shader_objects\n#define GL_PROGRAM_OBJECT_ARB             0x8B40\n#define GL_SHADER_OBJECT_ARB              0x8B48\n#define GL_OBJECT_TYPE_ARB                0x8B4E\n#define GL_OBJECT_SUBTYPE_ARB             0x8B4F\n#define GL_FLOAT_VEC2_ARB                 0x8B50\n#define GL_FLOAT_VEC3_ARB                 0x8B51\n#define GL_FLOAT_VEC4_ARB                 0x8B52\n#define GL_INT_VEC2_ARB                   0x8B53\n#define GL_INT_VEC3_ARB                   0x8B54\n#define GL_INT_VEC4_ARB                   0x8B55\n#define GL_BOOL_ARB                       0x8B56\n#define GL_BOOL_VEC2_ARB                  0x8B57\n#define GL_BOOL_VEC3_ARB                  0x8B58\n#define GL_BOOL_VEC4_ARB                  0x8B59\n#define GL_FLOAT_MAT2_ARB                 0x8B5A\n#define GL_FLOAT_MAT3_ARB                 0x8B5B\n#define GL_FLOAT_MAT4_ARB                 0x8B5C\n#define GL_SAMPLER_1D_ARB                 0x8B5D\n#define GL_SAMPLER_2D_ARB                 0x8B5E\n#define GL_SAMPLER_3D_ARB                 0x8B5F\n#define GL_SAMPLER_CUBE_ARB               0x8B60\n#define GL_SAMPLER_1D_SHADOW_ARB          0x8B61\n#define GL_SAMPLER_2D_SHADOW_ARB          0x8B62\n#define GL_SAMPLER_2D_RECT_ARB            0x8B63\n#define GL_SAMPLER_2D_RECT_SHADOW_ARB     0x8B64\n#define GL_OBJECT_DELETE_STATUS_ARB       0x8B80\n#define GL_OBJECT_COMPILE_STATUS_ARB      0x8B81\n#define GL_OBJECT_LINK_STATUS_ARB         0x8B82\n#define GL_OBJECT_VALIDATE_STATUS_ARB     0x8B83\n#define GL_OBJECT_INFO_LOG_LENGTH_ARB     0x8B84\n#define GL_OBJECT_ATTACHED_OBJECTS_ARB    0x8B85\n#define GL_OBJECT_ACTIVE_UNIFORMS_ARB     0x8B86\n#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87\n#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88\n#endif\n\n#ifndef GL_ARB_vertex_shader\n#define GL_VERTEX_SHADER_ARB              0x8B31\n#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A\n#define GL_MAX_VARYING_FLOATS_ARB         0x8B4B\n#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C\n#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D\n#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB   0x8B89\n#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A\n#endif\n\n#ifndef GL_ARB_fragment_shader\n#define GL_FRAGMENT_SHADER_ARB            0x8B30\n#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49\n#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B\n#endif\n\n#ifndef GL_ARB_shading_language_100\n#define GL_SHADING_LANGUAGE_VERSION_ARB   0x8B8C\n#endif\n\n#ifndef GL_ARB_texture_non_power_of_two\n#endif\n\n#ifndef GL_ARB_point_sprite\n#define GL_POINT_SPRITE_ARB               0x8861\n#define GL_COORD_REPLACE_ARB              0x8862\n#endif\n\n#ifndef GL_ARB_fragment_program_shadow\n#endif\n\n#ifndef GL_ARB_draw_buffers\n#define GL_MAX_DRAW_BUFFERS_ARB           0x8824\n#define GL_DRAW_BUFFER0_ARB               0x8825\n#define GL_DRAW_BUFFER1_ARB               0x8826\n#define GL_DRAW_BUFFER2_ARB               0x8827\n#define GL_DRAW_BUFFER3_ARB               0x8828\n#define GL_DRAW_BUFFER4_ARB               0x8829\n#define GL_DRAW_BUFFER5_ARB               0x882A\n#define GL_DRAW_BUFFER6_ARB               0x882B\n#define GL_DRAW_BUFFER7_ARB               0x882C\n#define GL_DRAW_BUFFER8_ARB               0x882D\n#define GL_DRAW_BUFFER9_ARB               0x882E\n#define GL_DRAW_BUFFER10_ARB              0x882F\n#define GL_DRAW_BUFFER11_ARB              0x8830\n#define GL_DRAW_BUFFER12_ARB              0x8831\n#define GL_DRAW_BUFFER13_ARB              0x8832\n#define GL_DRAW_BUFFER14_ARB              0x8833\n#define GL_DRAW_BUFFER15_ARB              0x8834\n#endif\n\n#ifndef GL_ARB_texture_rectangle\n#define GL_TEXTURE_RECTANGLE_ARB          0x84F5\n#define GL_TEXTURE_BINDING_RECTANGLE_ARB  0x84F6\n#define GL_PROXY_TEXTURE_RECTANGLE_ARB    0x84F7\n#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8\n#endif\n\n#ifndef GL_ARB_color_buffer_float\n#define GL_RGBA_FLOAT_MODE_ARB            0x8820\n#define GL_CLAMP_VERTEX_COLOR_ARB         0x891A\n#define GL_CLAMP_FRAGMENT_COLOR_ARB       0x891B\n#define GL_CLAMP_READ_COLOR_ARB           0x891C\n#define GL_FIXED_ONLY_ARB                 0x891D\n#endif\n\n#ifndef GL_ARB_half_float_pixel\n#define GL_HALF_FLOAT_ARB                 0x140B\n#endif\n\n#ifndef GL_ARB_texture_float\n#define GL_TEXTURE_RED_TYPE_ARB           0x8C10\n#define GL_TEXTURE_GREEN_TYPE_ARB         0x8C11\n#define GL_TEXTURE_BLUE_TYPE_ARB          0x8C12\n#define GL_TEXTURE_ALPHA_TYPE_ARB         0x8C13\n#define GL_TEXTURE_LUMINANCE_TYPE_ARB     0x8C14\n#define GL_TEXTURE_INTENSITY_TYPE_ARB     0x8C15\n#define GL_TEXTURE_DEPTH_TYPE_ARB         0x8C16\n#define GL_UNSIGNED_NORMALIZED_ARB        0x8C17\n#define GL_RGBA32F_ARB                    0x8814\n#define GL_RGB32F_ARB                     0x8815\n#define GL_ALPHA32F_ARB                   0x8816\n#define GL_INTENSITY32F_ARB               0x8817\n#define GL_LUMINANCE32F_ARB               0x8818\n#define GL_LUMINANCE_ALPHA32F_ARB         0x8819\n#define GL_RGBA16F_ARB                    0x881A\n#define GL_RGB16F_ARB                     0x881B\n#define GL_ALPHA16F_ARB                   0x881C\n#define GL_INTENSITY16F_ARB               0x881D\n#define GL_LUMINANCE16F_ARB               0x881E\n#define GL_LUMINANCE_ALPHA16F_ARB         0x881F\n#endif\n\n#ifndef GL_ARB_pixel_buffer_object\n#define GL_PIXEL_PACK_BUFFER_ARB          0x88EB\n#define GL_PIXEL_UNPACK_BUFFER_ARB        0x88EC\n#define GL_PIXEL_PACK_BUFFER_BINDING_ARB  0x88ED\n#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF\n#endif\n\n#ifndef GL_EXT_abgr\n#define GL_ABGR_EXT                       0x8000\n#endif\n\n#ifndef GL_EXT_blend_color\n#define GL_CONSTANT_COLOR_EXT             0x8001\n#define GL_ONE_MINUS_CONSTANT_COLOR_EXT   0x8002\n#define GL_CONSTANT_ALPHA_EXT             0x8003\n#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT   0x8004\n#define GL_BLEND_COLOR_EXT                0x8005\n#endif\n\n#ifndef GL_EXT_polygon_offset\n#define GL_POLYGON_OFFSET_EXT             0x8037\n#define GL_POLYGON_OFFSET_FACTOR_EXT      0x8038\n#define GL_POLYGON_OFFSET_BIAS_EXT        0x8039\n#endif\n\n#ifndef GL_EXT_texture\n#define GL_ALPHA4_EXT                     0x803B\n#define GL_ALPHA8_EXT                     0x803C\n#define GL_ALPHA12_EXT                    0x803D\n#define GL_ALPHA16_EXT                    0x803E\n#define GL_LUMINANCE4_EXT                 0x803F\n#define GL_LUMINANCE8_EXT                 0x8040\n#define GL_LUMINANCE12_EXT                0x8041\n#define GL_LUMINANCE16_EXT                0x8042\n#define GL_LUMINANCE4_ALPHA4_EXT          0x8043\n#define GL_LUMINANCE6_ALPHA2_EXT          0x8044\n#define GL_LUMINANCE8_ALPHA8_EXT          0x8045\n#define GL_LUMINANCE12_ALPHA4_EXT         0x8046\n#define GL_LUMINANCE12_ALPHA12_EXT        0x8047\n#define GL_LUMINANCE16_ALPHA16_EXT        0x8048\n#define GL_INTENSITY_EXT                  0x8049\n#define GL_INTENSITY4_EXT                 0x804A\n#define GL_INTENSITY8_EXT                 0x804B\n#define GL_INTENSITY12_EXT                0x804C\n#define GL_INTENSITY16_EXT                0x804D\n#define GL_RGB2_EXT                       0x804E\n#define GL_RGB4_EXT                       0x804F\n#define GL_RGB5_EXT                       0x8050\n#define GL_RGB8_EXT                       0x8051\n#define GL_RGB10_EXT                      0x8052\n#define GL_RGB12_EXT                      0x8053\n#define GL_RGB16_EXT                      0x8054\n#define GL_RGBA2_EXT                      0x8055\n#define GL_RGBA4_EXT                      0x8056\n#define GL_RGB5_A1_EXT                    0x8057\n#define GL_RGBA8_EXT                      0x8058\n#define GL_RGB10_A2_EXT                   0x8059\n#define GL_RGBA12_EXT                     0x805A\n#define GL_RGBA16_EXT                     0x805B\n#define GL_TEXTURE_RED_SIZE_EXT           0x805C\n#define GL_TEXTURE_GREEN_SIZE_EXT         0x805D\n#define GL_TEXTURE_BLUE_SIZE_EXT          0x805E\n#define GL_TEXTURE_ALPHA_SIZE_EXT         0x805F\n#define GL_TEXTURE_LUMINANCE_SIZE_EXT     0x8060\n#define GL_TEXTURE_INTENSITY_SIZE_EXT     0x8061\n#define GL_REPLACE_EXT                    0x8062\n#define GL_PROXY_TEXTURE_1D_EXT           0x8063\n#define GL_PROXY_TEXTURE_2D_EXT           0x8064\n#define GL_TEXTURE_TOO_LARGE_EXT          0x8065\n#endif\n\n#ifndef GL_EXT_texture3D\n#define GL_PACK_SKIP_IMAGES_EXT           0x806B\n#define GL_PACK_IMAGE_HEIGHT_EXT          0x806C\n#define GL_UNPACK_SKIP_IMAGES_EXT         0x806D\n#define GL_UNPACK_IMAGE_HEIGHT_EXT        0x806E\n#define GL_TEXTURE_3D_EXT                 0x806F\n#define GL_PROXY_TEXTURE_3D_EXT           0x8070\n#define GL_TEXTURE_DEPTH_EXT              0x8071\n#define GL_TEXTURE_WRAP_R_EXT             0x8072\n#define GL_MAX_3D_TEXTURE_SIZE_EXT        0x8073\n#endif\n\n#ifndef GL_SGIS_texture_filter4\n#define GL_FILTER4_SGIS                   0x8146\n#define GL_TEXTURE_FILTER4_SIZE_SGIS      0x8147\n#endif\n\n#ifndef GL_EXT_subtexture\n#endif\n\n#ifndef GL_EXT_copy_texture\n#endif\n\n#ifndef GL_EXT_histogram\n#define GL_HISTOGRAM_EXT                  0x8024\n#define GL_PROXY_HISTOGRAM_EXT            0x8025\n#define GL_HISTOGRAM_WIDTH_EXT            0x8026\n#define GL_HISTOGRAM_FORMAT_EXT           0x8027\n#define GL_HISTOGRAM_RED_SIZE_EXT         0x8028\n#define GL_HISTOGRAM_GREEN_SIZE_EXT       0x8029\n#define GL_HISTOGRAM_BLUE_SIZE_EXT        0x802A\n#define GL_HISTOGRAM_ALPHA_SIZE_EXT       0x802B\n#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT   0x802C\n#define GL_HISTOGRAM_SINK_EXT             0x802D\n#define GL_MINMAX_EXT                     0x802E\n#define GL_MINMAX_FORMAT_EXT              0x802F\n#define GL_MINMAX_SINK_EXT                0x8030\n#define GL_TABLE_TOO_LARGE_EXT            0x8031\n#endif\n\n#ifndef GL_EXT_convolution\n#define GL_CONVOLUTION_1D_EXT             0x8010\n#define GL_CONVOLUTION_2D_EXT             0x8011\n#define GL_SEPARABLE_2D_EXT               0x8012\n#define GL_CONVOLUTION_BORDER_MODE_EXT    0x8013\n#define GL_CONVOLUTION_FILTER_SCALE_EXT   0x8014\n#define GL_CONVOLUTION_FILTER_BIAS_EXT    0x8015\n#define GL_REDUCE_EXT                     0x8016\n#define GL_CONVOLUTION_FORMAT_EXT         0x8017\n#define GL_CONVOLUTION_WIDTH_EXT          0x8018\n#define GL_CONVOLUTION_HEIGHT_EXT         0x8019\n#define GL_MAX_CONVOLUTION_WIDTH_EXT      0x801A\n#define GL_MAX_CONVOLUTION_HEIGHT_EXT     0x801B\n#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C\n#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D\n#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E\n#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F\n#define GL_POST_CONVOLUTION_RED_BIAS_EXT  0x8020\n#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021\n#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022\n#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023\n#endif\n\n#ifndef GL_SGI_color_matrix\n#define GL_COLOR_MATRIX_SGI               0x80B1\n#define GL_COLOR_MATRIX_STACK_DEPTH_SGI   0x80B2\n#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3\n#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4\n#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5\n#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6\n#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7\n#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8\n#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9\n#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA\n#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB\n#endif\n\n#ifndef GL_SGI_color_table\n#define GL_COLOR_TABLE_SGI                0x80D0\n#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1\n#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2\n#define GL_PROXY_COLOR_TABLE_SGI          0x80D3\n#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4\n#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5\n#define GL_COLOR_TABLE_SCALE_SGI          0x80D6\n#define GL_COLOR_TABLE_BIAS_SGI           0x80D7\n#define GL_COLOR_TABLE_FORMAT_SGI         0x80D8\n#define GL_COLOR_TABLE_WIDTH_SGI          0x80D9\n#define GL_COLOR_TABLE_RED_SIZE_SGI       0x80DA\n#define GL_COLOR_TABLE_GREEN_SIZE_SGI     0x80DB\n#define GL_COLOR_TABLE_BLUE_SIZE_SGI      0x80DC\n#define GL_COLOR_TABLE_ALPHA_SIZE_SGI     0x80DD\n#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE\n#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF\n#endif\n\n#ifndef GL_SGIS_pixel_texture\n#define GL_PIXEL_TEXTURE_SGIS             0x8353\n#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354\n#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355\n#define GL_PIXEL_GROUP_COLOR_SGIS         0x8356\n#endif\n\n#ifndef GL_SGIX_pixel_texture\n#define GL_PIXEL_TEX_GEN_SGIX             0x8139\n#define GL_PIXEL_TEX_GEN_MODE_SGIX        0x832B\n#endif\n\n#ifndef GL_SGIS_texture4D\n#define GL_PACK_SKIP_VOLUMES_SGIS         0x8130\n#define GL_PACK_IMAGE_DEPTH_SGIS          0x8131\n#define GL_UNPACK_SKIP_VOLUMES_SGIS       0x8132\n#define GL_UNPACK_IMAGE_DEPTH_SGIS        0x8133\n#define GL_TEXTURE_4D_SGIS                0x8134\n#define GL_PROXY_TEXTURE_4D_SGIS          0x8135\n#define GL_TEXTURE_4DSIZE_SGIS            0x8136\n#define GL_TEXTURE_WRAP_Q_SGIS            0x8137\n#define GL_MAX_4D_TEXTURE_SIZE_SGIS       0x8138\n#define GL_TEXTURE_4D_BINDING_SGIS        0x814F\n#endif\n\n#ifndef GL_SGI_texture_color_table\n#define GL_TEXTURE_COLOR_TABLE_SGI        0x80BC\n#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI  0x80BD\n#endif\n\n#ifndef GL_EXT_cmyka\n#define GL_CMYK_EXT                       0x800C\n#define GL_CMYKA_EXT                      0x800D\n#define GL_PACK_CMYK_HINT_EXT             0x800E\n#define GL_UNPACK_CMYK_HINT_EXT           0x800F\n#endif\n\n#ifndef GL_EXT_texture_object\n#define GL_TEXTURE_PRIORITY_EXT           0x8066\n#define GL_TEXTURE_RESIDENT_EXT           0x8067\n#define GL_TEXTURE_1D_BINDING_EXT         0x8068\n#define GL_TEXTURE_2D_BINDING_EXT         0x8069\n#define GL_TEXTURE_3D_BINDING_EXT         0x806A\n#endif\n\n#ifndef GL_SGIS_detail_texture\n#define GL_DETAIL_TEXTURE_2D_SGIS         0x8095\n#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096\n#define GL_LINEAR_DETAIL_SGIS             0x8097\n#define GL_LINEAR_DETAIL_ALPHA_SGIS       0x8098\n#define GL_LINEAR_DETAIL_COLOR_SGIS       0x8099\n#define GL_DETAIL_TEXTURE_LEVEL_SGIS      0x809A\n#define GL_DETAIL_TEXTURE_MODE_SGIS       0x809B\n#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C\n#endif\n\n#ifndef GL_SGIS_sharpen_texture\n#define GL_LINEAR_SHARPEN_SGIS            0x80AD\n#define GL_LINEAR_SHARPEN_ALPHA_SGIS      0x80AE\n#define GL_LINEAR_SHARPEN_COLOR_SGIS      0x80AF\n#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0\n#endif\n\n#ifndef GL_EXT_packed_pixels\n#define GL_UNSIGNED_BYTE_3_3_2_EXT        0x8032\n#define GL_UNSIGNED_SHORT_4_4_4_4_EXT     0x8033\n#define GL_UNSIGNED_SHORT_5_5_5_1_EXT     0x8034\n#define GL_UNSIGNED_INT_8_8_8_8_EXT       0x8035\n#define GL_UNSIGNED_INT_10_10_10_2_EXT    0x8036\n#endif\n\n#ifndef GL_SGIS_texture_lod\n#define GL_TEXTURE_MIN_LOD_SGIS           0x813A\n#define GL_TEXTURE_MAX_LOD_SGIS           0x813B\n#define GL_TEXTURE_BASE_LEVEL_SGIS        0x813C\n#define GL_TEXTURE_MAX_LEVEL_SGIS         0x813D\n#endif\n\n#ifndef GL_SGIS_multisample\n#define GL_MULTISAMPLE_SGIS               0x809D\n#define GL_SAMPLE_ALPHA_TO_MASK_SGIS      0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE_SGIS       0x809F\n#define GL_SAMPLE_MASK_SGIS               0x80A0\n#define GL_1PASS_SGIS                     0x80A1\n#define GL_2PASS_0_SGIS                   0x80A2\n#define GL_2PASS_1_SGIS                   0x80A3\n#define GL_4PASS_0_SGIS                   0x80A4\n#define GL_4PASS_1_SGIS                   0x80A5\n#define GL_4PASS_2_SGIS                   0x80A6\n#define GL_4PASS_3_SGIS                   0x80A7\n#define GL_SAMPLE_BUFFERS_SGIS            0x80A8\n#define GL_SAMPLES_SGIS                   0x80A9\n#define GL_SAMPLE_MASK_VALUE_SGIS         0x80AA\n#define GL_SAMPLE_MASK_INVERT_SGIS        0x80AB\n#define GL_SAMPLE_PATTERN_SGIS            0x80AC\n#endif\n\n#ifndef GL_EXT_rescale_normal\n#define GL_RESCALE_NORMAL_EXT             0x803A\n#endif\n\n#ifndef GL_EXT_vertex_array\n#define GL_VERTEX_ARRAY_EXT               0x8074\n#define GL_NORMAL_ARRAY_EXT               0x8075\n#define GL_COLOR_ARRAY_EXT                0x8076\n#define GL_INDEX_ARRAY_EXT                0x8077\n#define GL_TEXTURE_COORD_ARRAY_EXT        0x8078\n#define GL_EDGE_FLAG_ARRAY_EXT            0x8079\n#define GL_VERTEX_ARRAY_SIZE_EXT          0x807A\n#define GL_VERTEX_ARRAY_TYPE_EXT          0x807B\n#define GL_VERTEX_ARRAY_STRIDE_EXT        0x807C\n#define GL_VERTEX_ARRAY_COUNT_EXT         0x807D\n#define GL_NORMAL_ARRAY_TYPE_EXT          0x807E\n#define GL_NORMAL_ARRAY_STRIDE_EXT        0x807F\n#define GL_NORMAL_ARRAY_COUNT_EXT         0x8080\n#define GL_COLOR_ARRAY_SIZE_EXT           0x8081\n#define GL_COLOR_ARRAY_TYPE_EXT           0x8082\n#define GL_COLOR_ARRAY_STRIDE_EXT         0x8083\n#define GL_COLOR_ARRAY_COUNT_EXT          0x8084\n#define GL_INDEX_ARRAY_TYPE_EXT           0x8085\n#define GL_INDEX_ARRAY_STRIDE_EXT         0x8086\n#define GL_INDEX_ARRAY_COUNT_EXT          0x8087\n#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT   0x8088\n#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT   0x8089\n#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A\n#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT  0x808B\n#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT     0x808C\n#define GL_EDGE_FLAG_ARRAY_COUNT_EXT      0x808D\n#define GL_VERTEX_ARRAY_POINTER_EXT       0x808E\n#define GL_NORMAL_ARRAY_POINTER_EXT       0x808F\n#define GL_COLOR_ARRAY_POINTER_EXT        0x8090\n#define GL_INDEX_ARRAY_POINTER_EXT        0x8091\n#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092\n#define GL_EDGE_FLAG_ARRAY_POINTER_EXT    0x8093\n#endif\n\n#ifndef GL_EXT_misc_attribute\n#endif\n\n#ifndef GL_SGIS_generate_mipmap\n#define GL_GENERATE_MIPMAP_SGIS           0x8191\n#define GL_GENERATE_MIPMAP_HINT_SGIS      0x8192\n#endif\n\n#ifndef GL_SGIX_clipmap\n#define GL_LINEAR_CLIPMAP_LINEAR_SGIX     0x8170\n#define GL_TEXTURE_CLIPMAP_CENTER_SGIX    0x8171\n#define GL_TEXTURE_CLIPMAP_FRAME_SGIX     0x8172\n#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX    0x8173\n#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174\n#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175\n#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX     0x8176\n#define GL_MAX_CLIPMAP_DEPTH_SGIX         0x8177\n#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178\n#define GL_NEAREST_CLIPMAP_NEAREST_SGIX   0x844D\n#define GL_NEAREST_CLIPMAP_LINEAR_SGIX    0x844E\n#define GL_LINEAR_CLIPMAP_NEAREST_SGIX    0x844F\n#endif\n\n#ifndef GL_SGIX_shadow\n#define GL_TEXTURE_COMPARE_SGIX           0x819A\n#define GL_TEXTURE_COMPARE_OPERATOR_SGIX  0x819B\n#define GL_TEXTURE_LEQUAL_R_SGIX          0x819C\n#define GL_TEXTURE_GEQUAL_R_SGIX          0x819D\n#endif\n\n#ifndef GL_SGIS_texture_edge_clamp\n#define GL_CLAMP_TO_EDGE_SGIS             0x812F\n#endif\n\n#ifndef GL_SGIS_texture_border_clamp\n#define GL_CLAMP_TO_BORDER_SGIS           0x812D\n#endif\n\n#ifndef GL_EXT_blend_minmax\n#define GL_FUNC_ADD_EXT                   0x8006\n#define GL_MIN_EXT                        0x8007\n#define GL_MAX_EXT                        0x8008\n#define GL_BLEND_EQUATION_EXT             0x8009\n#endif\n\n#ifndef GL_EXT_blend_subtract\n#define GL_FUNC_SUBTRACT_EXT              0x800A\n#define GL_FUNC_REVERSE_SUBTRACT_EXT      0x800B\n#endif\n\n#ifndef GL_EXT_blend_logic_op\n#endif\n\n#ifndef GL_SGIX_interlace\n#define GL_INTERLACE_SGIX                 0x8094\n#endif\n\n#ifndef GL_SGIX_pixel_tiles\n#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E\n#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F\n#define GL_PIXEL_TILE_WIDTH_SGIX          0x8140\n#define GL_PIXEL_TILE_HEIGHT_SGIX         0x8141\n#define GL_PIXEL_TILE_GRID_WIDTH_SGIX     0x8142\n#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX    0x8143\n#define GL_PIXEL_TILE_GRID_DEPTH_SGIX     0x8144\n#define GL_PIXEL_TILE_CACHE_SIZE_SGIX     0x8145\n#endif\n\n#ifndef GL_SGIS_texture_select\n#define GL_DUAL_ALPHA4_SGIS               0x8110\n#define GL_DUAL_ALPHA8_SGIS               0x8111\n#define GL_DUAL_ALPHA12_SGIS              0x8112\n#define GL_DUAL_ALPHA16_SGIS              0x8113\n#define GL_DUAL_LUMINANCE4_SGIS           0x8114\n#define GL_DUAL_LUMINANCE8_SGIS           0x8115\n#define GL_DUAL_LUMINANCE12_SGIS          0x8116\n#define GL_DUAL_LUMINANCE16_SGIS          0x8117\n#define GL_DUAL_INTENSITY4_SGIS           0x8118\n#define GL_DUAL_INTENSITY8_SGIS           0x8119\n#define GL_DUAL_INTENSITY12_SGIS          0x811A\n#define GL_DUAL_INTENSITY16_SGIS          0x811B\n#define GL_DUAL_LUMINANCE_ALPHA4_SGIS     0x811C\n#define GL_DUAL_LUMINANCE_ALPHA8_SGIS     0x811D\n#define GL_QUAD_ALPHA4_SGIS               0x811E\n#define GL_QUAD_ALPHA8_SGIS               0x811F\n#define GL_QUAD_LUMINANCE4_SGIS           0x8120\n#define GL_QUAD_LUMINANCE8_SGIS           0x8121\n#define GL_QUAD_INTENSITY4_SGIS           0x8122\n#define GL_QUAD_INTENSITY8_SGIS           0x8123\n#define GL_DUAL_TEXTURE_SELECT_SGIS       0x8124\n#define GL_QUAD_TEXTURE_SELECT_SGIS       0x8125\n#endif\n\n#ifndef GL_SGIX_sprite\n#define GL_SPRITE_SGIX                    0x8148\n#define GL_SPRITE_MODE_SGIX               0x8149\n#define GL_SPRITE_AXIS_SGIX               0x814A\n#define GL_SPRITE_TRANSLATION_SGIX        0x814B\n#define GL_SPRITE_AXIAL_SGIX              0x814C\n#define GL_SPRITE_OBJECT_ALIGNED_SGIX     0x814D\n#define GL_SPRITE_EYE_ALIGNED_SGIX        0x814E\n#endif\n\n#ifndef GL_SGIX_texture_multi_buffer\n#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E\n#endif\n\n#ifndef GL_EXT_point_parameters\n#define GL_POINT_SIZE_MIN_EXT             0x8126\n#define GL_POINT_SIZE_MAX_EXT             0x8127\n#define GL_POINT_FADE_THRESHOLD_SIZE_EXT  0x8128\n#define GL_DISTANCE_ATTENUATION_EXT       0x8129\n#endif\n\n#ifndef GL_SGIS_point_parameters\n#define GL_POINT_SIZE_MIN_SGIS            0x8126\n#define GL_POINT_SIZE_MAX_SGIS            0x8127\n#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128\n#define GL_DISTANCE_ATTENUATION_SGIS      0x8129\n#endif\n\n#ifndef GL_SGIX_instruments\n#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180\n#define GL_INSTRUMENT_MEASUREMENTS_SGIX   0x8181\n#endif\n\n#ifndef GL_SGIX_texture_scale_bias\n#define GL_POST_TEXTURE_FILTER_BIAS_SGIX  0x8179\n#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A\n#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B\n#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C\n#endif\n\n#ifndef GL_SGIX_framezoom\n#define GL_FRAMEZOOM_SGIX                 0x818B\n#define GL_FRAMEZOOM_FACTOR_SGIX          0x818C\n#define GL_MAX_FRAMEZOOM_FACTOR_SGIX      0x818D\n#endif\n\n#ifndef GL_SGIX_tag_sample_buffer\n#endif\n\n#ifndef GL_FfdMaskSGIX\n#define GL_TEXTURE_DEFORMATION_BIT_SGIX   0x00000001\n#define GL_GEOMETRY_DEFORMATION_BIT_SGIX  0x00000002\n#endif\n\n#ifndef GL_SGIX_polynomial_ffd\n#define GL_GEOMETRY_DEFORMATION_SGIX      0x8194\n#define GL_TEXTURE_DEFORMATION_SGIX       0x8195\n#define GL_DEFORMATIONS_MASK_SGIX         0x8196\n#define GL_MAX_DEFORMATION_ORDER_SGIX     0x8197\n#endif\n\n#ifndef GL_SGIX_reference_plane\n#define GL_REFERENCE_PLANE_SGIX           0x817D\n#define GL_REFERENCE_PLANE_EQUATION_SGIX  0x817E\n#endif\n\n#ifndef GL_SGIX_flush_raster\n#endif\n\n#ifndef GL_SGIX_depth_texture\n#define GL_DEPTH_COMPONENT16_SGIX         0x81A5\n#define GL_DEPTH_COMPONENT24_SGIX         0x81A6\n#define GL_DEPTH_COMPONENT32_SGIX         0x81A7\n#endif\n\n#ifndef GL_SGIS_fog_function\n#define GL_FOG_FUNC_SGIS                  0x812A\n#define GL_FOG_FUNC_POINTS_SGIS           0x812B\n#define GL_MAX_FOG_FUNC_POINTS_SGIS       0x812C\n#endif\n\n#ifndef GL_SGIX_fog_offset\n#define GL_FOG_OFFSET_SGIX                0x8198\n#define GL_FOG_OFFSET_VALUE_SGIX          0x8199\n#endif\n\n#ifndef GL_HP_image_transform\n#define GL_IMAGE_SCALE_X_HP               0x8155\n#define GL_IMAGE_SCALE_Y_HP               0x8156\n#define GL_IMAGE_TRANSLATE_X_HP           0x8157\n#define GL_IMAGE_TRANSLATE_Y_HP           0x8158\n#define GL_IMAGE_ROTATE_ANGLE_HP          0x8159\n#define GL_IMAGE_ROTATE_ORIGIN_X_HP       0x815A\n#define GL_IMAGE_ROTATE_ORIGIN_Y_HP       0x815B\n#define GL_IMAGE_MAG_FILTER_HP            0x815C\n#define GL_IMAGE_MIN_FILTER_HP            0x815D\n#define GL_IMAGE_CUBIC_WEIGHT_HP          0x815E\n#define GL_CUBIC_HP                       0x815F\n#define GL_AVERAGE_HP                     0x8160\n#define GL_IMAGE_TRANSFORM_2D_HP          0x8161\n#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162\n#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163\n#endif\n\n#ifndef GL_HP_convolution_border_modes\n#define GL_IGNORE_BORDER_HP               0x8150\n#define GL_CONSTANT_BORDER_HP             0x8151\n#define GL_REPLICATE_BORDER_HP            0x8153\n#define GL_CONVOLUTION_BORDER_COLOR_HP    0x8154\n#endif\n\n#ifndef GL_INGR_palette_buffer\n#endif\n\n#ifndef GL_SGIX_texture_add_env\n#define GL_TEXTURE_ENV_BIAS_SGIX          0x80BE\n#endif\n\n#ifndef GL_EXT_color_subtable\n#endif\n\n#ifndef GL_PGI_vertex_hints\n#define GL_VERTEX_DATA_HINT_PGI           0x1A22A\n#define GL_VERTEX_CONSISTENT_HINT_PGI     0x1A22B\n#define GL_MATERIAL_SIDE_HINT_PGI         0x1A22C\n#define GL_MAX_VERTEX_HINT_PGI            0x1A22D\n#define GL_COLOR3_BIT_PGI                 0x00010000\n#define GL_COLOR4_BIT_PGI                 0x00020000\n#define GL_EDGEFLAG_BIT_PGI               0x00040000\n#define GL_INDEX_BIT_PGI                  0x00080000\n#define GL_MAT_AMBIENT_BIT_PGI            0x00100000\n#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000\n#define GL_MAT_DIFFUSE_BIT_PGI            0x00400000\n#define GL_MAT_EMISSION_BIT_PGI           0x00800000\n#define GL_MAT_COLOR_INDEXES_BIT_PGI      0x01000000\n#define GL_MAT_SHININESS_BIT_PGI          0x02000000\n#define GL_MAT_SPECULAR_BIT_PGI           0x04000000\n#define GL_NORMAL_BIT_PGI                 0x08000000\n#define GL_TEXCOORD1_BIT_PGI              0x10000000\n#define GL_TEXCOORD2_BIT_PGI              0x20000000\n#define GL_TEXCOORD3_BIT_PGI              0x40000000\n#define GL_TEXCOORD4_BIT_PGI              0x80000000\n#define GL_VERTEX23_BIT_PGI               0x00000004\n#define GL_VERTEX4_BIT_PGI                0x00000008\n#endif\n\n#ifndef GL_PGI_misc_hints\n#define GL_PREFER_DOUBLEBUFFER_HINT_PGI   0x1A1F8\n#define GL_CONSERVE_MEMORY_HINT_PGI       0x1A1FD\n#define GL_RECLAIM_MEMORY_HINT_PGI        0x1A1FE\n#define GL_NATIVE_GRAPHICS_HANDLE_PGI     0x1A202\n#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203\n#define GL_NATIVE_GRAPHICS_END_HINT_PGI   0x1A204\n#define GL_ALWAYS_FAST_HINT_PGI           0x1A20C\n#define GL_ALWAYS_SOFT_HINT_PGI           0x1A20D\n#define GL_ALLOW_DRAW_OBJ_HINT_PGI        0x1A20E\n#define GL_ALLOW_DRAW_WIN_HINT_PGI        0x1A20F\n#define GL_ALLOW_DRAW_FRG_HINT_PGI        0x1A210\n#define GL_ALLOW_DRAW_MEM_HINT_PGI        0x1A211\n#define GL_STRICT_DEPTHFUNC_HINT_PGI      0x1A216\n#define GL_STRICT_LIGHTING_HINT_PGI       0x1A217\n#define GL_STRICT_SCISSOR_HINT_PGI        0x1A218\n#define GL_FULL_STIPPLE_HINT_PGI          0x1A219\n#define GL_CLIP_NEAR_HINT_PGI             0x1A220\n#define GL_CLIP_FAR_HINT_PGI              0x1A221\n#define GL_WIDE_LINE_HINT_PGI             0x1A222\n#define GL_BACK_NORMALS_HINT_PGI          0x1A223\n#endif\n\n#ifndef GL_EXT_paletted_texture\n#define GL_COLOR_INDEX1_EXT               0x80E2\n#define GL_COLOR_INDEX2_EXT               0x80E3\n#define GL_COLOR_INDEX4_EXT               0x80E4\n#define GL_COLOR_INDEX8_EXT               0x80E5\n#define GL_COLOR_INDEX12_EXT              0x80E6\n#define GL_COLOR_INDEX16_EXT              0x80E7\n#define GL_TEXTURE_INDEX_SIZE_EXT         0x80ED\n#endif\n\n#ifndef GL_EXT_clip_volume_hint\n#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT  0x80F0\n#endif\n\n#ifndef GL_SGIX_list_priority\n#define GL_LIST_PRIORITY_SGIX             0x8182\n#endif\n\n#ifndef GL_SGIX_ir_instrument1\n#define GL_IR_INSTRUMENT1_SGIX            0x817F\n#endif\n\n#ifndef GL_SGIX_calligraphic_fragment\n#define GL_CALLIGRAPHIC_FRAGMENT_SGIX     0x8183\n#endif\n\n#ifndef GL_SGIX_texture_lod_bias\n#define GL_TEXTURE_LOD_BIAS_S_SGIX        0x818E\n#define GL_TEXTURE_LOD_BIAS_T_SGIX        0x818F\n#define GL_TEXTURE_LOD_BIAS_R_SGIX        0x8190\n#endif\n\n#ifndef GL_SGIX_shadow_ambient\n#define GL_SHADOW_AMBIENT_SGIX            0x80BF\n#endif\n\n#ifndef GL_EXT_index_texture\n#endif\n\n#ifndef GL_EXT_index_material\n#define GL_INDEX_MATERIAL_EXT             0x81B8\n#define GL_INDEX_MATERIAL_PARAMETER_EXT   0x81B9\n#define GL_INDEX_MATERIAL_FACE_EXT        0x81BA\n#endif\n\n#ifndef GL_EXT_index_func\n#define GL_INDEX_TEST_EXT                 0x81B5\n#define GL_INDEX_TEST_FUNC_EXT            0x81B6\n#define GL_INDEX_TEST_REF_EXT             0x81B7\n#endif\n\n#ifndef GL_EXT_index_array_formats\n#define GL_IUI_V2F_EXT                    0x81AD\n#define GL_IUI_V3F_EXT                    0x81AE\n#define GL_IUI_N3F_V2F_EXT                0x81AF\n#define GL_IUI_N3F_V3F_EXT                0x81B0\n#define GL_T2F_IUI_V2F_EXT                0x81B1\n#define GL_T2F_IUI_V3F_EXT                0x81B2\n#define GL_T2F_IUI_N3F_V2F_EXT            0x81B3\n#define GL_T2F_IUI_N3F_V3F_EXT            0x81B4\n#endif\n\n#ifndef GL_EXT_compiled_vertex_array\n#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT   0x81A8\n#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT   0x81A9\n#endif\n\n#ifndef GL_EXT_cull_vertex\n#define GL_CULL_VERTEX_EXT                0x81AA\n#define GL_CULL_VERTEX_EYE_POSITION_EXT   0x81AB\n#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC\n#endif\n\n#ifndef GL_SGIX_ycrcb\n#define GL_YCRCB_422_SGIX                 0x81BB\n#define GL_YCRCB_444_SGIX                 0x81BC\n#endif\n\n#ifndef GL_SGIX_fragment_lighting\n#define GL_FRAGMENT_LIGHTING_SGIX         0x8400\n#define GL_FRAGMENT_COLOR_MATERIAL_SGIX   0x8401\n#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402\n#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403\n#define GL_MAX_FRAGMENT_LIGHTS_SGIX       0x8404\n#define GL_MAX_ACTIVE_LIGHTS_SGIX         0x8405\n#define GL_CURRENT_RASTER_NORMAL_SGIX     0x8406\n#define GL_LIGHT_ENV_MODE_SGIX            0x8407\n#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408\n#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409\n#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A\n#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B\n#define GL_FRAGMENT_LIGHT0_SGIX           0x840C\n#define GL_FRAGMENT_LIGHT1_SGIX           0x840D\n#define GL_FRAGMENT_LIGHT2_SGIX           0x840E\n#define GL_FRAGMENT_LIGHT3_SGIX           0x840F\n#define GL_FRAGMENT_LIGHT4_SGIX           0x8410\n#define GL_FRAGMENT_LIGHT5_SGIX           0x8411\n#define GL_FRAGMENT_LIGHT6_SGIX           0x8412\n#define GL_FRAGMENT_LIGHT7_SGIX           0x8413\n#endif\n\n#ifndef GL_IBM_rasterpos_clip\n#define GL_RASTER_POSITION_UNCLIPPED_IBM  0x19262\n#endif\n\n#ifndef GL_HP_texture_lighting\n#define GL_TEXTURE_LIGHTING_MODE_HP       0x8167\n#define GL_TEXTURE_POST_SPECULAR_HP       0x8168\n#define GL_TEXTURE_PRE_SPECULAR_HP        0x8169\n#endif\n\n#ifndef GL_EXT_draw_range_elements\n#define GL_MAX_ELEMENTS_VERTICES_EXT      0x80E8\n#define GL_MAX_ELEMENTS_INDICES_EXT       0x80E9\n#endif\n\n#ifndef GL_WIN_phong_shading\n#define GL_PHONG_WIN                      0x80EA\n#define GL_PHONG_HINT_WIN                 0x80EB\n#endif\n\n#ifndef GL_WIN_specular_fog\n#define GL_FOG_SPECULAR_TEXTURE_WIN       0x80EC\n#endif\n\n#ifndef GL_EXT_light_texture\n#define GL_FRAGMENT_MATERIAL_EXT          0x8349\n#define GL_FRAGMENT_NORMAL_EXT            0x834A\n#define GL_FRAGMENT_COLOR_EXT             0x834C\n#define GL_ATTENUATION_EXT                0x834D\n#define GL_SHADOW_ATTENUATION_EXT         0x834E\n#define GL_TEXTURE_APPLICATION_MODE_EXT   0x834F\n#define GL_TEXTURE_LIGHT_EXT              0x8350\n#define GL_TEXTURE_MATERIAL_FACE_EXT      0x8351\n#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352\n/* reuse GL_FRAGMENT_DEPTH_EXT */\n#endif\n\n#ifndef GL_SGIX_blend_alpha_minmax\n#define GL_ALPHA_MIN_SGIX                 0x8320\n#define GL_ALPHA_MAX_SGIX                 0x8321\n#endif\n\n#ifndef GL_SGIX_impact_pixel_texture\n#define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX   0x8184\n#define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX     0x8185\n#define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX     0x8186\n#define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187\n#define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188\n#define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX    0x8189\n#define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX    0x818A\n#endif\n\n#ifndef GL_EXT_bgra\n#define GL_BGR_EXT                        0x80E0\n#define GL_BGRA_EXT                       0x80E1\n#endif\n\n#ifndef GL_SGIX_async\n#define GL_ASYNC_MARKER_SGIX              0x8329\n#endif\n\n#ifndef GL_SGIX_async_pixel\n#define GL_ASYNC_TEX_IMAGE_SGIX           0x835C\n#define GL_ASYNC_DRAW_PIXELS_SGIX         0x835D\n#define GL_ASYNC_READ_PIXELS_SGIX         0x835E\n#define GL_MAX_ASYNC_TEX_IMAGE_SGIX       0x835F\n#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX     0x8360\n#define GL_MAX_ASYNC_READ_PIXELS_SGIX     0x8361\n#endif\n\n#ifndef GL_SGIX_async_histogram\n#define GL_ASYNC_HISTOGRAM_SGIX           0x832C\n#define GL_MAX_ASYNC_HISTOGRAM_SGIX       0x832D\n#endif\n\n#ifndef GL_INTEL_texture_scissor\n#endif\n\n#ifndef GL_INTEL_parallel_arrays\n#define GL_PARALLEL_ARRAYS_INTEL          0x83F4\n#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5\n#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6\n#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7\n#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8\n#endif\n\n#ifndef GL_HP_occlusion_test\n#define GL_OCCLUSION_TEST_HP              0x8165\n#define GL_OCCLUSION_TEST_RESULT_HP       0x8166\n#endif\n\n#ifndef GL_EXT_pixel_transform\n#define GL_PIXEL_TRANSFORM_2D_EXT         0x8330\n#define GL_PIXEL_MAG_FILTER_EXT           0x8331\n#define GL_PIXEL_MIN_FILTER_EXT           0x8332\n#define GL_PIXEL_CUBIC_WEIGHT_EXT         0x8333\n#define GL_CUBIC_EXT                      0x8334\n#define GL_AVERAGE_EXT                    0x8335\n#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336\n#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337\n#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT  0x8338\n#endif\n\n#ifndef GL_EXT_pixel_transform_color_table\n#endif\n\n#ifndef GL_EXT_shared_texture_palette\n#define GL_SHARED_TEXTURE_PALETTE_EXT     0x81FB\n#endif\n\n#ifndef GL_EXT_separate_specular_color\n#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT  0x81F8\n#define GL_SINGLE_COLOR_EXT               0x81F9\n#define GL_SEPARATE_SPECULAR_COLOR_EXT    0x81FA\n#endif\n\n#ifndef GL_EXT_secondary_color\n#define GL_COLOR_SUM_EXT                  0x8458\n#define GL_CURRENT_SECONDARY_COLOR_EXT    0x8459\n#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A\n#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B\n#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C\n#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D\n#define GL_SECONDARY_COLOR_ARRAY_EXT      0x845E\n#endif\n\n#ifndef GL_EXT_texture_perturb_normal\n#define GL_PERTURB_EXT                    0x85AE\n#define GL_TEXTURE_NORMAL_EXT             0x85AF\n#endif\n\n#ifndef GL_EXT_multi_draw_arrays\n#endif\n\n#ifndef GL_EXT_fog_coord\n#define GL_FOG_COORDINATE_SOURCE_EXT      0x8450\n#define GL_FOG_COORDINATE_EXT             0x8451\n#define GL_FRAGMENT_DEPTH_EXT             0x8452\n#define GL_CURRENT_FOG_COORDINATE_EXT     0x8453\n#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT  0x8454\n#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455\n#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456\n#define GL_FOG_COORDINATE_ARRAY_EXT       0x8457\n#endif\n\n#ifndef GL_REND_screen_coordinates\n#define GL_SCREEN_COORDINATES_REND        0x8490\n#define GL_INVERTED_SCREEN_W_REND         0x8491\n#endif\n\n#ifndef GL_EXT_coordinate_frame\n#define GL_TANGENT_ARRAY_EXT              0x8439\n#define GL_BINORMAL_ARRAY_EXT             0x843A\n#define GL_CURRENT_TANGENT_EXT            0x843B\n#define GL_CURRENT_BINORMAL_EXT           0x843C\n#define GL_TANGENT_ARRAY_TYPE_EXT         0x843E\n#define GL_TANGENT_ARRAY_STRIDE_EXT       0x843F\n#define GL_BINORMAL_ARRAY_TYPE_EXT        0x8440\n#define GL_BINORMAL_ARRAY_STRIDE_EXT      0x8441\n#define GL_TANGENT_ARRAY_POINTER_EXT      0x8442\n#define GL_BINORMAL_ARRAY_POINTER_EXT     0x8443\n#define GL_MAP1_TANGENT_EXT               0x8444\n#define GL_MAP2_TANGENT_EXT               0x8445\n#define GL_MAP1_BINORMAL_EXT              0x8446\n#define GL_MAP2_BINORMAL_EXT              0x8447\n#endif\n\n#ifndef GL_EXT_texture_env_combine\n#define GL_COMBINE_EXT                    0x8570\n#define GL_COMBINE_RGB_EXT                0x8571\n#define GL_COMBINE_ALPHA_EXT              0x8572\n#define GL_RGB_SCALE_EXT                  0x8573\n#define GL_ADD_SIGNED_EXT                 0x8574\n#define GL_INTERPOLATE_EXT                0x8575\n#define GL_CONSTANT_EXT                   0x8576\n#define GL_PRIMARY_COLOR_EXT              0x8577\n#define GL_PREVIOUS_EXT                   0x8578\n#define GL_SOURCE0_RGB_EXT                0x8580\n#define GL_SOURCE1_RGB_EXT                0x8581\n#define GL_SOURCE2_RGB_EXT                0x8582\n#define GL_SOURCE0_ALPHA_EXT              0x8588\n#define GL_SOURCE1_ALPHA_EXT              0x8589\n#define GL_SOURCE2_ALPHA_EXT              0x858A\n#define GL_OPERAND0_RGB_EXT               0x8590\n#define GL_OPERAND1_RGB_EXT               0x8591\n#define GL_OPERAND2_RGB_EXT               0x8592\n#define GL_OPERAND0_ALPHA_EXT             0x8598\n#define GL_OPERAND1_ALPHA_EXT             0x8599\n#define GL_OPERAND2_ALPHA_EXT             0x859A\n#endif\n\n#ifndef GL_APPLE_specular_vector\n#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0\n#endif\n\n#ifndef GL_APPLE_transform_hint\n#define GL_TRANSFORM_HINT_APPLE           0x85B1\n#endif\n\n#ifndef GL_SGIX_fog_scale\n#define GL_FOG_SCALE_SGIX                 0x81FC\n#define GL_FOG_SCALE_VALUE_SGIX           0x81FD\n#endif\n\n#ifndef GL_SUNX_constant_data\n#define GL_UNPACK_CONSTANT_DATA_SUNX      0x81D5\n#define GL_TEXTURE_CONSTANT_DATA_SUNX     0x81D6\n#endif\n\n#ifndef GL_SUN_global_alpha\n#define GL_GLOBAL_ALPHA_SUN               0x81D9\n#define GL_GLOBAL_ALPHA_FACTOR_SUN        0x81DA\n#endif\n\n#ifndef GL_SUN_triangle_list\n#define GL_RESTART_SUN                    0x0001\n#define GL_REPLACE_MIDDLE_SUN             0x0002\n#define GL_REPLACE_OLDEST_SUN             0x0003\n#define GL_TRIANGLE_LIST_SUN              0x81D7\n#define GL_REPLACEMENT_CODE_SUN           0x81D8\n#define GL_REPLACEMENT_CODE_ARRAY_SUN     0x85C0\n#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1\n#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2\n#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3\n#define GL_R1UI_V3F_SUN                   0x85C4\n#define GL_R1UI_C4UB_V3F_SUN              0x85C5\n#define GL_R1UI_C3F_V3F_SUN               0x85C6\n#define GL_R1UI_N3F_V3F_SUN               0x85C7\n#define GL_R1UI_C4F_N3F_V3F_SUN           0x85C8\n#define GL_R1UI_T2F_V3F_SUN               0x85C9\n#define GL_R1UI_T2F_N3F_V3F_SUN           0x85CA\n#define GL_R1UI_T2F_C4F_N3F_V3F_SUN       0x85CB\n#endif\n\n#ifndef GL_SUN_vertex\n#endif\n\n#ifndef GL_EXT_blend_func_separate\n#define GL_BLEND_DST_RGB_EXT              0x80C8\n#define GL_BLEND_SRC_RGB_EXT              0x80C9\n#define GL_BLEND_DST_ALPHA_EXT            0x80CA\n#define GL_BLEND_SRC_ALPHA_EXT            0x80CB\n#endif\n\n#ifndef GL_INGR_color_clamp\n#define GL_RED_MIN_CLAMP_INGR             0x8560\n#define GL_GREEN_MIN_CLAMP_INGR           0x8561\n#define GL_BLUE_MIN_CLAMP_INGR            0x8562\n#define GL_ALPHA_MIN_CLAMP_INGR           0x8563\n#define GL_RED_MAX_CLAMP_INGR             0x8564\n#define GL_GREEN_MAX_CLAMP_INGR           0x8565\n#define GL_BLUE_MAX_CLAMP_INGR            0x8566\n#define GL_ALPHA_MAX_CLAMP_INGR           0x8567\n#endif\n\n#ifndef GL_INGR_interlace_read\n#define GL_INTERLACE_READ_INGR            0x8568\n#endif\n\n#ifndef GL_EXT_stencil_wrap\n#define GL_INCR_WRAP_EXT                  0x8507\n#define GL_DECR_WRAP_EXT                  0x8508\n#endif\n\n#ifndef GL_EXT_422_pixels\n#define GL_422_EXT                        0x80CC\n#define GL_422_REV_EXT                    0x80CD\n#define GL_422_AVERAGE_EXT                0x80CE\n#define GL_422_REV_AVERAGE_EXT            0x80CF\n#endif\n\n#ifndef GL_NV_texgen_reflection\n#define GL_NORMAL_MAP_NV                  0x8511\n#define GL_REFLECTION_MAP_NV              0x8512\n#endif\n\n#ifndef GL_EXT_texture_cube_map\n#define GL_NORMAL_MAP_EXT                 0x8511\n#define GL_REFLECTION_MAP_EXT             0x8512\n#define GL_TEXTURE_CUBE_MAP_EXT           0x8513\n#define GL_TEXTURE_BINDING_CUBE_MAP_EXT   0x8514\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A\n#define GL_PROXY_TEXTURE_CUBE_MAP_EXT     0x851B\n#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT  0x851C\n#endif\n\n#ifndef GL_SUN_convolution_border_modes\n#define GL_WRAP_BORDER_SUN                0x81D4\n#endif\n\n#ifndef GL_EXT_texture_env_add\n#endif\n\n#ifndef GL_EXT_texture_lod_bias\n#define GL_MAX_TEXTURE_LOD_BIAS_EXT       0x84FD\n#define GL_TEXTURE_FILTER_CONTROL_EXT     0x8500\n#define GL_TEXTURE_LOD_BIAS_EXT           0x8501\n#endif\n\n#ifndef GL_EXT_texture_filter_anisotropic\n#define GL_TEXTURE_MAX_ANISOTROPY_EXT     0x84FE\n#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF\n#endif\n\n#ifndef GL_EXT_vertex_weighting\n#define GL_MODELVIEW0_STACK_DEPTH_EXT     GL_MODELVIEW_STACK_DEPTH\n#define GL_MODELVIEW1_STACK_DEPTH_EXT     0x8502\n#define GL_MODELVIEW0_MATRIX_EXT          GL_MODELVIEW_MATRIX\n#define GL_MODELVIEW1_MATRIX_EXT          0x8506\n#define GL_VERTEX_WEIGHTING_EXT           0x8509\n#define GL_MODELVIEW0_EXT                 GL_MODELVIEW\n#define GL_MODELVIEW1_EXT                 0x850A\n#define GL_CURRENT_VERTEX_WEIGHT_EXT      0x850B\n#define GL_VERTEX_WEIGHT_ARRAY_EXT        0x850C\n#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT   0x850D\n#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT   0x850E\n#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F\n#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510\n#endif\n\n#ifndef GL_NV_light_max_exponent\n#define GL_MAX_SHININESS_NV               0x8504\n#define GL_MAX_SPOT_EXPONENT_NV           0x8505\n#endif\n\n#ifndef GL_NV_vertex_array_range\n#define GL_VERTEX_ARRAY_RANGE_NV          0x851D\n#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV   0x851E\n#define GL_VERTEX_ARRAY_RANGE_VALID_NV    0x851F\n#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520\n#define GL_VERTEX_ARRAY_RANGE_POINTER_NV  0x8521\n#endif\n\n#ifndef GL_NV_register_combiners\n#define GL_REGISTER_COMBINERS_NV          0x8522\n#define GL_VARIABLE_A_NV                  0x8523\n#define GL_VARIABLE_B_NV                  0x8524\n#define GL_VARIABLE_C_NV                  0x8525\n#define GL_VARIABLE_D_NV                  0x8526\n#define GL_VARIABLE_E_NV                  0x8527\n#define GL_VARIABLE_F_NV                  0x8528\n#define GL_VARIABLE_G_NV                  0x8529\n#define GL_CONSTANT_COLOR0_NV             0x852A\n#define GL_CONSTANT_COLOR1_NV             0x852B\n#define GL_PRIMARY_COLOR_NV               0x852C\n#define GL_SECONDARY_COLOR_NV             0x852D\n#define GL_SPARE0_NV                      0x852E\n#define GL_SPARE1_NV                      0x852F\n#define GL_DISCARD_NV                     0x8530\n#define GL_E_TIMES_F_NV                   0x8531\n#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532\n#define GL_UNSIGNED_IDENTITY_NV           0x8536\n#define GL_UNSIGNED_INVERT_NV             0x8537\n#define GL_EXPAND_NORMAL_NV               0x8538\n#define GL_EXPAND_NEGATE_NV               0x8539\n#define GL_HALF_BIAS_NORMAL_NV            0x853A\n#define GL_HALF_BIAS_NEGATE_NV            0x853B\n#define GL_SIGNED_IDENTITY_NV             0x853C\n#define GL_SIGNED_NEGATE_NV               0x853D\n#define GL_SCALE_BY_TWO_NV                0x853E\n#define GL_SCALE_BY_FOUR_NV               0x853F\n#define GL_SCALE_BY_ONE_HALF_NV           0x8540\n#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV   0x8541\n#define GL_COMBINER_INPUT_NV              0x8542\n#define GL_COMBINER_MAPPING_NV            0x8543\n#define GL_COMBINER_COMPONENT_USAGE_NV    0x8544\n#define GL_COMBINER_AB_DOT_PRODUCT_NV     0x8545\n#define GL_COMBINER_CD_DOT_PRODUCT_NV     0x8546\n#define GL_COMBINER_MUX_SUM_NV            0x8547\n#define GL_COMBINER_SCALE_NV              0x8548\n#define GL_COMBINER_BIAS_NV               0x8549\n#define GL_COMBINER_AB_OUTPUT_NV          0x854A\n#define GL_COMBINER_CD_OUTPUT_NV          0x854B\n#define GL_COMBINER_SUM_OUTPUT_NV         0x854C\n#define GL_MAX_GENERAL_COMBINERS_NV       0x854D\n#define GL_NUM_GENERAL_COMBINERS_NV       0x854E\n#define GL_COLOR_SUM_CLAMP_NV             0x854F\n#define GL_COMBINER0_NV                   0x8550\n#define GL_COMBINER1_NV                   0x8551\n#define GL_COMBINER2_NV                   0x8552\n#define GL_COMBINER3_NV                   0x8553\n#define GL_COMBINER4_NV                   0x8554\n#define GL_COMBINER5_NV                   0x8555\n#define GL_COMBINER6_NV                   0x8556\n#define GL_COMBINER7_NV                   0x8557\n/* reuse GL_TEXTURE0_ARB */\n/* reuse GL_TEXTURE1_ARB */\n/* reuse GL_ZERO */\n/* reuse GL_NONE */\n/* reuse GL_FOG */\n#endif\n\n#ifndef GL_NV_fog_distance\n#define GL_FOG_DISTANCE_MODE_NV           0x855A\n#define GL_EYE_RADIAL_NV                  0x855B\n#define GL_EYE_PLANE_ABSOLUTE_NV          0x855C\n/* reuse GL_EYE_PLANE */\n#endif\n\n#ifndef GL_NV_texgen_emboss\n#define GL_EMBOSS_LIGHT_NV                0x855D\n#define GL_EMBOSS_CONSTANT_NV             0x855E\n#define GL_EMBOSS_MAP_NV                  0x855F\n#endif\n\n#ifndef GL_NV_blend_square\n#endif\n\n#ifndef GL_NV_texture_env_combine4\n#define GL_COMBINE4_NV                    0x8503\n#define GL_SOURCE3_RGB_NV                 0x8583\n#define GL_SOURCE3_ALPHA_NV               0x858B\n#define GL_OPERAND3_RGB_NV                0x8593\n#define GL_OPERAND3_ALPHA_NV              0x859B\n#endif\n\n#ifndef GL_MESA_resize_buffers\n#endif\n\n#ifndef GL_MESA_window_pos\n#endif\n\n#ifndef GL_EXT_texture_compression_s3tc\n#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT   0x83F0\n#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  0x83F1\n#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  0x83F2\n#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  0x83F3\n#endif\n\n#ifndef GL_IBM_cull_vertex\n#define GL_CULL_VERTEX_IBM                103050\n#endif\n\n#ifndef GL_IBM_multimode_draw_arrays\n#endif\n\n#ifndef GL_IBM_vertex_array_lists\n#define GL_VERTEX_ARRAY_LIST_IBM          103070\n#define GL_NORMAL_ARRAY_LIST_IBM          103071\n#define GL_COLOR_ARRAY_LIST_IBM           103072\n#define GL_INDEX_ARRAY_LIST_IBM           103073\n#define GL_TEXTURE_COORD_ARRAY_LIST_IBM   103074\n#define GL_EDGE_FLAG_ARRAY_LIST_IBM       103075\n#define GL_FOG_COORDINATE_ARRAY_LIST_IBM  103076\n#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077\n#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM   103080\n#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM   103081\n#define GL_COLOR_ARRAY_LIST_STRIDE_IBM    103082\n#define GL_INDEX_ARRAY_LIST_STRIDE_IBM    103083\n#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084\n#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085\n#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086\n#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087\n#endif\n\n#ifndef GL_SGIX_subsample\n#define GL_PACK_SUBSAMPLE_RATE_SGIX       0x85A0\n#define GL_UNPACK_SUBSAMPLE_RATE_SGIX     0x85A1\n#define GL_PIXEL_SUBSAMPLE_4444_SGIX      0x85A2\n#define GL_PIXEL_SUBSAMPLE_2424_SGIX      0x85A3\n#define GL_PIXEL_SUBSAMPLE_4242_SGIX      0x85A4\n#endif\n\n#ifndef GL_SGIX_ycrcb_subsample\n#endif\n\n#ifndef GL_SGIX_ycrcba\n#define GL_YCRCB_SGIX                     0x8318\n#define GL_YCRCBA_SGIX                    0x8319\n#endif\n\n#ifndef GL_SGI_depth_pass_instrument\n#define GL_DEPTH_PASS_INSTRUMENT_SGIX     0x8310\n#define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311\n#define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312\n#endif\n\n#ifndef GL_3DFX_texture_compression_FXT1\n#define GL_COMPRESSED_RGB_FXT1_3DFX       0x86B0\n#define GL_COMPRESSED_RGBA_FXT1_3DFX      0x86B1\n#endif\n\n#ifndef GL_3DFX_multisample\n#define GL_MULTISAMPLE_3DFX               0x86B2\n#define GL_SAMPLE_BUFFERS_3DFX            0x86B3\n#define GL_SAMPLES_3DFX                   0x86B4\n#define GL_MULTISAMPLE_BIT_3DFX           0x20000000\n#endif\n\n#ifndef GL_3DFX_tbuffer\n#endif\n\n#ifndef GL_EXT_multisample\n#define GL_MULTISAMPLE_EXT                0x809D\n#define GL_SAMPLE_ALPHA_TO_MASK_EXT       0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE_EXT        0x809F\n#define GL_SAMPLE_MASK_EXT                0x80A0\n#define GL_1PASS_EXT                      0x80A1\n#define GL_2PASS_0_EXT                    0x80A2\n#define GL_2PASS_1_EXT                    0x80A3\n#define GL_4PASS_0_EXT                    0x80A4\n#define GL_4PASS_1_EXT                    0x80A5\n#define GL_4PASS_2_EXT                    0x80A6\n#define GL_4PASS_3_EXT                    0x80A7\n#define GL_SAMPLE_BUFFERS_EXT             0x80A8\n#define GL_SAMPLES_EXT                    0x80A9\n#define GL_SAMPLE_MASK_VALUE_EXT          0x80AA\n#define GL_SAMPLE_MASK_INVERT_EXT         0x80AB\n#define GL_SAMPLE_PATTERN_EXT             0x80AC\n#define GL_MULTISAMPLE_BIT_EXT            0x20000000\n#endif\n\n#ifndef GL_SGIX_vertex_preclip\n#define GL_VERTEX_PRECLIP_SGIX            0x83EE\n#define GL_VERTEX_PRECLIP_HINT_SGIX       0x83EF\n#endif\n\n#ifndef GL_SGIX_convolution_accuracy\n#define GL_CONVOLUTION_HINT_SGIX          0x8316\n#endif\n\n#ifndef GL_SGIX_resample\n#define GL_PACK_RESAMPLE_SGIX             0x842C\n#define GL_UNPACK_RESAMPLE_SGIX           0x842D\n#define GL_RESAMPLE_REPLICATE_SGIX        0x842E\n#define GL_RESAMPLE_ZERO_FILL_SGIX        0x842F\n#define GL_RESAMPLE_DECIMATE_SGIX         0x8430\n#endif\n\n#ifndef GL_SGIS_point_line_texgen\n#define GL_EYE_DISTANCE_TO_POINT_SGIS     0x81F0\n#define GL_OBJECT_DISTANCE_TO_POINT_SGIS  0x81F1\n#define GL_EYE_DISTANCE_TO_LINE_SGIS      0x81F2\n#define GL_OBJECT_DISTANCE_TO_LINE_SGIS   0x81F3\n#define GL_EYE_POINT_SGIS                 0x81F4\n#define GL_OBJECT_POINT_SGIS              0x81F5\n#define GL_EYE_LINE_SGIS                  0x81F6\n#define GL_OBJECT_LINE_SGIS               0x81F7\n#endif\n\n#ifndef GL_SGIS_texture_color_mask\n#define GL_TEXTURE_COLOR_WRITEMASK_SGIS   0x81EF\n#endif\n\n#ifndef GL_EXT_texture_env_dot3\n#define GL_DOT3_RGB_EXT                   0x8740\n#define GL_DOT3_RGBA_EXT                  0x8741\n#endif\n\n#ifndef GL_ATI_texture_mirror_once\n#define GL_MIRROR_CLAMP_ATI               0x8742\n#define GL_MIRROR_CLAMP_TO_EDGE_ATI       0x8743\n#endif\n\n#ifndef GL_NV_fence\n#define GL_ALL_COMPLETED_NV               0x84F2\n#define GL_FENCE_STATUS_NV                0x84F3\n#define GL_FENCE_CONDITION_NV             0x84F4\n#endif\n\n#ifndef GL_IBM_texture_mirrored_repeat\n#define GL_MIRRORED_REPEAT_IBM            0x8370\n#endif\n\n#ifndef GL_NV_evaluators\n#define GL_EVAL_2D_NV                     0x86C0\n#define GL_EVAL_TRIANGULAR_2D_NV          0x86C1\n#define GL_MAP_TESSELLATION_NV            0x86C2\n#define GL_MAP_ATTRIB_U_ORDER_NV          0x86C3\n#define GL_MAP_ATTRIB_V_ORDER_NV          0x86C4\n#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5\n#define GL_EVAL_VERTEX_ATTRIB0_NV         0x86C6\n#define GL_EVAL_VERTEX_ATTRIB1_NV         0x86C7\n#define GL_EVAL_VERTEX_ATTRIB2_NV         0x86C8\n#define GL_EVAL_VERTEX_ATTRIB3_NV         0x86C9\n#define GL_EVAL_VERTEX_ATTRIB4_NV         0x86CA\n#define GL_EVAL_VERTEX_ATTRIB5_NV         0x86CB\n#define GL_EVAL_VERTEX_ATTRIB6_NV         0x86CC\n#define GL_EVAL_VERTEX_ATTRIB7_NV         0x86CD\n#define GL_EVAL_VERTEX_ATTRIB8_NV         0x86CE\n#define GL_EVAL_VERTEX_ATTRIB9_NV         0x86CF\n#define GL_EVAL_VERTEX_ATTRIB10_NV        0x86D0\n#define GL_EVAL_VERTEX_ATTRIB11_NV        0x86D1\n#define GL_EVAL_VERTEX_ATTRIB12_NV        0x86D2\n#define GL_EVAL_VERTEX_ATTRIB13_NV        0x86D3\n#define GL_EVAL_VERTEX_ATTRIB14_NV        0x86D4\n#define GL_EVAL_VERTEX_ATTRIB15_NV        0x86D5\n#define GL_MAX_MAP_TESSELLATION_NV        0x86D6\n#define GL_MAX_RATIONAL_EVAL_ORDER_NV     0x86D7\n#endif\n\n#ifndef GL_NV_packed_depth_stencil\n#define GL_DEPTH_STENCIL_NV               0x84F9\n#define GL_UNSIGNED_INT_24_8_NV           0x84FA\n#endif\n\n#ifndef GL_NV_register_combiners2\n#define GL_PER_STAGE_CONSTANTS_NV         0x8535\n#endif\n\n#ifndef GL_NV_texture_compression_vtc\n#endif\n\n#ifndef GL_NV_texture_rectangle\n#define GL_TEXTURE_RECTANGLE_NV           0x84F5\n#define GL_TEXTURE_BINDING_RECTANGLE_NV   0x84F6\n#define GL_PROXY_TEXTURE_RECTANGLE_NV     0x84F7\n#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV  0x84F8\n#endif\n\n#ifndef GL_NV_texture_shader\n#define GL_OFFSET_TEXTURE_RECTANGLE_NV    0x864C\n#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D\n#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E\n#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9\n#define GL_UNSIGNED_INT_S8_S8_8_8_NV      0x86DA\n#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV  0x86DB\n#define GL_DSDT_MAG_INTENSITY_NV          0x86DC\n#define GL_SHADER_CONSISTENT_NV           0x86DD\n#define GL_TEXTURE_SHADER_NV              0x86DE\n#define GL_SHADER_OPERATION_NV            0x86DF\n#define GL_CULL_MODES_NV                  0x86E0\n#define GL_OFFSET_TEXTURE_MATRIX_NV       0x86E1\n#define GL_OFFSET_TEXTURE_SCALE_NV        0x86E2\n#define GL_OFFSET_TEXTURE_BIAS_NV         0x86E3\n#define GL_OFFSET_TEXTURE_2D_MATRIX_NV    GL_OFFSET_TEXTURE_MATRIX_NV\n#define GL_OFFSET_TEXTURE_2D_SCALE_NV     GL_OFFSET_TEXTURE_SCALE_NV\n#define GL_OFFSET_TEXTURE_2D_BIAS_NV      GL_OFFSET_TEXTURE_BIAS_NV\n#define GL_PREVIOUS_TEXTURE_INPUT_NV      0x86E4\n#define GL_CONST_EYE_NV                   0x86E5\n#define GL_PASS_THROUGH_NV                0x86E6\n#define GL_CULL_FRAGMENT_NV               0x86E7\n#define GL_OFFSET_TEXTURE_2D_NV           0x86E8\n#define GL_DEPENDENT_AR_TEXTURE_2D_NV     0x86E9\n#define GL_DEPENDENT_GB_TEXTURE_2D_NV     0x86EA\n#define GL_DOT_PRODUCT_NV                 0x86EC\n#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV   0x86ED\n#define GL_DOT_PRODUCT_TEXTURE_2D_NV      0x86EE\n#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0\n#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1\n#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2\n#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3\n#define GL_HILO_NV                        0x86F4\n#define GL_DSDT_NV                        0x86F5\n#define GL_DSDT_MAG_NV                    0x86F6\n#define GL_DSDT_MAG_VIB_NV                0x86F7\n#define GL_HILO16_NV                      0x86F8\n#define GL_SIGNED_HILO_NV                 0x86F9\n#define GL_SIGNED_HILO16_NV               0x86FA\n#define GL_SIGNED_RGBA_NV                 0x86FB\n#define GL_SIGNED_RGBA8_NV                0x86FC\n#define GL_SIGNED_RGB_NV                  0x86FE\n#define GL_SIGNED_RGB8_NV                 0x86FF\n#define GL_SIGNED_LUMINANCE_NV            0x8701\n#define GL_SIGNED_LUMINANCE8_NV           0x8702\n#define GL_SIGNED_LUMINANCE_ALPHA_NV      0x8703\n#define GL_SIGNED_LUMINANCE8_ALPHA8_NV    0x8704\n#define GL_SIGNED_ALPHA_NV                0x8705\n#define GL_SIGNED_ALPHA8_NV               0x8706\n#define GL_SIGNED_INTENSITY_NV            0x8707\n#define GL_SIGNED_INTENSITY8_NV           0x8708\n#define GL_DSDT8_NV                       0x8709\n#define GL_DSDT8_MAG8_NV                  0x870A\n#define GL_DSDT8_MAG8_INTENSITY8_NV       0x870B\n#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV   0x870C\n#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D\n#define GL_HI_SCALE_NV                    0x870E\n#define GL_LO_SCALE_NV                    0x870F\n#define GL_DS_SCALE_NV                    0x8710\n#define GL_DT_SCALE_NV                    0x8711\n#define GL_MAGNITUDE_SCALE_NV             0x8712\n#define GL_VIBRANCE_SCALE_NV              0x8713\n#define GL_HI_BIAS_NV                     0x8714\n#define GL_LO_BIAS_NV                     0x8715\n#define GL_DS_BIAS_NV                     0x8716\n#define GL_DT_BIAS_NV                     0x8717\n#define GL_MAGNITUDE_BIAS_NV              0x8718\n#define GL_VIBRANCE_BIAS_NV               0x8719\n#define GL_TEXTURE_BORDER_VALUES_NV       0x871A\n#define GL_TEXTURE_HI_SIZE_NV             0x871B\n#define GL_TEXTURE_LO_SIZE_NV             0x871C\n#define GL_TEXTURE_DS_SIZE_NV             0x871D\n#define GL_TEXTURE_DT_SIZE_NV             0x871E\n#define GL_TEXTURE_MAG_SIZE_NV            0x871F\n#endif\n\n#ifndef GL_NV_texture_shader2\n#define GL_DOT_PRODUCT_TEXTURE_3D_NV      0x86EF\n#endif\n\n#ifndef GL_NV_vertex_array_range2\n#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533\n#endif\n\n#ifndef GL_NV_vertex_program\n#define GL_VERTEX_PROGRAM_NV              0x8620\n#define GL_VERTEX_STATE_PROGRAM_NV        0x8621\n#define GL_ATTRIB_ARRAY_SIZE_NV           0x8623\n#define GL_ATTRIB_ARRAY_STRIDE_NV         0x8624\n#define GL_ATTRIB_ARRAY_TYPE_NV           0x8625\n#define GL_CURRENT_ATTRIB_NV              0x8626\n#define GL_PROGRAM_LENGTH_NV              0x8627\n#define GL_PROGRAM_STRING_NV              0x8628\n#define GL_MODELVIEW_PROJECTION_NV        0x8629\n#define GL_IDENTITY_NV                    0x862A\n#define GL_INVERSE_NV                     0x862B\n#define GL_TRANSPOSE_NV                   0x862C\n#define GL_INVERSE_TRANSPOSE_NV           0x862D\n#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E\n#define GL_MAX_TRACK_MATRICES_NV          0x862F\n#define GL_MATRIX0_NV                     0x8630\n#define GL_MATRIX1_NV                     0x8631\n#define GL_MATRIX2_NV                     0x8632\n#define GL_MATRIX3_NV                     0x8633\n#define GL_MATRIX4_NV                     0x8634\n#define GL_MATRIX5_NV                     0x8635\n#define GL_MATRIX6_NV                     0x8636\n#define GL_MATRIX7_NV                     0x8637\n#define GL_CURRENT_MATRIX_STACK_DEPTH_NV  0x8640\n#define GL_CURRENT_MATRIX_NV              0x8641\n#define GL_VERTEX_PROGRAM_POINT_SIZE_NV   0x8642\n#define GL_VERTEX_PROGRAM_TWO_SIDE_NV     0x8643\n#define GL_PROGRAM_PARAMETER_NV           0x8644\n#define GL_ATTRIB_ARRAY_POINTER_NV        0x8645\n#define GL_PROGRAM_TARGET_NV              0x8646\n#define GL_PROGRAM_RESIDENT_NV            0x8647\n#define GL_TRACK_MATRIX_NV                0x8648\n#define GL_TRACK_MATRIX_TRANSFORM_NV      0x8649\n#define GL_VERTEX_PROGRAM_BINDING_NV      0x864A\n#define GL_PROGRAM_ERROR_POSITION_NV      0x864B\n#define GL_VERTEX_ATTRIB_ARRAY0_NV        0x8650\n#define GL_VERTEX_ATTRIB_ARRAY1_NV        0x8651\n#define GL_VERTEX_ATTRIB_ARRAY2_NV        0x8652\n#define GL_VERTEX_ATTRIB_ARRAY3_NV        0x8653\n#define GL_VERTEX_ATTRIB_ARRAY4_NV        0x8654\n#define GL_VERTEX_ATTRIB_ARRAY5_NV        0x8655\n#define GL_VERTEX_ATTRIB_ARRAY6_NV        0x8656\n#define GL_VERTEX_ATTRIB_ARRAY7_NV        0x8657\n#define GL_VERTEX_ATTRIB_ARRAY8_NV        0x8658\n#define GL_VERTEX_ATTRIB_ARRAY9_NV        0x8659\n#define GL_VERTEX_ATTRIB_ARRAY10_NV       0x865A\n#define GL_VERTEX_ATTRIB_ARRAY11_NV       0x865B\n#define GL_VERTEX_ATTRIB_ARRAY12_NV       0x865C\n#define GL_VERTEX_ATTRIB_ARRAY13_NV       0x865D\n#define GL_VERTEX_ATTRIB_ARRAY14_NV       0x865E\n#define GL_VERTEX_ATTRIB_ARRAY15_NV       0x865F\n#define GL_MAP1_VERTEX_ATTRIB0_4_NV       0x8660\n#define GL_MAP1_VERTEX_ATTRIB1_4_NV       0x8661\n#define GL_MAP1_VERTEX_ATTRIB2_4_NV       0x8662\n#define GL_MAP1_VERTEX_ATTRIB3_4_NV       0x8663\n#define GL_MAP1_VERTEX_ATTRIB4_4_NV       0x8664\n#define GL_MAP1_VERTEX_ATTRIB5_4_NV       0x8665\n#define GL_MAP1_VERTEX_ATTRIB6_4_NV       0x8666\n#define GL_MAP1_VERTEX_ATTRIB7_4_NV       0x8667\n#define GL_MAP1_VERTEX_ATTRIB8_4_NV       0x8668\n#define GL_MAP1_VERTEX_ATTRIB9_4_NV       0x8669\n#define GL_MAP1_VERTEX_ATTRIB10_4_NV      0x866A\n#define GL_MAP1_VERTEX_ATTRIB11_4_NV      0x866B\n#define GL_MAP1_VERTEX_ATTRIB12_4_NV      0x866C\n#define GL_MAP1_VERTEX_ATTRIB13_4_NV      0x866D\n#define GL_MAP1_VERTEX_ATTRIB14_4_NV      0x866E\n#define GL_MAP1_VERTEX_ATTRIB15_4_NV      0x866F\n#define GL_MAP2_VERTEX_ATTRIB0_4_NV       0x8670\n#define GL_MAP2_VERTEX_ATTRIB1_4_NV       0x8671\n#define GL_MAP2_VERTEX_ATTRIB2_4_NV       0x8672\n#define GL_MAP2_VERTEX_ATTRIB3_4_NV       0x8673\n#define GL_MAP2_VERTEX_ATTRIB4_4_NV       0x8674\n#define GL_MAP2_VERTEX_ATTRIB5_4_NV       0x8675\n#define GL_MAP2_VERTEX_ATTRIB6_4_NV       0x8676\n#define GL_MAP2_VERTEX_ATTRIB7_4_NV       0x8677\n#define GL_MAP2_VERTEX_ATTRIB8_4_NV       0x8678\n#define GL_MAP2_VERTEX_ATTRIB9_4_NV       0x8679\n#define GL_MAP2_VERTEX_ATTRIB10_4_NV      0x867A\n#define GL_MAP2_VERTEX_ATTRIB11_4_NV      0x867B\n#define GL_MAP2_VERTEX_ATTRIB12_4_NV      0x867C\n#define GL_MAP2_VERTEX_ATTRIB13_4_NV      0x867D\n#define GL_MAP2_VERTEX_ATTRIB14_4_NV      0x867E\n#define GL_MAP2_VERTEX_ATTRIB15_4_NV      0x867F\n#endif\n\n#ifndef GL_SGIX_texture_coordinate_clamp\n#define GL_TEXTURE_MAX_CLAMP_S_SGIX       0x8369\n#define GL_TEXTURE_MAX_CLAMP_T_SGIX       0x836A\n#define GL_TEXTURE_MAX_CLAMP_R_SGIX       0x836B\n#endif\n\n#ifndef GL_SGIX_scalebias_hint\n#define GL_SCALEBIAS_HINT_SGIX            0x8322\n#endif\n\n#ifndef GL_OML_interlace\n#define GL_INTERLACE_OML                  0x8980\n#define GL_INTERLACE_READ_OML             0x8981\n#endif\n\n#ifndef GL_OML_subsample\n#define GL_FORMAT_SUBSAMPLE_24_24_OML     0x8982\n#define GL_FORMAT_SUBSAMPLE_244_244_OML   0x8983\n#endif\n\n#ifndef GL_OML_resample\n#define GL_PACK_RESAMPLE_OML              0x8984\n#define GL_UNPACK_RESAMPLE_OML            0x8985\n#define GL_RESAMPLE_REPLICATE_OML         0x8986\n#define GL_RESAMPLE_ZERO_FILL_OML         0x8987\n#define GL_RESAMPLE_AVERAGE_OML           0x8988\n#define GL_RESAMPLE_DECIMATE_OML          0x8989\n#endif\n\n#ifndef GL_NV_copy_depth_to_color\n#define GL_DEPTH_STENCIL_TO_RGBA_NV       0x886E\n#define GL_DEPTH_STENCIL_TO_BGRA_NV       0x886F\n#endif\n\n#ifndef GL_ATI_envmap_bumpmap\n#define GL_BUMP_ROT_MATRIX_ATI            0x8775\n#define GL_BUMP_ROT_MATRIX_SIZE_ATI       0x8776\n#define GL_BUMP_NUM_TEX_UNITS_ATI         0x8777\n#define GL_BUMP_TEX_UNITS_ATI             0x8778\n#define GL_DUDV_ATI                       0x8779\n#define GL_DU8DV8_ATI                     0x877A\n#define GL_BUMP_ENVMAP_ATI                0x877B\n#define GL_BUMP_TARGET_ATI                0x877C\n#endif\n\n#ifndef GL_ATI_fragment_shader\n#define GL_FRAGMENT_SHADER_ATI            0x8920\n#define GL_REG_0_ATI                      0x8921\n#define GL_REG_1_ATI                      0x8922\n#define GL_REG_2_ATI                      0x8923\n#define GL_REG_3_ATI                      0x8924\n#define GL_REG_4_ATI                      0x8925\n#define GL_REG_5_ATI                      0x8926\n#define GL_REG_6_ATI                      0x8927\n#define GL_REG_7_ATI                      0x8928\n#define GL_REG_8_ATI                      0x8929\n#define GL_REG_9_ATI                      0x892A\n#define GL_REG_10_ATI                     0x892B\n#define GL_REG_11_ATI                     0x892C\n#define GL_REG_12_ATI                     0x892D\n#define GL_REG_13_ATI                     0x892E\n#define GL_REG_14_ATI                     0x892F\n#define GL_REG_15_ATI                     0x8930\n#define GL_REG_16_ATI                     0x8931\n#define GL_REG_17_ATI                     0x8932\n#define GL_REG_18_ATI                     0x8933\n#define GL_REG_19_ATI                     0x8934\n#define GL_REG_20_ATI                     0x8935\n#define GL_REG_21_ATI                     0x8936\n#define GL_REG_22_ATI                     0x8937\n#define GL_REG_23_ATI                     0x8938\n#define GL_REG_24_ATI                     0x8939\n#define GL_REG_25_ATI                     0x893A\n#define GL_REG_26_ATI                     0x893B\n#define GL_REG_27_ATI                     0x893C\n#define GL_REG_28_ATI                     0x893D\n#define GL_REG_29_ATI                     0x893E\n#define GL_REG_30_ATI                     0x893F\n#define GL_REG_31_ATI                     0x8940\n#define GL_CON_0_ATI                      0x8941\n#define GL_CON_1_ATI                      0x8942\n#define GL_CON_2_ATI                      0x8943\n#define GL_CON_3_ATI                      0x8944\n#define GL_CON_4_ATI                      0x8945\n#define GL_CON_5_ATI                      0x8946\n#define GL_CON_6_ATI                      0x8947\n#define GL_CON_7_ATI                      0x8948\n#define GL_CON_8_ATI                      0x8949\n#define GL_CON_9_ATI                      0x894A\n#define GL_CON_10_ATI                     0x894B\n#define GL_CON_11_ATI                     0x894C\n#define GL_CON_12_ATI                     0x894D\n#define GL_CON_13_ATI                     0x894E\n#define GL_CON_14_ATI                     0x894F\n#define GL_CON_15_ATI                     0x8950\n#define GL_CON_16_ATI                     0x8951\n#define GL_CON_17_ATI                     0x8952\n#define GL_CON_18_ATI                     0x8953\n#define GL_CON_19_ATI                     0x8954\n#define GL_CON_20_ATI                     0x8955\n#define GL_CON_21_ATI                     0x8956\n#define GL_CON_22_ATI                     0x8957\n#define GL_CON_23_ATI                     0x8958\n#define GL_CON_24_ATI                     0x8959\n#define GL_CON_25_ATI                     0x895A\n#define GL_CON_26_ATI                     0x895B\n#define GL_CON_27_ATI                     0x895C\n#define GL_CON_28_ATI                     0x895D\n#define GL_CON_29_ATI                     0x895E\n#define GL_CON_30_ATI                     0x895F\n#define GL_CON_31_ATI                     0x8960\n#define GL_MOV_ATI                        0x8961\n#define GL_ADD_ATI                        0x8963\n#define GL_MUL_ATI                        0x8964\n#define GL_SUB_ATI                        0x8965\n#define GL_DOT3_ATI                       0x8966\n#define GL_DOT4_ATI                       0x8967\n#define GL_MAD_ATI                        0x8968\n#define GL_LERP_ATI                       0x8969\n#define GL_CND_ATI                        0x896A\n#define GL_CND0_ATI                       0x896B\n#define GL_DOT2_ADD_ATI                   0x896C\n#define GL_SECONDARY_INTERPOLATOR_ATI     0x896D\n#define GL_NUM_FRAGMENT_REGISTERS_ATI     0x896E\n#define GL_NUM_FRAGMENT_CONSTANTS_ATI     0x896F\n#define GL_NUM_PASSES_ATI                 0x8970\n#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI  0x8971\n#define GL_NUM_INSTRUCTIONS_TOTAL_ATI     0x8972\n#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973\n#define GL_NUM_LOOPBACK_COMPONENTS_ATI    0x8974\n#define GL_COLOR_ALPHA_PAIRING_ATI        0x8975\n#define GL_SWIZZLE_STR_ATI                0x8976\n#define GL_SWIZZLE_STQ_ATI                0x8977\n#define GL_SWIZZLE_STR_DR_ATI             0x8978\n#define GL_SWIZZLE_STQ_DQ_ATI             0x8979\n#define GL_SWIZZLE_STRQ_ATI               0x897A\n#define GL_SWIZZLE_STRQ_DQ_ATI            0x897B\n#define GL_RED_BIT_ATI                    0x00000001\n#define GL_GREEN_BIT_ATI                  0x00000002\n#define GL_BLUE_BIT_ATI                   0x00000004\n#define GL_2X_BIT_ATI                     0x00000001\n#define GL_4X_BIT_ATI                     0x00000002\n#define GL_8X_BIT_ATI                     0x00000004\n#define GL_HALF_BIT_ATI                   0x00000008\n#define GL_QUARTER_BIT_ATI                0x00000010\n#define GL_EIGHTH_BIT_ATI                 0x00000020\n#define GL_SATURATE_BIT_ATI               0x00000040\n#define GL_COMP_BIT_ATI                   0x00000002\n#define GL_NEGATE_BIT_ATI                 0x00000004\n#define GL_BIAS_BIT_ATI                   0x00000008\n#endif\n\n#ifndef GL_ATI_pn_triangles\n#define GL_PN_TRIANGLES_ATI               0x87F0\n#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1\n#define GL_PN_TRIANGLES_POINT_MODE_ATI    0x87F2\n#define GL_PN_TRIANGLES_NORMAL_MODE_ATI   0x87F3\n#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4\n#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5\n#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6\n#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7\n#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8\n#endif\n\n#ifndef GL_ATI_vertex_array_object\n#define GL_STATIC_ATI                     0x8760\n#define GL_DYNAMIC_ATI                    0x8761\n#define GL_PRESERVE_ATI                   0x8762\n#define GL_DISCARD_ATI                    0x8763\n#define GL_OBJECT_BUFFER_SIZE_ATI         0x8764\n#define GL_OBJECT_BUFFER_USAGE_ATI        0x8765\n#define GL_ARRAY_OBJECT_BUFFER_ATI        0x8766\n#define GL_ARRAY_OBJECT_OFFSET_ATI        0x8767\n#endif\n\n#ifndef GL_EXT_vertex_shader\n#define GL_VERTEX_SHADER_EXT              0x8780\n#define GL_VERTEX_SHADER_BINDING_EXT      0x8781\n#define GL_OP_INDEX_EXT                   0x8782\n#define GL_OP_NEGATE_EXT                  0x8783\n#define GL_OP_DOT3_EXT                    0x8784\n#define GL_OP_DOT4_EXT                    0x8785\n#define GL_OP_MUL_EXT                     0x8786\n#define GL_OP_ADD_EXT                     0x8787\n#define GL_OP_MADD_EXT                    0x8788\n#define GL_OP_FRAC_EXT                    0x8789\n#define GL_OP_MAX_EXT                     0x878A\n#define GL_OP_MIN_EXT                     0x878B\n#define GL_OP_SET_GE_EXT                  0x878C\n#define GL_OP_SET_LT_EXT                  0x878D\n#define GL_OP_CLAMP_EXT                   0x878E\n#define GL_OP_FLOOR_EXT                   0x878F\n#define GL_OP_ROUND_EXT                   0x8790\n#define GL_OP_EXP_BASE_2_EXT              0x8791\n#define GL_OP_LOG_BASE_2_EXT              0x8792\n#define GL_OP_POWER_EXT                   0x8793\n#define GL_OP_RECIP_EXT                   0x8794\n#define GL_OP_RECIP_SQRT_EXT              0x8795\n#define GL_OP_SUB_EXT                     0x8796\n#define GL_OP_CROSS_PRODUCT_EXT           0x8797\n#define GL_OP_MULTIPLY_MATRIX_EXT         0x8798\n#define GL_OP_MOV_EXT                     0x8799\n#define GL_OUTPUT_VERTEX_EXT              0x879A\n#define GL_OUTPUT_COLOR0_EXT              0x879B\n#define GL_OUTPUT_COLOR1_EXT              0x879C\n#define GL_OUTPUT_TEXTURE_COORD0_EXT      0x879D\n#define GL_OUTPUT_TEXTURE_COORD1_EXT      0x879E\n#define GL_OUTPUT_TEXTURE_COORD2_EXT      0x879F\n#define GL_OUTPUT_TEXTURE_COORD3_EXT      0x87A0\n#define GL_OUTPUT_TEXTURE_COORD4_EXT      0x87A1\n#define GL_OUTPUT_TEXTURE_COORD5_EXT      0x87A2\n#define GL_OUTPUT_TEXTURE_COORD6_EXT      0x87A3\n#define GL_OUTPUT_TEXTURE_COORD7_EXT      0x87A4\n#define GL_OUTPUT_TEXTURE_COORD8_EXT      0x87A5\n#define GL_OUTPUT_TEXTURE_COORD9_EXT      0x87A6\n#define GL_OUTPUT_TEXTURE_COORD10_EXT     0x87A7\n#define GL_OUTPUT_TEXTURE_COORD11_EXT     0x87A8\n#define GL_OUTPUT_TEXTURE_COORD12_EXT     0x87A9\n#define GL_OUTPUT_TEXTURE_COORD13_EXT     0x87AA\n#define GL_OUTPUT_TEXTURE_COORD14_EXT     0x87AB\n#define GL_OUTPUT_TEXTURE_COORD15_EXT     0x87AC\n#define GL_OUTPUT_TEXTURE_COORD16_EXT     0x87AD\n#define GL_OUTPUT_TEXTURE_COORD17_EXT     0x87AE\n#define GL_OUTPUT_TEXTURE_COORD18_EXT     0x87AF\n#define GL_OUTPUT_TEXTURE_COORD19_EXT     0x87B0\n#define GL_OUTPUT_TEXTURE_COORD20_EXT     0x87B1\n#define GL_OUTPUT_TEXTURE_COORD21_EXT     0x87B2\n#define GL_OUTPUT_TEXTURE_COORD22_EXT     0x87B3\n#define GL_OUTPUT_TEXTURE_COORD23_EXT     0x87B4\n#define GL_OUTPUT_TEXTURE_COORD24_EXT     0x87B5\n#define GL_OUTPUT_TEXTURE_COORD25_EXT     0x87B6\n#define GL_OUTPUT_TEXTURE_COORD26_EXT     0x87B7\n#define GL_OUTPUT_TEXTURE_COORD27_EXT     0x87B8\n#define GL_OUTPUT_TEXTURE_COORD28_EXT     0x87B9\n#define GL_OUTPUT_TEXTURE_COORD29_EXT     0x87BA\n#define GL_OUTPUT_TEXTURE_COORD30_EXT     0x87BB\n#define GL_OUTPUT_TEXTURE_COORD31_EXT     0x87BC\n#define GL_OUTPUT_FOG_EXT                 0x87BD\n#define GL_SCALAR_EXT                     0x87BE\n#define GL_VECTOR_EXT                     0x87BF\n#define GL_MATRIX_EXT                     0x87C0\n#define GL_VARIANT_EXT                    0x87C1\n#define GL_INVARIANT_EXT                  0x87C2\n#define GL_LOCAL_CONSTANT_EXT             0x87C3\n#define GL_LOCAL_EXT                      0x87C4\n#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5\n#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6\n#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7\n#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8\n#define GL_MAX_VERTEX_SHADER_LOCALS_EXT   0x87C9\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE\n#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF\n#define GL_VERTEX_SHADER_VARIANTS_EXT     0x87D0\n#define GL_VERTEX_SHADER_INVARIANTS_EXT   0x87D1\n#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2\n#define GL_VERTEX_SHADER_LOCALS_EXT       0x87D3\n#define GL_VERTEX_SHADER_OPTIMIZED_EXT    0x87D4\n#define GL_X_EXT                          0x87D5\n#define GL_Y_EXT                          0x87D6\n#define GL_Z_EXT                          0x87D7\n#define GL_W_EXT                          0x87D8\n#define GL_NEGATIVE_X_EXT                 0x87D9\n#define GL_NEGATIVE_Y_EXT                 0x87DA\n#define GL_NEGATIVE_Z_EXT                 0x87DB\n#define GL_NEGATIVE_W_EXT                 0x87DC\n#define GL_ZERO_EXT                       0x87DD\n#define GL_ONE_EXT                        0x87DE\n#define GL_NEGATIVE_ONE_EXT               0x87DF\n#define GL_NORMALIZED_RANGE_EXT           0x87E0\n#define GL_FULL_RANGE_EXT                 0x87E1\n#define GL_CURRENT_VERTEX_EXT             0x87E2\n#define GL_MVP_MATRIX_EXT                 0x87E3\n#define GL_VARIANT_VALUE_EXT              0x87E4\n#define GL_VARIANT_DATATYPE_EXT           0x87E5\n#define GL_VARIANT_ARRAY_STRIDE_EXT       0x87E6\n#define GL_VARIANT_ARRAY_TYPE_EXT         0x87E7\n#define GL_VARIANT_ARRAY_EXT              0x87E8\n#define GL_VARIANT_ARRAY_POINTER_EXT      0x87E9\n#define GL_INVARIANT_VALUE_EXT            0x87EA\n#define GL_INVARIANT_DATATYPE_EXT         0x87EB\n#define GL_LOCAL_CONSTANT_VALUE_EXT       0x87EC\n#define GL_LOCAL_CONSTANT_DATATYPE_EXT    0x87ED\n#endif\n\n#ifndef GL_ATI_vertex_streams\n#define GL_MAX_VERTEX_STREAMS_ATI         0x876B\n#define GL_VERTEX_STREAM0_ATI             0x876C\n#define GL_VERTEX_STREAM1_ATI             0x876D\n#define GL_VERTEX_STREAM2_ATI             0x876E\n#define GL_VERTEX_STREAM3_ATI             0x876F\n#define GL_VERTEX_STREAM4_ATI             0x8770\n#define GL_VERTEX_STREAM5_ATI             0x8771\n#define GL_VERTEX_STREAM6_ATI             0x8772\n#define GL_VERTEX_STREAM7_ATI             0x8773\n#define GL_VERTEX_SOURCE_ATI              0x8774\n#endif\n\n#ifndef GL_ATI_element_array\n#define GL_ELEMENT_ARRAY_ATI              0x8768\n#define GL_ELEMENT_ARRAY_TYPE_ATI         0x8769\n#define GL_ELEMENT_ARRAY_POINTER_ATI      0x876A\n#endif\n\n#ifndef GL_SUN_mesh_array\n#define GL_QUAD_MESH_SUN                  0x8614\n#define GL_TRIANGLE_MESH_SUN              0x8615\n#endif\n\n#ifndef GL_SUN_slice_accum\n#define GL_SLICE_ACCUM_SUN                0x85CC\n#endif\n\n#ifndef GL_NV_multisample_filter_hint\n#define GL_MULTISAMPLE_FILTER_HINT_NV     0x8534\n#endif\n\n#ifndef GL_NV_depth_clamp\n#define GL_DEPTH_CLAMP_NV                 0x864F\n#endif\n\n#ifndef GL_NV_occlusion_query\n#define GL_PIXEL_COUNTER_BITS_NV          0x8864\n#define GL_CURRENT_OCCLUSION_QUERY_ID_NV  0x8865\n#define GL_PIXEL_COUNT_NV                 0x8866\n#define GL_PIXEL_COUNT_AVAILABLE_NV       0x8867\n#endif\n\n#ifndef GL_NV_point_sprite\n#define GL_POINT_SPRITE_NV                0x8861\n#define GL_COORD_REPLACE_NV               0x8862\n#define GL_POINT_SPRITE_R_MODE_NV         0x8863\n#endif\n\n#ifndef GL_NV_texture_shader3\n#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850\n#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851\n#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852\n#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853\n#define GL_OFFSET_HILO_TEXTURE_2D_NV      0x8854\n#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855\n#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856\n#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857\n#define GL_DEPENDENT_HILO_TEXTURE_2D_NV   0x8858\n#define GL_DEPENDENT_RGB_TEXTURE_3D_NV    0x8859\n#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A\n#define GL_DOT_PRODUCT_PASS_THROUGH_NV    0x885B\n#define GL_DOT_PRODUCT_TEXTURE_1D_NV      0x885C\n#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D\n#define GL_HILO8_NV                       0x885E\n#define GL_SIGNED_HILO8_NV                0x885F\n#define GL_FORCE_BLUE_TO_ONE_NV           0x8860\n#endif\n\n#ifndef GL_NV_vertex_program1_1\n#endif\n\n#ifndef GL_EXT_shadow_funcs\n#endif\n\n#ifndef GL_EXT_stencil_two_side\n#define GL_STENCIL_TEST_TWO_SIDE_EXT      0x8910\n#define GL_ACTIVE_STENCIL_FACE_EXT        0x8911\n#endif\n\n#ifndef GL_ATI_text_fragment_shader\n#define GL_TEXT_FRAGMENT_SHADER_ATI       0x8200\n#endif\n\n#ifndef GL_APPLE_client_storage\n#define GL_UNPACK_CLIENT_STORAGE_APPLE    0x85B2\n#endif\n\n#ifndef GL_APPLE_element_array\n#define GL_ELEMENT_ARRAY_APPLE            0x8768\n#define GL_ELEMENT_ARRAY_TYPE_APPLE       0x8769\n#define GL_ELEMENT_ARRAY_POINTER_APPLE    0x876A\n#endif\n\n#ifndef GL_APPLE_fence\n#define GL_DRAW_PIXELS_APPLE              0x8A0A\n#define GL_FENCE_APPLE                    0x8A0B\n#endif\n\n#ifndef GL_APPLE_vertex_array_object\n#define GL_VERTEX_ARRAY_BINDING_APPLE     0x85B5\n#endif\n\n#ifndef GL_APPLE_vertex_array_range\n#define GL_VERTEX_ARRAY_RANGE_APPLE       0x851D\n#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E\n#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F\n#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521\n#define GL_STORAGE_CACHED_APPLE           0x85BE\n#define GL_STORAGE_SHARED_APPLE           0x85BF\n#endif\n\n#ifndef GL_APPLE_ycbcr_422\n#define GL_YCBCR_422_APPLE                0x85B9\n#define GL_UNSIGNED_SHORT_8_8_APPLE       0x85BA\n#define GL_UNSIGNED_SHORT_8_8_REV_APPLE   0x85BB\n#endif\n\n#ifndef GL_S3_s3tc\n#define GL_RGB_S3TC                       0x83A0\n#define GL_RGB4_S3TC                      0x83A1\n#define GL_RGBA_S3TC                      0x83A2\n#define GL_RGBA4_S3TC                     0x83A3\n#endif\n\n#ifndef GL_ATI_draw_buffers\n#define GL_MAX_DRAW_BUFFERS_ATI           0x8824\n#define GL_DRAW_BUFFER0_ATI               0x8825\n#define GL_DRAW_BUFFER1_ATI               0x8826\n#define GL_DRAW_BUFFER2_ATI               0x8827\n#define GL_DRAW_BUFFER3_ATI               0x8828\n#define GL_DRAW_BUFFER4_ATI               0x8829\n#define GL_DRAW_BUFFER5_ATI               0x882A\n#define GL_DRAW_BUFFER6_ATI               0x882B\n#define GL_DRAW_BUFFER7_ATI               0x882C\n#define GL_DRAW_BUFFER8_ATI               0x882D\n#define GL_DRAW_BUFFER9_ATI               0x882E\n#define GL_DRAW_BUFFER10_ATI              0x882F\n#define GL_DRAW_BUFFER11_ATI              0x8830\n#define GL_DRAW_BUFFER12_ATI              0x8831\n#define GL_DRAW_BUFFER13_ATI              0x8832\n#define GL_DRAW_BUFFER14_ATI              0x8833\n#define GL_DRAW_BUFFER15_ATI              0x8834\n#endif\n\n#ifndef GL_ATI_pixel_format_float\n#define GL_TYPE_RGBA_FLOAT_ATI            0x8820\n#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835\n#endif\n\n#ifndef GL_ATI_texture_env_combine3\n#define GL_MODULATE_ADD_ATI               0x8744\n#define GL_MODULATE_SIGNED_ADD_ATI        0x8745\n#define GL_MODULATE_SUBTRACT_ATI          0x8746\n#endif\n\n#ifndef GL_ATI_texture_float\n#define GL_RGBA_FLOAT32_ATI               0x8814\n#define GL_RGB_FLOAT32_ATI                0x8815\n#define GL_ALPHA_FLOAT32_ATI              0x8816\n#define GL_INTENSITY_FLOAT32_ATI          0x8817\n#define GL_LUMINANCE_FLOAT32_ATI          0x8818\n#define GL_LUMINANCE_ALPHA_FLOAT32_ATI    0x8819\n#define GL_RGBA_FLOAT16_ATI               0x881A\n#define GL_RGB_FLOAT16_ATI                0x881B\n#define GL_ALPHA_FLOAT16_ATI              0x881C\n#define GL_INTENSITY_FLOAT16_ATI          0x881D\n#define GL_LUMINANCE_FLOAT16_ATI          0x881E\n#define GL_LUMINANCE_ALPHA_FLOAT16_ATI    0x881F\n#endif\n\n#ifndef GL_NV_float_buffer\n#define GL_FLOAT_R_NV                     0x8880\n#define GL_FLOAT_RG_NV                    0x8881\n#define GL_FLOAT_RGB_NV                   0x8882\n#define GL_FLOAT_RGBA_NV                  0x8883\n#define GL_FLOAT_R16_NV                   0x8884\n#define GL_FLOAT_R32_NV                   0x8885\n#define GL_FLOAT_RG16_NV                  0x8886\n#define GL_FLOAT_RG32_NV                  0x8887\n#define GL_FLOAT_RGB16_NV                 0x8888\n#define GL_FLOAT_RGB32_NV                 0x8889\n#define GL_FLOAT_RGBA16_NV                0x888A\n#define GL_FLOAT_RGBA32_NV                0x888B\n#define GL_TEXTURE_FLOAT_COMPONENTS_NV    0x888C\n#define GL_FLOAT_CLEAR_COLOR_VALUE_NV     0x888D\n#define GL_FLOAT_RGBA_MODE_NV             0x888E\n#endif\n\n#ifndef GL_NV_fragment_program\n#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868\n#define GL_FRAGMENT_PROGRAM_NV            0x8870\n#define GL_MAX_TEXTURE_COORDS_NV          0x8871\n#define GL_MAX_TEXTURE_IMAGE_UNITS_NV     0x8872\n#define GL_FRAGMENT_PROGRAM_BINDING_NV    0x8873\n#define GL_PROGRAM_ERROR_STRING_NV        0x8874\n#endif\n\n#ifndef GL_NV_half_float\n#define GL_HALF_FLOAT_NV                  0x140B\n#endif\n\n#ifndef GL_NV_pixel_data_range\n#define GL_WRITE_PIXEL_DATA_RANGE_NV      0x8878\n#define GL_READ_PIXEL_DATA_RANGE_NV       0x8879\n#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A\n#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B\n#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C\n#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D\n#endif\n\n#ifndef GL_NV_primitive_restart\n#define GL_PRIMITIVE_RESTART_NV           0x8558\n#define GL_PRIMITIVE_RESTART_INDEX_NV     0x8559\n#endif\n\n#ifndef GL_NV_texture_expand_normal\n#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F\n#endif\n\n#ifndef GL_NV_vertex_program2\n#endif\n\n#ifndef GL_ATI_map_object_buffer\n#endif\n\n#ifndef GL_ATI_separate_stencil\n#define GL_STENCIL_BACK_FUNC_ATI          0x8800\n#define GL_STENCIL_BACK_FAIL_ATI          0x8801\n#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802\n#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803\n#endif\n\n#ifndef GL_ATI_vertex_attrib_array_object\n#endif\n\n#ifndef GL_OES_read_format\n#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A\n#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B\n#endif\n\n#ifndef GL_EXT_depth_bounds_test\n#define GL_DEPTH_BOUNDS_TEST_EXT          0x8890\n#define GL_DEPTH_BOUNDS_EXT               0x8891\n#endif\n\n#ifndef GL_EXT_texture_mirror_clamp\n#define GL_MIRROR_CLAMP_EXT               0x8742\n#define GL_MIRROR_CLAMP_TO_EDGE_EXT       0x8743\n#define GL_MIRROR_CLAMP_TO_BORDER_EXT     0x8912\n#endif\n\n#ifndef GL_EXT_blend_equation_separate\n#define GL_BLEND_EQUATION_RGB_EXT         GL_BLEND_EQUATION\n#define GL_BLEND_EQUATION_ALPHA_EXT       0x883D\n#endif\n\n#ifndef GL_MESA_pack_invert\n#define GL_PACK_INVERT_MESA               0x8758\n#endif\n\n#ifndef GL_MESA_ycbcr_texture\n#define GL_UNSIGNED_SHORT_8_8_MESA        0x85BA\n#define GL_UNSIGNED_SHORT_8_8_REV_MESA    0x85BB\n#define GL_YCBCR_MESA                     0x8757\n#endif\n\n#ifndef GL_EXT_pixel_buffer_object\n#define GL_PIXEL_PACK_BUFFER_EXT          0x88EB\n#define GL_PIXEL_UNPACK_BUFFER_EXT        0x88EC\n#define GL_PIXEL_PACK_BUFFER_BINDING_EXT  0x88ED\n#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF\n#endif\n\n#ifndef GL_NV_fragment_program_option\n#endif\n\n#ifndef GL_NV_fragment_program2\n#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4\n#define GL_MAX_PROGRAM_CALL_DEPTH_NV      0x88F5\n#define GL_MAX_PROGRAM_IF_DEPTH_NV        0x88F6\n#define GL_MAX_PROGRAM_LOOP_DEPTH_NV      0x88F7\n#define GL_MAX_PROGRAM_LOOP_COUNT_NV      0x88F8\n#endif\n\n#ifndef GL_NV_vertex_program2_option\n/* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */\n/* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */\n#endif\n\n#ifndef GL_NV_vertex_program3\n/* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */\n#endif\n\n#ifndef GL_EXT_framebuffer_object\n#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506\n#define GL_MAX_RENDERBUFFER_SIZE_EXT      0x84E8\n#define GL_FRAMEBUFFER_BINDING_EXT        0x8CA6\n#define GL_RENDERBUFFER_BINDING_EXT       0x8CA7\n#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0\n#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4\n#define GL_FRAMEBUFFER_COMPLETE_EXT       0x8CD5\n#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6\n#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7\n#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8\n#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9\n#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA\n#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB\n#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC\n#define GL_FRAMEBUFFER_UNSUPPORTED_EXT    0x8CDD\n#define GL_MAX_COLOR_ATTACHMENTS_EXT      0x8CDF\n#define GL_COLOR_ATTACHMENT0_EXT          0x8CE0\n#define GL_COLOR_ATTACHMENT1_EXT          0x8CE1\n#define GL_COLOR_ATTACHMENT2_EXT          0x8CE2\n#define GL_COLOR_ATTACHMENT3_EXT          0x8CE3\n#define GL_COLOR_ATTACHMENT4_EXT          0x8CE4\n#define GL_COLOR_ATTACHMENT5_EXT          0x8CE5\n#define GL_COLOR_ATTACHMENT6_EXT          0x8CE6\n#define GL_COLOR_ATTACHMENT7_EXT          0x8CE7\n#define GL_COLOR_ATTACHMENT8_EXT          0x8CE8\n#define GL_COLOR_ATTACHMENT9_EXT          0x8CE9\n#define GL_COLOR_ATTACHMENT10_EXT         0x8CEA\n#define GL_COLOR_ATTACHMENT11_EXT         0x8CEB\n#define GL_COLOR_ATTACHMENT12_EXT         0x8CEC\n#define GL_COLOR_ATTACHMENT13_EXT         0x8CED\n#define GL_COLOR_ATTACHMENT14_EXT         0x8CEE\n#define GL_COLOR_ATTACHMENT15_EXT         0x8CEF\n#define GL_DEPTH_ATTACHMENT_EXT           0x8D00\n#define GL_STENCIL_ATTACHMENT_EXT         0x8D20\n#define GL_FRAMEBUFFER_EXT                0x8D40\n#define GL_RENDERBUFFER_EXT               0x8D41\n#define GL_RENDERBUFFER_WIDTH_EXT         0x8D42\n#define GL_RENDERBUFFER_HEIGHT_EXT        0x8D43\n#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44\n#define GL_STENCIL_INDEX1_EXT             0x8D46\n#define GL_STENCIL_INDEX4_EXT             0x8D47\n#define GL_STENCIL_INDEX8_EXT             0x8D48\n#define GL_STENCIL_INDEX16_EXT            0x8D49\n#define GL_RENDERBUFFER_RED_SIZE_EXT      0x8D50\n#define GL_RENDERBUFFER_GREEN_SIZE_EXT    0x8D51\n#define GL_RENDERBUFFER_BLUE_SIZE_EXT     0x8D52\n#define GL_RENDERBUFFER_ALPHA_SIZE_EXT    0x8D53\n#define GL_RENDERBUFFER_DEPTH_SIZE_EXT    0x8D54\n#define GL_RENDERBUFFER_STENCIL_SIZE_EXT  0x8D55\n#endif\n\n#ifndef GL_GREMEDY_string_marker\n#endif\n\n\n/*************************************************************/\n\n#include <stddef.h>\n#ifndef GL_VERSION_2_0\n/* GL type for program/shader text */\ntypedef char GLchar;\t\t\t/* native character */\n#endif\n\n#ifndef GL_VERSION_1_5\n/* GL types for handling large vertex buffer objects */\ntypedef ptrdiff_t GLintptr;\ntypedef ptrdiff_t GLsizeiptr;\n#endif\n\n#ifndef GL_ARB_vertex_buffer_object\n/* GL types for handling large vertex buffer objects */\ntypedef ptrdiff_t GLintptrARB;\ntypedef ptrdiff_t GLsizeiptrARB;\n#endif\n\n#ifndef GL_ARB_shader_objects\n/* GL types for handling shader object handles and program/shader text */\ntypedef char GLcharARB;\t\t/* native character */\ntypedef unsigned int GLhandleARB;\t/* shader object handle */\n#endif\n\n/* GL types for \"half\" precision (s10e5) float data in host memory */\n#ifndef GL_ARB_half_float_pixel\ntypedef unsigned short GLhalfARB;\n#endif\n\n#ifndef GL_NV_half_float\ntypedef unsigned short GLhalfNV;\n#endif\n\n#ifndef GL_VERSION_1_2\n#define GL_VERSION_1_2 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendColor (GLclampf, GLclampf, GLclampf, GLclampf);\nGLAPI void APIENTRY glBlendEquation (GLenum);\nGLAPI void APIENTRY glDrawRangeElements (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);\nGLAPI void APIENTRY glColorTable (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glColorTableParameterfv (GLenum, GLenum, const GLfloat *);\nGLAPI void APIENTRY glColorTableParameteriv (GLenum, GLenum, const GLint *);\nGLAPI void APIENTRY glCopyColorTable (GLenum, GLenum, GLint, GLint, GLsizei);\nGLAPI void APIENTRY glGetColorTable (GLenum, GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetColorTableParameterfv (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetColorTableParameteriv (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glColorSubTable (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glCopyColorSubTable (GLenum, GLsizei, GLint, GLint, GLsizei);\nGLAPI void APIENTRY glConvolutionFilter1D (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glConvolutionFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glConvolutionParameterf (GLenum, GLenum, GLfloat);\nGLAPI void APIENTRY glConvolutionParameterfv (GLenum, GLenum, const GLfloat *);\nGLAPI void APIENTRY glConvolutionParameteri (GLenum, GLenum, GLint);\nGLAPI void APIENTRY glConvolutionParameteriv (GLenum, GLenum, const GLint *);\nGLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum, GLenum, GLint, GLint, GLsizei);\nGLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);\nGLAPI void APIENTRY glGetConvolutionFilter (GLenum, GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetConvolutionParameterfv (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetConvolutionParameteriv (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetSeparableFilter (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);\nGLAPI void APIENTRY glSeparableFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);\nGLAPI void APIENTRY glGetHistogram (GLenum, GLboolean, GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetHistogramParameterfv (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetHistogramParameteriv (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetMinmax (GLenum, GLboolean, GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetMinmaxParameterfv (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetMinmaxParameteriv (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glHistogram (GLenum, GLsizei, GLenum, GLboolean);\nGLAPI void APIENTRY glMinmax (GLenum, GLenum, GLboolean);\nGLAPI void APIENTRY glResetHistogram (GLenum);\nGLAPI void APIENTRY glResetMinmax (GLenum);\nGLAPI void APIENTRY glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glCopyTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);\ntypedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);\ntypedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);\ntypedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);\ntypedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\n#endif\n\n#ifndef GL_VERSION_1_3\n#define GL_VERSION_1_3 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glActiveTexture (GLenum);\nGLAPI void APIENTRY glClientActiveTexture (GLenum);\nGLAPI void APIENTRY glMultiTexCoord1d (GLenum, GLdouble);\nGLAPI void APIENTRY glMultiTexCoord1dv (GLenum, const GLdouble *);\nGLAPI void APIENTRY glMultiTexCoord1f (GLenum, GLfloat);\nGLAPI void APIENTRY glMultiTexCoord1fv (GLenum, const GLfloat *);\nGLAPI void APIENTRY glMultiTexCoord1i (GLenum, GLint);\nGLAPI void APIENTRY glMultiTexCoord1iv (GLenum, const GLint *);\nGLAPI void APIENTRY glMultiTexCoord1s (GLenum, GLshort);\nGLAPI void APIENTRY glMultiTexCoord1sv (GLenum, const GLshort *);\nGLAPI void APIENTRY glMultiTexCoord2d (GLenum, GLdouble, GLdouble);\nGLAPI void APIENTRY glMultiTexCoord2dv (GLenum, const GLdouble *);\nGLAPI void APIENTRY glMultiTexCoord2f (GLenum, GLfloat, GLfloat);\nGLAPI void APIENTRY glMultiTexCoord2fv (GLenum, const GLfloat *);\nGLAPI void APIENTRY glMultiTexCoord2i (GLenum, GLint, GLint);\nGLAPI void APIENTRY glMultiTexCoord2iv (GLenum, const GLint *);\nGLAPI void APIENTRY glMultiTexCoord2s (GLenum, GLshort, GLshort);\nGLAPI void APIENTRY glMultiTexCoord2sv (GLenum, const GLshort *);\nGLAPI void APIENTRY glMultiTexCoord3d (GLenum, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glMultiTexCoord3dv (GLenum, const GLdouble *);\nGLAPI void APIENTRY glMultiTexCoord3f (GLenum, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glMultiTexCoord3fv (GLenum, const GLfloat *);\nGLAPI void APIENTRY glMultiTexCoord3i (GLenum, GLint, GLint, GLint);\nGLAPI void APIENTRY glMultiTexCoord3iv (GLenum, const GLint *);\nGLAPI void APIENTRY glMultiTexCoord3s (GLenum, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glMultiTexCoord3sv (GLenum, const GLshort *);\nGLAPI void APIENTRY glMultiTexCoord4d (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glMultiTexCoord4dv (GLenum, const GLdouble *);\nGLAPI void APIENTRY glMultiTexCoord4f (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glMultiTexCoord4fv (GLenum, const GLfloat *);\nGLAPI void APIENTRY glMultiTexCoord4i (GLenum, GLint, GLint, GLint, GLint);\nGLAPI void APIENTRY glMultiTexCoord4iv (GLenum, const GLint *);\nGLAPI void APIENTRY glMultiTexCoord4s (GLenum, GLshort, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glMultiTexCoord4sv (GLenum, const GLshort *);\nGLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *);\nGLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *);\nGLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *);\nGLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *);\nGLAPI void APIENTRY glSampleCoverage (GLclampf, GLboolean);\nGLAPI void APIENTRY glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glGetCompressedTexImage (GLenum, GLint, GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);\ntypedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);\ntypedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);\n#endif\n\n#ifndef GL_VERSION_1_4\n#define GL_VERSION_1_4 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendFuncSeparate (GLenum, GLenum, GLenum, GLenum);\nGLAPI void APIENTRY glFogCoordf (GLfloat);\nGLAPI void APIENTRY glFogCoordfv (const GLfloat *);\nGLAPI void APIENTRY glFogCoordd (GLdouble);\nGLAPI void APIENTRY glFogCoorddv (const GLdouble *);\nGLAPI void APIENTRY glFogCoordPointer (GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glMultiDrawArrays (GLenum, GLint *, GLsizei *, GLsizei);\nGLAPI void APIENTRY glMultiDrawElements (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);\nGLAPI void APIENTRY glPointParameterf (GLenum, GLfloat);\nGLAPI void APIENTRY glPointParameterfv (GLenum, const GLfloat *);\nGLAPI void APIENTRY glPointParameteri (GLenum, GLint);\nGLAPI void APIENTRY glPointParameteriv (GLenum, const GLint *);\nGLAPI void APIENTRY glSecondaryColor3b (GLbyte, GLbyte, GLbyte);\nGLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *);\nGLAPI void APIENTRY glSecondaryColor3d (GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *);\nGLAPI void APIENTRY glSecondaryColor3f (GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *);\nGLAPI void APIENTRY glSecondaryColor3i (GLint, GLint, GLint);\nGLAPI void APIENTRY glSecondaryColor3iv (const GLint *);\nGLAPI void APIENTRY glSecondaryColor3s (GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glSecondaryColor3sv (const GLshort *);\nGLAPI void APIENTRY glSecondaryColor3ub (GLubyte, GLubyte, GLubyte);\nGLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *);\nGLAPI void APIENTRY glSecondaryColor3ui (GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *);\nGLAPI void APIENTRY glSecondaryColor3us (GLushort, GLushort, GLushort);\nGLAPI void APIENTRY glSecondaryColor3usv (const GLushort *);\nGLAPI void APIENTRY glSecondaryColorPointer (GLint, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glWindowPos2d (GLdouble, GLdouble);\nGLAPI void APIENTRY glWindowPos2dv (const GLdouble *);\nGLAPI void APIENTRY glWindowPos2f (GLfloat, GLfloat);\nGLAPI void APIENTRY glWindowPos2fv (const GLfloat *);\nGLAPI void APIENTRY glWindowPos2i (GLint, GLint);\nGLAPI void APIENTRY glWindowPos2iv (const GLint *);\nGLAPI void APIENTRY glWindowPos2s (GLshort, GLshort);\nGLAPI void APIENTRY glWindowPos2sv (const GLshort *);\nGLAPI void APIENTRY glWindowPos3d (GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glWindowPos3dv (const GLdouble *);\nGLAPI void APIENTRY glWindowPos3f (GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glWindowPos3fv (const GLfloat *);\nGLAPI void APIENTRY glWindowPos3i (GLint, GLint, GLint);\nGLAPI void APIENTRY glWindowPos3iv (const GLint *);\nGLAPI void APIENTRY glWindowPos3s (GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glWindowPos3sv (const GLshort *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\ntypedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v);\n#endif\n\n#ifndef GL_VERSION_1_5\n#define GL_VERSION_1_5 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenQueries (GLsizei, GLuint *);\nGLAPI void APIENTRY glDeleteQueries (GLsizei, const GLuint *);\nGLAPI GLboolean APIENTRY glIsQuery (GLuint);\nGLAPI void APIENTRY glBeginQuery (GLenum, GLuint);\nGLAPI void APIENTRY glEndQuery (GLenum);\nGLAPI void APIENTRY glGetQueryiv (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetQueryObjectiv (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetQueryObjectuiv (GLuint, GLenum, GLuint *);\nGLAPI void APIENTRY glBindBuffer (GLenum, GLuint);\nGLAPI void APIENTRY glDeleteBuffers (GLsizei, const GLuint *);\nGLAPI void APIENTRY glGenBuffers (GLsizei, GLuint *);\nGLAPI GLboolean APIENTRY glIsBuffer (GLuint);\nGLAPI void APIENTRY glBufferData (GLenum, GLsizeiptr, const GLvoid *, GLenum);\nGLAPI void APIENTRY glBufferSubData (GLenum, GLintptr, GLsizeiptr, const GLvoid *);\nGLAPI void APIENTRY glGetBufferSubData (GLenum, GLintptr, GLsizeiptr, GLvoid *);\nGLAPI GLvoid* APIENTRY glMapBuffer (GLenum, GLenum);\nGLAPI GLboolean APIENTRY glUnmapBuffer (GLenum);\nGLAPI void APIENTRY glGetBufferParameteriv (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetBufferPointerv (GLenum, GLenum, GLvoid* *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);\ntypedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);\ntypedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);\ntypedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);\ntypedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);\ntypedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);\ntypedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params);\n#endif\n\n#ifndef GL_VERSION_2_0\n#define GL_VERSION_2_0 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendEquationSeparate (GLenum, GLenum);\nGLAPI void APIENTRY glDrawBuffers (GLsizei, const GLenum *);\nGLAPI void APIENTRY glStencilOpSeparate (GLenum, GLenum, GLenum, GLenum);\nGLAPI void APIENTRY glStencilFuncSeparate (GLenum, GLenum, GLint, GLuint);\nGLAPI void APIENTRY glStencilMaskSeparate (GLenum, GLuint);\nGLAPI void APIENTRY glAttachShader (GLuint, GLuint);\nGLAPI void APIENTRY glBindAttribLocation (GLuint, GLuint, const GLchar *);\nGLAPI void APIENTRY glCompileShader (GLuint);\nGLAPI GLuint APIENTRY glCreateProgram (void);\nGLAPI GLuint APIENTRY glCreateShader (GLenum);\nGLAPI void APIENTRY glDeleteProgram (GLuint);\nGLAPI void APIENTRY glDeleteShader (GLuint);\nGLAPI void APIENTRY glDetachShader (GLuint, GLuint);\nGLAPI void APIENTRY glDisableVertexAttribArray (GLuint);\nGLAPI void APIENTRY glEnableVertexAttribArray (GLuint);\nGLAPI void APIENTRY glGetActiveAttrib (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);\nGLAPI void APIENTRY glGetActiveUniform (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);\nGLAPI void APIENTRY glGetAttachedShaders (GLuint, GLsizei, GLsizei *, GLuint *);\nGLAPI GLint APIENTRY glGetAttribLocation (GLuint, const GLchar *);\nGLAPI void APIENTRY glGetProgramiv (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetProgramInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);\nGLAPI void APIENTRY glGetShaderiv (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetShaderInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);\nGLAPI void APIENTRY glGetShaderSource (GLuint, GLsizei, GLsizei *, GLchar *);\nGLAPI GLint APIENTRY glGetUniformLocation (GLuint, const GLchar *);\nGLAPI void APIENTRY glGetUniformfv (GLuint, GLint, GLfloat *);\nGLAPI void APIENTRY glGetUniformiv (GLuint, GLint, GLint *);\nGLAPI void APIENTRY glGetVertexAttribdv (GLuint, GLenum, GLdouble *);\nGLAPI void APIENTRY glGetVertexAttribfv (GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetVertexAttribiv (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetVertexAttribPointerv (GLuint, GLenum, GLvoid* *);\nGLAPI GLboolean APIENTRY glIsProgram (GLuint);\nGLAPI GLboolean APIENTRY glIsShader (GLuint);\nGLAPI void APIENTRY glLinkProgram (GLuint);\nGLAPI void APIENTRY glShaderSource (GLuint, GLsizei, const GLchar* *, const GLint *);\nGLAPI void APIENTRY glUseProgram (GLuint);\nGLAPI void APIENTRY glUniform1f (GLint, GLfloat);\nGLAPI void APIENTRY glUniform2f (GLint, GLfloat, GLfloat);\nGLAPI void APIENTRY glUniform3f (GLint, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glUniform4f (GLint, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glUniform1i (GLint, GLint);\nGLAPI void APIENTRY glUniform2i (GLint, GLint, GLint);\nGLAPI void APIENTRY glUniform3i (GLint, GLint, GLint, GLint);\nGLAPI void APIENTRY glUniform4i (GLint, GLint, GLint, GLint, GLint);\nGLAPI void APIENTRY glUniform1fv (GLint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glUniform2fv (GLint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glUniform3fv (GLint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glUniform4fv (GLint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glUniform1iv (GLint, GLsizei, const GLint *);\nGLAPI void APIENTRY glUniform2iv (GLint, GLsizei, const GLint *);\nGLAPI void APIENTRY glUniform3iv (GLint, GLsizei, const GLint *);\nGLAPI void APIENTRY glUniform4iv (GLint, GLsizei, const GLint *);\nGLAPI void APIENTRY glUniformMatrix2fv (GLint, GLsizei, GLboolean, const GLfloat *);\nGLAPI void APIENTRY glUniformMatrix3fv (GLint, GLsizei, GLboolean, const GLfloat *);\nGLAPI void APIENTRY glUniformMatrix4fv (GLint, GLsizei, GLboolean, const GLfloat *);\nGLAPI void APIENTRY glValidateProgram (GLuint);\nGLAPI void APIENTRY glVertexAttrib1d (GLuint, GLdouble);\nGLAPI void APIENTRY glVertexAttrib1dv (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib1f (GLuint, GLfloat);\nGLAPI void APIENTRY glVertexAttrib1fv (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib1s (GLuint, GLshort);\nGLAPI void APIENTRY glVertexAttrib1sv (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib2d (GLuint, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexAttrib2dv (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib2f (GLuint, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexAttrib2fv (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib2s (GLuint, GLshort, GLshort);\nGLAPI void APIENTRY glVertexAttrib2sv (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib3d (GLuint, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexAttrib3dv (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib3f (GLuint, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexAttrib3fv (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib3s (GLuint, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glVertexAttrib3sv (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib4Nbv (GLuint, const GLbyte *);\nGLAPI void APIENTRY glVertexAttrib4Niv (GLuint, const GLint *);\nGLAPI void APIENTRY glVertexAttrib4Nsv (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib4Nub (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);\nGLAPI void APIENTRY glVertexAttrib4Nubv (GLuint, const GLubyte *);\nGLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint, const GLuint *);\nGLAPI void APIENTRY glVertexAttrib4Nusv (GLuint, const GLushort *);\nGLAPI void APIENTRY glVertexAttrib4bv (GLuint, const GLbyte *);\nGLAPI void APIENTRY glVertexAttrib4d (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexAttrib4dv (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib4f (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexAttrib4fv (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib4iv (GLuint, const GLint *);\nGLAPI void APIENTRY glVertexAttrib4s (GLuint, GLshort, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glVertexAttrib4sv (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib4ubv (GLuint, const GLubyte *);\nGLAPI void APIENTRY glVertexAttrib4uiv (GLuint, const GLuint *);\nGLAPI void APIENTRY glVertexAttrib4usv (GLuint, const GLushort *);\nGLAPI void APIENTRY glVertexAttribPointer (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);\ntypedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);\ntypedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);\ntypedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);\ntypedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);\ntypedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);\ntypedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);\ntypedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);\ntypedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);\ntypedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);\ntypedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);\ntypedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);\ntypedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);\ntypedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\ntypedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj);\ntypedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);\ntypedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);\ntypedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);\ntypedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader);\ntypedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);\ntypedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);\n#endif\n\n#ifndef GL_ARB_multitexture\n#define GL_ARB_multitexture 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glActiveTextureARB (GLenum);\nGLAPI void APIENTRY glClientActiveTextureARB (GLenum);\nGLAPI void APIENTRY glMultiTexCoord1dARB (GLenum, GLdouble);\nGLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum, const GLdouble *);\nGLAPI void APIENTRY glMultiTexCoord1fARB (GLenum, GLfloat);\nGLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum, const GLfloat *);\nGLAPI void APIENTRY glMultiTexCoord1iARB (GLenum, GLint);\nGLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum, const GLint *);\nGLAPI void APIENTRY glMultiTexCoord1sARB (GLenum, GLshort);\nGLAPI void APIENTRY glMultiTexCoord1svARB (GLenum, const GLshort *);\nGLAPI void APIENTRY glMultiTexCoord2dARB (GLenum, GLdouble, GLdouble);\nGLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum, const GLdouble *);\nGLAPI void APIENTRY glMultiTexCoord2fARB (GLenum, GLfloat, GLfloat);\nGLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum, const GLfloat *);\nGLAPI void APIENTRY glMultiTexCoord2iARB (GLenum, GLint, GLint);\nGLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum, const GLint *);\nGLAPI void APIENTRY glMultiTexCoord2sARB (GLenum, GLshort, GLshort);\nGLAPI void APIENTRY glMultiTexCoord2svARB (GLenum, const GLshort *);\nGLAPI void APIENTRY glMultiTexCoord3dARB (GLenum, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum, const GLdouble *);\nGLAPI void APIENTRY glMultiTexCoord3fARB (GLenum, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum, const GLfloat *);\nGLAPI void APIENTRY glMultiTexCoord3iARB (GLenum, GLint, GLint, GLint);\nGLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum, const GLint *);\nGLAPI void APIENTRY glMultiTexCoord3sARB (GLenum, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glMultiTexCoord3svARB (GLenum, const GLshort *);\nGLAPI void APIENTRY glMultiTexCoord4dARB (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum, const GLdouble *);\nGLAPI void APIENTRY glMultiTexCoord4fARB (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum, const GLfloat *);\nGLAPI void APIENTRY glMultiTexCoord4iARB (GLenum, GLint, GLint, GLint, GLint);\nGLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum, const GLint *);\nGLAPI void APIENTRY glMultiTexCoord4sARB (GLenum, GLshort, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glMultiTexCoord4svARB (GLenum, const GLshort *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);\ntypedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);\n#endif\n\n#ifndef GL_ARB_transpose_matrix\n#define GL_ARB_transpose_matrix 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *);\nGLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *);\nGLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *);\nGLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);\n#endif\n\n#ifndef GL_ARB_multisample\n#define GL_ARB_multisample 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSampleCoverageARB (GLclampf, GLboolean);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert);\n#endif\n\n#ifndef GL_ARB_texture_env_add\n#define GL_ARB_texture_env_add 1\n#endif\n\n#ifndef GL_ARB_texture_cube_map\n#define GL_ARB_texture_cube_map 1\n#endif\n\n#ifndef GL_ARB_texture_compression\n#define GL_ARB_texture_compression 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexImage1DARB (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glGetCompressedTexImageARB (GLenum, GLint, GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img);\n#endif\n\n#ifndef GL_ARB_texture_border_clamp\n#define GL_ARB_texture_border_clamp 1\n#endif\n\n#ifndef GL_ARB_point_parameters\n#define GL_ARB_point_parameters 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPointParameterfARB (GLenum, GLfloat);\nGLAPI void APIENTRY glPointParameterfvARB (GLenum, const GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);\n#endif\n\n#ifndef GL_ARB_vertex_blend\n#define GL_ARB_vertex_blend 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glWeightbvARB (GLint, const GLbyte *);\nGLAPI void APIENTRY glWeightsvARB (GLint, const GLshort *);\nGLAPI void APIENTRY glWeightivARB (GLint, const GLint *);\nGLAPI void APIENTRY glWeightfvARB (GLint, const GLfloat *);\nGLAPI void APIENTRY glWeightdvARB (GLint, const GLdouble *);\nGLAPI void APIENTRY glWeightubvARB (GLint, const GLubyte *);\nGLAPI void APIENTRY glWeightusvARB (GLint, const GLushort *);\nGLAPI void APIENTRY glWeightuivARB (GLint, const GLuint *);\nGLAPI void APIENTRY glWeightPointerARB (GLint, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glVertexBlendARB (GLint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);\n#endif\n\n#ifndef GL_ARB_matrix_palette\n#define GL_ARB_matrix_palette 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint);\nGLAPI void APIENTRY glMatrixIndexubvARB (GLint, const GLubyte *);\nGLAPI void APIENTRY glMatrixIndexusvARB (GLint, const GLushort *);\nGLAPI void APIENTRY glMatrixIndexuivARB (GLint, const GLuint *);\nGLAPI void APIENTRY glMatrixIndexPointerARB (GLint, GLenum, GLsizei, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);\ntypedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);\ntypedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);\ntypedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);\ntypedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\n#endif\n\n#ifndef GL_ARB_texture_env_combine\n#define GL_ARB_texture_env_combine 1\n#endif\n\n#ifndef GL_ARB_texture_env_crossbar\n#define GL_ARB_texture_env_crossbar 1\n#endif\n\n#ifndef GL_ARB_texture_env_dot3\n#define GL_ARB_texture_env_dot3 1\n#endif\n\n#ifndef GL_ARB_texture_mirrored_repeat\n#define GL_ARB_texture_mirrored_repeat 1\n#endif\n\n#ifndef GL_ARB_depth_texture\n#define GL_ARB_depth_texture 1\n#endif\n\n#ifndef GL_ARB_shadow\n#define GL_ARB_shadow 1\n#endif\n\n#ifndef GL_ARB_shadow_ambient\n#define GL_ARB_shadow_ambient 1\n#endif\n\n#ifndef GL_ARB_window_pos\n#define GL_ARB_window_pos 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glWindowPos2dARB (GLdouble, GLdouble);\nGLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *);\nGLAPI void APIENTRY glWindowPos2fARB (GLfloat, GLfloat);\nGLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *);\nGLAPI void APIENTRY glWindowPos2iARB (GLint, GLint);\nGLAPI void APIENTRY glWindowPos2ivARB (const GLint *);\nGLAPI void APIENTRY glWindowPos2sARB (GLshort, GLshort);\nGLAPI void APIENTRY glWindowPos2svARB (const GLshort *);\nGLAPI void APIENTRY glWindowPos3dARB (GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *);\nGLAPI void APIENTRY glWindowPos3fARB (GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *);\nGLAPI void APIENTRY glWindowPos3iARB (GLint, GLint, GLint);\nGLAPI void APIENTRY glWindowPos3ivARB (const GLint *);\nGLAPI void APIENTRY glWindowPos3sARB (GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glWindowPos3svARB (const GLshort *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v);\n#endif\n\n#ifndef GL_ARB_vertex_program\n#define GL_ARB_vertex_program 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexAttrib1dARB (GLuint, GLdouble);\nGLAPI void APIENTRY glVertexAttrib1dvARB (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib1fARB (GLuint, GLfloat);\nGLAPI void APIENTRY glVertexAttrib1fvARB (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib1sARB (GLuint, GLshort);\nGLAPI void APIENTRY glVertexAttrib1svARB (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib2dARB (GLuint, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexAttrib2dvARB (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib2fARB (GLuint, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexAttrib2fvARB (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib2sARB (GLuint, GLshort, GLshort);\nGLAPI void APIENTRY glVertexAttrib2svARB (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib3dARB (GLuint, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexAttrib3dvARB (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib3fARB (GLuint, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexAttrib3fvARB (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib3sARB (GLuint, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glVertexAttrib3svARB (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint, const GLbyte *);\nGLAPI void APIENTRY glVertexAttrib4NivARB (GLuint, const GLint *);\nGLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib4NubARB (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);\nGLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint, const GLubyte *);\nGLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint, const GLuint *);\nGLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint, const GLushort *);\nGLAPI void APIENTRY glVertexAttrib4bvARB (GLuint, const GLbyte *);\nGLAPI void APIENTRY glVertexAttrib4dARB (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexAttrib4dvARB (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib4fARB (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexAttrib4fvARB (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib4ivARB (GLuint, const GLint *);\nGLAPI void APIENTRY glVertexAttrib4sARB (GLuint, GLshort, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glVertexAttrib4svARB (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint, const GLubyte *);\nGLAPI void APIENTRY glVertexAttrib4uivARB (GLuint, const GLuint *);\nGLAPI void APIENTRY glVertexAttrib4usvARB (GLuint, const GLushort *);\nGLAPI void APIENTRY glVertexAttribPointerARB (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint);\nGLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint);\nGLAPI void APIENTRY glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glBindProgramARB (GLenum, GLuint);\nGLAPI void APIENTRY glDeleteProgramsARB (GLsizei, const GLuint *);\nGLAPI void APIENTRY glGenProgramsARB (GLsizei, GLuint *);\nGLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum, GLuint, const GLdouble *);\nGLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum, GLuint, const GLfloat *);\nGLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum, GLuint, const GLdouble *);\nGLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum, GLuint, const GLfloat *);\nGLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum, GLuint, GLdouble *);\nGLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum, GLuint, GLfloat *);\nGLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum, GLuint, GLdouble *);\nGLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum, GLuint, GLfloat *);\nGLAPI void APIENTRY glGetProgramivARB (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetProgramStringARB (GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetVertexAttribdvARB (GLuint, GLenum, GLdouble *);\nGLAPI void APIENTRY glGetVertexAttribfvARB (GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetVertexAttribivARB (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint, GLenum, GLvoid* *);\nGLAPI GLboolean APIENTRY glIsProgramARB (GLuint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);\ntypedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string);\ntypedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);\ntypedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);\ntypedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer);\ntypedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program);\n#endif\n\n#ifndef GL_ARB_fragment_program\n#define GL_ARB_fragment_program 1\n/* All ARB_fragment_program entry points are shared with ARB_vertex_program. */\n#endif\n\n#ifndef GL_ARB_vertex_buffer_object\n#define GL_ARB_vertex_buffer_object 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindBufferARB (GLenum, GLuint);\nGLAPI void APIENTRY glDeleteBuffersARB (GLsizei, const GLuint *);\nGLAPI void APIENTRY glGenBuffersARB (GLsizei, GLuint *);\nGLAPI GLboolean APIENTRY glIsBufferARB (GLuint);\nGLAPI void APIENTRY glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum);\nGLAPI void APIENTRY glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *);\nGLAPI void APIENTRY glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *);\nGLAPI GLvoid* APIENTRY glMapBufferARB (GLenum, GLenum);\nGLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum);\nGLAPI void APIENTRY glGetBufferParameterivARB (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);\ntypedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);\ntypedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);\ntypedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);\ntypedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data);\ntypedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);\ntypedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params);\n#endif\n\n#ifndef GL_ARB_occlusion_query\n#define GL_ARB_occlusion_query 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenQueriesARB (GLsizei, GLuint *);\nGLAPI void APIENTRY glDeleteQueriesARB (GLsizei, const GLuint *);\nGLAPI GLboolean APIENTRY glIsQueryARB (GLuint);\nGLAPI void APIENTRY glBeginQueryARB (GLenum, GLuint);\nGLAPI void APIENTRY glEndQueryARB (GLenum);\nGLAPI void APIENTRY glGetQueryivARB (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetQueryObjectivARB (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetQueryObjectuivARB (GLuint, GLenum, GLuint *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);\n#endif\n\n#ifndef GL_ARB_shader_objects\n#define GL_ARB_shader_objects 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDeleteObjectARB (GLhandleARB);\nGLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum);\nGLAPI void APIENTRY glDetachObjectARB (GLhandleARB, GLhandleARB);\nGLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum);\nGLAPI void APIENTRY glShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *);\nGLAPI void APIENTRY glCompileShaderARB (GLhandleARB);\nGLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void);\nGLAPI void APIENTRY glAttachObjectARB (GLhandleARB, GLhandleARB);\nGLAPI void APIENTRY glLinkProgramARB (GLhandleARB);\nGLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB);\nGLAPI void APIENTRY glValidateProgramARB (GLhandleARB);\nGLAPI void APIENTRY glUniform1fARB (GLint, GLfloat);\nGLAPI void APIENTRY glUniform2fARB (GLint, GLfloat, GLfloat);\nGLAPI void APIENTRY glUniform3fARB (GLint, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glUniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glUniform1iARB (GLint, GLint);\nGLAPI void APIENTRY glUniform2iARB (GLint, GLint, GLint);\nGLAPI void APIENTRY glUniform3iARB (GLint, GLint, GLint, GLint);\nGLAPI void APIENTRY glUniform4iARB (GLint, GLint, GLint, GLint, GLint);\nGLAPI void APIENTRY glUniform1fvARB (GLint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glUniform2fvARB (GLint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glUniform3fvARB (GLint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glUniform4fvARB (GLint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glUniform1ivARB (GLint, GLsizei, const GLint *);\nGLAPI void APIENTRY glUniform2ivARB (GLint, GLsizei, const GLint *);\nGLAPI void APIENTRY glUniform3ivARB (GLint, GLsizei, const GLint *);\nGLAPI void APIENTRY glUniform4ivARB (GLint, GLsizei, const GLint *);\nGLAPI void APIENTRY glUniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *);\nGLAPI void APIENTRY glUniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *);\nGLAPI void APIENTRY glUniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *);\nGLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB, GLenum, GLint *);\nGLAPI void APIENTRY glGetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);\nGLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *);\nGLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB, const GLcharARB *);\nGLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);\nGLAPI void APIENTRY glGetUniformfvARB (GLhandleARB, GLint, GLfloat *);\nGLAPI void APIENTRY glGetUniformivARB (GLhandleARB, GLint, GLint *);\nGLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);\ntypedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname);\ntypedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);\ntypedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);\ntypedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length);\ntypedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);\ntypedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void);\ntypedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);\ntypedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj);\ntypedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);\ntypedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);\ntypedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);\ntypedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);\ntypedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);\ntypedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);\n#endif\n\n#ifndef GL_ARB_vertex_shader\n#define GL_ARB_vertex_shader 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *);\nGLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);\nGLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB, const GLcharARB *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);\ntypedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);\ntypedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);\n#endif\n\n#ifndef GL_ARB_fragment_shader\n#define GL_ARB_fragment_shader 1\n#endif\n\n#ifndef GL_ARB_shading_language_100\n#define GL_ARB_shading_language_100 1\n#endif\n\n#ifndef GL_ARB_texture_non_power_of_two\n#define GL_ARB_texture_non_power_of_two 1\n#endif\n\n#ifndef GL_ARB_point_sprite\n#define GL_ARB_point_sprite 1\n#endif\n\n#ifndef GL_ARB_fragment_program_shadow\n#define GL_ARB_fragment_program_shadow 1\n#endif\n\n#ifndef GL_ARB_draw_buffers\n#define GL_ARB_draw_buffers 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawBuffersARB (GLsizei, const GLenum *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);\n#endif\n\n#ifndef GL_ARB_texture_rectangle\n#define GL_ARB_texture_rectangle 1\n#endif\n\n#ifndef GL_ARB_color_buffer_float\n#define GL_ARB_color_buffer_float 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glClampColorARB (GLenum, GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);\n#endif\n\n#ifndef GL_ARB_half_float_pixel\n#define GL_ARB_half_float_pixel 1\n#endif\n\n#ifndef GL_ARB_texture_float\n#define GL_ARB_texture_float 1\n#endif\n\n#ifndef GL_ARB_pixel_buffer_object\n#define GL_ARB_pixel_buffer_object 1\n#endif\n\n#ifndef GL_EXT_abgr\n#define GL_EXT_abgr 1\n#endif\n\n#ifndef GL_EXT_blend_color\n#define GL_EXT_blend_color 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendColorEXT (GLclampf, GLclampf, GLclampf, GLclampf);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);\n#endif\n\n#ifndef GL_EXT_polygon_offset\n#define GL_EXT_polygon_offset 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPolygonOffsetEXT (GLfloat, GLfloat);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias);\n#endif\n\n#ifndef GL_EXT_texture\n#define GL_EXT_texture 1\n#endif\n\n#ifndef GL_EXT_texture3D\n#define GL_EXT_texture3D 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexImage3DEXT (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);\n#endif\n\n#ifndef GL_SGIS_texture_filter4\n#define GL_SGIS_texture_filter4 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glTexFilterFuncSGIS (GLenum, GLenum, GLsizei, const GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights);\ntypedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);\n#endif\n\n#ifndef GL_EXT_subtexture\n#define GL_EXT_subtexture 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexSubImage1DEXT (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);\n#endif\n\n#ifndef GL_EXT_copy_texture\n#define GL_EXT_copy_texture 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCopyTexImage1DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint);\nGLAPI void APIENTRY glCopyTexImage2DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint);\nGLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei);\nGLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);\nGLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\n#endif\n\n#ifndef GL_EXT_histogram\n#define GL_EXT_histogram 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetHistogramEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetMinmaxEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glHistogramEXT (GLenum, GLsizei, GLenum, GLboolean);\nGLAPI void APIENTRY glMinmaxEXT (GLenum, GLenum, GLboolean);\nGLAPI void APIENTRY glResetHistogramEXT (GLenum);\nGLAPI void APIENTRY glResetMinmaxEXT (GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);\ntypedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target);\n#endif\n\n#ifndef GL_EXT_convolution\n#define GL_EXT_convolution 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glConvolutionParameterfEXT (GLenum, GLenum, GLfloat);\nGLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum, GLenum, const GLfloat *);\nGLAPI void APIENTRY glConvolutionParameteriEXT (GLenum, GLenum, GLint);\nGLAPI void APIENTRY glConvolutionParameterivEXT (GLenum, GLenum, const GLint *);\nGLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum, GLenum, GLint, GLint, GLsizei);\nGLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);\nGLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum, GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetSeparableFilterEXT (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);\nGLAPI void APIENTRY glSeparableFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);\ntypedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);\n#endif\n\n#ifndef GL_EXT_color_matrix\n#define GL_EXT_color_matrix 1\n#endif\n\n#ifndef GL_SGI_color_table\n#define GL_SGI_color_table 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorTableSGI (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glColorTableParameterfvSGI (GLenum, GLenum, const GLfloat *);\nGLAPI void APIENTRY glColorTableParameterivSGI (GLenum, GLenum, const GLint *);\nGLAPI void APIENTRY glCopyColorTableSGI (GLenum, GLenum, GLint, GLint, GLsizei);\nGLAPI void APIENTRY glGetColorTableSGI (GLenum, GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum, GLenum, GLint *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);\ntypedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params);\n#endif\n\n#ifndef GL_SGIX_pixel_texture\n#define GL_SGIX_pixel_texture 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPixelTexGenSGIX (GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode);\n#endif\n\n#ifndef GL_SGIS_pixel_texture\n#define GL_SGIS_pixel_texture 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum, GLint);\nGLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum, const GLint *);\nGLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum, GLfloat);\nGLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum, const GLfloat *);\nGLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum, GLint *);\nGLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum, GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params);\n#endif\n\n#ifndef GL_SGIS_texture4D\n#define GL_SGIS_texture4D 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexImage4DSGIS (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glTexSubImage4DSGIS (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels);\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels);\n#endif\n\n#ifndef GL_SGI_texture_color_table\n#define GL_SGI_texture_color_table 1\n#endif\n\n#ifndef GL_EXT_cmyka\n#define GL_EXT_cmyka 1\n#endif\n\n#ifndef GL_EXT_texture_object\n#define GL_EXT_texture_object 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei, const GLuint *, GLboolean *);\nGLAPI void APIENTRY glBindTextureEXT (GLenum, GLuint);\nGLAPI void APIENTRY glDeleteTexturesEXT (GLsizei, const GLuint *);\nGLAPI void APIENTRY glGenTexturesEXT (GLsizei, GLuint *);\nGLAPI GLboolean APIENTRY glIsTextureEXT (GLuint);\nGLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei, const GLuint *, const GLclampf *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);\ntypedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture);\ntypedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures);\ntypedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures);\ntypedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture);\ntypedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities);\n#endif\n\n#ifndef GL_SGIS_detail_texture\n#define GL_SGIS_detail_texture 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDetailTexFuncSGIS (GLenum, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum, GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);\ntypedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points);\n#endif\n\n#ifndef GL_SGIS_sharpen_texture\n#define GL_SGIS_sharpen_texture 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum, GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);\ntypedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points);\n#endif\n\n#ifndef GL_EXT_packed_pixels\n#define GL_EXT_packed_pixels 1\n#endif\n\n#ifndef GL_SGIS_texture_lod\n#define GL_SGIS_texture_lod 1\n#endif\n\n#ifndef GL_SGIS_multisample\n#define GL_SGIS_multisample 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSampleMaskSGIS (GLclampf, GLboolean);\nGLAPI void APIENTRY glSamplePatternSGIS (GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert);\ntypedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern);\n#endif\n\n#ifndef GL_EXT_rescale_normal\n#define GL_EXT_rescale_normal 1\n#endif\n\n#ifndef GL_EXT_vertex_array\n#define GL_EXT_vertex_array 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glArrayElementEXT (GLint);\nGLAPI void APIENTRY glColorPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glDrawArraysEXT (GLenum, GLint, GLsizei);\nGLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei, GLsizei, const GLboolean *);\nGLAPI void APIENTRY glGetPointervEXT (GLenum, GLvoid* *);\nGLAPI void APIENTRY glIndexPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glNormalPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glTexCoordPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glVertexPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i);\ntypedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);\ntypedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer);\ntypedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params);\ntypedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);\n#endif\n\n#ifndef GL_EXT_misc_attribute\n#define GL_EXT_misc_attribute 1\n#endif\n\n#ifndef GL_SGIS_generate_mipmap\n#define GL_SGIS_generate_mipmap 1\n#endif\n\n#ifndef GL_SGIX_clipmap\n#define GL_SGIX_clipmap 1\n#endif\n\n#ifndef GL_SGIX_shadow\n#define GL_SGIX_shadow 1\n#endif\n\n#ifndef GL_SGIS_texture_edge_clamp\n#define GL_SGIS_texture_edge_clamp 1\n#endif\n\n#ifndef GL_SGIS_texture_border_clamp\n#define GL_SGIS_texture_border_clamp 1\n#endif\n\n#ifndef GL_EXT_blend_minmax\n#define GL_EXT_blend_minmax 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendEquationEXT (GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);\n#endif\n\n#ifndef GL_EXT_blend_subtract\n#define GL_EXT_blend_subtract 1\n#endif\n\n#ifndef GL_EXT_blend_logic_op\n#define GL_EXT_blend_logic_op 1\n#endif\n\n#ifndef GL_SGIX_interlace\n#define GL_SGIX_interlace 1\n#endif\n\n#ifndef GL_SGIX_pixel_tiles\n#define GL_SGIX_pixel_tiles 1\n#endif\n\n#ifndef GL_SGIX_texture_select\n#define GL_SGIX_texture_select 1\n#endif\n\n#ifndef GL_SGIX_sprite\n#define GL_SGIX_sprite 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSpriteParameterfSGIX (GLenum, GLfloat);\nGLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum, const GLfloat *);\nGLAPI void APIENTRY glSpriteParameteriSGIX (GLenum, GLint);\nGLAPI void APIENTRY glSpriteParameterivSGIX (GLenum, const GLint *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params);\n#endif\n\n#ifndef GL_SGIX_texture_multi_buffer\n#define GL_SGIX_texture_multi_buffer 1\n#endif\n\n#ifndef GL_EXT_point_parameters\n#define GL_EXT_point_parameters 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPointParameterfEXT (GLenum, GLfloat);\nGLAPI void APIENTRY glPointParameterfvEXT (GLenum, const GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);\n#endif\n\n#ifndef GL_SGIS_point_parameters\n#define GL_SGIS_point_parameters 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPointParameterfSGIS (GLenum, GLfloat);\nGLAPI void APIENTRY glPointParameterfvSGIS (GLenum, const GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);\n#endif\n\n#ifndef GL_SGIX_instruments\n#define GL_SGIX_instruments 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLint APIENTRY glGetInstrumentsSGIX (void);\nGLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei, GLint *);\nGLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *);\nGLAPI void APIENTRY glReadInstrumentsSGIX (GLint);\nGLAPI void APIENTRY glStartInstrumentsSGIX (void);\nGLAPI void APIENTRY glStopInstrumentsSGIX (GLint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void);\ntypedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer);\ntypedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p);\ntypedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker);\ntypedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void);\ntypedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker);\n#endif\n\n#ifndef GL_SGIX_texture_scale_bias\n#define GL_SGIX_texture_scale_bias 1\n#endif\n\n#ifndef GL_SGIX_framezoom\n#define GL_SGIX_framezoom 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFrameZoomSGIX (GLint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor);\n#endif\n\n#ifndef GL_SGIX_tag_sample_buffer\n#define GL_SGIX_tag_sample_buffer 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTagSampleBufferSGIX (void);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);\n#endif\n\n#ifndef GL_SGIX_polynomial_ffd\n#define GL_SGIX_polynomial_ffd 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDeformationMap3dSGIX (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *);\nGLAPI void APIENTRY glDeformationMap3fSGIX (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *);\nGLAPI void APIENTRY glDeformSGIX (GLbitfield);\nGLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);\ntypedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);\ntypedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask);\ntypedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask);\n#endif\n\n#ifndef GL_SGIX_reference_plane\n#define GL_SGIX_reference_plane 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation);\n#endif\n\n#ifndef GL_SGIX_flush_raster\n#define GL_SGIX_flush_raster 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFlushRasterSGIX (void);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void);\n#endif\n\n#ifndef GL_SGIX_depth_texture\n#define GL_SGIX_depth_texture 1\n#endif\n\n#ifndef GL_SGIS_fog_function\n#define GL_SGIS_fog_function 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFogFuncSGIS (GLsizei, const GLfloat *);\nGLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points);\ntypedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points);\n#endif\n\n#ifndef GL_SGIX_fog_offset\n#define GL_SGIX_fog_offset 1\n#endif\n\n#ifndef GL_HP_image_transform\n#define GL_HP_image_transform 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glImageTransformParameteriHP (GLenum, GLenum, GLint);\nGLAPI void APIENTRY glImageTransformParameterfHP (GLenum, GLenum, GLfloat);\nGLAPI void APIENTRY glImageTransformParameterivHP (GLenum, GLenum, const GLint *);\nGLAPI void APIENTRY glImageTransformParameterfvHP (GLenum, GLenum, const GLfloat *);\nGLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum, GLenum, GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);\n#endif\n\n#ifndef GL_HP_convolution_border_modes\n#define GL_HP_convolution_border_modes 1\n#endif\n\n#ifndef GL_SGIX_texture_add_env\n#define GL_SGIX_texture_add_env 1\n#endif\n\n#ifndef GL_EXT_color_subtable\n#define GL_EXT_color_subtable 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorSubTableEXT (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glCopyColorSubTableEXT (GLenum, GLsizei, GLint, GLint, GLsizei);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);\ntypedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);\n#endif\n\n#ifndef GL_PGI_vertex_hints\n#define GL_PGI_vertex_hints 1\n#endif\n\n#ifndef GL_PGI_misc_hints\n#define GL_PGI_misc_hints 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glHintPGI (GLenum, GLint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode);\n#endif\n\n#ifndef GL_EXT_paletted_texture\n#define GL_EXT_paletted_texture 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorTableEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);\nGLAPI void APIENTRY glGetColorTableEXT (GLenum, GLenum, GLenum, GLvoid *);\nGLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum, GLenum, GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);\n#endif\n\n#ifndef GL_EXT_clip_volume_hint\n#define GL_EXT_clip_volume_hint 1\n#endif\n\n#ifndef GL_SGIX_list_priority\n#define GL_SGIX_list_priority 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetListParameterfvSGIX (GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetListParameterivSGIX (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glListParameterfSGIX (GLuint, GLenum, GLfloat);\nGLAPI void APIENTRY glListParameterfvSGIX (GLuint, GLenum, const GLfloat *);\nGLAPI void APIENTRY glListParameteriSGIX (GLuint, GLenum, GLint);\nGLAPI void APIENTRY glListParameterivSGIX (GLuint, GLenum, const GLint *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params);\n#endif\n\n#ifndef GL_SGIX_ir_instrument1\n#define GL_SGIX_ir_instrument1 1\n#endif\n\n#ifndef GL_SGIX_calligraphic_fragment\n#define GL_SGIX_calligraphic_fragment 1\n#endif\n\n#ifndef GL_SGIX_texture_lod_bias\n#define GL_SGIX_texture_lod_bias 1\n#endif\n\n#ifndef GL_SGIX_shadow_ambient\n#define GL_SGIX_shadow_ambient 1\n#endif\n\n#ifndef GL_EXT_index_texture\n#define GL_EXT_index_texture 1\n#endif\n\n#ifndef GL_EXT_index_material\n#define GL_EXT_index_material 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glIndexMaterialEXT (GLenum, GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode);\n#endif\n\n#ifndef GL_EXT_index_func\n#define GL_EXT_index_func 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glIndexFuncEXT (GLenum, GLclampf);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref);\n#endif\n\n#ifndef GL_EXT_index_array_formats\n#define GL_EXT_index_array_formats 1\n#endif\n\n#ifndef GL_EXT_compiled_vertex_array\n#define GL_EXT_compiled_vertex_array 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glLockArraysEXT (GLint, GLsizei);\nGLAPI void APIENTRY glUnlockArraysEXT (void);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);\ntypedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void);\n#endif\n\n#ifndef GL_EXT_cull_vertex\n#define GL_EXT_cull_vertex 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCullParameterdvEXT (GLenum, GLdouble *);\nGLAPI void APIENTRY glCullParameterfvEXT (GLenum, GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params);\n#endif\n\n#ifndef GL_SGIX_ycrcb\n#define GL_SGIX_ycrcb 1\n#endif\n\n#ifndef GL_SGIX_fragment_lighting\n#define GL_SGIX_fragment_lighting 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum, GLenum);\nGLAPI void APIENTRY glFragmentLightfSGIX (GLenum, GLenum, GLfloat);\nGLAPI void APIENTRY glFragmentLightfvSGIX (GLenum, GLenum, const GLfloat *);\nGLAPI void APIENTRY glFragmentLightiSGIX (GLenum, GLenum, GLint);\nGLAPI void APIENTRY glFragmentLightivSGIX (GLenum, GLenum, const GLint *);\nGLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum, GLfloat);\nGLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum, const GLfloat *);\nGLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum, GLint);\nGLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum, const GLint *);\nGLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum, GLenum, GLfloat);\nGLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum, GLenum, const GLfloat *);\nGLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum, GLenum, GLint);\nGLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum, GLenum, const GLint *);\nGLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glLightEnviSGIX (GLenum, GLint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param);\n#endif\n\n#ifndef GL_IBM_rasterpos_clip\n#define GL_IBM_rasterpos_clip 1\n#endif\n\n#ifndef GL_HP_texture_lighting\n#define GL_HP_texture_lighting 1\n#endif\n\n#ifndef GL_EXT_draw_range_elements\n#define GL_EXT_draw_range_elements 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawRangeElementsEXT (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);\n#endif\n\n#ifndef GL_WIN_phong_shading\n#define GL_WIN_phong_shading 1\n#endif\n\n#ifndef GL_WIN_specular_fog\n#define GL_WIN_specular_fog 1\n#endif\n\n#ifndef GL_EXT_light_texture\n#define GL_EXT_light_texture 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glApplyTextureEXT (GLenum);\nGLAPI void APIENTRY glTextureLightEXT (GLenum);\nGLAPI void APIENTRY glTextureMaterialEXT (GLenum, GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname);\ntypedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode);\n#endif\n\n#ifndef GL_SGIX_blend_alpha_minmax\n#define GL_SGIX_blend_alpha_minmax 1\n#endif\n\n#ifndef GL_EXT_bgra\n#define GL_EXT_bgra 1\n#endif\n\n#ifndef GL_SGIX_async\n#define GL_SGIX_async 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glAsyncMarkerSGIX (GLuint);\nGLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *);\nGLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *);\nGLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei);\nGLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint, GLsizei);\nGLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker);\ntypedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp);\ntypedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp);\ntypedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range);\ntypedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range);\ntypedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker);\n#endif\n\n#ifndef GL_SGIX_async_pixel\n#define GL_SGIX_async_pixel 1\n#endif\n\n#ifndef GL_SGIX_async_histogram\n#define GL_SGIX_async_histogram 1\n#endif\n\n#ifndef GL_INTEL_parallel_arrays\n#define GL_INTEL_parallel_arrays 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexPointervINTEL (GLint, GLenum, const GLvoid* *);\nGLAPI void APIENTRY glNormalPointervINTEL (GLenum, const GLvoid* *);\nGLAPI void APIENTRY glColorPointervINTEL (GLint, GLenum, const GLvoid* *);\nGLAPI void APIENTRY glTexCoordPointervINTEL (GLint, GLenum, const GLvoid* *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);\ntypedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer);\ntypedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);\ntypedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);\n#endif\n\n#ifndef GL_HP_occlusion_test\n#define GL_HP_occlusion_test 1\n#endif\n\n#ifndef GL_EXT_pixel_transform\n#define GL_EXT_pixel_transform 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum, GLenum, GLint);\nGLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum, GLenum, GLfloat);\nGLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum, GLenum, const GLint *);\nGLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum, GLenum, const GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);\n#endif\n\n#ifndef GL_EXT_pixel_transform_color_table\n#define GL_EXT_pixel_transform_color_table 1\n#endif\n\n#ifndef GL_EXT_shared_texture_palette\n#define GL_EXT_shared_texture_palette 1\n#endif\n\n#ifndef GL_EXT_separate_specular_color\n#define GL_EXT_separate_specular_color 1\n#endif\n\n#ifndef GL_EXT_secondary_color\n#define GL_EXT_secondary_color 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte, GLbyte, GLbyte);\nGLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *);\nGLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *);\nGLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *);\nGLAPI void APIENTRY glSecondaryColor3iEXT (GLint, GLint, GLint);\nGLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *);\nGLAPI void APIENTRY glSecondaryColor3sEXT (GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *);\nGLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte, GLubyte, GLubyte);\nGLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *);\nGLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *);\nGLAPI void APIENTRY glSecondaryColor3usEXT (GLushort, GLushort, GLushort);\nGLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *);\nGLAPI void APIENTRY glSecondaryColorPointerEXT (GLint, GLenum, GLsizei, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\n#endif\n\n#ifndef GL_EXT_texture_perturb_normal\n#define GL_EXT_texture_perturb_normal 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTextureNormalEXT (GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode);\n#endif\n\n#ifndef GL_EXT_multi_draw_arrays\n#define GL_EXT_multi_draw_arrays 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);\nGLAPI void APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);\n#endif\n\n#ifndef GL_EXT_fog_coord\n#define GL_EXT_fog_coord 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFogCoordfEXT (GLfloat);\nGLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *);\nGLAPI void APIENTRY glFogCoorddEXT (GLdouble);\nGLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *);\nGLAPI void APIENTRY glFogCoordPointerEXT (GLenum, GLsizei, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);\n#endif\n\n#ifndef GL_REND_screen_coordinates\n#define GL_REND_screen_coordinates 1\n#endif\n\n#ifndef GL_EXT_coordinate_frame\n#define GL_EXT_coordinate_frame 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTangent3bEXT (GLbyte, GLbyte, GLbyte);\nGLAPI void APIENTRY glTangent3bvEXT (const GLbyte *);\nGLAPI void APIENTRY glTangent3dEXT (GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glTangent3dvEXT (const GLdouble *);\nGLAPI void APIENTRY glTangent3fEXT (GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glTangent3fvEXT (const GLfloat *);\nGLAPI void APIENTRY glTangent3iEXT (GLint, GLint, GLint);\nGLAPI void APIENTRY glTangent3ivEXT (const GLint *);\nGLAPI void APIENTRY glTangent3sEXT (GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glTangent3svEXT (const GLshort *);\nGLAPI void APIENTRY glBinormal3bEXT (GLbyte, GLbyte, GLbyte);\nGLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *);\nGLAPI void APIENTRY glBinormal3dEXT (GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *);\nGLAPI void APIENTRY glBinormal3fEXT (GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *);\nGLAPI void APIENTRY glBinormal3iEXT (GLint, GLint, GLint);\nGLAPI void APIENTRY glBinormal3ivEXT (const GLint *);\nGLAPI void APIENTRY glBinormal3sEXT (GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glBinormal3svEXT (const GLshort *);\nGLAPI void APIENTRY glTangentPointerEXT (GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glBinormalPointerEXT (GLenum, GLsizei, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz);\ntypedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz);\ntypedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz);\ntypedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz);\ntypedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz);\ntypedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);\n#endif\n\n#ifndef GL_EXT_texture_env_combine\n#define GL_EXT_texture_env_combine 1\n#endif\n\n#ifndef GL_APPLE_specular_vector\n#define GL_APPLE_specular_vector 1\n#endif\n\n#ifndef GL_APPLE_transform_hint\n#define GL_APPLE_transform_hint 1\n#endif\n\n#ifndef GL_SGIX_fog_scale\n#define GL_SGIX_fog_scale 1\n#endif\n\n#ifndef GL_SUNX_constant_data\n#define GL_SUNX_constant_data 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFinishTextureSUNX (void);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void);\n#endif\n\n#ifndef GL_SUN_global_alpha\n#define GL_SUN_global_alpha 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte);\nGLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort);\nGLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint);\nGLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat);\nGLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble);\nGLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte);\nGLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort);\nGLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor);\n#endif\n\n#ifndef GL_SUN_triangle_list\n#define GL_SUN_triangle_list 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glReplacementCodeuiSUN (GLuint);\nGLAPI void APIENTRY glReplacementCodeusSUN (GLushort);\nGLAPI void APIENTRY glReplacementCodeubSUN (GLubyte);\nGLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *);\nGLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *);\nGLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *);\nGLAPI void APIENTRY glReplacementCodePointerSUN (GLenum, GLsizei, const GLvoid* *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer);\n#endif\n\n#ifndef GL_SUN_vertex\n#define GL_SUN_vertex 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat);\nGLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *, const GLfloat *);\nGLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *, const GLfloat *);\nGLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat, GLfloat, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *, const GLubyte *, const GLfloat *);\nGLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *, const GLfloat *);\nGLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *, const GLubyte *, const GLfloat *);\nGLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\n#endif\n\n#ifndef GL_EXT_blend_func_separate\n#define GL_EXT_blend_func_separate 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum, GLenum, GLenum, GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\n#endif\n\n#ifndef GL_INGR_blend_func_separate\n#define GL_INGR_blend_func_separate 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum, GLenum, GLenum, GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\n#endif\n\n#ifndef GL_INGR_color_clamp\n#define GL_INGR_color_clamp 1\n#endif\n\n#ifndef GL_INGR_interlace_read\n#define GL_INGR_interlace_read 1\n#endif\n\n#ifndef GL_EXT_stencil_wrap\n#define GL_EXT_stencil_wrap 1\n#endif\n\n#ifndef GL_EXT_422_pixels\n#define GL_EXT_422_pixels 1\n#endif\n\n#ifndef GL_NV_texgen_reflection\n#define GL_NV_texgen_reflection 1\n#endif\n\n#ifndef GL_SUN_convolution_border_modes\n#define GL_SUN_convolution_border_modes 1\n#endif\n\n#ifndef GL_EXT_texture_env_add\n#define GL_EXT_texture_env_add 1\n#endif\n\n#ifndef GL_EXT_texture_lod_bias\n#define GL_EXT_texture_lod_bias 1\n#endif\n\n#ifndef GL_EXT_texture_filter_anisotropic\n#define GL_EXT_texture_filter_anisotropic 1\n#endif\n\n#ifndef GL_EXT_vertex_weighting\n#define GL_EXT_vertex_weighting 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexWeightfEXT (GLfloat);\nGLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *);\nGLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei, GLenum, GLsizei, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight);\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer);\n#endif\n\n#ifndef GL_NV_light_max_exponent\n#define GL_NV_light_max_exponent 1\n#endif\n\n#ifndef GL_NV_vertex_array_range\n#define GL_NV_vertex_array_range 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFlushVertexArrayRangeNV (void);\nGLAPI void APIENTRY glVertexArrayRangeNV (GLsizei, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer);\n#endif\n\n#ifndef GL_NV_register_combiners\n#define GL_NV_register_combiners 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCombinerParameterfvNV (GLenum, const GLfloat *);\nGLAPI void APIENTRY glCombinerParameterfNV (GLenum, GLfloat);\nGLAPI void APIENTRY glCombinerParameterivNV (GLenum, const GLint *);\nGLAPI void APIENTRY glCombinerParameteriNV (GLenum, GLint);\nGLAPI void APIENTRY glCombinerInputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum);\nGLAPI void APIENTRY glCombinerOutputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLboolean, GLboolean, GLboolean);\nGLAPI void APIENTRY glFinalCombinerInputNV (GLenum, GLenum, GLenum, GLenum);\nGLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum, GLenum, GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum, GLenum, GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum, GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum, GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum, GLenum, GLint *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);\ntypedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);\ntypedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);\ntypedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params);\n#endif\n\n#ifndef GL_NV_fog_distance\n#define GL_NV_fog_distance 1\n#endif\n\n#ifndef GL_NV_texgen_emboss\n#define GL_NV_texgen_emboss 1\n#endif\n\n#ifndef GL_NV_blend_square\n#define GL_NV_blend_square 1\n#endif\n\n#ifndef GL_NV_texture_env_combine4\n#define GL_NV_texture_env_combine4 1\n#endif\n\n#ifndef GL_MESA_resize_buffers\n#define GL_MESA_resize_buffers 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glResizeBuffersMESA (void);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void);\n#endif\n\n#ifndef GL_MESA_window_pos\n#define GL_MESA_window_pos 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glWindowPos2dMESA (GLdouble, GLdouble);\nGLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *);\nGLAPI void APIENTRY glWindowPos2fMESA (GLfloat, GLfloat);\nGLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *);\nGLAPI void APIENTRY glWindowPos2iMESA (GLint, GLint);\nGLAPI void APIENTRY glWindowPos2ivMESA (const GLint *);\nGLAPI void APIENTRY glWindowPos2sMESA (GLshort, GLshort);\nGLAPI void APIENTRY glWindowPos2svMESA (const GLshort *);\nGLAPI void APIENTRY glWindowPos3dMESA (GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *);\nGLAPI void APIENTRY glWindowPos3fMESA (GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *);\nGLAPI void APIENTRY glWindowPos3iMESA (GLint, GLint, GLint);\nGLAPI void APIENTRY glWindowPos3ivMESA (const GLint *);\nGLAPI void APIENTRY glWindowPos3sMESA (GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glWindowPos3svMESA (const GLshort *);\nGLAPI void APIENTRY glWindowPos4dMESA (GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *);\nGLAPI void APIENTRY glWindowPos4fMESA (GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *);\nGLAPI void APIENTRY glWindowPos4iMESA (GLint, GLint, GLint, GLint);\nGLAPI void APIENTRY glWindowPos4ivMESA (const GLint *);\nGLAPI void APIENTRY glWindowPos4sMESA (GLshort, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glWindowPos4svMESA (const GLshort *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v);\n#endif\n\n#ifndef GL_IBM_cull_vertex\n#define GL_IBM_cull_vertex 1\n#endif\n\n#ifndef GL_IBM_multimode_draw_arrays\n#define GL_IBM_multimode_draw_arrays 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *, const GLint *, const GLsizei *, GLsizei, GLint);\nGLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *, const GLsizei *, GLenum, const GLvoid* const *, GLsizei, GLint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);\ntypedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride);\n#endif\n\n#ifndef GL_IBM_vertex_array_lists\n#define GL_IBM_vertex_array_lists 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);\nGLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);\nGLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint, const GLboolean* *, GLint);\nGLAPI void APIENTRY glFogCoordPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);\nGLAPI void APIENTRY glIndexPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);\nGLAPI void APIENTRY glNormalPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);\nGLAPI void APIENTRY glTexCoordPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);\nGLAPI void APIENTRY glVertexPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);\n#endif\n\n#ifndef GL_SGIX_subsample\n#define GL_SGIX_subsample 1\n#endif\n\n#ifndef GL_SGIX_ycrcba\n#define GL_SGIX_ycrcba 1\n#endif\n\n#ifndef GL_SGIX_ycrcb_subsample\n#define GL_SGIX_ycrcb_subsample 1\n#endif\n\n#ifndef GL_SGIX_depth_pass_instrument\n#define GL_SGIX_depth_pass_instrument 1\n#endif\n\n#ifndef GL_3DFX_texture_compression_FXT1\n#define GL_3DFX_texture_compression_FXT1 1\n#endif\n\n#ifndef GL_3DFX_multisample\n#define GL_3DFX_multisample 1\n#endif\n\n#ifndef GL_3DFX_tbuffer\n#define GL_3DFX_tbuffer 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTbufferMask3DFX (GLuint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask);\n#endif\n\n#ifndef GL_EXT_multisample\n#define GL_EXT_multisample 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSampleMaskEXT (GLclampf, GLboolean);\nGLAPI void APIENTRY glSamplePatternEXT (GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert);\ntypedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern);\n#endif\n\n#ifndef GL_SGIX_vertex_preclip\n#define GL_SGIX_vertex_preclip 1\n#endif\n\n#ifndef GL_SGIX_convolution_accuracy\n#define GL_SGIX_convolution_accuracy 1\n#endif\n\n#ifndef GL_SGIX_resample\n#define GL_SGIX_resample 1\n#endif\n\n#ifndef GL_SGIS_point_line_texgen\n#define GL_SGIS_point_line_texgen 1\n#endif\n\n#ifndef GL_SGIS_texture_color_mask\n#define GL_SGIS_texture_color_mask 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean, GLboolean, GLboolean, GLboolean);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\n#endif\n\n#ifndef GL_SGIX_igloo_interface\n#define GL_SGIX_igloo_interface 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glIglooInterfaceSGIX (GLenum, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params);\n#endif\n\n#ifndef GL_EXT_texture_env_dot3\n#define GL_EXT_texture_env_dot3 1\n#endif\n\n#ifndef GL_ATI_texture_mirror_once\n#define GL_ATI_texture_mirror_once 1\n#endif\n\n#ifndef GL_NV_fence\n#define GL_NV_fence 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);\nGLAPI void APIENTRY glGenFencesNV (GLsizei, GLuint *);\nGLAPI GLboolean APIENTRY glIsFenceNV (GLuint);\nGLAPI GLboolean APIENTRY glTestFenceNV (GLuint);\nGLAPI void APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glFinishFenceNV (GLuint);\nGLAPI void APIENTRY glSetFenceNV (GLuint, GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);\ntypedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);\ntypedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);\ntypedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);\ntypedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);\ntypedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);\n#endif\n\n#ifndef GL_NV_evaluators\n#define GL_NV_evaluators 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLint, GLint, GLboolean, const GLvoid *);\nGLAPI void APIENTRY glMapParameterivNV (GLenum, GLenum, const GLint *);\nGLAPI void APIENTRY glMapParameterfvNV (GLenum, GLenum, const GLfloat *);\nGLAPI void APIENTRY glGetMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLboolean, GLvoid *);\nGLAPI void APIENTRY glGetMapParameterivNV (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGetMapParameterfvNV (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum, GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glEvalMapsNV (GLenum, GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points);\ntypedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points);\ntypedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode);\n#endif\n\n#ifndef GL_NV_packed_depth_stencil\n#define GL_NV_packed_depth_stencil 1\n#endif\n\n#ifndef GL_NV_register_combiners2\n#define GL_NV_register_combiners2 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum, GLenum, const GLfloat *);\nGLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum, GLenum, GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params);\n#endif\n\n#ifndef GL_NV_texture_compression_vtc\n#define GL_NV_texture_compression_vtc 1\n#endif\n\n#ifndef GL_NV_texture_rectangle\n#define GL_NV_texture_rectangle 1\n#endif\n\n#ifndef GL_NV_texture_shader\n#define GL_NV_texture_shader 1\n#endif\n\n#ifndef GL_NV_texture_shader2\n#define GL_NV_texture_shader2 1\n#endif\n\n#ifndef GL_NV_vertex_array_range2\n#define GL_NV_vertex_array_range2 1\n#endif\n\n#ifndef GL_NV_vertex_program\n#define GL_NV_vertex_program 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei, const GLuint *, GLboolean *);\nGLAPI void APIENTRY glBindProgramNV (GLenum, GLuint);\nGLAPI void APIENTRY glDeleteProgramsNV (GLsizei, const GLuint *);\nGLAPI void APIENTRY glExecuteProgramNV (GLenum, GLuint, const GLfloat *);\nGLAPI void APIENTRY glGenProgramsNV (GLsizei, GLuint *);\nGLAPI void APIENTRY glGetProgramParameterdvNV (GLenum, GLuint, GLenum, GLdouble *);\nGLAPI void APIENTRY glGetProgramParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetProgramivNV (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetProgramStringNV (GLuint, GLenum, GLubyte *);\nGLAPI void APIENTRY glGetTrackMatrixivNV (GLenum, GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetVertexAttribdvNV (GLuint, GLenum, GLdouble *);\nGLAPI void APIENTRY glGetVertexAttribfvNV (GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetVertexAttribivNV (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint, GLenum, GLvoid* *);\nGLAPI GLboolean APIENTRY glIsProgramNV (GLuint);\nGLAPI void APIENTRY glLoadProgramNV (GLenum, GLuint, GLsizei, const GLubyte *);\nGLAPI void APIENTRY glProgramParameter4dNV (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glProgramParameter4dvNV (GLenum, GLuint, const GLdouble *);\nGLAPI void APIENTRY glProgramParameter4fNV (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glProgramParameter4fvNV (GLenum, GLuint, const GLfloat *);\nGLAPI void APIENTRY glProgramParameters4dvNV (GLenum, GLuint, GLuint, const GLdouble *);\nGLAPI void APIENTRY glProgramParameters4fvNV (GLenum, GLuint, GLuint, const GLfloat *);\nGLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei, const GLuint *);\nGLAPI void APIENTRY glTrackMatrixNV (GLenum, GLuint, GLenum, GLenum);\nGLAPI void APIENTRY glVertexAttribPointerNV (GLuint, GLint, GLenum, GLsizei, const GLvoid *);\nGLAPI void APIENTRY glVertexAttrib1dNV (GLuint, GLdouble);\nGLAPI void APIENTRY glVertexAttrib1dvNV (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib1fNV (GLuint, GLfloat);\nGLAPI void APIENTRY glVertexAttrib1fvNV (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib1sNV (GLuint, GLshort);\nGLAPI void APIENTRY glVertexAttrib1svNV (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib2dNV (GLuint, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexAttrib2dvNV (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib2fNV (GLuint, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexAttrib2fvNV (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib2sNV (GLuint, GLshort, GLshort);\nGLAPI void APIENTRY glVertexAttrib2svNV (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib3dNV (GLuint, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexAttrib3dvNV (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib3fNV (GLuint, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexAttrib3fvNV (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib3sNV (GLuint, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glVertexAttrib3svNV (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib4dNV (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexAttrib4dvNV (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVertexAttrib4fNV (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexAttrib4fvNV (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVertexAttrib4sNV (GLuint, GLshort, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glVertexAttrib4svNV (GLuint, const GLshort *);\nGLAPI void APIENTRY glVertexAttrib4ubNV (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);\nGLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint, const GLubyte *);\nGLAPI void APIENTRY glVertexAttribs1dvNV (GLuint, GLsizei, const GLdouble *);\nGLAPI void APIENTRY glVertexAttribs1fvNV (GLuint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glVertexAttribs1svNV (GLuint, GLsizei, const GLshort *);\nGLAPI void APIENTRY glVertexAttribs2dvNV (GLuint, GLsizei, const GLdouble *);\nGLAPI void APIENTRY glVertexAttribs2fvNV (GLuint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glVertexAttribs2svNV (GLuint, GLsizei, const GLshort *);\nGLAPI void APIENTRY glVertexAttribs3dvNV (GLuint, GLsizei, const GLdouble *);\nGLAPI void APIENTRY glVertexAttribs3fvNV (GLuint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glVertexAttribs3svNV (GLuint, GLsizei, const GLshort *);\nGLAPI void APIENTRY glVertexAttribs4dvNV (GLuint, GLsizei, const GLdouble *);\nGLAPI void APIENTRY glVertexAttribs4fvNV (GLuint, GLsizei, const GLfloat *);\nGLAPI void APIENTRY glVertexAttribs4svNV (GLuint, GLsizei, const GLshort *);\nGLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint, GLsizei, const GLubyte *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences);\ntypedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);\ntypedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs);\ntypedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program);\ntypedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);\ntypedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLuint count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLuint count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);\ntypedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v);\n#endif\n\n#ifndef GL_SGIX_texture_coordinate_clamp\n#define GL_SGIX_texture_coordinate_clamp 1\n#endif\n\n#ifndef GL_SGIX_scalebias_hint\n#define GL_SGIX_scalebias_hint 1\n#endif\n\n#ifndef GL_OML_interlace\n#define GL_OML_interlace 1\n#endif\n\n#ifndef GL_OML_subsample\n#define GL_OML_subsample 1\n#endif\n\n#ifndef GL_OML_resample\n#define GL_OML_resample 1\n#endif\n\n#ifndef GL_NV_copy_depth_to_color\n#define GL_NV_copy_depth_to_color 1\n#endif\n\n#ifndef GL_ATI_envmap_bumpmap\n#define GL_ATI_envmap_bumpmap 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexBumpParameterivATI (GLenum, const GLint *);\nGLAPI void APIENTRY glTexBumpParameterfvATI (GLenum, const GLfloat *);\nGLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum, GLint *);\nGLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum, GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param);\ntypedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param);\ntypedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param);\ntypedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param);\n#endif\n\n#ifndef GL_ATI_fragment_shader\n#define GL_ATI_fragment_shader 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint);\nGLAPI void APIENTRY glBindFragmentShaderATI (GLuint);\nGLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint);\nGLAPI void APIENTRY glBeginFragmentShaderATI (void);\nGLAPI void APIENTRY glEndFragmentShaderATI (void);\nGLAPI void APIENTRY glPassTexCoordATI (GLuint, GLuint, GLenum);\nGLAPI void APIENTRY glSampleMapATI (GLuint, GLuint, GLenum);\nGLAPI void APIENTRY glColorFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glColorFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glColorFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint, const GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range);\ntypedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void);\ntypedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void);\ntypedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle);\ntypedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle);\ntypedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);\ntypedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);\ntypedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);\ntypedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);\ntypedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);\ntypedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);\ntypedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value);\n#endif\n\n#ifndef GL_ATI_pn_triangles\n#define GL_ATI_pn_triangles 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPNTrianglesiATI (GLenum, GLint);\nGLAPI void APIENTRY glPNTrianglesfATI (GLenum, GLfloat);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param);\n#endif\n\n#ifndef GL_ATI_vertex_array_object\n#define GL_ATI_vertex_array_object 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei, const GLvoid *, GLenum);\nGLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint);\nGLAPI void APIENTRY glUpdateObjectBufferATI (GLuint, GLuint, GLsizei, const GLvoid *, GLenum);\nGLAPI void APIENTRY glGetObjectBufferfvATI (GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetObjectBufferivATI (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glFreeObjectBufferATI (GLuint);\nGLAPI void APIENTRY glArrayObjectATI (GLenum, GLint, GLenum, GLsizei, GLuint, GLuint);\nGLAPI void APIENTRY glGetArrayObjectfvATI (GLenum, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetArrayObjectivATI (GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glVariantArrayObjectATI (GLuint, GLenum, GLsizei, GLuint, GLuint);\nGLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint, GLenum, GLint *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage);\ntypedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve);\ntypedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);\ntypedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);\ntypedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params);\n#endif\n\n#ifndef GL_EXT_vertex_shader\n#define GL_EXT_vertex_shader 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBeginVertexShaderEXT (void);\nGLAPI void APIENTRY glEndVertexShaderEXT (void);\nGLAPI void APIENTRY glBindVertexShaderEXT (GLuint);\nGLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint);\nGLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint);\nGLAPI void APIENTRY glShaderOp1EXT (GLenum, GLuint, GLuint);\nGLAPI void APIENTRY glShaderOp2EXT (GLenum, GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glShaderOp3EXT (GLenum, GLuint, GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glSwizzleEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);\nGLAPI void APIENTRY glWriteMaskEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);\nGLAPI void APIENTRY glInsertComponentEXT (GLuint, GLuint, GLuint);\nGLAPI void APIENTRY glExtractComponentEXT (GLuint, GLuint, GLuint);\nGLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum, GLenum, GLenum, GLuint);\nGLAPI void APIENTRY glSetInvariantEXT (GLuint, GLenum, const GLvoid *);\nGLAPI void APIENTRY glSetLocalConstantEXT (GLuint, GLenum, const GLvoid *);\nGLAPI void APIENTRY glVariantbvEXT (GLuint, const GLbyte *);\nGLAPI void APIENTRY glVariantsvEXT (GLuint, const GLshort *);\nGLAPI void APIENTRY glVariantivEXT (GLuint, const GLint *);\nGLAPI void APIENTRY glVariantfvEXT (GLuint, const GLfloat *);\nGLAPI void APIENTRY glVariantdvEXT (GLuint, const GLdouble *);\nGLAPI void APIENTRY glVariantubvEXT (GLuint, const GLubyte *);\nGLAPI void APIENTRY glVariantusvEXT (GLuint, const GLushort *);\nGLAPI void APIENTRY glVariantuivEXT (GLuint, const GLuint *);\nGLAPI void APIENTRY glVariantPointerEXT (GLuint, GLenum, GLuint, const GLvoid *);\nGLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint);\nGLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint);\nGLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum, GLenum);\nGLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum, GLenum);\nGLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum, GLenum, GLenum);\nGLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum, GLenum);\nGLAPI GLuint APIENTRY glBindParameterEXT (GLenum);\nGLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint, GLenum);\nGLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint, GLenum, GLboolean *);\nGLAPI void APIENTRY glGetVariantIntegervEXT (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetVariantFloatvEXT (GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetVariantPointervEXT (GLuint, GLenum, GLvoid* *);\nGLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint, GLenum, GLboolean *);\nGLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint, GLenum, GLboolean *);\nGLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint, GLenum, GLfloat *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void);\ntypedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void);\ntypedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id);\ntypedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range);\ntypedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1);\ntypedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2);\ntypedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);\ntypedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);\ntypedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);\ntypedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);\ntypedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);\ntypedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);\ntypedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);\ntypedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);\ntypedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr);\ntypedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr);\ntypedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr);\ntypedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr);\ntypedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr);\ntypedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr);\ntypedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr);\ntypedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr);\ntypedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr);\ntypedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);\ntypedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value);\ntypedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value);\ntypedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value);\ntypedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value);\ntypedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value);\ntypedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap);\ntypedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);\ntypedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);\ntypedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);\ntypedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data);\ntypedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);\ntypedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);\ntypedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);\ntypedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);\ntypedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);\ntypedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);\n#endif\n\n#ifndef GL_ATI_vertex_streams\n#define GL_ATI_vertex_streams 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexStream1sATI (GLenum, GLshort);\nGLAPI void APIENTRY glVertexStream1svATI (GLenum, const GLshort *);\nGLAPI void APIENTRY glVertexStream1iATI (GLenum, GLint);\nGLAPI void APIENTRY glVertexStream1ivATI (GLenum, const GLint *);\nGLAPI void APIENTRY glVertexStream1fATI (GLenum, GLfloat);\nGLAPI void APIENTRY glVertexStream1fvATI (GLenum, const GLfloat *);\nGLAPI void APIENTRY glVertexStream1dATI (GLenum, GLdouble);\nGLAPI void APIENTRY glVertexStream1dvATI (GLenum, const GLdouble *);\nGLAPI void APIENTRY glVertexStream2sATI (GLenum, GLshort, GLshort);\nGLAPI void APIENTRY glVertexStream2svATI (GLenum, const GLshort *);\nGLAPI void APIENTRY glVertexStream2iATI (GLenum, GLint, GLint);\nGLAPI void APIENTRY glVertexStream2ivATI (GLenum, const GLint *);\nGLAPI void APIENTRY glVertexStream2fATI (GLenum, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexStream2fvATI (GLenum, const GLfloat *);\nGLAPI void APIENTRY glVertexStream2dATI (GLenum, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexStream2dvATI (GLenum, const GLdouble *);\nGLAPI void APIENTRY glVertexStream3sATI (GLenum, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glVertexStream3svATI (GLenum, const GLshort *);\nGLAPI void APIENTRY glVertexStream3iATI (GLenum, GLint, GLint, GLint);\nGLAPI void APIENTRY glVertexStream3ivATI (GLenum, const GLint *);\nGLAPI void APIENTRY glVertexStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexStream3fvATI (GLenum, const GLfloat *);\nGLAPI void APIENTRY glVertexStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexStream3dvATI (GLenum, const GLdouble *);\nGLAPI void APIENTRY glVertexStream4sATI (GLenum, GLshort, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glVertexStream4svATI (GLenum, const GLshort *);\nGLAPI void APIENTRY glVertexStream4iATI (GLenum, GLint, GLint, GLint, GLint);\nGLAPI void APIENTRY glVertexStream4ivATI (GLenum, const GLint *);\nGLAPI void APIENTRY glVertexStream4fATI (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glVertexStream4fvATI (GLenum, const GLfloat *);\nGLAPI void APIENTRY glVertexStream4dATI (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glVertexStream4dvATI (GLenum, const GLdouble *);\nGLAPI void APIENTRY glNormalStream3bATI (GLenum, GLbyte, GLbyte, GLbyte);\nGLAPI void APIENTRY glNormalStream3bvATI (GLenum, const GLbyte *);\nGLAPI void APIENTRY glNormalStream3sATI (GLenum, GLshort, GLshort, GLshort);\nGLAPI void APIENTRY glNormalStream3svATI (GLenum, const GLshort *);\nGLAPI void APIENTRY glNormalStream3iATI (GLenum, GLint, GLint, GLint);\nGLAPI void APIENTRY glNormalStream3ivATI (GLenum, const GLint *);\nGLAPI void APIENTRY glNormalStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glNormalStream3fvATI (GLenum, const GLfloat *);\nGLAPI void APIENTRY glNormalStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glNormalStream3dvATI (GLenum, const GLdouble *);\nGLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum);\nGLAPI void APIENTRY glVertexBlendEnviATI (GLenum, GLint);\nGLAPI void APIENTRY glVertexBlendEnvfATI (GLenum, GLfloat);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream);\ntypedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param);\n#endif\n\n#ifndef GL_ATI_element_array\n#define GL_ATI_element_array 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glElementPointerATI (GLenum, const GLvoid *);\nGLAPI void APIENTRY glDrawElementArrayATI (GLenum, GLsizei);\nGLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum, GLuint, GLuint, GLsizei);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count);\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count);\n#endif\n\n#ifndef GL_SUN_mesh_array\n#define GL_SUN_mesh_array 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawMeshArraysSUN (GLenum, GLint, GLsizei, GLsizei);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width);\n#endif\n\n#ifndef GL_SUN_slice_accum\n#define GL_SUN_slice_accum 1\n#endif\n\n#ifndef GL_NV_multisample_filter_hint\n#define GL_NV_multisample_filter_hint 1\n#endif\n\n#ifndef GL_NV_depth_clamp\n#define GL_NV_depth_clamp 1\n#endif\n\n#ifndef GL_NV_occlusion_query\n#define GL_NV_occlusion_query 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei, GLuint *);\nGLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei, const GLuint *);\nGLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint);\nGLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint);\nGLAPI void APIENTRY glEndOcclusionQueryNV (void);\nGLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint, GLenum, GLint *);\nGLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint, GLenum, GLuint *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void);\ntypedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params);\n#endif\n\n#ifndef GL_NV_point_sprite\n#define GL_NV_point_sprite 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPointParameteriNV (GLenum, GLint);\nGLAPI void APIENTRY glPointParameterivNV (GLenum, const GLint *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params);\n#endif\n\n#ifndef GL_NV_texture_shader3\n#define GL_NV_texture_shader3 1\n#endif\n\n#ifndef GL_NV_vertex_program1_1\n#define GL_NV_vertex_program1_1 1\n#endif\n\n#ifndef GL_EXT_shadow_funcs\n#define GL_EXT_shadow_funcs 1\n#endif\n\n#ifndef GL_EXT_stencil_two_side\n#define GL_EXT_stencil_two_side 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glActiveStencilFaceEXT (GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);\n#endif\n\n#ifndef GL_ATI_text_fragment_shader\n#define GL_ATI_text_fragment_shader 1\n#endif\n\n#ifndef GL_APPLE_client_storage\n#define GL_APPLE_client_storage 1\n#endif\n\n#ifndef GL_APPLE_element_array\n#define GL_APPLE_element_array 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glElementPointerAPPLE (GLenum, const GLvoid *);\nGLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum, GLint, GLsizei);\nGLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, GLint, GLsizei);\nGLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum, const GLint *, const GLsizei *, GLsizei);\nGLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, const GLint *, const GLsizei *, GLsizei);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count);\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);\ntypedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);\n#endif\n\n#ifndef GL_APPLE_fence\n#define GL_APPLE_fence 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenFencesAPPLE (GLsizei, GLuint *);\nGLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei, const GLuint *);\nGLAPI void APIENTRY glSetFenceAPPLE (GLuint);\nGLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint);\nGLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint);\nGLAPI void APIENTRY glFinishFenceAPPLE (GLuint);\nGLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum, GLuint);\nGLAPI void APIENTRY glFinishObjectAPPLE (GLenum, GLint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences);\ntypedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences);\ntypedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence);\ntypedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence);\ntypedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence);\ntypedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence);\ntypedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name);\ntypedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name);\n#endif\n\n#ifndef GL_APPLE_vertex_array_object\n#define GL_APPLE_vertex_array_object 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint);\nGLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei, const GLuint *);\nGLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei, const GLuint *);\nGLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);\ntypedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);\ntypedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);\ntypedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);\n#endif\n\n#ifndef GL_APPLE_vertex_array_range\n#define GL_APPLE_vertex_array_range 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei, GLvoid *);\nGLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei, GLvoid *);\nGLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum, GLint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param);\n#endif\n\n#ifndef GL_APPLE_ycbcr_422\n#define GL_APPLE_ycbcr_422 1\n#endif\n\n#ifndef GL_S3_s3tc\n#define GL_S3_s3tc 1\n#endif\n\n#ifndef GL_ATI_draw_buffers\n#define GL_ATI_draw_buffers 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawBuffersATI (GLsizei, const GLenum *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs);\n#endif\n\n#ifndef GL_ATI_pixel_format_float\n#define GL_ATI_pixel_format_float 1\n/* This is really a WGL extension, but defines some associated GL enums.\n * ATI does not export \"GL_ATI_pixel_format_float\" in the GL_EXTENSIONS string.\n */\n#endif\n\n#ifndef GL_ATI_texture_env_combine3\n#define GL_ATI_texture_env_combine3 1\n#endif\n\n#ifndef GL_ATI_texture_float\n#define GL_ATI_texture_float 1\n#endif\n\n#ifndef GL_NV_float_buffer\n#define GL_NV_float_buffer 1\n#endif\n\n#ifndef GL_NV_fragment_program\n#define GL_NV_fragment_program 1\n/* Some NV_fragment_program entry points are shared with ARB_vertex_program. */\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint, GLsizei, const GLubyte *, GLfloat, GLfloat, GLfloat, GLfloat);\nGLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint, GLsizei, const GLubyte *, GLdouble, GLdouble, GLdouble, GLdouble);\nGLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint, GLsizei, const GLubyte *, const GLfloat *);\nGLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint, GLsizei, const GLubyte *, const GLdouble *);\nGLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint, GLsizei, const GLubyte *, GLfloat *);\nGLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint, GLsizei, const GLubyte *, GLdouble *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);\n#endif\n\n#ifndef GL_NV_half_float\n#define GL_NV_half_float 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertex2hNV (GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glVertex3hNV (GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glVertex4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glNormal3hNV (GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glColor3hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glColor4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glColor4hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glTexCoord1hNV (GLhalfNV);\nGLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glTexCoord2hNV (GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glTexCoord3hNV (GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glTexCoord4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glMultiTexCoord1hNV (GLenum, GLhalfNV);\nGLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum, const GLhalfNV *);\nGLAPI void APIENTRY glMultiTexCoord2hNV (GLenum, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum, const GLhalfNV *);\nGLAPI void APIENTRY glMultiTexCoord3hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum, const GLhalfNV *);\nGLAPI void APIENTRY glMultiTexCoord4hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum, const GLhalfNV *);\nGLAPI void APIENTRY glFogCoordhNV (GLhalfNV);\nGLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *);\nGLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *);\nGLAPI void APIENTRY glVertexWeighthNV (GLhalfNV);\nGLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *);\nGLAPI void APIENTRY glVertexAttrib1hNV (GLuint, GLhalfNV);\nGLAPI void APIENTRY glVertexAttrib1hvNV (GLuint, const GLhalfNV *);\nGLAPI void APIENTRY glVertexAttrib2hNV (GLuint, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glVertexAttrib2hvNV (GLuint, const GLhalfNV *);\nGLAPI void APIENTRY glVertexAttrib3hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glVertexAttrib3hvNV (GLuint, const GLhalfNV *);\nGLAPI void APIENTRY glVertexAttrib4hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);\nGLAPI void APIENTRY glVertexAttrib4hvNV (GLuint, const GLhalfNV *);\nGLAPI void APIENTRY glVertexAttribs1hvNV (GLuint, GLsizei, const GLhalfNV *);\nGLAPI void APIENTRY glVertexAttribs2hvNV (GLuint, GLsizei, const GLhalfNV *);\nGLAPI void APIENTRY glVertexAttribs3hvNV (GLuint, GLsizei, const GLhalfNV *);\nGLAPI void APIENTRY glVertexAttribs4hvNV (GLuint, GLsizei, const GLhalfNV *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y);\ntypedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z);\ntypedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);\ntypedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);\ntypedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);\ntypedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s);\ntypedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t);\ntypedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r);\ntypedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);\ntypedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);\ntypedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);\n#endif\n\n#ifndef GL_NV_pixel_data_range\n#define GL_NV_pixel_data_range 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPixelDataRangeNV (GLenum, GLsizei, GLvoid *);\nGLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer);\ntypedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);\n#endif\n\n#ifndef GL_NV_primitive_restart\n#define GL_NV_primitive_restart 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPrimitiveRestartNV (void);\nGLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void);\ntypedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index);\n#endif\n\n#ifndef GL_NV_texture_expand_normal\n#define GL_NV_texture_expand_normal 1\n#endif\n\n#ifndef GL_NV_vertex_program2\n#define GL_NV_vertex_program2 1\n#endif\n\n#ifndef GL_ATI_map_object_buffer\n#define GL_ATI_map_object_buffer 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint);\nGLAPI void APIENTRY glUnmapObjectBufferATI (GLuint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer);\n#endif\n\n#ifndef GL_ATI_separate_stencil\n#define GL_ATI_separate_stencil 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glStencilOpSeparateATI (GLenum, GLenum, GLenum, GLenum);\nGLAPI void APIENTRY glStencilFuncSeparateATI (GLenum, GLenum, GLint, GLuint);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);\ntypedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);\n#endif\n\n#ifndef GL_ATI_vertex_attrib_array_object\n#define GL_ATI_vertex_attrib_array_object 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint, GLint, GLenum, GLboolean, GLsizei, GLuint, GLuint);\nGLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint, GLenum, GLfloat *);\nGLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint, GLenum, GLint *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params);\n#endif\n\n#ifndef GL_OES_read_format\n#define GL_OES_read_format 1\n#endif\n\n#ifndef GL_EXT_depth_bounds_test\n#define GL_EXT_depth_bounds_test 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDepthBoundsEXT (GLclampd, GLclampd);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax);\n#endif\n\n#ifndef GL_EXT_texture_mirror_clamp\n#define GL_EXT_texture_mirror_clamp 1\n#endif\n\n#ifndef GL_EXT_blend_equation_separate\n#define GL_EXT_blend_equation_separate 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum, GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha);\n#endif\n\n#ifndef GL_MESA_pack_invert\n#define GL_MESA_pack_invert 1\n#endif\n\n#ifndef GL_MESA_ycbcr_texture\n#define GL_MESA_ycbcr_texture 1\n#endif\n\n#ifndef GL_EXT_pixel_buffer_object\n#define GL_EXT_pixel_buffer_object 1\n#endif\n\n#ifndef GL_NV_fragment_program_option\n#define GL_NV_fragment_program_option 1\n#endif\n\n#ifndef GL_NV_fragment_program2\n#define GL_NV_fragment_program2 1\n#endif\n\n#ifndef GL_NV_vertex_program2_option\n#define GL_NV_vertex_program2_option 1\n#endif\n\n#ifndef GL_NV_vertex_program3\n#define GL_NV_vertex_program3 1\n#endif\n\n#ifndef GL_EXT_framebuffer_object\n#define GL_EXT_framebuffer_object 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint);\nGLAPI void APIENTRY glBindRenderbufferEXT (GLenum, GLuint);\nGLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei, const GLuint *);\nGLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei, GLuint *);\nGLAPI void APIENTRY glRenderbufferStorageEXT (GLenum, GLenum, GLsizei, GLsizei);\nGLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum, GLenum, GLint *);\nGLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint);\nGLAPI void APIENTRY glBindFramebufferEXT (GLenum, GLuint);\nGLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei, const GLuint *);\nGLAPI void APIENTRY glGenFramebuffersEXT (GLsizei, GLuint *);\nGLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum);\nGLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum, GLenum, GLenum, GLuint, GLint);\nGLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum, GLenum, GLenum, GLuint, GLint);\nGLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLint);\nGLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum, GLenum, GLenum, GLuint);\nGLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum, GLenum, GLenum, GLint *);\nGLAPI void APIENTRY glGenerateMipmapEXT (GLenum);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);\ntypedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);\ntypedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);\ntypedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);\ntypedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);\ntypedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);\ntypedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);\n#endif\n\n#ifndef GL_GREMEDY_string_marker\n#define GL_GREMEDY_string_marker 1\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei, const GLvoid *);\n#endif /* GL_GLEXT_PROTOTYPES */\ntypedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string);\n#endif\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "SparCraft/source/glext/wglext.h",
    "content": "#ifndef __wglext_h_\n#define __wglext_h_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n** License Applicability. Except to the extent portions of this file are\n** made subject to an alternative license as permitted in the SGI Free\n** Software License B, Version 1.1 (the \"License\"), the contents of this\n** file are subject only to the provisions of the License. You may not use\n** this file except in compliance with the License. You may obtain a copy\n** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600\n** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:\n** \n** http://oss.sgi.com/projects/FreeB\n** \n** Note that, as provided in the License, the Software is distributed on an\n** \"AS IS\" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS\n** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND\n** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A\n** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.\n** \n** Original Code. The Original Code is: OpenGL Sample Implementation,\n** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,\n** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc.\n** Copyright in any portions created by third parties is as indicated\n** elsewhere herein. All Rights Reserved.\n** \n** Additional Notice Provisions: This software was created using the\n** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has\n** not been independently verified as being compliant with the OpenGL(R)\n** version 1.2.1 Specification.\n*/\n\n#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)\n#define WIN32_LEAN_AND_MEAN 1\n#include <windows.h>\n#endif\n\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\n#ifndef GLAPI\n#define GLAPI extern\n#endif\n\n/*************************************************************/\n\n/* Header file version number */\n/* wglext.h last updated 2005/01/07 */\n/* Current version at http://oss.sgi.com/projects/ogl-sample/registry/ */\n#define WGL_WGLEXT_VERSION 6\n\n#ifndef WGL_ARB_buffer_region\n#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001\n#define WGL_BACK_COLOR_BUFFER_BIT_ARB  0x00000002\n#define WGL_DEPTH_BUFFER_BIT_ARB       0x00000004\n#define WGL_STENCIL_BUFFER_BIT_ARB     0x00000008\n#endif\n\n#ifndef WGL_ARB_multisample\n#define WGL_SAMPLE_BUFFERS_ARB         0x2041\n#define WGL_SAMPLES_ARB                0x2042\n#endif\n\n#ifndef WGL_ARB_extensions_string\n#endif\n\n#ifndef WGL_ARB_pixel_format\n#define WGL_NUMBER_PIXEL_FORMATS_ARB   0x2000\n#define WGL_DRAW_TO_WINDOW_ARB         0x2001\n#define WGL_DRAW_TO_BITMAP_ARB         0x2002\n#define WGL_ACCELERATION_ARB           0x2003\n#define WGL_NEED_PALETTE_ARB           0x2004\n#define WGL_NEED_SYSTEM_PALETTE_ARB    0x2005\n#define WGL_SWAP_LAYER_BUFFERS_ARB     0x2006\n#define WGL_SWAP_METHOD_ARB            0x2007\n#define WGL_NUMBER_OVERLAYS_ARB        0x2008\n#define WGL_NUMBER_UNDERLAYS_ARB       0x2009\n#define WGL_TRANSPARENT_ARB            0x200A\n#define WGL_TRANSPARENT_RED_VALUE_ARB  0x2037\n#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038\n#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039\n#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A\n#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B\n#define WGL_SHARE_DEPTH_ARB            0x200C\n#define WGL_SHARE_STENCIL_ARB          0x200D\n#define WGL_SHARE_ACCUM_ARB            0x200E\n#define WGL_SUPPORT_GDI_ARB            0x200F\n#define WGL_SUPPORT_OPENGL_ARB         0x2010\n#define WGL_DOUBLE_BUFFER_ARB          0x2011\n#define WGL_STEREO_ARB                 0x2012\n#define WGL_PIXEL_TYPE_ARB             0x2013\n#define WGL_COLOR_BITS_ARB             0x2014\n#define WGL_RED_BITS_ARB               0x2015\n#define WGL_RED_SHIFT_ARB              0x2016\n#define WGL_GREEN_BITS_ARB             0x2017\n#define WGL_GREEN_SHIFT_ARB            0x2018\n#define WGL_BLUE_BITS_ARB              0x2019\n#define WGL_BLUE_SHIFT_ARB             0x201A\n#define WGL_ALPHA_BITS_ARB             0x201B\n#define WGL_ALPHA_SHIFT_ARB            0x201C\n#define WGL_ACCUM_BITS_ARB             0x201D\n#define WGL_ACCUM_RED_BITS_ARB         0x201E\n#define WGL_ACCUM_GREEN_BITS_ARB       0x201F\n#define WGL_ACCUM_BLUE_BITS_ARB        0x2020\n#define WGL_ACCUM_ALPHA_BITS_ARB       0x2021\n#define WGL_DEPTH_BITS_ARB             0x2022\n#define WGL_STENCIL_BITS_ARB           0x2023\n#define WGL_AUX_BUFFERS_ARB            0x2024\n#define WGL_NO_ACCELERATION_ARB        0x2025\n#define WGL_GENERIC_ACCELERATION_ARB   0x2026\n#define WGL_FULL_ACCELERATION_ARB      0x2027\n#define WGL_SWAP_EXCHANGE_ARB          0x2028\n#define WGL_SWAP_COPY_ARB              0x2029\n#define WGL_SWAP_UNDEFINED_ARB         0x202A\n#define WGL_TYPE_RGBA_ARB              0x202B\n#define WGL_TYPE_COLORINDEX_ARB        0x202C\n#endif\n\n#ifndef WGL_ARB_make_current_read\n#define ERROR_INVALID_PIXEL_TYPE_ARB   0x2043\n#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054\n#endif\n\n#ifndef WGL_ARB_pbuffer\n#define WGL_DRAW_TO_PBUFFER_ARB        0x202D\n#define WGL_MAX_PBUFFER_PIXELS_ARB     0x202E\n#define WGL_MAX_PBUFFER_WIDTH_ARB      0x202F\n#define WGL_MAX_PBUFFER_HEIGHT_ARB     0x2030\n#define WGL_PBUFFER_LARGEST_ARB        0x2033\n#define WGL_PBUFFER_WIDTH_ARB          0x2034\n#define WGL_PBUFFER_HEIGHT_ARB         0x2035\n#define WGL_PBUFFER_LOST_ARB           0x2036\n#endif\n\n#ifndef WGL_ARB_render_texture\n#define WGL_BIND_TO_TEXTURE_RGB_ARB    0x2070\n#define WGL_BIND_TO_TEXTURE_RGBA_ARB   0x2071\n#define WGL_TEXTURE_FORMAT_ARB         0x2072\n#define WGL_TEXTURE_TARGET_ARB         0x2073\n#define WGL_MIPMAP_TEXTURE_ARB         0x2074\n#define WGL_TEXTURE_RGB_ARB            0x2075\n#define WGL_TEXTURE_RGBA_ARB           0x2076\n#define WGL_NO_TEXTURE_ARB             0x2077\n#define WGL_TEXTURE_CUBE_MAP_ARB       0x2078\n#define WGL_TEXTURE_1D_ARB             0x2079\n#define WGL_TEXTURE_2D_ARB             0x207A\n#define WGL_MIPMAP_LEVEL_ARB           0x207B\n#define WGL_CUBE_MAP_FACE_ARB          0x207C\n#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D\n#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E\n#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F\n#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080\n#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081\n#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082\n#define WGL_FRONT_LEFT_ARB             0x2083\n#define WGL_FRONT_RIGHT_ARB            0x2084\n#define WGL_BACK_LEFT_ARB              0x2085\n#define WGL_BACK_RIGHT_ARB             0x2086\n#define WGL_AUX0_ARB                   0x2087\n#define WGL_AUX1_ARB                   0x2088\n#define WGL_AUX2_ARB                   0x2089\n#define WGL_AUX3_ARB                   0x208A\n#define WGL_AUX4_ARB                   0x208B\n#define WGL_AUX5_ARB                   0x208C\n#define WGL_AUX6_ARB                   0x208D\n#define WGL_AUX7_ARB                   0x208E\n#define WGL_AUX8_ARB                   0x208F\n#define WGL_AUX9_ARB                   0x2090\n#endif\n\n#ifndef WGL_ARB_pixel_format_float\n#define WGL_TYPE_RGBA_FLOAT_ARB        0x21A0\n#endif\n\n#ifndef WGL_EXT_make_current_read\n#define ERROR_INVALID_PIXEL_TYPE_EXT   0x2043\n#endif\n\n#ifndef WGL_EXT_pixel_format\n#define WGL_NUMBER_PIXEL_FORMATS_EXT   0x2000\n#define WGL_DRAW_TO_WINDOW_EXT         0x2001\n#define WGL_DRAW_TO_BITMAP_EXT         0x2002\n#define WGL_ACCELERATION_EXT           0x2003\n#define WGL_NEED_PALETTE_EXT           0x2004\n#define WGL_NEED_SYSTEM_PALETTE_EXT    0x2005\n#define WGL_SWAP_LAYER_BUFFERS_EXT     0x2006\n#define WGL_SWAP_METHOD_EXT            0x2007\n#define WGL_NUMBER_OVERLAYS_EXT        0x2008\n#define WGL_NUMBER_UNDERLAYS_EXT       0x2009\n#define WGL_TRANSPARENT_EXT            0x200A\n#define WGL_TRANSPARENT_VALUE_EXT      0x200B\n#define WGL_SHARE_DEPTH_EXT            0x200C\n#define WGL_SHARE_STENCIL_EXT          0x200D\n#define WGL_SHARE_ACCUM_EXT            0x200E\n#define WGL_SUPPORT_GDI_EXT            0x200F\n#define WGL_SUPPORT_OPENGL_EXT         0x2010\n#define WGL_DOUBLE_BUFFER_EXT          0x2011\n#define WGL_STEREO_EXT                 0x2012\n#define WGL_PIXEL_TYPE_EXT             0x2013\n#define WGL_COLOR_BITS_EXT             0x2014\n#define WGL_RED_BITS_EXT               0x2015\n#define WGL_RED_SHIFT_EXT              0x2016\n#define WGL_GREEN_BITS_EXT             0x2017\n#define WGL_GREEN_SHIFT_EXT            0x2018\n#define WGL_BLUE_BITS_EXT              0x2019\n#define WGL_BLUE_SHIFT_EXT             0x201A\n#define WGL_ALPHA_BITS_EXT             0x201B\n#define WGL_ALPHA_SHIFT_EXT            0x201C\n#define WGL_ACCUM_BITS_EXT             0x201D\n#define WGL_ACCUM_RED_BITS_EXT         0x201E\n#define WGL_ACCUM_GREEN_BITS_EXT       0x201F\n#define WGL_ACCUM_BLUE_BITS_EXT        0x2020\n#define WGL_ACCUM_ALPHA_BITS_EXT       0x2021\n#define WGL_DEPTH_BITS_EXT             0x2022\n#define WGL_STENCIL_BITS_EXT           0x2023\n#define WGL_AUX_BUFFERS_EXT            0x2024\n#define WGL_NO_ACCELERATION_EXT        0x2025\n#define WGL_GENERIC_ACCELERATION_EXT   0x2026\n#define WGL_FULL_ACCELERATION_EXT      0x2027\n#define WGL_SWAP_EXCHANGE_EXT          0x2028\n#define WGL_SWAP_COPY_EXT              0x2029\n#define WGL_SWAP_UNDEFINED_EXT         0x202A\n#define WGL_TYPE_RGBA_EXT              0x202B\n#define WGL_TYPE_COLORINDEX_EXT        0x202C\n#endif\n\n#ifndef WGL_EXT_pbuffer\n#define WGL_DRAW_TO_PBUFFER_EXT        0x202D\n#define WGL_MAX_PBUFFER_PIXELS_EXT     0x202E\n#define WGL_MAX_PBUFFER_WIDTH_EXT      0x202F\n#define WGL_MAX_PBUFFER_HEIGHT_EXT     0x2030\n#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT  0x2031\n#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032\n#define WGL_PBUFFER_LARGEST_EXT        0x2033\n#define WGL_PBUFFER_WIDTH_EXT          0x2034\n#define WGL_PBUFFER_HEIGHT_EXT         0x2035\n#endif\n\n#ifndef WGL_EXT_depth_float\n#define WGL_DEPTH_FLOAT_EXT            0x2040\n#endif\n\n#ifndef WGL_3DFX_multisample\n#define WGL_SAMPLE_BUFFERS_3DFX        0x2060\n#define WGL_SAMPLES_3DFX               0x2061\n#endif\n\n#ifndef WGL_EXT_multisample\n#define WGL_SAMPLE_BUFFERS_EXT         0x2041\n#define WGL_SAMPLES_EXT                0x2042\n#endif\n\n#ifndef WGL_I3D_digital_video_control\n#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050\n#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051\n#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052\n#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053\n#endif\n\n#ifndef WGL_I3D_gamma\n#define WGL_GAMMA_TABLE_SIZE_I3D       0x204E\n#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D  0x204F\n#endif\n\n#ifndef WGL_I3D_genlock\n#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044\n#define WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D 0x2045\n#define WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D 0x2046\n#define WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D 0x2047\n#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048\n#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049\n#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A\n#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B\n#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C\n#endif\n\n#ifndef WGL_I3D_image_buffer\n#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001\n#define WGL_IMAGE_BUFFER_LOCK_I3D      0x00000002\n#endif\n\n#ifndef WGL_I3D_swap_frame_lock\n#endif\n\n#ifndef WGL_NV_render_depth_texture\n#define WGL_BIND_TO_TEXTURE_DEPTH_NV   0x20A3\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4\n#define WGL_DEPTH_TEXTURE_FORMAT_NV    0x20A5\n#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6\n#define WGL_DEPTH_COMPONENT_NV         0x20A7\n#endif\n\n#ifndef WGL_NV_render_texture_rectangle\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1\n#define WGL_TEXTURE_RECTANGLE_NV       0x20A2\n#endif\n\n#ifndef WGL_ATI_pixel_format_float\n#define WGL_TYPE_RGBA_FLOAT_ATI        0x21A0\n#endif\n\n#ifndef WGL_NV_float_buffer\n#define WGL_FLOAT_COMPONENTS_NV        0x20B0\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4\n#define WGL_TEXTURE_FLOAT_R_NV         0x20B5\n#define WGL_TEXTURE_FLOAT_RG_NV        0x20B6\n#define WGL_TEXTURE_FLOAT_RGB_NV       0x20B7\n#define WGL_TEXTURE_FLOAT_RGBA_NV      0x20B8\n#endif\n\n\n/*************************************************************/\n\n#ifndef WGL_ARB_pbuffer\nDECLARE_HANDLE(HPBUFFERARB);\n#endif\n#ifndef WGL_EXT_pbuffer\nDECLARE_HANDLE(HPBUFFEREXT);\n#endif\n\n#ifndef WGL_ARB_buffer_region\n#define WGL_ARB_buffer_region 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern HANDLE WINAPI wglCreateBufferRegionARB (HDC, int, UINT);\nextern VOID WINAPI wglDeleteBufferRegionARB (HANDLE);\nextern BOOL WINAPI wglSaveBufferRegionARB (HANDLE, int, int, int, int);\nextern BOOL WINAPI wglRestoreBufferRegionARB (HANDLE, int, int, int, int, int, int);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType);\ntypedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion);\ntypedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height);\ntypedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc);\n#endif\n\n#ifndef WGL_ARB_multisample\n#define WGL_ARB_multisample 1\n#endif\n\n#ifndef WGL_ARB_extensions_string\n#define WGL_ARB_extensions_string 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern const char * WINAPI wglGetExtensionsStringARB (HDC);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);\n#endif\n\n#ifndef WGL_ARB_pixel_format\n#define WGL_ARB_pixel_format 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglGetPixelFormatAttribivARB (HDC, int, int, UINT, const int *, int *);\nextern BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC, int, int, UINT, const int *, FLOAT *);\nextern BOOL WINAPI wglChoosePixelFormatARB (HDC, const int *, const FLOAT *, UINT, int *, UINT *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);\ntypedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);\ntypedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);\n#endif\n\n#ifndef WGL_ARB_make_current_read\n#define WGL_ARB_make_current_read 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglMakeContextCurrentARB (HDC, HDC, HGLRC);\nextern HDC WINAPI wglGetCurrentReadDCARB (void);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);\ntypedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void);\n#endif\n\n#ifndef WGL_ARB_pbuffer\n#define WGL_ARB_pbuffer 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern HPBUFFERARB WINAPI wglCreatePbufferARB (HDC, int, int, int, const int *);\nextern HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB);\nextern int WINAPI wglReleasePbufferDCARB (HPBUFFERARB, HDC);\nextern BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB);\nextern BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB, int, int *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);\ntypedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer);\ntypedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC);\ntypedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer);\ntypedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue);\n#endif\n\n#ifndef WGL_ARB_render_texture\n#define WGL_ARB_render_texture 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglBindTexImageARB (HPBUFFERARB, int);\nextern BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB, int);\nextern BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB, const int *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);\ntypedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);\ntypedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList);\n#endif\n\n#ifndef WGL_ARB_pixel_format_float\n#define WGL_ARB_pixel_format_float 1\n#endif\n\n#ifndef WGL_EXT_display_color_table\n#define WGL_EXT_display_color_table 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort);\nextern GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *, GLuint);\nextern GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort);\nextern VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id);\ntypedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length);\ntypedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id);\ntypedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id);\n#endif\n\n#ifndef WGL_EXT_extensions_string\n#define WGL_EXT_extensions_string 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern const char * WINAPI wglGetExtensionsStringEXT (void);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void);\n#endif\n\n#ifndef WGL_EXT_make_current_read\n#define WGL_EXT_make_current_read 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglMakeContextCurrentEXT (HDC, HDC, HGLRC);\nextern HDC WINAPI wglGetCurrentReadDCEXT (void);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);\ntypedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void);\n#endif\n\n#ifndef WGL_EXT_pbuffer\n#define WGL_EXT_pbuffer 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC, int, int, int, const int *);\nextern HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT);\nextern int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT, HDC);\nextern BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT);\nextern BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT, int, int *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);\ntypedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer);\ntypedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC);\ntypedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer);\ntypedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue);\n#endif\n\n#ifndef WGL_EXT_pixel_format\n#define WGL_EXT_pixel_format 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC, int, int, UINT, int *, int *);\nextern BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC, int, int, UINT, int *, FLOAT *);\nextern BOOL WINAPI wglChoosePixelFormatEXT (HDC, const int *, const FLOAT *, UINT, int *, UINT *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues);\ntypedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues);\ntypedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);\n#endif\n\n#ifndef WGL_EXT_swap_control\n#define WGL_EXT_swap_control 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglSwapIntervalEXT (int);\nextern int WINAPI wglGetSwapIntervalEXT (void);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);\ntypedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);\n#endif\n\n#ifndef WGL_EXT_depth_float\n#define WGL_EXT_depth_float 1\n#endif\n\n#ifndef WGL_NV_vertex_array_range\n#define WGL_NV_vertex_array_range 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern void* WINAPI wglAllocateMemoryNV (GLsizei, GLfloat, GLfloat, GLfloat);\nextern void WINAPI wglFreeMemoryNV (void *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef void* (WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);\ntypedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer);\n#endif\n\n#ifndef WGL_3DFX_multisample\n#define WGL_3DFX_multisample 1\n#endif\n\n#ifndef WGL_EXT_multisample\n#define WGL_EXT_multisample 1\n#endif\n\n#ifndef WGL_OML_sync_control\n#define WGL_OML_sync_control 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglGetSyncValuesOML (HDC, INT64 *, INT64 *, INT64 *);\nextern BOOL WINAPI wglGetMscRateOML (HDC, INT32 *, INT32 *);\nextern INT64 WINAPI wglSwapBuffersMscOML (HDC, INT64, INT64, INT64);\nextern INT64 WINAPI wglSwapLayerBuffersMscOML (HDC, int, INT64, INT64, INT64);\nextern BOOL WINAPI wglWaitForMscOML (HDC, INT64, INT64, INT64, INT64 *, INT64 *, INT64 *);\nextern BOOL WINAPI wglWaitForSbcOML (HDC, INT64, INT64 *, INT64 *, INT64 *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);\ntypedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator);\ntypedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);\ntypedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);\ntypedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);\ntypedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);\n#endif\n\n#ifndef WGL_I3D_digital_video_control\n#define WGL_I3D_digital_video_control 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC, int, int *);\nextern BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC, int, const int *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);\ntypedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);\n#endif\n\n#ifndef WGL_I3D_gamma\n#define WGL_I3D_gamma 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglGetGammaTableParametersI3D (HDC, int, int *);\nextern BOOL WINAPI wglSetGammaTableParametersI3D (HDC, int, const int *);\nextern BOOL WINAPI wglGetGammaTableI3D (HDC, int, USHORT *, USHORT *, USHORT *);\nextern BOOL WINAPI wglSetGammaTableI3D (HDC, int, const USHORT *, const USHORT *, const USHORT *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);\ntypedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);\ntypedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue);\ntypedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue);\n#endif\n\n#ifndef WGL_I3D_genlock\n#define WGL_I3D_genlock 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglEnableGenlockI3D (HDC);\nextern BOOL WINAPI wglDisableGenlockI3D (HDC);\nextern BOOL WINAPI wglIsEnabledGenlockI3D (HDC, BOOL *);\nextern BOOL WINAPI wglGenlockSourceI3D (HDC, UINT);\nextern BOOL WINAPI wglGetGenlockSourceI3D (HDC, UINT *);\nextern BOOL WINAPI wglGenlockSourceEdgeI3D (HDC, UINT);\nextern BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC, UINT *);\nextern BOOL WINAPI wglGenlockSampleRateI3D (HDC, UINT);\nextern BOOL WINAPI wglGetGenlockSampleRateI3D (HDC, UINT *);\nextern BOOL WINAPI wglGenlockSourceDelayI3D (HDC, UINT);\nextern BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC, UINT *);\nextern BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC, UINT *, UINT *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC);\ntypedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC);\ntypedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag);\ntypedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource);\ntypedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource);\ntypedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge);\ntypedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge);\ntypedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate);\ntypedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate);\ntypedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay);\ntypedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay);\ntypedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay);\n#endif\n\n#ifndef WGL_I3D_image_buffer\n#define WGL_I3D_image_buffer 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern LPVOID WINAPI wglCreateImageBufferI3D (HDC, DWORD, UINT);\nextern BOOL WINAPI wglDestroyImageBufferI3D (HDC, LPVOID);\nextern BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC, const HANDLE *, const LPVOID *, const DWORD *, UINT);\nextern BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC, const LPVOID *, UINT);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags);\ntypedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress);\ntypedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count);\ntypedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count);\n#endif\n\n#ifndef WGL_I3D_swap_frame_lock\n#define WGL_I3D_swap_frame_lock 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglEnableFrameLockI3D (void);\nextern BOOL WINAPI wglDisableFrameLockI3D (void);\nextern BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *);\nextern BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void);\ntypedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void);\ntypedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag);\ntypedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag);\n#endif\n\n#ifndef WGL_I3D_swap_frame_usage\n#define WGL_I3D_swap_frame_usage 1\n#ifdef WGL_WGLEXT_PROTOTYPES\nextern BOOL WINAPI wglGetFrameUsageI3D (float *);\nextern BOOL WINAPI wglBeginFrameTrackingI3D (void);\nextern BOOL WINAPI wglEndFrameTrackingI3D (void);\nextern BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *, DWORD *, float *);\n#endif /* WGL_WGLEXT_PROTOTYPES */\ntypedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage);\ntypedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void);\ntypedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void);\ntypedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage);\n#endif\n\n#ifndef WGL_ATI_pixel_format_float\n#define WGL_ATI_pixel_format_float 1\n#endif\n\n#ifndef WGL_NV_float_buffer\n#define WGL_NV_float_buffer 1\n#endif\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "SparCraft/source/glfont2/glfont.cc",
    "content": "//*********************************************************\n//GLFONT.CPP -- glFont routines\n//Copyright (c) 1998 Brad Fish\n//Copyright (c) 2002 Henri Kyrki\n//See glFont.txt for terms of use\n//10.5 2002\n//*********************************************************\n\n#include \"glfont.h\"\n\n#ifdef USING_VISUALIZATION_LIBRARIES\n\n//*********************************************************\n//GLFontBase\n//*********************************************************\n\nGLFontBase::GLFontBase() : ok(FALSE)\n{\n}\n\nvoid GLFontBase::CreateImpl(const std::string &Filename, GLuint Tex, bool PixelPerfect)\n{\n\tFont.Char = NULL;\n\tFreeResources();\n\tFILE *Input;\n\n\t//Open font file\n\tif ((Input = fopen(Filename.c_str(), \"rb\")) == NULL)\n    {\n        printf(\"Can't open font\\n\");\n\t\tthrow GLFontError::InvalidFile();\n    }\n\t//Read glFont structure\n\tsize_t rr = fread(&Font, sizeof(GLFONT), 1, Input);\n\n\t//Save texture number\n\tFont.Tex = Tex;\n\n\t//Get number of characters\n\tint Num = Font.IntEnd - Font.IntStart + 1;\n\n\t//Allocate memory for characters\n\t//if ((Font.Char = (GLFONTCHAR *)malloc(sizeof(GLFONTCHAR) * Num)) == NULL)\n\tFont.Char = new GLFONTCHAR[Num];\n\n\t//Read glFont characters\n\trr = fread(Font.Char, sizeof(GLFONTCHAR), Num, Input);\n\n\t//Get texture size\n\tNum = Font.TexWidth * Font.TexHeight * 2;\n\n\t//Allocate memory for texture data\n\t//TexBytes = (char *)malloc(Num)\n\tchar *TexBytes = new char[Num];\n\n\t//Read texture data\n\trr = fread(TexBytes, sizeof(char), Num, Input);\n\n\t//Set texture attributes\n\tglBindTexture(GL_TEXTURE_2D, Font.Tex);\n\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);\n\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);\n\tif(PixelPerfect)\n\t{\n\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n\t}\n\telse\n\t{\n\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\t}\n\tglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\n\n\t//Create texture\n\tglTexImage2D(GL_TEXTURE_2D, 0, 2, Font.TexWidth, Font.TexHeight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (void *)TexBytes);\n\n\t//Clean up\n\n\tdelete []TexBytes;\n\tfclose(Input);\n\n\tok = TRUE;\n}\n//*********************************************************\nvoid GLFontBase::FreeResources ()\n{\n\t//Free character memory\n\tif (Font.Char != NULL) delete []Font.Char;\n\tok = FALSE;\n}\n//*********************************************************\nvoid GLFontBase::Begin ()\n{\n\tif (!ok)\n\t{\n\t\tthrow GLFontError::InvalidFont();\n\t}\n\n\tglBindTexture(GL_TEXTURE_2D, Font.Tex);\n}\n//*********************************************************\nGLFontBase::~GLFontBase ()\n{\n\tFreeResources();\n}\n\n//*********************************************************\n//PixelPerfectGLFont\n//*********************************************************\n\nPixelPerfectGLFont::PixelPerfectGLFont()\n{\n}\n//*********************************************************\nvoid PixelPerfectGLFont::Create(const std::string &Filename, GLuint Tex)\n{\n\tGLFontBase::CreateImpl(Filename, Tex, TRUE);\n\tfor (int i = 0; i < Font.IntEnd - Font.IntStart + 1; i++)\n\t{\n\t\tFont.Char[i].width = (int)((Font.Char[i].tx2 - Font.Char[i].tx1)*Font.TexWidth);\n\t\tFont.Char[i].height = (int)((Font.Char[i].ty2 - Font.Char[i].ty1)*Font.TexHeight);\n\t}\n}\n//*********************************************************\nvoid PixelPerfectGLFont::TextOut (std::string String, int x, int y, int z)\n{\n\t//Return if we don't have a valid glFont\n\tif (!ok)\n\t{\n\t\tthrow GLFontError::InvalidFont();\n\t}\n\n\t//Get length of string\n\tint Length = String.length();\n\n\t//Begin rendering quads\n\tglBegin(GL_QUADS);\n\n\t//Loop through characters\n\tfor (int i = 0; i < Length; i++)\n\t{\n\t\t//Get pointer to glFont character\n\t\tGLFONTCHAR *Char = &Font.Char[(int)String[i] - Font.IntStart];\n\n\t\t//Specify vertices and texture coordinates\n\t\tglTexCoord2f(Char->tx1, Char->ty1);\n\t\tglVertex3i(x, y, z);\n\t\tglTexCoord2f(Char->tx1, Char->ty2);\n\t\tglVertex3i(x, y + Char->height, z);\n\t\tglTexCoord2f(Char->tx2, Char->ty2);\n\t\tglVertex3i(x + Char->width, y + Char->height, z);\n\t\tglTexCoord2f(Char->tx2, Char->ty1);\n\t\tglVertex3i(x + Char->width, y, z);\n\n\t\t//Move to next character\n\t\tx += Char->width;\n\t}\n\n\t//Stop rendering quads\n\tglEnd();\n}\n\n//*********************************************************\n//GLFont\n//*********************************************************\n\nGLFont::GLFont()\n{\n}\n//*********************************************************\nvoid GLFont::Create(const std::string &Filename, GLuint Tex)\n{\n\tGLFontBase::CreateImpl(Filename, Tex, FALSE);\n}\n//*********************************************************\nvoid GLFont::TextOut (std::string String, float x, float y, float z)\n{\n\t//Return if we don't have a valid glFont\n\tif (!ok)\n\t{\n\t\tthrow GLFontError::InvalidFont();\n\t}\n\n\t//Get length of string\n\tint Length = String.length();\n\n\t//Begin rendering quads\n\tglBegin(GL_QUADS);\n\n\t//Loop through characters\n\tfor (int i = 0; i < Length; i++)\n\t{\n\t\t//Get pointer to glFont character\n\t\tGLFONTCHAR *Char = &Font.Char[(int)String[i] - Font.IntStart];\n\n\t\t//Specify vertices and texture coordinates\n\t\tglTexCoord2f(Char->tx1, Char->ty1);\n\t\tglVertex3f(x, y, z);\n\t\tglTexCoord2f(Char->tx1, Char->ty2);\n\t\tglVertex3f(x, y + Char->dy, z);\n\t\tglTexCoord2f(Char->tx2, Char->ty2);\n\t\tglVertex3f(x + Char->dx, y + Char->dy, z);\n\t\tglTexCoord2f(Char->tx2, Char->ty1);\n\t\tglVertex3f(x + Char->dx, y, z);\n\n\t\t//Move to next character\n\t\tx += Char->dx;\n\t}\n\n\t//Stop rendering quads\n\tglEnd();\n}\n\n//End of file\n\n#endif\n\n"
  },
  {
    "path": "SparCraft/source/glfont2/glfont.h",
    "content": "#include \"../Common.h\"\n\n#ifdef USING_VISUALIZATION_LIBRARIES\n\n#pragma once\n\n//*********************************************************\n//GLFONT.H -- Header for GLFONT.CPP\n//Copyright (c) 1998 Brad Fish\n//Copyright (c) 2002 Henri Kyrki\n//See glFont.txt for terms of use\n//10.5 2002\n//*********************************************************\n\n#ifndef TRUE\n#define TRUE\t1\n#endif\n\n#ifndef FALSE\n#define FALSE\t0\n#endif\n\n#include <string>\n#include <SDL.h>\n#include <SDL_opengl.h>\n#include <GL/gl.h>\n\nnamespace GLFontError {\n\tstruct InvalidFile{};\n\tstruct InvalidFont{};\n}\n\nclass GLFontBase {\npublic:\n\tGLFontBase();\n\tvoid Begin();\n\tvirtual ~GLFontBase();\nprotected:\n\n\tvoid CreateImpl(const std::string &FileName, GLuint Tex, bool PixelPerfect = FALSE);\n\n\ttypedef struct\n\t{\n\tunion {\n\t\tfloat dx;\n\t\tint width;\n\t};\n\tunion {\n\t\tfloat dy;\n\t\tint height;\n\t};\n\tfloat tx1, ty1;\n\tfloat tx2, ty2;\n\t} GLFONTCHAR;\n\n\ttypedef struct\n\t{\n\tint Tex;\n\tint TexWidth, TexHeight;\n\tint IntStart, IntEnd;\n\tGLFONTCHAR *Char;\n\t} GLFONT;\n\n\tGLFONT Font;\n\tbool ok;\nprivate:\n\tvoid FreeResources();\n};\n\nclass GLFont : public GLFontBase {\npublic:\n\tGLFont();\n\tvoid Create(const std::string &FileName, GLuint Tex);\n\tvoid TextOut (std::string String, float x, float y, float z);\n};\n\nclass PixelPerfectGLFont : public GLFontBase {\npublic:\n\tPixelPerfectGLFont();\n\tvoid Create(const std::string &FileName, GLuint Tex);\n\tvoid TextOut (std::string String, int x, int y, int z);\n};\n\n#endif\n"
  },
  {
    "path": "SparCraft/source/gui/GUI.cpp",
    "content": "#include \"GUI.h\"\n#include \"BWAPI.h\"\n#include <cassert>\n#include <iostream>\n\nusing namespace SparCraft;\n\nconst size_t MaxStarCraftTextures                   = 512;\nconst int GUI::TextureFont                 = 256;\n\nGLfloat ColorWhite[4] = {1.0f, 1.0f, 1.0f, 1.0f};\n\nGUI::GUI(int width, int height) \n    : _initialWidth(width)\n    , _initialHeight(height)\n    , _cameraX(0)\n    , _cameraY(0)\n    , _previousMouseX(0)\n    , _previousMouseY(0)\n    , _isStarted(false)\n    , _mousePressed(false)\n    , _shiftPressed(false)\n    , _currentFrame(0)\n    , _previousRenderTime(0)\n    , _guiGame(*this)\n{\n    if (SDL_Init(SDL_INIT_VIDEO) != 0)\n    {\n        std::cout << \"Could not initialize SDL\\n\";\n        exit(-1);\n    }\n\n    onStart();\n}\n\nGUI::~GUI()\n{\n    SDL_Quit();\n}\n\nbool GUI::isStarted() const\n{\n    return _isStarted;\n}\n\n// This function must be called before OnFrame\nvoid GUI::onStart()\n{\n    // if we've already called OnStart, don't re-initialize everything\n    if (_isStarted)\n    {\n        return;\n    }\n\n    // the top-left corner of the scene will be 0, 0\n    _cameraX = 0;\n    _cameraY = 0;\n\n    // double buffer and swap attributes, makes switching scenes fast\n    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);\n    SDL_GL_SetSwapInterval(1);\n\n    // set up the window that the OpenGL context will be bound to\n    _window = SDL_CreateWindow(\"StarCraft OpenGL Visualization\", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _initialWidth, _initialHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);\n\n    // set the glcontext to the window we just created\n    _glcontext = SDL_GL_CreateContext(_window);\n\n    // load all the Starcraft textures that we'll need\n    loadTextures();\n\n    // enable alpha blending for transparency\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glEnable(GL_BLEND);\n\n    // set up the viewport\n    glViewport(0, 0, width(), height());\n\n    _isStarted = true;\n}\n\nvoid GUI::onFrame()\n{\n    SPARCRAFT_ASSERT(isStarted(), \"Must initialize GUI before calling OnFrame()\");\n\n    // Handle input events\n    handleEvents();\n\n    // Render the frame\n    glClear(GL_COLOR_BUFFER_BIT);\n    render();\n\n    SDL_GL_SwapWindow(_window);\n}\n\nvoid GUI::handleEvents()\n{\n    // Handle SDL events\n    SDL_Event event;\n    while (SDL_PollEvent(&event))\n    {\n        const bool pressed(event.key.state == SDL_PRESSED);\n        switch (event.type)\n        {\n            case SDL_MOUSEMOTION:\n            {\n                if ((_previousMouseX != 0 || _previousMouseY != 0) && (event.motion.state & SDL_BUTTON_LEFT))\n                {\n                    _cameraX -= event.motion.xrel;\n                    _cameraY -= event.motion.yrel;\n                }\n\n                _previousMouseX = event.motion.x;\n                _previousMouseY = event.motion.y;\n                break;\n            }\n            case SDL_KEYDOWN:\n            {\n                switch (event.key.keysym.sym)\n                {\n                case SDLK_LSHIFT:\n                    _shiftPressed = pressed;\n                    break;\n                case SDLK_p:\n                {\n                    \n                }\n                }\n                break;\n            }\n            case SDL_KEYUP:\n            {\n                switch (event.key.keysym.sym)\n                {\n                case SDLK_LSHIFT:\n                    _shiftPressed = pressed;\n                    break;\n                }\n                break;\n            }\n            case SDL_MOUSEWHEEL:\n            {\n\n                break;\n            }\n            case SDL_MOUSEBUTTONDOWN:\n            {\n\n\t\t\t\n                break;\n            }\n            case SDL_MOUSEBUTTONUP:\n            {\n                if (event.button.button == SDL_BUTTON_LEFT)\n                {\n\n                }\n                break;\n            }\n            case SDL_WINDOWEVENT_RESIZED:\n            {\n            \n                break;\n            }\n            case SDL_QUIT:\n            {\n                std::cerr << \"SDL_QUIT caught\\n\\n\";\n                exit(0);\n            }\n        }\n    }\n}\n\nvoid GUI::render()\n{\n    Timer renderTimer;\n    renderTimer.start();\n\n    glViewport(0, 0, width(), height());\n\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    {\n        glOrtho(0, width(), height(), 0, -1, 1);\n\n        glMatrixMode(GL_MODELVIEW);\n        glPushMatrix();\n        {\n            glTranslatef(static_cast<float>(-_cameraX),static_cast<float>(-_cameraY),0);\n              \n            _guiGame.onFrame();\n\n            //drawAllBWAPIUnits();\n            \n            //GUITools::DrawTexturedRect(Position(0,0), Position(200,200), TextureFont, ColorWhite);\n            //GUITools::DrawString(Position(300, 300), \"Test String\", ColorWhite);\n        }\n\n        glPopMatrix();\n    }\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n\n    _currentFrame++;\n}\n\nint GUI::width()\n{\n    int x, y;\n    SDL_GetWindowSize(_window, &x, &y);\n\n    return x;\n}\n\nint GUI::height()\n{\n    int x, y;\n    SDL_GetWindowSize(_window, &x, &y);\n\n    return y;\n}\n\nvoid GUI::setCenter(int x, int y)\n{\n    _cameraX = -(width() - x) / 2;\n    _cameraY = -(height() - y) / 2;\n}\n\nvoid GUI::drawAllBWAPIUnits()\n{\n    Position p(0, 0);\n    size_t maxHeight = 0;\n\n    std::vector<int> allIDs;\n\n    for (const auto & kv : _techTypeTextureID)\n    {\n        allIDs.push_back(kv.second);\n    }\n\n    for (const auto & kv : _upgradeTypeTextureID)\n    {\n        allIDs.push_back(kv.second);\n    }\n\n    for (const auto & kv : _unitTypeTextureID)\n    {\n        allIDs.push_back(kv.second);\n    }\n\n    for (const auto & id : allIDs)\n    {\n        if (p.x() + _textureSizes[id].x() > width())\n        {\n            p = Position(0, p.y() + maxHeight);\n            maxHeight = 0;\n        }\n\n        GUITools::DrawTexturedRect(p, p + _textureSizes[id], id, ColorWhite);\n            \n        maxHeight = std::max((size_t)_textureSizes[id].y(), maxHeight);\n            \n        p = p + (Position(_textureSizes[id].x(), 0));\n    }\n}\n\nvoid GUI::drawUnitType(const BWAPI::UnitType & type, const Position & p)\n{\n    const int id = _unitTypeTextureID[type];\n    //GUITools::DrawString(p, type.getName(), ColorWhite);\n    Position pos = p - Position(_textureSizes[id].x()/2, _textureSizes[id].y()/2);\n\n    GUITools::DrawTexturedRect(pos, pos + _textureSizes[id], id, ColorWhite);\n}\n\nvoid GUI::loadTextures()\n{\n    std::string imageDir = \"../asset/images/\";\n\n    // set up the vectors that will hold the textures\n    _textures = std::vector<GLuint>(MaxStarCraftTextures, 0);\n    _textureSizes = std::vector<Position>(MaxStarCraftTextures);\n    glGenTextures(MaxStarCraftTextures, &_textures[0]);\n\n    // load all the starcraft unit textures\n    size_t textureNumber = 1;\n    for (const BWAPI::UnitType & type : BWAPI::UnitTypes::allUnitTypes())\n    {\n        if (loadTexture(textureNumber, imageDir + GetTextureFileName(type)))\n        {\n            _unitTypeTextureID[type] = textureNumber;\n            textureNumber++;\n        }\n    }\n\n    for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes())\n    {\n        if (loadTexture(textureNumber, imageDir + GetTextureFileName(type)))\n        {\n            _techTypeTextureID[type] = textureNumber;\n            textureNumber++;\n        }\n    }\n\n    for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes())\n    {\n        if (loadTexture(textureNumber, imageDir + GetTextureFileName(type)))\n        {\n            _upgradeTypeTextureID[type] = textureNumber;\n            textureNumber++;\n        }\n    }\n    \n    loadTexture(TextureFont, imageDir + \"fonts/alpha_trans.png\");\n\n    std::cout << \"\\n\\nSuccessfully loaded \" << textureNumber << \" textures\\n\\n\";\n}\n\nbool GUI::loadTexture(int textureNumber, const std::string & fileName)\n{\n    struct stat buf;\n    if (stat(fileName.c_str(), &buf) == -1)\n    {\n        //std::cout << \"Couldn't find texture: \" << fileName << std::endl;\n        return false;\n    }\n\n    SDL_Surface *surface2 = IMG_Load(fileName.c_str());\n    GLenum texture_format = GL_RGBA;\n    GLint nOfColors = 4;\n\n    if (surface2 != NULL)\n    {\n        glBindTexture( GL_TEXTURE_2D, textureNumber );\n\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n        glTexImage2D(GL_TEXTURE_2D, 0, texture_format, surface2->w, surface2->h, 0, texture_format, GL_UNSIGNED_BYTE, surface2->pixels);\n    } \n    else \n    {\n        printf(\"SDL could not load image: %s\\n\", SDL_GetError());\n    }    \n\n    if (surface2) \n    { \n        _textureSizes[textureNumber] = Position(surface2->w, surface2->h);\n        SDL_FreeSurface( surface2 );\n    }\n\n    //std::cout << textureNumber << \"Loaded: \" << fileName << std::endl;\n\n    return true;\n}\n\nbool GUI::saveScreenshotBMP(const std::string & filename) \n{\n    SDL_Surface * image = SDL_CreateRGBSurface(SDL_SWSURFACE, width(), height(), 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);\n\n    glReadBuffer(GL_FRONT);\n    glReadPixels(0, 0, width(), height(), GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);\n\n    SDL_SaveBMP(image, filename.c_str());\n    SDL_FreeSurface(image);\n\n    return true;\n}\n\nstd::string GUI::GetTextureFileName(const BWAPI::TechType & type)\n{\n\tstd::string filename = \"command_icons/\" + type.getName() + \".png\";\n\n\tfor (size_t i(0); i < filename.size(); ++i)\n\t{\n\t\tif (filename[i] == ' ')\n\t\t{\n\t\t\tfilename[i] = '_';\n\t\t}\n\t}\n\n\treturn filename;\n}\n\nstd::string GUI::GetTextureFileName(const BWAPI::UnitType & type)\n{\n\tstd::string filename = \"units/\" + type.getName() + \".png\";\n\n\tfor (size_t i(0); i < filename.size(); ++i)\n\t{\n\t\tif (filename[i] == ' ')\n\t\t{\n\t\t\tfilename[i] = '_';\n\t\t}\n\t}\n\n\treturn filename;\n}\n\nstd::string GUI::GetTextureFileName(const BWAPI::UpgradeType & type)\n{\n\tstd::string filename = \"command_icons/\" + type.getName() + \".png\";\n\n\tfor (size_t i(0); i < filename.size(); ++i)\n\t{\n\t\tif (filename[i] == ' ')\n\t\t{\n\t\t\tfilename[i] = '_';\n\t\t}\n\t}\n\n\treturn filename;\n}\n\nvoid GUI::setGame(const Game & game)\n{\n    _guiGame.setGame(game);\n}\n\nconst Game & GUI::getGame() const\n{\n    return _guiGame.getGame();\n}\n"
  },
  {
    "path": "SparCraft/source/gui/GUI.h",
    "content": "#pragma once\n\n#include \"../SparCraft.h\"\n#include \"../Timer.h\"\n#include \"../Position.hpp\"\n#include \"BWAPI.h\"\n#include \"GUITools.h\"\n#include \"GUIGame.h\"\n#include <vector>\n\n#include <SDL.h>\n#undef main\n\n#include <SDL_opengl.h>\n#include <SDL_image.h>\n#include \"GUITools.h\"\n#include <sys/stat.h>\n\nnamespace SparCraft\n{\n\nclass GUI\n{\n    int                 _initialWidth;\n    int                 _initialHeight;\n    int                 _windowSizeY;\n    int                 _cameraX;\n    int                 _cameraY;\n    bool                _isStarted;\n    int                 _previousMouseX;\n    int                 _previousMouseY;\n    bool                _mousePressed;\n    bool                _shiftPressed;\n    double              _previousRenderTime;\n\n    size_t              _currentFrame;\n\n    SDL_Window *        _window;\n    SDL_Surface *       _surface;\n    SDL_GLContext       _glcontext;\n\n    GUIGame             _guiGame;\n\n    std::vector<GLuint>     _textures;\n    std::vector<Position>   _textureSizes;\n\n    std::map<BWAPI::UnitType, int> _unitTypeTextureID;\n    std::map<BWAPI::TechType, int> _techTypeTextureID;\n    std::map<BWAPI::UpgradeType, int> _upgradeTypeTextureID;\n    \n    void handleEvents();\n    void render();\n    void renderTextGlut(int x, int y, std::string & s);\n    void loadTextures();\n    bool loadTexture(int textureNumber, const std::string & fileName);\n    void onResize(SDL_Event & event);\n    void drawAllBWAPIUnits();\n    void onStart();\n    void testRender();\n    \n    bool isStarted() const;\n\n    static std::string GetTextureFileName(const BWAPI::UnitType & type);\n    static std::string GetTextureFileName(const BWAPI::UpgradeType & type);\n    static std::string GetTextureFileName(const BWAPI::TechType & type);\n\npublic:\n    \n    static const int TextureASCIIOffset;\n    static const int TextureFont;\n    \n    GUI(int width, int height);\n    ~GUI();\n\n    int width();\n    int height();\n\n    void onFrame();\n    void setCenter(int x, int y);\n    void setGame(const Game & game);\n    void drawUnitType(const BWAPI::UnitType & type, const Position & p);\n\n    const Game & getGame() const;\n\n    bool saveScreenshotBMP(const std::string & filename);\n};\n}\n"
  },
  {
    "path": "SparCraft/source/gui/GUIGame.cpp",
    "content": "#include \"GUIGame.h\"\n#include \"GUITools.h\"\n#include \"GUI.h\"\n\nusing namespace SparCraft;\n\nGLfloat White[4] = {1.0f, 1.0f, 1.0f, 1.0f};\n\nGLfloat PlayerColors[2][4] = {{1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 0.0f, 1.0f}};\nGLfloat PlayerColorsDark[2][4] = {{0.7f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.7f, 0.0f, 1.0f}};\n\nGUIGame::GUIGame(GUI & gui)\n    : _game(GameState(), 0)\n    , _gui(gui)\n{\n\n}\n\nvoid GUIGame::onFrame()\n{\n    drawGame();\n    drawHPBars();\n\n    Timer turnTimer;\n    turnTimer.start();\n    if (!_game.gameOver())\n    {\n        _game.playNextTurn();\n        _previousTurnTimer =  turnTimer.getElapsedTimeInMilliSec();\n\n        for (size_t p(0); p < 2; ++p)\n        {\n            Player_UCT *        uct = dynamic_cast<Player_UCT *>        (_game.getPlayer(p).get());\n            Player_AlphaBeta *  ab  = dynamic_cast<Player_AlphaBeta *>  (_game.getPlayer(p).get());\n\n            if (uct) \n            { \n                setParams(p, uct->getParams().getDescription());\n                setResults(p, uct->getResults().getDescription());\n            }\n\n            if (ab) \n            { \n                setParams(p, ab->getParams().getDescription()); \n                setResults(p, ab->results().getDescription());\n            }\n        }\n    }\n\n    drawParameters(5, 15);\n    drawSearchResults(5, 150);\n    drawInfo();\n}\n\nvoid GUIGame::drawInfo()\n{\n    std::stringstream ss;\n    ss << \"Frame Draw Time: \" << _previousDrawGameTimer << \"ms\\n\\n\";\n    ss << \"Turn Time: \" << _previousTurnTimer << \"ms\";\n\n    GUITools::DrawString(Position(5, _gui.height()-20), ss.str(), White);\n}\n\nvoid GUIGame::drawGame()\n{\n    Timer drawGameTimer;\n    drawGameTimer.start();\n\n    const GameState & state = _game.getState();\n\n    for (size_t p(0); p < 2; ++p)\n    {\n        for (size_t u(0); u < state.numUnits(p); u++)\n        {\n            drawUnit(state.getUnit(p, u));\n        }\n    }\n\n    _previousDrawGameTimer = drawGameTimer.getElapsedTimeInMilliSec();\n}\n\nvoid GUIGame::drawHPBars()\n{\n    const GameState & state = _game.getState();\n\n    for (IDType p(0); p<Constants::Num_Players; ++p)\n    {\n        for (IDType u(0); u<_initialState.numUnits(p); ++u)\n        {\n            int barHeight = 12;\n\n            const Unit &\t\t\tunit(state.getUnitDirect(p,u));\n\n            const Position\t\t\tpos(1000+170*p,40+barHeight*u);\n            const BWAPI::UnitType\ttype(unit.type());\n\n            const int\t\t\t\tx0(pos.x());\n            const int\t\t\t\tx1(pos.x() + 150);\n            const int\t\t\t\ty0(pos.y());\n            const int\t\t\t\ty1(pos.y() + 15);\n\n            // draw the unit HP box\n            double\tpercHP = (double)unit.currentHP() / (double)unit.maxHP();\n            int\t\tw = 150;\n            int\t\th = barHeight;\n            int\t\tcw = (int)(w * percHP);\n            int\t\txx = pos.x() - w/2;\n            int\t\tyy = pos.y() - h - (y1-y0)/2;\n\n            if (unit.isAlive())\n            {\n                GUITools::DrawRectGradient(Position(xx,yy),Position(xx+cw,yy+h),PlayerColors[p], PlayerColorsDark[p]);\n            }\n\n            //if (unit.ID() < 255)\n            //{\n            //\tglEnable( GL_TEXTURE_2D );\n            //\t\tglBindTexture( GL_TEXTURE_2D, unit.type().getID() );\n\n            //\t\t// draw the unit to the screen\n            //\t\tglColor4f(1, 1, 1, 1);\n            //\t\tglBegin( GL_QUADS );\n            //\t\t\tglTexCoord3d(0.0,0.0,.5); glVertex2i(xx, yy);\n            //\t\t\tglTexCoord3d(0.0,1.0,.5); glVertex2i(xx, yy+h);\n            //\t\t\tglTexCoord3d(1.0,1.0,.5); glVertex2i(xx+h,yy+h);\n            //\t\t\tglTexCoord3d(1.0,0.0,.5); glVertex2i(xx+h, yy);\n            //\t\tglEnd();\n            //\tglDisable( GL_TEXTURE_2D );\n            //}\n        }\n    }\n}\n\nvoid GUIGame::drawParameters(int x, int y)\n{\n    int size = 11;\n    int spacing = 3;\n    int colwidth = 175;\n    int playerspacing = 350;\n\n    for (size_t pp(0); pp < 2; ++pp)\n    {\n        GUITools::DrawString(Position(x+pp*playerspacing, y), \"Player 1 Settings\", PlayerColors[pp]);\n\n        for (size_t p(0); _params[pp].size() > 0 && p<_params[pp][0].size(); ++p)\n        {\n            GUITools::DrawString(Position(x+pp*playerspacing, y+((p+1)*(size+spacing))), _params[pp][0][p], White);\n            GUITools::DrawString(Position(x+pp*playerspacing+colwidth, y+((p+1)*(size+spacing))), _params[pp][1][p], White);\n        }\n    }\n\n    //// Player 1 Settings\n    //if (_params[0].size() > 0)\n    //{\n    //    GUITools::DrawString(Position(x, y), \"Player 1 Settings\", PlayerColors[0]);\n\n    //    for (size_t p(0); _params[0].size() > 0 && p<_params[0][0].size(); ++p)\n    //    {\n    //        GUITools::DrawString(Position(x, y+((p+1)*(size+spacing))), _params[0][0][p], White);\n    //        GUITools::DrawString(Position(x+colwidth, y+((p+1)*(size+spacing))), _params[0][1][p], White);\n    //    }\n    //}\n\n    //if (_params[1].size() > 0)\n    //{\n    //    // Player 2 Settings\n    //    x += playerspacing;\n    //    glColor3f(0.0, 1.0, 0.0);\n    //    DrawText(x, y , size, \"Player 2 Settings\");\n    //    glColor3f(1.0, 1.0, 1.0);\n\n    //    for (size_t p(0); params[1].size() > 0 && p<params[1][0].size(); ++p)\n    //    {\n    //        DrawText(x, y+((p+1)*(size+spacing)), size, params[1][0][p]);\n    //        DrawText(x+colwidth, y+((p+1)*(size+spacing)), size, params[1][1][p]);\n    //    }\n    //}\n}\n\nvoid GUIGame::drawSearchResults(int x, int y)\n{\n\tint size = 11;\n    int spacing = 3;\n    int colwidth = 175;\n    int playerspacing = 350;\n\n    for (size_t pp(0); pp < 2; ++pp)\n    {\n        GUITools::DrawString(Position(x+pp*playerspacing, y), \"Player 1 Search Results\", PlayerColors[pp]);\n\n        for (size_t p(0); _results[pp].size() > 0 && p<_results[pp][0].size(); ++p)\n        {\n            GUITools::DrawString(Position(x+pp*playerspacing, y+((p+1)*(size+spacing))), _results[pp][0][p], White);\n            GUITools::DrawString(Position(x+pp*playerspacing+colwidth, y+((p+1)*(size+spacing))), _results[pp][1][p], White);\n        }\n    }\n}\n\nvoid GUIGame::drawUnit(const Unit & unit)\n{\n    if (!unit.isAlive())\n    {\n        return;\n    }\n    \n    const int healthBoxHeight = 4;\n\n    const GameState & state = _game.getState();\n    const BWAPI::UnitType & type = unit.type();\n    const Position pos(unit.currentPosition(state.getTime()));\n\n    _gui.drawUnitType(unit.type(), pos);\n\n    const int x0(pos.x() - type.dimensionUp());\n\tconst int x1(pos.x() + type.dimensionDown());\n\tconst int y0(pos.y() - type.dimensionUp());\n\tconst int y1(pos.y() + type.dimensionDown());\n\n    double\tpercHP = (double)unit.currentHP() / (double)unit.maxHP();\n\tint\t\tcw = (int)((x1-x0) * percHP);\n\tint\t\txx = pos.x() - (x1-x0)/2;\n\tint\t\tyy = pos.y() - healthBoxHeight - (y1-y0)/2 - 5;\n\n    GUITools::DrawRect(Position(xx, yy), Position(xx+cw, yy+healthBoxHeight), PlayerColors[unit.player()]);\n\n    const Action & action = unit.previousAction();\n            \n\tif (action.type() == ActionTypes::MOVE)\n\t{\n\t\tglColor4f(1, 1, 1, 0.75);\n\t\tglBegin(GL_LINES);\n\t\t\tglVertex2i(pos.x(), pos.y());\n\t\t\tglVertex2i(unit.pos().x(), unit.pos().y());\n\t\tglEnd( );\n\t}\n\telse if (action.type() == ActionTypes::ATTACK)\n\t{\n\t\tconst Unit &\ttarget(state.getUnit(state.getEnemy(unit.player()), action.index()));\n\t\tconst Position\ttargetPos(target.currentPosition(state.getTime()));\n\n        GUITools::DrawLine(pos, targetPos, 1, PlayerColors[unit.player()]);\n\t}\n}\n\nvoid GUIGame::setGame(const Game & g)\n{\n    _game = g;\n    _initialState = g.getState();\n}\n\nconst Game & GUIGame::getGame() const\n{\n    return _game;\n}\n\nvoid GUIGame::setResults(const IDType & player, const std::vector<std::vector<std::string> > & r)\n{\n\t_results[player] = r;\n}\n\nvoid GUIGame::setParams(const IDType & player, const std::vector<std::vector<std::string> > & p)\n{\n\t_params[player] = p;\n}"
  },
  {
    "path": "SparCraft/source/gui/GUIGame.h",
    "content": "#pragma once\n\n#include \"../SparCraft.h\"\n\nnamespace SparCraft\n{\n\nclass GUI;\nclass GUIGame\n{\n\tGUI &           _gui;\n    Game            _game;\n    double          _previousDrawGameTimer;\n    double          _previousTurnTimer;\n    GameState       _initialState;\n\n    std::vector<std::vector<std::string> > _params[2];\n    std::vector<std::vector<std::string> > _results[2];\n    std::vector<std::vector<std::string> > _exp;\n\n    void drawGame();\n    void drawInfo();\n    void drawHPBars();\n    void drawUnit(const Unit & unit);\n    void drawParameters(int x, int y);\n    void drawSearchResults(int x, int y);\n\n    void setResults(const IDType & player, const std::vector<std::vector<std::string> > & r);\n    void setParams(const IDType & player, const std::vector<std::vector<std::string> > & p);\n\npublic:\n\n    GUIGame(GUI & gui);\n\n    const Game & getGame() const;\n    void setGame(const Game & g);\n    void onFrame();\n};\n\n}\n"
  },
  {
    "path": "SparCraft/source/gui/GUITools.cpp",
    "content": "#include \"GUITools.h\"\n#include \"GUI.h\"\n\nnamespace SparCraft\n{\nnamespace GUITools\n{\n    void DrawString(const Position & p, const std::string & text, const GLfloat * rgba) \n    {\n        Position origin(p);\n        Position fontSize(8,8);\n\n        int linePos = 0;\n        for (size_t i(0); i < text.length(); ++i)\n        {\n            if (text[i] == '\\n') \n            { \n                origin = Position(p.x(), origin.y() + fontSize.y()); \n                linePos = 0;\n            }\n            else\n            {\n                Position charStart = Position(origin.x() + linePos*fontSize.x(), origin.y() - fontSize.y());\n                Position charEnd = charStart + fontSize;\n\n                DrawChar(charStart, charEnd, text[i], rgba);\n                    \n                linePos++;    \n            }\n        }\n    }\n\n    const size_t FontTextureSize = 128;\n    const size_t CharSize = 8;\n    const float CharDelta = 1.0f / 16.0f;\n    void DrawChar(const Position & tl, const Position & br, char ch, const GLfloat * rgba) \n    {\n        float xPos = ((ch % 16) / 16.0f);\n        float yPos = (ch >> 4) / 16.0f;\n        \n        glPushMatrix();\n            glEnable( GL_TEXTURE_2D );\n                glColor4fv(rgba);\n                glBindTexture( GL_TEXTURE_2D, GUI::TextureFont );\n                glBegin( GL_QUADS );\n                    glTexCoord2f(xPos,yPos);                        glVertex2i(tl.x(), tl.y());\n                    glTexCoord2f(xPos+CharDelta,yPos);              glVertex2i(br.x(), tl.y());\n                    glTexCoord2f(xPos+CharDelta,yPos+CharDelta);    glVertex2i(br.x(), br.y());\n                    glTexCoord2f(xPos,yPos+CharDelta);              glVertex2i(tl.x(), br.y());\n                glEnd();\n            glDisable( GL_TEXTURE_2D );\n        glPopMatrix();\n    }\n\n    void DrawLine(const Position & p1, const Position & p2, const float thickness, const GLfloat * rgba)\n    {\n        glPushMatrix();\n            glLineWidth(thickness); \n            glColor4fv(rgba);\n            glBegin(GL_LINES);\n                glVertex2i(p1.x(),p1.y());\n                glVertex2i(p2.x(),p2.y());\n            glEnd();\n        glPopMatrix();\n    }\n\n    void DrawCircle(const Position & pos, float r, int num_segments) \n    { \n        float theta = 2 * (float)3.1415926 / float(num_segments); \n        float c = cosf(theta);//precalculate the sine and cosine\n        float s = sinf(theta);\n        float t;\n\n        float x = r;//we start at angle = 0 \n        float y = 0; \n\n        glBegin(GL_LINE_LOOP); \n            for(int ii = 0; ii < num_segments; ii++) \n            { \n                glVertex2f(x + pos.x(), y + pos.y());//output vertex \n\n                //apply the rotation matrix\n                t = x;\n                x = c * x - s * y;\n                y = s * t + c * y;\n            } \n        glEnd(); \n    }\n\n    void DrawRect(const Position & tl, const Position & br, const GLfloat * rgba)\n    {\n        glPushMatrix();\n            glColor4fv(rgba);\n            glBegin(GL_QUADS);\n                glVertex2i(tl.x(),tl.y());\n                glVertex2i(br.x(),tl.y());\n                glVertex2i(br.x(),br.y());\n                glVertex2i(tl.x(),br.y());\n            glEnd();\n        glPopMatrix();\n    }\n\n    void DrawRectGradient(const Position & tl, const Position & br, const GLfloat * rgbaLeft, const GLfloat * rgbaRight)\n    {\n        glPushMatrix();\n            glBegin(GL_QUADS);\n                glColor4fv(rgbaLeft);  glVertex2i(tl.x(),tl.y());\n                glColor4fv(rgbaRight); glVertex2i(br.x(),tl.y());\n                glColor4fv(rgbaRight); glVertex2i(br.x(),br.y());\n                glColor4fv(rgbaLeft);  glVertex2i(tl.x(),br.y());\n            glEnd();\n        glPopMatrix();\n    }\n  \n    void DrawTexturedRect(const Position & tl, const Position & br, const int & textureID, const GLfloat * rgba)\n    {\n        glPushMatrix();\n            glEnable( GL_TEXTURE_2D );\n                glColor4fv(rgba);\n                glBindTexture( GL_TEXTURE_2D, textureID );\n                glBegin( GL_QUADS );\n                    glTexCoord2f(0.0,0.0); glVertex2i(tl.x(),tl.y());\n                    glTexCoord2f(1.0,0.0); glVertex2i(br.x(),tl.y());\n                    glTexCoord2f(1.0,1.0); glVertex2i(br.x(),br.y());\n                    glTexCoord2f(0.0,1.0); glVertex2i(tl.x(),br.y());\n                glEnd();\n            glDisable( GL_TEXTURE_2D );\n        glPopMatrix();\n    }\n\n    void DrawIconAndText(const Position & tl, const Position & br, const int & textureID, const int & textureID2, const GLfloat * rgba)\n    {\n        GLfloat white[4] = {1.0f, 1.0f, 1.0f, 1.0f};\n        Position iconSize = br - tl;\n        Position statusNumPos = tl + Position(-iconSize.scale(0.15f).x(), iconSize.scale(0.4f).y());\n        GUITools::DrawTexturedRect(tl, br, textureID, rgba);\n        GUITools::DrawTexturedRect(statusNumPos, statusNumPos + iconSize.scale(0.65f), textureID2, rgba); \n    }\n\n    \n}\n}\n"
  },
  {
    "path": "SparCraft/source/gui/GUITools.h",
    "content": "#pragma once\n\n#include \"../SparCraft.h\"\n#include <SDL.h>\n#include <SDL_opengl.h>\n\nnamespace SparCraft\n{\n    namespace GUITools\n    {\n        const int FLIP_VERTICAL = 1;\n        const int FLIP_HORIZONTAL = 2;\n\n        void DrawLine(const Position & p1, const Position & p2, const float thickness, const GLfloat * rgba);\n        void DrawString(const Position & p, const std::string & text, const GLfloat * rgba);\n        void DrawChar(const Position & tl, const Position & br, char ch, const GLfloat * rgba);\n        void DrawCircle(const Position & p, float r, int num_segments);\n        void DrawTexturedRect(const Position & tl, const Position & br, const int & textureID, const GLfloat * rgba); \n        void DrawRect(const Position & tl, const Position & br, const GLfloat * rgba); \n        void DrawRectGradient(const Position & tl, const Position & br, const GLfloat * rgbaLeft, const GLfloat * rgbaRight); \n        void SetColor(const GLfloat * src, GLfloat * dest);\n        void SetColor(const GLfloat * src, GLfloat * dest);\n    }\n}\n"
  },
  {
    "path": "SparCraft/source/main/SearchExperiment.cpp",
    "content": "#include \"SearchExperiment.h\"\n\nusing namespace SparCraft;\n\nSearchExperiment::SearchExperiment(const std::string & configFile)\n    : map(NULL)\n    , showDisplay(false)\n    , appendTimeStamp(true)\n\t, rand(0, std::numeric_limits<int>::max(), 0)\n{\n    configFileSmall = getBaseFilename(configFile);\n    map = new Map(40, 22);\n    setCurrentDateTime();\n    parseConfigFile(configFile);\n    writeConfig(configFile);\n    setupResults();\n}\n\nSearchExperiment::~SearchExperiment()\n{\n    if (map)\n    {\n        delete map;\n    }\n}\n\nvoid SearchExperiment::setupResults()\n{\n    size_t np1 = players[0].size();\n    size_t np2 = players[1].size();\n\n    resultsStateNumber  = ivvv(np1, ivv(np2, iv()));\n\tresultsNumUnits     = ivvv(np1, ivv(np2, iv()));\n\tresultsEval         = ivvv(np1, ivv(np2, iv()));\n\tresultsRounds       = ivvv(np1, ivv(np2, iv()));\n\tresultsTime         = dvvv(np1, dvv(np2, dv()));\n    numGames            = ivv(np1, iv(np2, 0));\n    numWins             = ivv(np1, iv(np2, 0));\n    numLosses           = ivv(np1, iv(np2, 0));\n    numDraws            = ivv(np1, iv(np2, 0));\n}\n\nvoid SearchExperiment::writeConfig(const std::string & configfile)\n{\n    std::ofstream config(getConfigOutFileName().c_str());\n    if (!config.is_open())\n    {\n        System::FatalError(\"Problem Opening Output File: Config\");\n    }\n\n    std::vector<std::string> lines(getLines(configfile));\n\n    for (size_t l(0); l<lines.size(); ++l)\n    {\n        config << lines[l] << std::endl;\n    }\n\n    config.close();\n}\n\nvoid SearchExperiment::writeResultsSummary()\n{\n\tstd::ofstream results(getResultsSummaryFileName().c_str());\n    if (!results.is_open())\n    {\n        System::FatalError(\"Problem Opening Output File: Results Summary\");\n    }\n\n\tfor (size_t p1(0); p1 < players[0].size(); ++p1)\n\t{\n        for (size_t p2(0); p2 < players[1].size(); ++p2)\n\t    {\n            double score = 0;\n            if (numGames[p1][p2] > 0)\n            {\n                score = ((double)numWins[p1][p2] / (double)(numGames[p1][p2])) + 0.5*((double)numDraws[p1][p2] / (double)numGames[p1][p2]);\n            }\n\n            results << std::setiosflags(std::ios::fixed) << std::setw(12) << std::setprecision(7) << score << \" \";\n        }\n\n        results << std::endl;\n\t}\n\n    results.close();\n}\n\nvoid SearchExperiment::padString(std::string & str, const size_t & length)\n{\n    while (str.length() < length)\n    {\n        str = str + \" \";\n    }\n}\n\nstd::string SearchExperiment::getResultsSummaryFileName()\n{\n    std::string res = resultsFile;\n    \n    if (appendTimeStamp)\n    {\n        res += \"_\" + getDateTimeString();\n    }\n\n    res += \"_results_summary.txt\";\n    return res;\n}\n\nstd::string SearchExperiment::getResultsOutFileName()\n{\n    std::string res = resultsFile;\n    \n    if (appendTimeStamp)\n    {\n        res += \"_\" + getDateTimeString();\n    }\n\n    res += \"_results_raw.txt\";\n    return res;\n}\n\nstd::string SearchExperiment::getConfigOutFileName()\n{\n    std::string conf = resultsFile;\n    \n    if (appendTimeStamp)\n    {\n        conf += \"_\" + getDateTimeString();\n    }\n\n    conf += \"_config.txt\";\n    return conf;\n}\n\nstd::string SearchExperiment::getDateTimeString()\n{\n    return timeString;\n}\n\nvoid SearchExperiment::setCurrentDateTime() \n{\n    time_t     now = time(0);\n    struct tm  tstruct;\n    char       buf[80];\n    \n    std::fill(buf, buf+80, '0');\n    tstruct = *localtime(&now);\n    strftime(buf, sizeof(buf), \"%Y-%m-%d_%X\", &tstruct);\n    //strftime(buf, sizeof(buf), \"%X\", &tstruct);\n\n    // need to replace ':' for windows filenames\n    for (int i(0); i<80; i++)\n    {\n        if (buf[i] == ':')\n        {\n            buf[i] = '-';\n        }\n    }\n\n    timeString = std::string(buf);\n}\n\nstd::vector<std::string> SearchExperiment::getLines(const std::string & filename)\n{\n    // set up the file\n    std::ifstream fin(filename.c_str());\n    if (!fin.is_open())\n    {\n         System::FatalError(\"Problem Opening File: \" + filename);\n    }\n\n\tstd::string line;\n\n    std::vector<std::string> lines;\n\n    // each line of the file will be a new player to add\n    while (fin.good())\n    {\n        // get the line and set up the string stream\n        getline(fin, line);\n       \n        // skip blank lines and comments\n        if (line.length() > 1 && line[0] != '#')\n        {\n            lines.push_back(line);\n        }\n    }\n\n\tfin.close();\n\n    return lines;\n}\n\nvoid SearchExperiment::parseConfigFile(const std::string & filename)\n{\n    std::vector<std::string> lines(getLines(filename));\n\n    for (size_t l(0); l<lines.size(); ++l)\n    {\n        std::istringstream iss(lines[l]);\n        std::string option;\n        iss >> option;\n\n        if (strcmp(option.c_str(), \"Player\") == 0)\n        {\n            addPlayer(lines[l]);\n        }\n        else if (strcmp(option.c_str(), \"State\") == 0)\n        {\n            addState(lines[l]);\n        }\n        else if (strcmp(option.c_str(), \"MapFile\") == 0)\n        {\n            std::string fileString;\n            iss >> fileString;\n            map = new Map;\n            map->load(fileString);\n        }\n        else if (strcmp(option.c_str(), \"Display\") == 0)\n        {\n            std::string option;\n            iss >> option;\n            iss >> imageDir;\n            if (strcmp(option.c_str(), \"true\") == 0)\n            {\n                showDisplay = true;\n            }\n        }\n        else if (strcmp(option.c_str(), \"ResultsFile\") == 0)\n        {\n            std::string fileString;\n            std::string append;\n            iss >> fileString;\n            iss >> append;\n            resultsFile = fileString;\n\n            appendTimeStamp = strcmp(append.c_str(), \"true\") == 0 ? true : false;\n        }\n        else if (strcmp(option.c_str(), \"PlayerUpgrade\") == 0)\n        {\n            int playerID(0);\n            std::string upgradeName;\n            int upgradeLevel(0);\n\n            iss >> playerID;\n            iss >> upgradeName;\n            iss >> upgradeLevel;\n\n            for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes())\n            {\n                if (type.getName().compare(upgradeName) == 0)\n                {\n                    PlayerProperties::Get(playerID).SetUpgradeLevel(type, upgradeLevel);\n                    break;\n                }\n            }\n        }\n        else if (strcmp(option.c_str(), \"PlayerTech\") == 0)\n        {\n            int playerID(0);\n            std::string techName;\n\n            iss >> playerID;\n            iss >> techName;\n\n            for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes())\n            {\n                if (type.getName().compare(techName) == 0)\n                {\n                    PlayerProperties::Get(playerID).SetResearched(type, true);\n                    break;\n                }\n            }\n        }\n        else\n        {\n            System::FatalError(\"Invalid Option in Configuration File: \" + option);\n        }\n    }\n}\n\nvoid SearchExperiment::addState(const std::string & line)\n{\n    std::istringstream iss(line);\n\n    // the first number is the playerID\n    std::string state;\n    std::string stateType;\n    int numStates;\n    \n    iss >> state;\n    iss >> stateType;\n    iss >> numStates;\n\n    if (strcmp(stateType.c_str(), \"StateSymmetric\") == 0)\n    { \n        int xLimit, yLimit;\n        iss >> xLimit;\n        iss >> yLimit;\n\n        std::vector<std::string> unitVec;\n        std::vector<int> numUnitVec;\n        std::string unitType;\n        int numUnits;\n\n        while (iss >> unitType)\n        {\n            iss >> numUnits;\n            unitVec.push_back(unitType);\n            numUnitVec.push_back(numUnits);\n        }\n\n        //std::cout << \"\\nAdding \" << numStates <<  \" Symmetric State(s)\\n\\n\";\n\n        for (int s(0); s<numStates; ++s)\n        {\n            states.push_back(getSymmetricState(unitVec, numUnitVec, xLimit, yLimit));\n        }\n    }\n    else if (strcmp(stateType.c_str(), \"StateRawDataFile\") == 0)\n    {\n        std::string filename;\n        iss >> filename;\n\n        for (int i(0); i<numStates; ++i)\n        {\n            states.push_back(GameState(filename));\n        }\n    }\n    else if (strcmp(stateType.c_str(), \"StateDescriptionFile\") == 0)\n    {\n        std::string filename;\n        iss >> filename;\n        \n        for (int i(0); i<numStates; ++i)\n        {\n            parseStateDescriptionFile(filename);\n        }\n    }\n    else if (strcmp(stateType.c_str(), \"SeparatedState\") == 0)\n    {\n        int xLimit, yLimit;\n        int cx1, cy1, cx2, cy2;\n        iss >> xLimit;\n        iss >> yLimit;\n        iss >> cx1;\n        iss >> cy1;\n        iss >> cx2;\n        iss >> cy2;\n\n        std::vector<std::string> unitVec;\n        std::vector<int> numUnitVec;\n        std::string unitType;\n        int numUnits;\n\n        while (iss >> unitType)\n        {\n            iss >> numUnits;\n            unitVec.push_back(unitType);\n            numUnitVec.push_back(numUnits);\n        }\n\n        //std::cout << \"\\nAdding \" << numStates <<  \" Symmetric State(s)\\n\\n\";\n\n        for (int s(0); s<numStates/2; ++s)\n        {\n            addSeparatedState(unitVec, numUnitVec, cx1, cy1, cx2, cy2, xLimit, yLimit);\n        }\n    }\n    else\n    {\n        System::FatalError(\"Invalid State Type in Configuration File: \" + stateType);\n    }  \n}\n\nvoid SearchExperiment::parseStateDescriptionFile(const std::string & fileName)\n{\n    std::vector<std::string> lines = getLines(fileName);\n    \n    GameState currentState;\n\n    for (size_t u(0); u<lines.size(); ++u)\n    {\n        std::stringstream iss(lines[u]);\n        std::string unitType;\n        int playerID(0);\n        int x(0);\n        int y(0);\n\n        iss >> unitType;\n        iss >> playerID;\n        iss >> x;\n        iss >> y;\n\n        currentState.addUnit(getUnitType(unitType), (IDType)playerID, Position(x, y));\n    }\n\n    states.push_back(currentState);\n}\n\nBWAPI::UnitType SearchExperiment::getUnitType(const std::string & unitTypeString)\n{\n    BWAPI::UnitType type;\n\n    for (const BWAPI::UnitType & t : BWAPI::UnitTypes::allUnitTypes())\n    {\n        if (t.getName().compare(unitTypeString) == 0)\n        {\n            type = t;\n        }\n    }\n\n    System::checkSupportedUnitType(type);\n\n    return type;\n}\n\nvoid SearchExperiment::addGameState(const GameState & state)\n{\n    if (states.size() >= 10000)\n    {\n        System::FatalError(\"Search Experiment cannot contain more than 10,000 states.\");\n    }\n}\n\nvoid SearchExperiment::addPlayer(const std::string & line)\n{\n    std::istringstream iss(line);\n\n    // Regular expressions for line validation (if I ever want to use them)\n    //std::regex ScriptRegex(\"[a-zA-Z]+[ ]+[0-1][ ]+[a-zA-Z]+[ ]*\");\n    //std::regex AlphaBetaRegex(\"[a-zA-Z]+[ ]+[0-1][ ]+[a-zA-Z]+[ ]+[0-9]+[ ]+[0-9]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]*\");\n    //std::regex UCTRegex(\"[a-zA-Z]+[ ]+[0-1][ ]+[a-zA-Z]+[ ]+[0-9]+[ ]+[0-9.]+[ ]+[0-9]+[ ]+[0-9]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]*\");\n    //std::regex PortfolioRegex(\"[a-zA-Z]+[ ]+[0-1][ ]+[a-zA-Z]+[ ]+[0-9]+[ ]+[a-zA-Z]+[ ]+[0-9]+[ ][0-9]+[ ]*\");\n\n    // the first number is the playerID\n\n    std::string player;\n    int playerID;\n    int playerModelID;\n    std::string playerModelString;\n    \n    iss >> player;\n    iss >> playerID;\n    iss >> playerModelString;\n\n    playerStrings[playerID].push_back(playerModelString);\n\n    playerModelID = PlayerModels::getID(playerModelString);\n\n    //std::cout << \"Player \" << playerID << \" adding type \" << playerModelString << \" (\" << playerModelID << \")\" << std::endl;\n\n   \tif (playerModelID == PlayerModels::AttackClosest)\t\t\n    { \n        players[playerID].push_back(PlayerPtr(new Player_AttackClosest(playerID))); \n    }\n\telse if (playerModelID == PlayerModels::AttackDPS)\n    { \n        players[playerID].push_back(PlayerPtr(new Player_AttackDPS(playerID))); \n    }\n\telse if (playerModelID == PlayerModels::AttackWeakest)\t\t\n    { \n        players[playerID].push_back(PlayerPtr(new Player_AttackWeakest(playerID))); \n    }\n\telse if (playerModelID == PlayerModels::Kiter)\t\t\t\t\n    { \n        players[playerID].push_back(PlayerPtr(new Player_Kiter(playerID))); \n    }\n\telse if (playerModelID == PlayerModels::KiterDPS)\t\t\t\n    { \n        players[playerID].push_back(PlayerPtr(new Player_KiterDPS(playerID))); \n    }\n    else if (playerModelID == PlayerModels::Kiter_NOKDPS)\t\t\t\n    { \n        players[playerID].push_back(PlayerPtr(new Player_Kiter_NOKDPS(playerID))); \n    }\n    else if (playerModelID == PlayerModels::Cluster)\t\t\t\n    { \n        players[playerID].push_back(PlayerPtr(new Player_Cluster(playerID))); \n    }\n\telse if (playerModelID == PlayerModels::NOKDPS)\t\n    { \n        players[playerID].push_back(PlayerPtr(new Player_NOKDPS(playerID))); \n    }\n\telse if (playerModelID == PlayerModels::Random)\t\t\t\t\n    { \n        players[playerID].push_back(PlayerPtr(new Player_Random(playerID))); \n    }\n    else if (playerModelID == PlayerModels::PortfolioGreedySearch)\t\t\t\t\n    { \n        std::string enemyPlayerModel;\n        size_t timeLimit(0);\n        int iterations(1);\n        int responses(0);\n\n        iss >> timeLimit;\n        iss >> enemyPlayerModel;\n        iss >> iterations;\n        iss >> responses;\n\n        players[playerID].push_back(PlayerPtr(new Player_PortfolioGreedySearch(playerID, PlayerModels::getID(enemyPlayerModel), iterations, responses, timeLimit))); \n    }\n    else if (playerModelID == PlayerModels::AlphaBeta)\n    {\n        int             timeLimitMS;\n        int             maxChildren;\n        std::string     moveOrdering;\n        std::string     evalMethod;\n        std::string     playoutScript1;\n        std::string     playoutScript2;\n        std::string     playerToMoveMethod;\n        std::string     opponentModelScript;\n\n        // read in the values\n        iss >> timeLimitMS;\n        iss >> maxChildren;\n        iss >> moveOrdering;\n        iss >> evalMethod;\n        iss >> playoutScript1;\n        iss >> playoutScript2;\n        iss >> playerToMoveMethod;\n        iss >> opponentModelScript;\n\n        // convert them to the proper enum types\n        int moveOrderingID      = MoveOrderMethod::getID(moveOrdering);\n        int evalMethodID        = EvaluationMethods::getID(evalMethod);\n        int playoutScriptID1    = PlayerModels::getID(playoutScript1);\n        int playoutScriptID2    = PlayerModels::getID(playoutScript2);\n        int playerToMoveID      = PlayerToMove::getID(playerToMoveMethod);\n        int opponentModelID     = PlayerModels::getID(opponentModelScript);\n\n        // construct the parameter object\n        AlphaBetaSearchParameters params;\n\n        // give the default parameters we can't set via options\n\t    params.setMaxDepth(50);\n        params.setSearchMethod(SearchMethods::IDAlphaBeta);\n\n        // set the parameters from the options in the file\n\t    params.setMaxPlayer(playerID);\n\t    params.setTimeLimit(timeLimitMS);\n        params.setMaxChildren(maxChildren);\n        params.setMoveOrderingMethod(moveOrderingID);\n        params.setEvalMethod(evalMethodID);\n        params.setSimScripts(playoutScriptID1, playoutScriptID2);\n        params.setPlayerToMoveMethod(playerToMoveID);\n\t\n        // add scripts for move ordering\n        if (moveOrderingID == MoveOrderMethod::ScriptFirst)\n        {\n            params.addOrderedMoveScript(PlayerModels::NOKDPS);\n            params.addOrderedMoveScript(PlayerModels::KiterDPS);\n            //params.addOrderedMoveScript(PlayerModels::Cluster);\n            //params.addOrderedMoveScript(PlayerModels::AttackWeakest);\n        }\n\n        // set opponent modeling if it's not none\n        if (opponentModelID != PlayerModels::None)\n        {\n            if (playerID == 0)\n            {\n                params.setSimScripts(playoutScriptID1, opponentModelID);\n                params.setPlayerModel(1, playoutScriptID2);\n            }\n            else\n            {\n                params.setSimScripts(opponentModelID, playoutScriptID2);\n                params.setPlayerModel(0, playoutScriptID1);\n            }\n        }\n\n        PlayerPtr abPlayer(new Player_AlphaBeta(playerID, params, TTPtr((TranspositionTable *)NULL)));\n        players[playerID].push_back(abPlayer); \n    }\n    else if (playerModelID == PlayerModels::UCT)\n    {\n        int             timeLimitMS;\n        double          cValue;\n        int             maxTraversals;\n        int             maxChildren;\n        std::string     moveOrdering;\n        std::string     evalMethod;\n        std::string     playoutScript1;\n        std::string     playoutScript2;\n        std::string     playerToMoveMethod;\n        std::string     opponentModelScript;\n\n        // read in the values\n        iss >> timeLimitMS;\n        iss >> cValue;\n        iss >> maxTraversals;\n        iss >> maxChildren;\n        iss >> moveOrdering;\n        iss >> evalMethod;\n        iss >> playoutScript1;\n        iss >> playoutScript2;\n        iss >> playerToMoveMethod;\n        iss >> opponentModelScript;\n\n        // convert them to the proper enum types\n        int moveOrderingID      = MoveOrderMethod::getID(moveOrdering);\n        int evalMethodID        = EvaluationMethods::getID(evalMethod);\n        int playoutScriptID1    = PlayerModels::getID(playoutScript1);\n        int playoutScriptID2    = PlayerModels::getID(playoutScript2);\n        int playerToMoveID      = PlayerToMove::getID(playerToMoveMethod);\n        int opponentModelID     = PlayerModels::getID(opponentModelScript);\n\n        // construct the parameter object\n        UCTSearchParameters params;\n\n        // set the parameters from the options in the file\n\t    params.setTimeLimit(timeLimitMS);\n        params.setCValue(cValue);\n\t    params.setMaxPlayer(playerID);\n        params.setMaxTraversals(maxTraversals);\n        params.setMaxChildren(maxChildren);\n        params.setMoveOrderingMethod(moveOrderingID);\n        params.setEvalMethod(evalMethodID);\n        params.setSimScripts(playoutScriptID1, playoutScriptID2);\n        params.setPlayerToMoveMethod(playerToMoveID);\n        //params.setGraphVizFilename(\"__uct.txt\");\n\n        // add scripts for move ordering\n        if (moveOrderingID == MoveOrderMethod::ScriptFirst)\n        {\n            params.addOrderedMoveScript(PlayerModels::NOKDPS);\n            params.addOrderedMoveScript(PlayerModels::KiterDPS);\n            //params.addOrderedMoveScript(PlayerModels::Cluster);\n        }\n\t\n        // set opponent modeling if it's not none\n        if (opponentModelID != PlayerModels::None)\n        {\n            if (playerID == 0)\n            {\n                params.setSimScripts(playoutScriptID1, opponentModelID);\n                params.setPlayerModel(1, playoutScriptID2);\n            }\n            else\n            {\n                params.setSimScripts(opponentModelID, playoutScriptID2);\n                params.setPlayerModel(0, playoutScriptID1);\n            }\n        }\n\n        PlayerPtr uctPlayer(new Player_UCT(playerID, params));\n        players[playerID].push_back(uctPlayer); \n    }\n\telse\n    {\n        System::FatalError(\"Invalid Player Type in Configuration File: \" + playerModelString);\n    }\n}\n\nPosition SearchExperiment::getRandomPosition(const PositionType & xlimit, const PositionType & ylimit)\n{\n\tint x = xlimit - (rand.nextInt() % (2*xlimit));\n\tint y = ylimit - (rand.nextInt() % (2*ylimit));\n\n\treturn Position(x, y);\n}\n\nGameState SearchExperiment::getSymmetricState( std::vector<std::string> & unitTypes, std::vector<int> & numUnits,\n\t\t\t\t\t\t\t\t                const PositionType & xLimit, const PositionType & yLimit)\n{\n\tGameState state;\n\n    Position mid(640, 360);\n\n    //std::cout << \"   Adding\";\n\n    // for each unit type to add\n    for (size_t i(0); i<unitTypes.size(); ++i)\n    {\n        BWAPI::UnitType type;\n        for (const BWAPI::UnitType & t : BWAPI::UnitTypes::allUnitTypes())\n        {\n            if (t.getName().compare(unitTypes[i]) == 0)\n            {\n                type = t;\n                break;\n            } \n        }\n\n        // add the symmetric unit for each count in the numUnits Vector\n        for (int u(0); u<numUnits[i]; ++u)\n\t    {\n            Position r((rand.nextInt() % (2*xLimit)) - xLimit, (rand.nextInt() % (2*yLimit)) - yLimit);\n            Position u1(mid.x() + r.x(), mid.y() + r.y());\n            Position u2(mid.x() - r.x(), mid.y() - r.y());\n\n            state.addUnit(type, Players::Player_One, u1);\n            state.addUnit(type, Players::Player_Two, u2);\n\t    }\n    }\n    \n    //std::cout << std::endl;\n\tstate.finishedMoving();\n\treturn state;\n}\n\nvoid SearchExperiment::addSeparatedState(  std::vector<std::string> & unitTypes, std::vector<int> & numUnits,\n                                                const PositionType cx1, const PositionType cy1, \n                                                const PositionType cx2, const PositionType cy2,\n\t\t\t\t\t\t\t\t                const PositionType & xLimit, const PositionType & yLimit)\n{\n\tGameState state;\n    GameState state2;\n\n    // for each unit type to add\n    for (size_t i(0); i<unitTypes.size(); ++i)\n    {\n        BWAPI::UnitType type;\n        for (const BWAPI::UnitType & t : BWAPI::UnitTypes::allUnitTypes())\n        {\n            if (t.getName().compare(unitTypes[i]) == 0)\n            {\n                type = t;\n                break;\n            } \n        }\n\n        // add the symmetric unit for each count in the numUnits Vector\n        for (int u(0); u<numUnits[i]; ++u)\n\t    {\n            Position r((rand.nextInt() % (2*xLimit)) - xLimit, (rand.nextInt() % (2*yLimit)) - yLimit);\n            Position u1(cx1 + r.x(), cy1 + r.y());\n            Position u2(cx2 - r.x(), cy2 - r.y());\n\n            state.addUnit(type, Players::Player_One, u1);\n            state.addUnit(type, Players::Player_Two, u2);\n            state2.addUnit(type, Players::Player_One, u2);\n            state2.addUnit(type, Players::Player_Two, u1);\n\t    }\n    }\n    \n\tstate.finishedMoving();\n\n\tstates.push_back(state);\n    states.push_back(state2);\n}\n\nsvv SearchExperiment::getExpDescription(const size_t & p1Ind, const size_t & p2Ind, const size_t & state)\n{\n    // 2-column description vector\n    svv desc(2, sv());\n\n    std::stringstream ss;\n\n    desc[0].push_back(\"Player 1:\");\n    desc[0].push_back(\"Player 2:\");\n    desc[0].push_back(\"State #:\");\n    desc[0].push_back(\"Units:\");\n\n    for (size_t p1(0); p1 < players[0].size(); ++p1)\n\t{\n        std::stringstream ss;\n        ss << \"P1 \" << p1 << \":\";\n        desc[0].push_back(ss.str());\n    }\n\n    for (size_t p2(0); p2 < players[1].size(); ++p2)\n\t{\n        std::stringstream ss;\n        ss << \"P2 \" << p2 << \":\";\n        desc[0].push_back(ss.str());\n    }\n\n    for (size_t p1(0); p1 < players[0].size(); ++p1)\n\t{\n        for (size_t p2(0); p2 < players[1].size(); ++p2)\n\t    {\n            std::stringstream ps;    \n            ps << p1 << \" vs \" << p2;\n            desc[0].push_back(ps.str());\n        }\n    }\n\n    ss << PlayerModels::getName(players[0][p1Ind]->getType());        desc[1].push_back(ss.str()); ss.str(std::string());\n    ss << PlayerModels::getName(players[1][p2Ind]->getType());        desc[1].push_back(ss.str()); ss.str(std::string());\n    ss << state << \" of \" << states.size();                         desc[1].push_back(ss.str()); ss.str(std::string());\n    ss << states[state].numUnits(0);                                desc[1].push_back(ss.str()); ss.str(std::string());\n\n    for (size_t p1(0); p1 < players[0].size(); ++p1)\n\t{\n        desc[1].push_back(PlayerModels::getName(players[0][p1]->getType()));\n    }\n\n    for (size_t p2(0); p2 < players[1].size(); ++p2)\n\t{\n        desc[1].push_back(PlayerModels::getName(players[1][p2]->getType()));\n    }\n\n    char buf[30];\n\tfor (size_t p1(0); p1 < players[0].size(); ++p1)\n\t{\n        for (size_t p2(0); p2 < players[1].size(); ++p2)\n\t    {\n            double score = 0;\n            if (numGames[p1][p2] > 0)\n            {\n                score = ((double)numWins[p1][p2] / (double)(numGames[p1][p2])) + 0.5*((double)numDraws[p1][p2] / (double)numGames[p1][p2]);\n            }\n\n            sprintf(buf, \"%.7lf\", score);\n\t\t    desc[1].push_back(std::string(buf));\n        }\n\t}\n\n    return desc;\n}\n\nstd::string SearchExperiment::getBaseFilename(const std::string & filename)\n{\n    for (int i(filename.length()-1); i>=0; --i)\n    {\n        if (filename[i] == '/' || filename[i] == '\\\\')\n        {\n            return filename.substr(i+1,filename.length());\n        }\n    }\n\n    return filename;\n}\n\nvoid SearchExperiment::runExperiment()\n{\n    std::ofstream results(getResultsOutFileName().c_str());\n    if (!results.is_open())\n    {\n        System::FatalError(\"Problem Opening Output File: Results Raw\");\n    }\n    \n    // set the map file for all states\n    for (size_t state(0); state < states.size(); ++state)\n\t{\n        states[state].setMap(map);\n    }\n\n\t#ifdef USING_VISUALIZATION_LIBRARIES\n\t\tGUI * disp = NULL;\n        if (showDisplay)\n        {\n            disp = new GUI(map ? map->getBuildTileWidth() : 40, map ? map->getBuildTileHeight() : 22);\n            disp->SetImageDir(imageDir);\n            disp->OnStart();\n\t\t    disp->LoadMapTexture(map, 19);\n        }\n\t#endif\n\n\tresults << \"   P1    P2    ST  UNIT       EVAL    RND           MS | UnitType PlayerID CurrentHP XPos YPos\\n\";\n    \n\t// for each player one player\n\tfor (size_t p1Player(0); p1Player < players[0].size(); p1Player++)\n\t{\n\t\t// for each player two player\n\t\tfor (size_t p2Player(0); p2Player < players[1].size(); p2Player++)\n\t\t{\n\t\t\t// for each state we care about\n\t\t\tfor (size_t state(2); state < states.size(); ++state)\n\t\t\t{\n                char buf[255];\n                fprintf(stderr, \"%s  \", configFileSmall.c_str());\n\t\t\t\tfprintf(stderr, \"%5d %5d %5d %5d\", (int)p1Player, (int)p2Player, (int)state, (int)states[state].numUnits(Players::Player_One));\n\t\t\t\tsprintf(buf, \"%5d %5d %5d %5d\", (int)p1Player, (int)p2Player, (int)state, (int)states[state].numUnits(Players::Player_One));\n                results << buf;\n\n\t\t\t\tresultsPlayers[0].push_back(p1Player);\n\t\t\t\tresultsPlayers[1].push_back(p2Player);\n\t\t\t\tresultsStateNumber[p1Player][p2Player].push_back(state);\n\t\t\t\tresultsNumUnits[p1Player][p2Player].push_back(states[state].numUnits(Players::Player_One));\n\t\t\t\t\n\t\t\t\t// get player one\n\t\t\t\tPlayerPtr playerOne(players[0][p1Player]);\n\n\t\t\t\t// give it a new transposition table if it's an alpha beta player\n\t\t\t\tPlayer_AlphaBeta * p1AB = dynamic_cast<Player_AlphaBeta *>(playerOne.get());\n\t\t\t\tif (p1AB)\n\t\t\t\t{\n\t\t\t\t\tp1AB->setTranspositionTable(TTPtr(new TranspositionTable()));\n\t\t\t\t}\n\n\t\t\t\t// get player two\n\t\t\t\tPlayerPtr playerTwo(players[1][p2Player]);\n\t\t\t\tPlayer_AlphaBeta * p2AB = dynamic_cast<Player_AlphaBeta *>(playerTwo.get());\n\t\t\t\tif (p2AB)\n\t\t\t\t{\n\t\t\t\t\tp2AB->setTranspositionTable(TTPtr(new TranspositionTable()));\n\t\t\t\t}\n\n\t\t\t\t// construct the game\n\t\t\t\tGame g(states[state], playerOne, playerTwo, 20000);\n                ScoreType gameEval = 0;\n\n                if (showDisplay)\n                {\n\t\t\t\t\tstatic GUI gui(1280, 720);\n                    gui.setGame(g);\n\n                    while (!gui.getGame().gameOver())\n                    {\n                        gui.onFrame();\n                    }\n\n                    gameEval = gui.getGame().getState().eval(Players::Player_One, SparCraft::EvaluationMethods::LTD2).val();\n                }\n                else\n                {\n                    gameEval = g.getState().eval(Players::Player_One, SparCraft::EvaluationMethods::LTD2).val();\n                }\n\n                numGames[p1Player][p2Player]++;\n                if (gameEval > 0)\n                {\n                    numWins[p1Player][p2Player]++;\n                }\n                else if (gameEval < 0)\n                {\n                    numLosses[p1Player][p2Player]++;\n                }\n                else if (gameEval == 0)\n                {\n                    numDraws[p1Player][p2Player]++;\n                }\n\n\t\t\t\tdouble ms = g.getTime();\n\t\t\t\tsprintf(buf, \" %10d %6d %12.2lf\", gameEval, g.getRounds(), ms);\n\t\t\t\tfprintf(stderr, \"%12d %12.2lf\\n\", gameEval, ms);\n\n\t\t\t\tresultsEval[p1Player][p2Player].push_back(gameEval);\n\t\t\t\tresultsRounds[p1Player][p2Player].push_back(g.getRounds());\n\t\t\t\tresultsTime[p1Player][p2Player].push_back(ms);\n\n                results << buf;\n                printStateUnits(results, g.getState());\n                results << std::endl;\n                \n                writeResultsSummary();\n\t\t\t}\n\t\t}\n\t}\n    \n    results.close();\n}\n\n\nvoid SearchExperiment::printStateUnits(std::ofstream & results, GameState & state)\n{\n    std::stringstream ss;\n    for (size_t p(0); p<Constants::Num_Players; ++p)\n    {\n        for (size_t u(0); u<state.numUnits(p); ++u)\n        {\n            Unit & unit(state.getUnit(p,u));\n            Position pos(unit.currentPosition(state.getTime()));\n                        \n            ss << \" | \" << unit.name() << \" \" << (int)unit.player() << \" \" << unit.currentHP() << \" \" << pos.x() << \" \" << pos.y();\n        }\n    }\n    results << ss.str();\n}"
  },
  {
    "path": "SparCraft/source/main/SearchExperiment.h",
    "content": "#pragma once\n\n#include \"../SparCraft.h\"\n#include \"../gui/GUI.h\"\n#include <iomanip>\n\nnamespace SparCraft\n{\n    class SearchExperiment;\n}\n\ntypedef std::vector<std::string> sv;\ntypedef std::vector<sv> svv;\ntypedef std::vector<int> iv;\ntypedef std::vector<iv> ivv;\ntypedef std::vector<ivv> ivvv;\ntypedef std::vector<double> dv;\ntypedef std::vector<dv> dvv;\ntypedef std::vector<dvv> dvvv;\n\nclass TranspositionTable;\n\nnamespace SparCraft\n{\nclass SearchExperiment\n{\n\tstd::vector<PlayerPtr>      players[2];\n    std::vector<std::string>    playerStrings[2];\n    std::vector<GameState>      states;\n    Map *                       map;\n    bool                        showDisplay;\n\n    std::string                 resultsFile;\n    bool                        appendTimeStamp;\n    std::string                 timeString;\n    std::string                 configFileFull;\n    std::string                 configFileSmall;\n    std::string                 imageDir;\n\n\tiv                          resultsPlayers[2];\n\tivvv                        resultsStateNumber;\n\tivvv                        resultsNumUnits;\n\tivvv                        resultsEval;\n\tivvv                        resultsRounds;\n\tdvvv                        resultsTime;\n    ivv                         numGames;\n\tivv                         numWins;\n    ivv                         numLosses;\n\tivv                         numDraws;\n\n\tRandomInt\t\t\t\t\trand;\n\n    void setupResults();\n    void addPlayer(const std::string & line);\n    void addState(const std::string & line);\n    void padString(std::string & str, const size_t & length);\n    void setCurrentDateTime();\n    std::string getDateTimeString();\n    svv getExpDescription(const size_t & p1, const size_t & p2, const size_t & state);\n\n    std::vector<std::string> getLines(const std::string & filename);\n\n    Position    getRandomPosition(  const PositionType & xlimit, const PositionType & ylimit);\n\n    void   addSeparatedState(\tstd::vector<std::string> & unitTypes, std::vector<int> & numUnits,\n                                    const int cx1, const int cy1, const int cx2, const int cy2,\n\t\t\t\t\t\t\t\t    const PositionType & xLimit, const PositionType & yLimit);\n\n    GameState   getSymmetricState(\tstd::vector<std::string> & unitTypes, std::vector<int> & numUnits,\n\t\t\t\t\t\t\t\t    const PositionType & xLimit, const PositionType & yLimit);\n    \n    GameState   getLineState(       const BWAPI::UnitType type1, const size_t & num1, \n                                    const BWAPI::UnitType type2, const size_t & num2,\n                                    const size_t xSpace, const size_t ySpace);\n\n    void        addLineStates(      std::vector<GameState> & states, int num);\n    \n    std::string getBaseFilename(const std::string & filename);\n    BWAPI::UnitType getUnitType(const std::string & unitTypeString);\n    void parseStateDescriptionFile(const std::string & fileName);\n    void parseConfigFile(const std::string & filename);\n    void writeConfig(const std::string & configfile);\n\tstd::string getResultsSummaryFileName();\n    std::string getResultsOutFileName();\n    std::string getConfigOutFileName();\n    std::string currentDateTime();\n    void printStateUnits(std::ofstream & results, GameState & state);\n    void addGameState(const GameState & state);\n\npublic:\n\n    SearchExperiment(const std::string & configFile);\n    ~SearchExperiment();\n\n    void runExperiment();\n\tvoid writeResultsSummary();\n};\n}\n"
  },
  {
    "path": "SparCraft/source/main/main.cpp",
    "content": "#ifndef WIN32\n#define APIENTRY\n#define APIENTRYP\n#endif\n\n#include \"../SparCraft.h\"\n#include \"SearchExperiment.h\"\n\nint main(int argc, char *argv[])\n{\n    SparCraft::init();\n\n    try\n    {\n        if (argc == 2)\n        {\n            SparCraft::SearchExperiment exp(argv[1]);\n            exp.runExperiment();\n        }\n        else\n        {\n            SparCraft::System::FatalError(\"Please provide experiment file as only argument\");\n        }\n    }\n    catch(int e)\n    {\n        if (e == SparCraft::System::SPARCRAFT_FATAL_ERROR)\n        {\n            std::cerr << \"\\nSparCraft FatalError Exception, Shutting Down\\n\\n\";\n        }\n        else\n        {\n            std::cerr << \"\\nUnknown Exception, Shutting Down\\n\\n\";\n        }\n    }\n   \n    return 0;\n}\n"
  },
  {
    "path": "UAlbertaBot/.gitignore",
    "content": "VisualStudio/Release\nVisualStudio/Debug\nsource/*.o"
  },
  {
    "path": "UAlbertaBot/Source/AutoObserver.cpp",
    "content": "#include \"AutoObserver.h\"\n#include \"WorkerManager.h\"\n#include \"Global.h\"\n\nusing namespace UAlbertaBot;\n\nAutoObserver::AutoObserver()\n{\n\n}\n\nvoid AutoObserver::onFrame()\n{\n    bool pickUnitToFollow = !m_observerFollowingUnit || !m_observerFollowingUnit->exists() || (BWAPI::Broodwar->getFrameCount() - m_cameraLastMoved > m_unitFollowFrames);\n\n    if (pickUnitToFollow)\n    {\n\t    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n\t    {\n\t\t    if (unit->isUnderAttack() || unit->isAttacking())\n\t\t    {\n\t\t\t    m_cameraLastMoved = BWAPI::Broodwar->getFrameCount();\n                m_unitFollowFrames = 6;\n                m_observerFollowingUnit = unit;\n                pickUnitToFollow = false;\n                break;\n\t\t    }\n        }\n    }\n\n    if (pickUnitToFollow)\n    {\n\t    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n\t    {\n\t\t    if (unit->isBeingConstructed() && (unit->getRemainingBuildTime() < 12))\n\t\t    {\n\t\t\t    m_cameraLastMoved = BWAPI::Broodwar->getFrameCount();\n                m_unitFollowFrames = 24;\n                m_observerFollowingUnit = unit;\n                pickUnitToFollow = false;\n                break;\n\t\t    }\n        }\n    }\n\n    if (pickUnitToFollow)\n    {\n\t    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n\t    {\n\t\t    if (Global::Workers().isWorkerScout(unit))\n\t\t    {\n\t\t\t    m_cameraLastMoved = BWAPI::Broodwar->getFrameCount();\n                m_unitFollowFrames = 6;\n                m_observerFollowingUnit = unit;\n                pickUnitToFollow = false;\n                break;\n\t\t    }\n        }\n    }\n\n    if (m_observerFollowingUnit && m_observerFollowingUnit->exists())\n    {\n        BWAPI::Broodwar->setScreenPosition(m_observerFollowingUnit->getPosition() - BWAPI::Position(320, 180));\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/AutoObserver.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace UAlbertaBot\n{\n\nclass AutoObserver\n{\n    int         m_cameraLastMoved = 0;\n    int         m_unitFollowFrames = 0;\n    BWAPI::Unit m_observerFollowingUnit = nullptr;\n\npublic:\n\n    AutoObserver();\n    void onFrame();\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/BOSSManager.cpp",
    "content": "#include \"Common.h\"\n#include \"BOSSManager.h\"\n#include \"UnitUtil.h\"\n#include \"Global.h\"\n#include \"ProductionManager.h\"\n#include \"WorkerManager.h\"\n#include \"StrategyManager.h\"\n#include \"Logger.h\"\n\nusing namespace UAlbertaBot;\n\n// constructor\nBOSSManager::BOSSManager() \n{\n\t\n}\n\nvoid BOSSManager::reset()\n{\n    m_previousSearchResults = BOSS::DFBB_BuildOrderSearchResults();\n    m_searchInProgress = false;\n    m_previousBuildOrder.clear();\n}\n\n// start a new search for a new goal\nvoid BOSSManager::startNewSearch(const std::vector<MetaPair> & goalUnits)\n{\n    size_t numWorkers   = UnitUtil::GetAllUnitCount(BWAPI::Broodwar->self()->getRace().getWorker());\n    size_t numDepots    = UnitUtil::GetAllUnitCount(BWAPI::Broodwar->self()->getRace().getResourceDepot())\n                        + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Lair)\n                        + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hive);\n\n    if (numWorkers == 0)\n    {\n        m_previousStatus = \"\\x08No Workers :(\";\n        return;\n    }\n\n    if (numDepots == 0)\n    {\n        m_previousStatus = \"\\x08No Depots :(\";\n        return;\n    }\n\n    // convert from UAlbertaBot's meta goal type to BOSS ActionType goal\n    try\n    {\n        BOSS::BuildOrderSearchGoal goal = GetGoal(goalUnits);\n\n        BOSS::GameState initialState(BWAPI::Broodwar, BWAPI::Broodwar->self(), Global::Production().buildingsQueued());\n\n        m_smartSearch = SearchPtr(new BOSS::DFBB_BuildOrderSmartSearch(initialState.getRace()));\n        m_smartSearch->setGoal(GetGoal(goalUnits));\n        m_smartSearch->setState(initialState);\n\n        m_searchInProgress = true;\n        m_previousSearchStartFrame = BWAPI::Broodwar->getFrameCount();\n        m_totalPreviousSearchTime = 0;\n        m_previousGoalUnits = goalUnits;\n    }\n    catch (const BOSS::BOSSException)\n    {\n        BWAPI::BroodwarPtr->printf(\"Exception in BOSS::GameState constructor, will try again next frame\");\n    }\n}\n\nvoid BOSSManager::drawSearchInformation(int x, int y) \n{\n\tif (!Config::Debug::DrawBuildOrderSearchInfo)\n    {\n        return;\n    }\n\n    // draw the background\n    int width = 155;\n    int height = 80;\n    BWAPI::Broodwar->drawBoxScreen(BWAPI::Position(x-5,y), BWAPI::Position(x+width, y+height), BWAPI::Colors::Black, true);\n\n    x += 5; y+=3;\n\n    BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y), \"%cBuildOrderSearch:\", '\\x04');\n    y += 10;\n    BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y), \"%s\", m_previousStatus.c_str());\n\n    for (size_t i(0); i < m_previousGoalUnits.size(); ++i)\n    {\n        if (m_previousGoalUnits[i].second > 0)\n        {\n            y += 10;\n            BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x,y), \"%d %s\", m_previousGoalUnits[i].second, m_previousGoalUnits[i].first.getName().c_str());\n        }\n    }\n    \n    BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y+25), \"Time (ms): %.3lf\", m_totalPreviousSearchTime);\n    BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y+35), \"Nodes: %d\", m_savedSearchResults.nodesExpanded);\n    BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y+45), \"BO Size: %d\", (int)m_savedSearchResults.buildOrder.size());\n}\n\nvoid BOSSManager::drawStateInformation(int x, int y) \n{\n\tif (!Config::Debug::DrawBOSSStateInfo)\n    {\n        return;\n    }\n\n    BOSS::GameState currentState(BWAPI::Broodwar, BWAPI::Broodwar->self(), Global::Production().buildingsQueued());\n    BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x-100, y+30), \"\\x04%s\", currentState.getBuildingData().toString().c_str());\n    BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x+150, y), \"\\x04%s\", currentState.toString().c_str());\n    \n}\n\n// tell the search to keep going for however long we have this frame\nvoid BOSSManager::update(double timeLimit)\n{\n    PROFILE_FUNCTION();\n\n    // if there's a search in progress, resume it\n    if (isSearchInProgress())\n    {\n        m_previousStatus.clear();\n\n        // give the search at least 5ms to search this frame\n        double realTimeLimit = timeLimit < 0 ? 5 : timeLimit;\n        m_smartSearch->setTimeLimit((int)realTimeLimit);\n        bool caughtException = false;\n\n\t\ttry\n        {\n            // call the search to continue searching\n            // this will resume a search in progress or start a new search if not yet started\n\t\t\tm_smartSearch->search();\n\t\t}\n        // catch any errors that might happen in the search\n\t\tcatch (const BOSS::BOSSException & exception)\n        {\n            UAB_ASSERT_WARNING(false, \"BOSS SmartSearch Exception: %s\", exception.what());\n\t\t\tBWAPI::Broodwar->drawTextScreen(0, 0, \"Previous search didn't find a solution, resorting to Naive Build Order\");\n            m_previousStatus = \"BOSSExeption\";\n            caughtException = true;\n\t\t}\n\n        m_totalPreviousSearchTime += m_smartSearch->getResults().timeElapsed;\n\n        // after the search finishes for this frame, check to see if we have a solution or if we hit the overall time limit\n        bool searchTimeOut = (BWAPI::Broodwar->getFrameCount() > (m_previousSearchStartFrame + Config::Macro::BOSSFrameLimit));\n        bool previousSearchComplete = searchTimeOut || m_smartSearch->getResults().solved || caughtException;\n        if (previousSearchComplete)\n        {\n            bool solved = m_smartSearch->getResults().solved && m_smartSearch->getResults().solutionFound;\n\n            // if we've found a solution, let us know\n            if (m_smartSearch->getResults().solved && Config::Debug::DrawBuildOrderSearchInfo)\n            {\n                //BWAPI::Broodwar->printf(\"Build order SOLVED in %d nodes\", (int)_smartSearch->getResults().nodesExpanded);\n            }\n\n            if (m_smartSearch->getResults().solved)\n            {\n                if (m_smartSearch->getResults().solutionFound)\n                {\n                    m_previousStatus = std::string(\"\\x07\") + \"BOSS Solve Solution\\n\";\n                }\n                else\n                {\n                    m_previousStatus = std::string(\"\\x03\") + \"BOSS Solve NoSolution\\n\";\n                }\n            }\n\n            // re-set all the search information to get read for the next search\n            m_searchInProgress = false;\n            m_previousSearchFinishFrame = BWAPI::Broodwar->getFrameCount();\n            m_previousSearchResults = m_smartSearch->getResults();\n            m_savedSearchResults = m_previousSearchResults;\n            m_previousBuildOrder = m_previousSearchResults.buildOrder;\n\n            if (solved && m_previousBuildOrder.size() == 0)\n            {\n                m_previousStatus = std::string(\"\\x07\") + \"BOSS Trivial Solve\\n\";\n            }\n\n            // if our search resulted in a build order of size 0 then something failed\n            if (!solved && m_previousBuildOrder.size() == 0)\n            {\n                // log the debug information since this shouldn't happen if everything goes to plan\n                /*std::stringstream ss;\n                ss << _smartSearch->getParameters().toString() << \"\\n\";\n                ss << \"searchTimeOut: \" << (searchTimeOut ? \"true\" : \"false\") << \"\\n\";\n                ss << \"caughtException: \" << (caughtException ? \"true\" : \"false\") << \"\\n\";\n                ss << \"getResults().solved: \" << (_smartSearch->getResults().solved ? \"true\" : \"false\") << \"\\n\";\n                ss << \"getResults().solutionFound: \" << (_smartSearch->getResults().solutionFound ? \"true\" : \"false\") << \"\\n\";\n                ss << \"nodes: \" << _savedSearchResults.nodesExpanded << \"\\n\";\n                ss << \"time: \" << _savedSearchResults.timeElapsed << \"\\n\";\n                Logger::LogOverwriteToFile(\"bwapi-data/AI/LastBadBuildOrder.txt\", ss.str());*/\n                \n                // so try another naive build order search as a last resort\n                BOSS::NaiveBuildOrderSearch nbos(m_smartSearch->getParameters().initialState, m_smartSearch->getParameters().goal);\n\n\t\t\t\ttry\n                {\n                    if (searchTimeOut)\n                    {\n                        m_previousStatus = std::string(\"\\x02\") + \"BOSS Timeout\\n\";\n                    }\n\n                    if (caughtException)\n                    {\n                        m_previousStatus = std::string(\"\\x02\") + \"BOSS Exception\\n\";\n                    }\n\n\t\t\t\t\tm_previousBuildOrder = nbos.solve();\n                    m_previousStatus += \"\\x03NBOS Solution\";\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n                // and if that search doesn't work then we're out of luck, no build orders forus\n\t\t\t\tcatch (const BOSS::BOSSException & exception)\n                {\n                    UAB_ASSERT_WARNING(false, \"BOSS Timeout Naive Search Exception: %s\", exception.what());\n                    m_previousStatus += \"\\x08Naive Exception\";\n                    if (Config::Debug::DrawBuildOrderSearchInfo)\n                    {\n\t\t\t\t\t    BWAPI::Broodwar->drawTextScreen(0, 20, \"No legal BuildOrder found, returning empty Build Order\");\n                    }\n\t\t\t\t\tm_previousBuildOrder = BOSS::BuildOrder();\n\t\t\t\t\treturn;\n\t\t\t\t}\n            }\n        }\n    }\n}\n\nvoid BOSSManager::logBadSearch()\n{\n    std::string s = m_smartSearch->getParameters().toString();\n\n}\n\nBOSS::BuildOrderSearchGoal BOSSManager::GetGoal(const std::vector<MetaPair> & goalUnits)\n{\n\tBOSS::BuildOrderSearchGoal goal(BOSS::Races::GetRaceID(BWAPI::Broodwar->self()->getRace()));\n\n\tfor (size_t i=0; i<goalUnits.size(); ++i)\n\t{\n\t\tgoal.setGoal(GetActionType(goalUnits[i].first), goalUnits[i].second);\n\t}\n\n\treturn goal;\n}\n\n// gets the StarcraftState corresponding to the beginning of a Melee game\nBOSS::GameState BOSSManager::getStartState()\n{\n    BOSS::GameState state(getRace());\n    state.setStartingState();\n\n\treturn state;\n}\n\nconst BOSS::RaceID BOSSManager::getRace() const\n{\n    BWAPI::Race r = BWAPI::Broodwar->self()->getRace();\n    if (r == BWAPI::Races::Protoss)\n    {\n        return BOSS::Races::Protoss;\n    }\n    else if (r == BWAPI::Races::Terran)\n    {\n        return BOSS::Races::Terran;\n    }\n    else if (r == BWAPI::Races::Zerg)\n    {\n        return BOSS::Races::Zerg;\n    }\n    else\n    {\n        BOSS_ASSERT(false, \"We should have had a valid race from BWAPI\");\n        return BOSS::Races::None;\n    }\n}\n\nbool BOSSManager::isSearchInProgress()\n{\n    return m_searchInProgress;\n}\n\n// converts SearchResults.buildOrder vector into vector of MetaType\nstd::vector<MetaType> BOSSManager::GetMetaVector(const BOSS::BuildOrder & buildOrder)\n{\n\tstd::vector<MetaType> metaVector;\n    \t\n\tfor (size_t i(0); i<buildOrder.size(); ++i)\n\t{\n\t\tmetaVector.push_back(GetMetaType(buildOrder[i]));\n\t}\n\n\treturn metaVector;\n}\n\n\nBuildOrder BOSSManager::getBuildOrder()\n{\n    return BuildOrder(BWAPI::Broodwar->self()->getRace(), GetMetaVector(m_previousBuildOrder));\n}\n\nBOSS::ActionType BOSSManager::GetActionType(const MetaType & t)\n{\n\t// set the appropriate type\n\tif (t.isUnit())\n\t{\n\t\treturn BOSS::ActionType(t.getUnitType());\n\t}\n\telse if (t.isUpgrade())\n\t{\n\t\treturn BOSS::ActionType(t.getUpgradeType());\n\t} \n\telse if (t.isTech())\n\t{\n\t\treturn BOSS::ActionType(t.getTechType());\n\t}\n\telse\n\t{\n\t\tUAB_ASSERT(false, \"Should have found a valid type here\");\n\t}\n\t\n\treturn BOSS::ActionType();\n}\n\nMetaType BOSSManager::GetMetaType(const BOSS::ActionType & a)\n{\n\t// set the appropriate type\n\tif (a.isUnit())\n\t{\n\t\treturn MetaType(a.getUnitType());\n\t}\n\telse if (a.isUpgrade())\n\t{\n\t\treturn MetaType(a.getUpgradeType());\n\t} \n\telse if (a.isTech())\n\t{\n\t\treturn MetaType(a.getTechType());\n\t}\n\telse\n\t{\n\t\tUAB_ASSERT(false, \"Should have found a valid type here\");\n\t}\n\t\n\treturn MetaType();\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/BOSSManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"../../BOSS/source/BOSS.h\"\n#include <memory>\n#include \"MetaType.h\"\n\nnamespace UAlbertaBot\n{\n    \ntypedef std::shared_ptr<BOSS::DFBB_BuildOrderSmartSearch> SearchPtr;\nclass BuildOrder;\n\nclass BOSSManager\n{\n    friend class Global;\n    \n    int         m_previousSearchStartFrame  = 0;\n    int         m_savedSearchStartFrame     = 0;\n    int         m_previousSearchFinishFrame = 0;\n    bool        m_searchInProgress          = false;\n    double      m_totalPreviousSearchTime   = 0;\n    std::string m_previousStatus            = \"No Searches\";\n    SearchPtr   m_smartSearch;\n    \n    std::vector<MetaPair>                   m_previousGoalUnits;\n    BOSS::DFBB_BuildOrderSearchResults      m_previousSearchResults;\n    BOSS::DFBB_BuildOrderSearchResults      m_savedSearchResults;\n    BOSS::BuildOrder                        m_previousBuildOrder;\n\n\tBOSS::GameState\t\t\t\t            getStartState();\n    const BOSS::RaceID                      getRace() const;\n    void                                    logBadSearch();\n\npublic:\n    \n\tBOSSManager();\n\n\tvoid update(double timeLimit);\n    void reset();\n    void startNewSearch(const std::vector<MetaPair> & goalUnits);\n\tvoid drawSearchInformation(int x, int y);\n    void drawStateInformation(int x, int y);\n    bool isSearchInProgress();\n\n    BuildOrder getBuildOrder();\n\n\tstatic BOSS::BuildOrderSearchGoal   GetGoal(const std::vector<MetaPair> & goalUnits);\t\n    static std::vector<MetaType>        GetMetaVector(const BOSS::BuildOrder & buildOrder);\n\tstatic BOSS::ActionType             GetActionType(const MetaType & t);\n\tstatic MetaType                     GetMetaType(const BOSS::ActionType & a);\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/BaseLocation.cpp",
    "content": "\n#include \"Common.h\"\n#include \"BaseLocation.h\"\n#include \"MapTools.h\"\n#include \"Global.h\"\n#include <sstream>\n#include <iostream>\n\nusing namespace UAlbertaBot;\n\nconst int NearBaseLocationTileDistance = 20;\n\nBaseLocation::BaseLocation(int baseID, const std::vector<BWAPI::Unit> & resources)\n    : m_baseID(baseID)\n{\n    PROFILE_FUNCTION();\n\n    m_isPlayerStartLocation[BWAPI::Broodwar->self()]  = false;\n    m_isPlayerStartLocation[BWAPI::Broodwar->enemy()] = false;\n    m_isPlayerOccupying[BWAPI::Broodwar->self()]      = false;\n    m_isPlayerOccupying[BWAPI::Broodwar->enemy()]     = false;\n\n    int resourceCenterX = 0;\n    int resourceCenterY = 0;\n\n    // add each of the resources to its corresponding container\n    for (auto & resource : resources)\n    {\n        if (resource->getType().isMineralField())\n        {\n            m_minerals.push_back(resource);\n            m_mineralPositions.push_back(resource->getPosition());\n\n            // add the position of the minerals to the center\n            resourceCenterX += resource->getPosition().x;\n            resourceCenterY += resource->getPosition().y;\n        }\n        else\n        {\n            m_geysers.push_back(resource);\n            m_geyserPositions.push_back(resource->getPosition());\n\n            // pull the resource center toward the geyser if it exists\n            resourceCenterX += resource->getPosition().x;\n            resourceCenterY += resource->getPosition().y;\n        }\n\n        // set the limits of the base location bounding box\n        const int resWidth = 32;\n        const int resHeight = 32;\n\n        m_left   = std::min(m_left, resource->getPosition().x - resWidth);\n        m_right  = std::max(m_right, resource->getPosition().x + resWidth);\n        m_top    = std::max(m_top, resource->getPosition().y + resHeight);\n        m_bottom = std::min(m_bottom, resource->getPosition().y - resHeight);\n    }\n\n    // calculate the center of the resources\n    const size_t numResources = m_minerals.size() + m_geysers.size();\n\n    m_centerOfResources = BWAPI::Position(m_left + (m_right-m_left)/2, m_top + (m_bottom-m_top)/2);\n\n    // compute this BaseLocation's DistanceMap, which will compute the ground distance\n    // from the center of its recourses to every other tile on the map\n    m_distanceMap = DistanceMap();\n    m_distanceMap.computeDistanceMap(BWAPI::TilePosition(m_centerOfResources));\n\n    // check to see if this is a start location for the map\n    for (auto & startTilePos : BWAPI::Broodwar->getStartLocations())\n    {\n        auto groundDistance = getGroundDistance(startTilePos);\n\n        if (containsPosition(BWAPI::Position(startTilePos)))\n        {\n            m_isStartLocation = true;\n            m_depotPosition = BWAPI::TilePosition(startTilePos);\n            m_startPosition = startTilePos;\n            break;\n        }\n    }\n\n    // if this base location position is near our own resource depot, it's our start location\n    for (auto & unit : BWAPI::Broodwar->getAllUnits())\n    {\n        if (unit->getPlayer() == BWAPI::Broodwar->self() && unit->getType().isResourceDepot())\n        {\n            if (containsPosition(unit->getPosition()))\n            {\n                m_isPlayerStartLocation[BWAPI::Broodwar->self()] = true;\n                m_isStartLocation = true;\n                m_isPlayerOccupying[BWAPI::Broodwar->self()] = true;\n                break;\n            }\n        }\n    }\n\n    // if it's not a start location, we need to calculate the depot position\n    if (!isStartLocation())\n    {\n        const BWAPI::UnitType depot = BWAPI::Broodwar->self()->getRace().getResourceDepot();\n\n        const int offsetX = 1;\n        const int offsetY = 1;\n\n        // the position of the depot will be the closest spot we can build one from the resource center\n        for (auto & tile : getClosestTiles())\n        {\n            // the build position will be up-left of where this tile is\n            // this means we are positioning the center of the resouce depot\n            const BWAPI::TilePosition buildTile(tile.x - offsetX, tile.y - offsetY);\n\n            if (BWAPI::Broodwar->canBuildHere(buildTile, depot))\n            {\n                m_depotPosition = buildTile;\n                break;\n            }\n        }\n    }\n}\n\n// TODO: calculate the actual depot position\nconst BWAPI::TilePosition & BaseLocation::getDepotPosition() const\n{\n    return m_depotPosition;\n}\n\nvoid BaseLocation::setPlayerOccupying(BWAPI::Player player, bool occupying)\n{\n    m_isPlayerOccupying[player] = occupying;\n\n    // if this base is a start location that's occupied by the enemy, it's that enemy's start location\n    if (occupying && player == BWAPI::Broodwar->enemy() && isStartLocation() && m_isPlayerStartLocation[player] == false)\n    {\n        m_isPlayerStartLocation[player] = true;\n    }\n}\n\nbool BaseLocation::isInResourceBox(int tileX, int tileY) const\n{\n    const int px = tileX * 32;\n    const int py = tileY * 32;\n    return px >= m_left && px < m_right && py < m_top && py >= m_bottom;\n}\n\nbool BaseLocation::isOccupiedByPlayer(BWAPI::Player player) const\n{\n    return m_isPlayerOccupying.at(player);\n}\n\nbool BaseLocation::isExplored() const\n{\n    return BWAPI::Broodwar->isExplored(BWAPI::TilePosition(m_centerOfResources));\n}\n\nbool BaseLocation::isPlayerStartLocation(BWAPI::Player player) const\n{\n    return m_isPlayerStartLocation.at(player);\n}\n\nbool BaseLocation::isConnected(const BWAPI::Position& pos) const\n{\n    return getGroundDistance(pos) >= 0;\n}\n\nbool BaseLocation::containsPosition(const BWAPI::Position & pos) const\n{\n    if (!pos.isValid() || (pos.x == 0 && pos.y == 0) || !isConnected(pos))\n    {\n        return false;\n    }\n\n    return (getGroundDistance(pos) < NearBaseLocationTileDistance);\n}\n\nconst std::vector<BWAPI::Unit> & BaseLocation::getGeysers() const\n{\n    return m_geysers;\n}\n\nconst std::vector<BWAPI::Unit> & BaseLocation::getMinerals() const\n{\n    return m_minerals;\n}\n\nconst BWAPI::Position & BaseLocation::getPosition() const\n{\n    return m_centerOfResources;\n}\n\nint BaseLocation::getGroundDistance(const BWAPI::Position & pos) const\n{\n    return m_distanceMap.getDistance(pos);\n}\n\nint BaseLocation::getGroundDistance(const BWAPI::TilePosition & pos) const\n{\n    return m_distanceMap.getDistance(pos);\n}\n\nbool BaseLocation::isStartLocation() const\n{\n    return m_isStartLocation;\n}\n\nconst std::vector<BWAPI::TilePosition> & BaseLocation::getClosestTiles() const\n{\n    return m_distanceMap.getSortedTiles();\n}\n\nvoid BaseLocation::draw()\n{\n    int radius = 16;\n\n    BWAPI::Broodwar->drawCircleMap(m_centerOfResources, 16, BWAPI::Color(255, 255, 0), true);\n\n    if (m_startPosition.x != 0)\n    {\n        BWAPI::Broodwar->drawLineMap(m_centerOfResources, BWAPI::Position(m_startPosition), BWAPI::Colors::Red);\n    }\n\n    std::stringstream ss;\n    ss << \"BaseLocation: \" << m_baseID << \"\\n\";\n    ss << \"Start Loc:    \" << (isStartLocation() ? \"true\" : \"false\") << \"\\n\";\n    ss << \"Minerals:     \" << m_mineralPositions.size() << \"\\n\";\n    ss << \"Geysers:      \" << m_geyserPositions.size() << \"\\n\";\n    ss << \"Occupied By:  \";\n\n    if (isOccupiedByPlayer(BWAPI::Broodwar->self()))\n    {\n        ss << \"Self \";\n    }\n\n    if (isOccupiedByPlayer(BWAPI::Broodwar->enemy()))\n    {\n        ss << \"Enemy \";\n    }\n\n\n    BWAPI::Broodwar->drawTextMap(BWAPI::Position(m_left, m_top + 3), ss.str().c_str());\n    BWAPI::Broodwar->drawTextMap(BWAPI::Position(m_left, m_bottom), ss.str().c_str());\n\n    // draw the base bounding box\n    BWAPI::Broodwar->drawLineMap(m_left, m_top, m_right, m_top, BWAPI::Colors::White);\n    BWAPI::Broodwar->drawLineMap(m_right, m_top, m_right, m_bottom, BWAPI::Colors::White);\n    BWAPI::Broodwar->drawLineMap(m_right, m_bottom, m_left, m_bottom, BWAPI::Colors::White);\n    BWAPI::Broodwar->drawLineMap(m_left, m_bottom, m_left, m_top, BWAPI::Colors::White);\n\n    for (auto & mineralPos : m_mineralPositions)\n    {\n        const BWAPI::TilePosition mineralTile(mineralPos);\n        Global::Map().drawTile(mineralTile.x,   mineralTile.y, BWAPI::Color(0, 255, 255));\n        Global::Map().drawTile(mineralTile.x-1, mineralTile.y, BWAPI::Color(0, 255, 255));\n    }\n\n    for (auto & geyserPos : m_geyserPositions)\n    {\n        const BWAPI::TilePosition geyserTile(geyserPos);\n        Global::Map().drawTile(geyserTile.x,   geyserTile.y,   BWAPI::Color(0, 255, 0));\n        Global::Map().drawTile(geyserTile.x+1, geyserTile.y,   BWAPI::Color(0, 255, 0));\n        Global::Map().drawTile(geyserTile.x-1, geyserTile.y,   BWAPI::Color(0, 255, 0));\n        Global::Map().drawTile(geyserTile.x-2, geyserTile.y,   BWAPI::Color(0, 255, 0));\n        Global::Map().drawTile(geyserTile.x,   geyserTile.y-1, BWAPI::Color(0, 255, 0));\n        Global::Map().drawTile(geyserTile.x+1, geyserTile.y-1, BWAPI::Color(0, 255, 0));\n        Global::Map().drawTile(geyserTile.x-1, geyserTile.y-1, BWAPI::Color(0, 255, 0));\n        Global::Map().drawTile(geyserTile.x-2, geyserTile.y-1, BWAPI::Color(0, 255, 0));\n\n        BWAPI::Broodwar->drawCircleMap(geyserPos, radius, BWAPI::Color(0, 255, 0), true);\n    }\n\n    if (m_isStartLocation)\n    {\n        BWAPI::Broodwar->drawCircleMap(BWAPI::Position(m_depotPosition), radius, BWAPI::Color(255, 0, 0));\n    }\n\n    BWAPI::Broodwar->drawBoxMap(m_depotPosition.x, m_depotPosition.y, m_depotPosition.x+32, m_depotPosition.y+32, BWAPI::Color(0, 0, 255));\n\n    //m_distanceMap.draw();\n}\n\nbool BaseLocation::isMineralOnly() const\n{\n    return getGeysers().empty();\n}"
  },
  {
    "path": "UAlbertaBot/Source/BaseLocation.h",
    "content": "#pragma once\n\n#include \"DistanceMap.h\"\n#include <map>\n#include <vector>\n\nnamespace UAlbertaBot\n{\n\nclass BaseLocation\n{\n    int\t\tm_baseID            = 0;\n    int     m_left              = std::numeric_limits<int>::max();\n    int     m_right             = std::numeric_limits<int>::lowest();\n    int     m_top               = std::numeric_limits<int>::lowest();\n    int     m_bottom            = std::numeric_limits<int>::max();\n    bool    m_isStartLocation   = false;\n    BWAPI::TilePosition         m_startPosition;\n\n    DistanceMap                 m_distanceMap;\n\n    BWAPI::TilePosition\t\t\tm_depotPosition;\n    BWAPI::Position\t\t\t\tm_centerOfResources;\n    std::vector<BWAPI::Unit>\tm_geysers;\n    std::vector<BWAPI::Unit>\tm_minerals;\n\n    std::vector<BWAPI::Position> m_mineralPositions;\n    std::vector<BWAPI::Position> m_geyserPositions;\n\n    std::map<BWAPI::Player, bool> m_isPlayerOccupying;\n    std::map<BWAPI::Player, bool> m_isPlayerStartLocation;\n    \npublic:\n\n    BaseLocation(int baseID, const std::vector<BWAPI::Unit>& resources);\n\n    bool isConnected(const BWAPI::Position& pos) const;\n    int getGroundDistance(const BWAPI::Position& pos) const;\n    int getGroundDistance(const BWAPI::TilePosition& pos) const;\n    bool isStartLocation() const;\n    bool isPlayerStartLocation(BWAPI::Player player) const;\n    bool isMineralOnly() const;\n    bool containsPosition(const BWAPI::Position& pos) const;\n    const BWAPI::TilePosition& getDepotPosition() const;\n    const BWAPI::Position& getPosition() const;\n    const std::vector<BWAPI::Unit>& getGeysers() const;\n    const std::vector<BWAPI::Unit>& getMinerals() const;\n    bool isOccupiedByPlayer(BWAPI::Player player) const;\n    bool isExplored() const;\n    bool isInResourceBox(int x, int y) const;\n\n    void setPlayerOccupying(BWAPI::Player player, bool occupying);\n\n    const std::vector<BWAPI::TilePosition>& getClosestTiles() const;\n\n    void draw();\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/BaseLocationManager.cpp",
    "content": "\n#include \"Common.h\"\n#include \"BaseLocationManager.h\"\n#include \"InformationManager.h\"\n#include \"MapTools.h\"\n#include \"Global.h\"\n#include \"UnitData.h\"\n\nusing namespace UAlbertaBot;\n\nBaseLocationManager::BaseLocationManager()\n{\n    onStart();\n}\n\nBWAPI::Position BaseLocationManager::calcCenter(const std::vector<BWAPI::Unit> & units)\n{\n    if (units.empty())\n    {\n        return BWAPI::Position(0, 0);\n    }\n\n    int cx = 0;\n    int cy = 0;\n\n    for (auto & unit : units)\n    {\n        cx += unit->getPosition().x;\n        cy += unit->getPosition().y;\n    }\n\n    return BWAPI::Position(cx / units.size(), cy / units.size());\n}\n\nvoid BaseLocationManager::onStart()\n{\n    PROFILE_FUNCTION();\n\n    m_tileBaseLocations = std::vector<std::vector<BaseLocation *>>(BWAPI::Broodwar->mapWidth(), std::vector<BaseLocation *>(BWAPI::Broodwar->mapHeight(), nullptr));\n    m_playerStartingBaseLocations[BWAPI::Broodwar->self()]  = nullptr;\n    m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] = nullptr;\n\n    // Use StarDraft to find the borders of the bases on the map\n    m_baseBorders = BaseBorderFinder(Global::Map().getStarDraftMap());\n    for (size_t baseID = 0; baseID < m_baseBorders.getBaseBorders().size(); baseID++)\n    {\n        const auto & border = m_baseBorders.getBaseBorders()[baseID];\n\n        // fill a vector with all the resource units in the border\n        std::vector<BWAPI::Unit> resources;\n\n        // for each static unit on the map\n        for (auto unit : BWAPI::Broodwar->getStaticNeutralUnits())\n        {\n            // if it's a resource\n            if (unit->getType().isMineralField() || unit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser)\n            {\n                BWAPI::TilePosition tile(unit->getPosition());\n\n                // if it's inside the border, add it to the vector\n                if (border.contains(tile.x, tile.y))\n                {\n                    resources.push_back(unit);\n                }\n            }\n        }\n\n        // add a baselocation containing these resources\n        m_baseLocationData.push_back(BaseLocation(baseID, resources));\n    }\n\n    // construct the vectors of base location pointers, this is safe since they will never change\n    for (auto & baseLocation : m_baseLocationData)\n    {\n        m_baseLocationPtrs.push_back(&baseLocation);\n\n        // if it's a start location, add it to the start locations\n        if (baseLocation.isStartLocation())\n        {\n            m_startingBaseLocations.push_back(&baseLocation);\n        }\n\n        // if it's our starting location, set the pointer\n        if (baseLocation.isPlayerStartLocation(BWAPI::Broodwar->self()))\n        {\n            m_playerStartingBaseLocations[BWAPI::Broodwar->self()] = &baseLocation;\n        }\n\n        if (baseLocation.isPlayerStartLocation(BWAPI::Broodwar->enemy()))\n        {\n            m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] = &baseLocation;\n        }\n    }\n\n    // construct the map of tile positions to base locations\n    for (int x=0; x < BWAPI::Broodwar->mapWidth(); ++x)\n    {\n        for (int y = 0; y < BWAPI::Broodwar->mapHeight(); ++y)\n        {\n            for (auto & baseLocation : m_baseLocationData)\n            {\n                BWAPI::Position pos(BWAPI::TilePosition(x, y));\n\n                if (baseLocation.containsPosition(pos))\n                {\n                    m_tileBaseLocations[x][y] = &baseLocation;\n\n                    break;\n                }\n            }\n        }\n    }\n\n    // construct the sets of occupied base locations\n    m_occupiedBaseLocations[BWAPI::Broodwar->self()] = std::set<const BaseLocation *>();\n    m_occupiedBaseLocations[BWAPI::Broodwar->enemy()] = std::set<const BaseLocation *>();\n}\n\nvoid BaseLocationManager::onFrame()\n{\n    PROFILE_FUNCTION();\n\n    drawBaseLocations();\n\n    // reset the player occupation information for each location\n    for (auto & baseLocation : m_baseLocationData)\n    {\n        baseLocation.setPlayerOccupying(BWAPI::Broodwar->self(), false);\n        baseLocation.setPlayerOccupying(BWAPI::Broodwar->self(), false);\n    }\n\n    // for each unit on the map, update which base location it may be occupying\n    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        // we only care about buildings on the ground\n        if (!unit->getType().isBuilding() || unit->isFlying())\n        {\n            continue;\n        }\n\n        BaseLocation * baseLocation = getBaseLocation(unit->getPosition());\n\n        if (baseLocation != nullptr)\n        {\n            baseLocation->setPlayerOccupying(unit->getPlayer(), true);\n        }\n    }\n\n    // update enemy base occupations\n    for (const auto & kv : Global::Info().getUnitInfo(BWAPI::Broodwar->enemy()))\n    {\n        const UnitInfo & ui = kv.second;\n\n        if (ui.type.isBuilding())\n        {\n            continue;\n        }\n\n        BaseLocation * baseLocation = getBaseLocation(ui.lastPosition);\n\n        if (baseLocation != nullptr)\n        {\n            baseLocation->setPlayerOccupying(BWAPI::Broodwar->enemy(), true);\n        }\n    }\n\n    // update the starting locations of the enemy player\n    // this will happen one of two ways:\n\n    // 1. we've seen the enemy base directly, so the baselocation will know\n    if (m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] == nullptr)\n    {\n        for (auto & baseLocation : m_baseLocationData)\n        {\n            if (baseLocation.isPlayerStartLocation(BWAPI::Broodwar->enemy()))\n            {\n                m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] = &baseLocation;\n            }\n        }\n    }\n\n    // 2. we've explored every other start location and haven't seen the enemy yet\n    if (m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] == nullptr)\n    {\n        const int numStartLocations = (int)getStartingBaseLocations().size();\n        int numExploredLocations = 0;\n        BaseLocation * unexplored = nullptr;\n\n        for (auto & baseLocation : m_baseLocationData)\n        {\n            if (!baseLocation.isStartLocation())\n            {\n                continue;\n            }\n\n            if (baseLocation.isExplored())\n            {\n                numExploredLocations++;\n            }\n            else\n            {\n                unexplored = &baseLocation;\n            }\n        }\n\n        // if we have explored all but one location, then the unexplored one is the enemy start location\n        if (numExploredLocations == numStartLocations - 1 && unexplored != nullptr)\n        {\n            m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] = unexplored;\n            unexplored->setPlayerOccupying(BWAPI::Broodwar->enemy(), true);\n        }\n    }\n\n    // update the occupied base locations for each player\n    m_occupiedBaseLocations[BWAPI::Broodwar->self()] = std::set<const BaseLocation *>();\n    m_occupiedBaseLocations[BWAPI::Broodwar->enemy()] = std::set<const BaseLocation *>();\n    for (auto & baseLocation : m_baseLocationData)\n    {\n        if (baseLocation.isOccupiedByPlayer(BWAPI::Broodwar->self()))\n        {\n            m_occupiedBaseLocations[BWAPI::Broodwar->self()].insert(&baseLocation);\n        }\n\n        if (baseLocation.isOccupiedByPlayer(BWAPI::Broodwar->enemy()))\n        {\n            m_occupiedBaseLocations[BWAPI::Broodwar->enemy()].insert(&baseLocation);\n        }\n    }\n\n    // sanity check: make sure we have as many starting locations as BWAPI says\n    if (getStartingBaseLocations().size() != BWAPI::Broodwar->getStartLocations().size())\n    {\n        std::cout << \"\\nWARNING: BaseLocationManager start location mismatch: \" << BWAPI::Broodwar->mapFileName() << \"\\n\";\n        std::cout << \"         BaseLocationManager found \" << getStartingBaseLocations().size() << \" starting locations\\n\";\n        std::cout << \"         BWAPI says that there are \" << BWAPI::Broodwar->getStartLocations().size() << \" starting locations\\n\\n\";\n\n        for (auto tp : BWAPI::Broodwar->getStartLocations())\n        {\n            BWAPI::Broodwar->drawCircleMap(BWAPI::Position(tp), 64, BWAPI::Colors::Red, true);\n        }\n    }\n}\n\nBaseLocation * BaseLocationManager::getBaseLocation(const BWAPI::Position & pos) const\n{\n    if (!pos.isValid()) { return nullptr; }\n\n    return m_tileBaseLocations[pos.x / 32][pos.y / 32];\n}\n\nvoid BaseLocationManager::drawBaseLocations()\n{\n    for (auto & baseLocation : m_baseLocationData)\n    {\n        baseLocation.draw();\n    }\n\n    // draw a purple sphere at the next expansion location\n    //BWAPI::TilePosition nextExpansionPosition = getNextExpansion(BWAPI::Broodwar->self());\n\n    //BWAPI::Broodwar->drawCircleMap(BWAPI::Position(nextExpansionPosition), 32, BWAPI::Color(255, 0, 255), true);\n    //BWAPI::Broodwar->drawTextMap(BWAPI::Position(nextExpansionPosition), \"Next Expansion Location\", BWAPI::Color(255, 0, 255));\n}\n\nconst std::vector<const BaseLocation *> & BaseLocationManager::getBaseLocations() const\n{\n    return m_baseLocationPtrs;\n}\n\nconst std::vector<const BaseLocation *> & BaseLocationManager::getStartingBaseLocations() const\n{\n    return m_startingBaseLocations;\n}\n\nconst BaseLocation * BaseLocationManager::getPlayerStartingBaseLocation(BWAPI::Player player) const\n{\n    return m_playerStartingBaseLocations.at(player);\n}\n\nconst std::set<const BaseLocation *> & BaseLocationManager::getOccupiedBaseLocations(BWAPI::Player player) const\n{\n    return m_occupiedBaseLocations.at(player);\n}\n\n\nBWAPI::TilePosition BaseLocationManager::getNextExpansion(BWAPI::Player player) const\n{\n    PROFILE_FUNCTION();\n\n    const BaseLocation * homeBase = getPlayerStartingBaseLocation(player);\n    const BaseLocation * closestBase = nullptr;\n    int minDistance = std::numeric_limits<int>::max();\n\n    BWAPI::TilePosition homeTile(homeBase->getPosition());\n\n    for (auto & base : getBaseLocations())\n    {\n        // skip mineral only and starting locations (TODO: fix this)\n        if (base->isMineralOnly() || base->isStartLocation())\n        {\n            continue;\n        }\n\n        // get the tile position of the base\n        BWAPI::TilePosition tile = base->getDepotPosition();\n\n        bool buildingInTheWay = false; // TODO: check if there are any units on the tile\n\n        if (buildingInTheWay)\n        {\n            continue;\n        }\n\n        // the base's distance from our main nexus\n        int distanceFromHome = homeBase->getGroundDistance(tile);\n\n        // if it is not connected, continue\n        if (distanceFromHome < 0)\n        {\n            continue;\n        }\n\n        if (!closestBase || distanceFromHome < minDistance)\n        {\n            closestBase = base;\n            minDistance = distanceFromHome;\n        }\n    }\n\n    return closestBase ? closestBase->getDepotPosition() : BWAPI::TilePosition(0, 0);\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/BaseLocationManager.h",
    "content": "#pragma once\n\n#include \"BaseLocation.h\"\n#include \"stardraft/BaseBorderFinder.hpp\"\n\nnamespace UAlbertaBot\n{\n\nclass BaseLocationManager\n{\n    friend class Global;\n\n    BaseBorderFinder m_baseBorders;\n\n    std::vector<BaseLocation>                               m_baseLocationData;\n    std::vector<const BaseLocation *>                       m_baseLocationPtrs;\n    std::vector<const BaseLocation *>                       m_startingBaseLocations;\n    std::map<BWAPI::Player, const BaseLocation *>           m_playerStartingBaseLocations;\n    std::map<BWAPI::Player, std::set<const BaseLocation *>> m_occupiedBaseLocations;\n    std::vector<std::vector<BaseLocation *>>                m_tileBaseLocations;\n\n    BaseLocation * getBaseLocation(const BWAPI::Position & pos) const;\n\n    BaseLocationManager();\n\npublic:\n\n    void onStart();\n    void onFrame();\n    void drawBaseLocations();\n\n    BWAPI::Position calcCenter(const std::vector<BWAPI::Unit> & units);\n\n    const std::vector<const BaseLocation *> & getBaseLocations() const;\n    const std::vector<const BaseLocation *> & getStartingBaseLocations() const;\n    const std::set<const BaseLocation *> & getOccupiedBaseLocations(BWAPI::Player player) const;\n    const BaseLocation * getPlayerStartingBaseLocation(BWAPI::Player player) const;\n\n    BWAPI::TilePosition getNextExpansion(BWAPI::Player player) const;\n\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/BuildOrder.cpp",
    "content": "#include \"BuildOrder.h\"\n\nusing namespace UAlbertaBot;\n\nBuildOrder::BuildOrder()\n{\n\n}\n\nBuildOrder::BuildOrder(const BWAPI::Race & race)\n    : m_race(race)\n{\n\n}\n\nBuildOrder::BuildOrder(const BWAPI::Race & race, const std::vector<MetaType> & metaVector)\n    : m_race(race)\n    , m_buildOrder(metaVector)\n{\n\n}\n\nvoid BuildOrder::add(const MetaType & t)\n{\n    UAB_ASSERT(t.getRace() == getRace(), \"Trying to add difference Race metatype to build order\");\n\n    m_buildOrder.push_back(t);\n}\n\nconst BWAPI::Race & BuildOrder::getRace() const\n{\n    return m_race;\n}\n\nconst size_t BuildOrder::size() const\n{\n    return m_buildOrder.size();\n}\n\nconst MetaType & BuildOrder::operator [] (const size_t & index) const\n{\n    return m_buildOrder[index];\n}\n\nMetaType & BuildOrder::operator [] (const size_t & index)\n{\n    return m_buildOrder[index];\n}"
  },
  {
    "path": "UAlbertaBot/Source/BuildOrder.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"MetaType.h\"\n\nnamespace UAlbertaBot\n{\n\nclass BuildOrder\n{\n    BWAPI::Race             m_race = BWAPI::Races::None;\n    std::vector<MetaType>   m_buildOrder;\n\npublic:\n\n    BuildOrder();\n    BuildOrder(const BWAPI::Race & race);\n    BuildOrder(const BWAPI::Race & race, const std::vector<MetaType> & metaVector);\n\n    void add(const MetaType & t);\n\n    const size_t size() const;\n    const BWAPI::Race & getRace() const;\n\n    const MetaType & operator [] (const size_t & index) const;\n    MetaType & operator [] (const size_t & index);\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/BuildOrderQueue.cpp",
    "content": "#include \"BuildOrderQueue.h\"\n\nusing namespace UAlbertaBot;\n\nBuildOrderQueue::BuildOrderQueue()\n{\n\n}\n\nvoid BuildOrderQueue::clearAll()\n{\n    // clear the queue\n    queue.clear();\n\n    // reset the priorities\n    highestPriority = 0;\n    lowestPriority = 0;\n}\n\nBuildOrderItem & BuildOrderQueue::getHighestPriorityItem()\n{\n    // reset the number of skipped items to zero\n    numSkippedItems = 0;\n\n    // the queue will be sorted with the highest priority at the back\n    return queue.back();\n}\n\nBuildOrderItem & BuildOrderQueue::getNextHighestPriorityItem()\n{\n    assert(queue.size() - 1 - numSkippedItems >= 0);\n\n    // the queue will be sorted with the highest priority at the back\n    return queue[queue.size() - 1 - numSkippedItems];\n}\n\nvoid BuildOrderQueue::skipItem()\n{\n    // make sure we can skip\n    assert(canSkipItem());\n\n    // skip it\n    numSkippedItems++;\n}\n\nbool BuildOrderQueue::canSkipItem()\n{\n    // does the queue have more elements\n    bool bigEnough = queue.size() > (size_t)(1 + numSkippedItems);\n\n    if (!bigEnough)\n    {\n        return false;\n    }\n\n    // is the current highest priority item not blocking a skip\n    bool highestNotBlocking = !queue[queue.size() - 1 - numSkippedItems].blocking;\n\n    // this tells us if we can skip\n    return highestNotBlocking;\n}\n\nvoid BuildOrderQueue::queueItem(BuildOrderItem b)\n{\n    // if the queue is empty, set the highest and lowest priorities\n    if (queue.empty())\n    {\n        highestPriority = b.priority;\n        lowestPriority = b.priority;\n    }\n\n    // push the item into the queue\n    if (b.priority <= lowestPriority)\n    {\n        queue.push_front(b);\n    }\n    else\n    {\n        queue.push_back(b);\n    }\n\n    // if the item is somewhere in the middle, we have to sort again\n    if ((queue.size() > 1) && (b.priority < highestPriority) && (b.priority > lowestPriority))\n    {\n        // sort the list in ascending order, putting highest priority at the top\n        std::sort(queue.begin(), queue.end());\n    }\n\n    // update the highest or lowest if it is beaten\n    highestPriority = (b.priority > highestPriority) ? b.priority : highestPriority;\n    lowestPriority  = (b.priority < lowestPriority)  ? b.priority : lowestPriority;\n}\n\nvoid BuildOrderQueue::queueAsHighestPriority(MetaType m, bool blocking, bool gasSteal)\n{\n    // the new priority will be higher\n    int newPriority = highestPriority + defaultPrioritySpacing;\n\n    // queue the item\n    queueItem(BuildOrderItem(m, newPriority, blocking, gasSteal));\n}\n\nvoid BuildOrderQueue::queueAsLowestPriority(MetaType m, bool blocking)\n{\n    // the new priority will be higher\n    int newPriority = lowestPriority - defaultPrioritySpacing;\n\n    // queue the item\n    queueItem(BuildOrderItem(m, newPriority, blocking));\n}\n\nvoid BuildOrderQueue::removeHighestPriorityItem()\n{\n    // remove the back element of the vector\n    queue.pop_back();\n\n    // if the list is not empty, set the highest accordingly\n    highestPriority = queue.empty() ? 0 : queue.back().priority;\n    lowestPriority  = queue.empty() ? 0 : lowestPriority;\n}\n\nvoid BuildOrderQueue::removeCurrentHighestPriorityItem()\n{\n    // remove the back element of the vector\n    queue.erase(queue.begin() + queue.size() - 1 - numSkippedItems);\n\n    //assert((int)(queue.size()) < size);\n\n    // if the list is not empty, set the highest accordingly\n    highestPriority = queue.empty() ? 0 : queue.back().priority;\n    lowestPriority  = queue.empty() ? 0 : lowestPriority;\n}\n\nsize_t BuildOrderQueue::size()\n{\n    return queue.size();\n}\n\nbool BuildOrderQueue::isEmpty()\n{\n    return (queue.size() == 0);\n}\n\nBuildOrderItem BuildOrderQueue::operator [] (int i)\n{\n    return queue[i];\n}\n\nvoid BuildOrderQueue::drawQueueInformation(int x, int y)\n{\n    //x = x + 25;\n\n    if (!Config::Debug::DrawProductionInfo)\n    {\n        return;\n    }\n\n    std::string prefix = \"\\x04\";\n\n    size_t reps = queue.size() < 12 ? queue.size() : 12;\n\n    // for each unit in the queue\n    for (size_t i(0); i<reps; i++) {\n\n        prefix = \"\\x04\";\n\n        const MetaType & type = queue[queue.size() - 1 - i].metaType;\n\n        if (type.isUnit())\n        {\n            if (type.getUnitType().isWorker())\n            {\n                prefix = \"\\x1F\";\n            }\n            else if (type.getUnitType().supplyProvided() > 0)\n            {\n                prefix = \"\\x03\";\n            }\n            else if (type.getUnitType().isRefinery())\n            {\n                prefix = \"\\x1E\";\n            }\n            else if (type.isBuilding())\n            {\n                prefix = \"\\x11\";\n            }\n            else if (type.getUnitType().groundWeapon() != BWAPI::WeaponTypes::None || type.getUnitType().airWeapon() != BWAPI::WeaponTypes::None)\n            {\n                prefix = \"\\x06\";\n            }\n        }\n\n        BWAPI::Broodwar->drawTextScreen(x, y+(i*10), \" %s%s\", prefix.c_str(), type.getName().c_str());\n    }\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/BuildOrderQueue.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"MetaType.h\"\n\nnamespace UAlbertaBot\n{\nstruct BuildOrderItem\n{\n    MetaType metaType;\t\t// the thing we want to 'build'\n    int      priority   = 0;\t// the priority at which to place it in the queue\n    bool     blocking   = false;\t// whether or not we block further items\n    bool     isGasSteal = false;\n\n    BuildOrderItem(MetaType m, int p, bool b, bool gasSteal = false)\n        : metaType(m)\n        , priority(p)\n        , blocking(b)\n        , isGasSteal(gasSteal)\n    {\n    }\n\n    bool operator<(const BuildOrderItem &x) const\n    {\n        return priority < x.priority;\n    }\n};\n\nclass BuildOrderQueue\n{\n    std::deque<BuildOrderItem> queue;\n\n    int lowestPriority          = 0;\n    int highestPriority         = 0;\n    int defaultPrioritySpacing  = 10;\n    int numSkippedItems         = 0;\n\npublic:\n\n    BuildOrderQueue();\n\n    void clearAll();\t\t\t\t\t\t\t\t\t\t\t// clears the entire build order queue\n    void skipItem();\t\t\t\t\t\t\t\t\t\t\t// increments skippedItems\n    void queueAsHighestPriority(MetaType m, bool blocking, bool gasSteal = false);\t\t// queues something at the highest priority\n    void queueAsLowestPriority(MetaType m, bool blocking);\t\t// queues something at the lowest priority\n    void queueItem(BuildOrderItem b);\t\t\t// queues something with a given priority\n    void removeHighestPriorityItem();\t\t\t\t\t\t\t\t// removes the highest priority item\n    void removeCurrentHighestPriorityItem();\n\n    int getHighestPriorityValue();\t\t\t\t\t\t\t\t// returns the highest priority value\n    int\tgetLowestPriorityValue();\t\t\t\t\t\t\t\t// returns the lowest priority value\n    size_t size();\t\t\t\t\t\t\t\t\t\t\t\t\t// returns the size of the queue\n\n    bool isEmpty();\n\n    void removeAll(MetaType m);\t\t\t\t\t\t\t\t\t// removes all matching meta types from queue\n\n    BuildOrderItem & getHighestPriorityItem();\t// returns the highest priority item\n    BuildOrderItem & getNextHighestPriorityItem();\t// returns the highest priority item\n\n    bool canSkipItem();\n    bool hasNextHighestPriorityItem();\t\t\t\t\t\t\t\t// returns the highest priority item\n\n    void drawQueueInformation(int x, int y);\n\n    // overload the bracket operator for ease of use\n    BuildOrderItem operator [] (int i);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/BuildingData.cpp",
    "content": "#include \"BuildingData.h\"\n\nusing namespace UAlbertaBot;\n\nBuildingData::BuildingData()\n{\n\n}\n\nvoid BuildingData::removeBuilding(const Building & b)\n{\n    auto & building = std::find(m_buildings.begin(), m_buildings.end(), b);\n\n    if (building != m_buildings.end())\n    {\n        m_buildings.erase(building);\n    }\n}\n\nstd::vector<Building> & BuildingData::getBuildings()\n{\n    return m_buildings;\n}\n\nvoid BuildingData::addBuilding(const Building & b)\n{\n    m_buildings.push_back(b);\n}\n\nbool BuildingData::isBeingBuilt(BWAPI::UnitType type)\n{\n    for (auto & b : m_buildings)\n    {\n        if (b.type == type)\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid BuildingData::removeBuildings(const std::vector<Building> & buildings)\n{\n    for (const auto & b : buildings)\n    {\n        removeBuilding(b);\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/BuildingData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace UAlbertaBot\n{\n\nnamespace BuildingStatus\n{\n    enum { Unassigned = 0, Assigned = 1, UnderConstruction = 2, Size = 3 };\n}\n\nclass Building \n{     \npublic:\n      \n    BWAPI::TilePosition     desiredPosition     = {0, 0};\n\tBWAPI::TilePosition     finalPosition       = BWAPI::TilePositions::None;\n    BWAPI::Position         position            = {0, 0};\n\tBWAPI::UnitType         type                = BWAPI::UnitTypes::Unknown;\n\tBWAPI::Unit             buildingUnit        = nullptr;\n\tBWAPI::Unit             builderUnit         = nullptr;\n    size_t                  status              = BuildingStatus::Unassigned;\n\tint                     lastOrderFrame      = 0;\n    bool                    isGasSteal          = false;     \n\tbool                    buildCommandGiven   = false;\n\tbool                    underConstruction   = false;\n\n\tBuilding() \n    {\n    } \n\n\t// constructor we use most often\n\tBuilding(BWAPI::UnitType t, BWAPI::TilePosition desired)\n\t\t: desiredPosition   (desired)\n        , type              (t)\n    {\n    }\n\n\t// equals operator\n\tbool operator==(const Building & b) \n    {\n\t\t// buildings are equal if their worker unit or building unit are equal\n\t\treturn (b.buildingUnit == buildingUnit) || (b.builderUnit == builderUnit);\n\t}\n};\n\nclass BuildingData \n{\n    std::vector<Building> m_buildings;\n\npublic:\n\n\tBuildingData();\n\t\n    std::vector<Building> & getBuildings();\n\n\tvoid        addBuilding(const Building & b);\n\tvoid        removeBuilding(const Building & b);\n    void        removeBuildings(const std::vector<Building> & buildings);\n\tbool        isBeingBuilt(BWAPI::UnitType type);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/BuildingManager.cpp",
    "content": "#include \"Common.h\"\n#include \"BuildingManager.h\"\n#include \"Micro.h\"\n#include \"ScoutManager.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n#include \"BuildingData.h\"\n#include \"WorkerManager.h\"\n#include \"BuildingPlacerManager.h\"\n\nusing namespace UAlbertaBot;\n\nBuildingManager::BuildingManager()\n{\n\n}\n\n// gets called every frame from GameCommander\nvoid BuildingManager::update()\n{\n    PROFILE_FUNCTION();\n\n    validateWorkersAndBuildings();          // check to see if assigned workers have died en route or while constructing\n    assignWorkersToUnassignedBuildings();   // assign workers to the unassigned buildings and label them 'planned'    \n    constructAssignedBuildings();           // for each planned building, if the worker isn't constructing, send the command    \n    checkForStartedConstruction();          // check to see if any buildings have started construction and update data structures    \n    checkForDeadTerranBuilders();           // if we are terran and a building is under construction without a worker, assign a new one    \n    checkForCompletedBuildings();           // check to see if any buildings have completed and update data structures\n    \n    drawBuildingInformation(200,50);\n    m_buildingPlacer.drawReservedTiles();\n}\n\nbool BuildingManager::isBeingBuilt(BWAPI::UnitType type)\n{\n    for (auto & b : m_buildings)\n    {\n        if (b.type == type)\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n// STEP 1: DO BOOK KEEPING ON WORKERS WHICH MAY HAVE DIED\nvoid BuildingManager::validateWorkersAndBuildings()\n{\n    PROFILE_FUNCTION();\n\n    // TODO: if a terran worker dies while constructing and its building\n    //       is under construction, place unit back into buildingsNeedingBuilders\n\n    std::vector<Building> toRemove;\n    \n    // find any buildings which have become obsolete\n    for (auto & b : m_buildings)\n    {\n        if (b.status != BuildingStatus::UnderConstruction)\n        {\n            continue;\n        }\n\n        if (b.buildingUnit == nullptr || !b.buildingUnit->getType().isBuilding() || b.buildingUnit->getHitPoints() <= 0)\n        {\n            toRemove.push_back(b);\n        }\n    }\n\n    removeBuildings(toRemove);\n}\n\n// STEP 2: ASSIGN WORKERS TO BUILDINGS WITHOUT THEM\nvoid BuildingManager::assignWorkersToUnassignedBuildings()\n{\n    PROFILE_FUNCTION();\n\n    // for each building that doesn't have a builder, assign one\n    for (Building & b : m_buildings)\n    {\n        if (b.status != BuildingStatus::Unassigned)\n        {\n            continue;\n        }\n\n        if (m_debugMode) { BWAPI::Broodwar->printf(\"Assigning Worker To: %s\",b.type.getName().c_str()); }\n\n        // grab a worker unit from WorkerManager which is closest to this final position\n        BWAPI::Unit workerToAssign = Global::Workers().getBuilder(b);\n\n        if (workerToAssign)\n        {\n            //BWAPI::Broodwar->printf(\"VALID WORKER BEING ASSIGNED: %d\", workerToAssign->getID());\n\n            // TODO: special case of terran building whose worker died mid construction\n            //       send the right click command to the buildingUnit to resume construction\n            //\t\t skip the buildingsAssigned step and push it back into buildingsUnderConstruction\n\n            b.builderUnit = workerToAssign;\n\n            BWAPI::TilePosition testLocation = getBuildingLocation(b);\n            if (!testLocation.isValid())\n            {\n                continue;\n            }\n\n            b.finalPosition = testLocation;\n\n            // reserve this building's space\n            m_buildingPlacer.reserveTiles(b.finalPosition,b.type.tileWidth(),b.type.tileHeight());\n\n            b.status = BuildingStatus::Assigned;\n        }\n    }\n}\n\n// STEP 3: ISSUE CONSTRUCTION ORDERS TO ASSIGN BUILDINGS AS NEEDED\nvoid BuildingManager::constructAssignedBuildings()\n{\n    PROFILE_FUNCTION();\n\n    for (auto & b : m_buildings)\n    {\n        if (b.status != BuildingStatus::Assigned)\n        {\n            continue;\n        }\n\n        // if that worker is not currently constructing\n        if (!b.builderUnit->isConstructing())\n        {\n            // if we haven't explored the build position, go there\n            if (!isBuildingPositionExplored(b))\n            {\n                Micro::SmartMove(b.builderUnit,BWAPI::Position(b.finalPosition));\n            }\n            // if this is not the first time we've sent this guy to build this\n            // it must be the case that something was in the way of building\n            else if (b.buildCommandGiven)\n            {\n                // tell worker manager the unit we had is not needed now, since we might not be able\n                // to get a valid location soon enough\n                Global::Workers().finishedWithWorker(b.builderUnit);\n\n                // free the previous location in reserved\n                m_buildingPlacer.freeTiles(b.finalPosition,b.type.tileWidth(),b.type.tileHeight());\n\n                // nullify its current builder unit\n                b.builderUnit = nullptr;\n\n                // reset the build command given flag\n                b.buildCommandGiven = false;\n\n                // add the building back to be assigned\n                b.status = BuildingStatus::Unassigned;\n            }\n            else\n            {\n                // issue the build order!\n                b.builderUnit->build(b.type,b.finalPosition);\n\n                // set the flag to true\n                b.buildCommandGiven = true;\n            }\n        }\n    }\n}\n\n// STEP 4: UPDATE DATA STRUCTURES FOR BUILDINGS STARTING CONSTRUCTION\nvoid BuildingManager::checkForStartedConstruction()\n{\n    PROFILE_FUNCTION();\n\n    // for each building unit which is being constructed\n    for (auto & buildingStarted : BWAPI::Broodwar->self()->getUnits())\n    {\n        // filter out units which aren't buildings under construction\n        if (!buildingStarted->getType().isBuilding() || !buildingStarted->isBeingConstructed())\n        {\n            continue;\n        }\n\n        // check all our building status objects to see if we have a match and if we do, update it\n        for (auto & b : m_buildings)\n        {\n            if (b.status != BuildingStatus::Assigned)\n            {\n                continue;\n            }\n        \n            // check if the positions match\n            if (b.finalPosition == buildingStarted->getTilePosition())\n            {\n                // the resources should now be spent, so unreserve them\n                m_reservedMinerals -= buildingStarted->getType().mineralPrice();\n                m_reservedGas      -= buildingStarted->getType().gasPrice();\n\n                // flag it as started and set the buildingUnit\n                b.underConstruction = true;\n                b.buildingUnit = buildingStarted;\n\n                // if we are zerg, the buildingUnit now becomes nullptr since it's destroyed\n                if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg)\n                {\n                    b.builderUnit = nullptr;\n                    // if we are protoss, give the worker back to worker manager\n                }\n                else if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Protoss)\n                {\n                    // if this was the gas steal unit then it's the scout worker so give it back to the scout manager\n                    if (b.isGasSteal)\n                    {\n                        Global::Scout().setWorkerScout(b.builderUnit);\n                    }\n                    // otherwise tell the worker manager we're finished with this unit\n                    else\n                    {\n                        Global::Workers().finishedWithWorker(b.builderUnit);\n                    }\n\n                    b.builderUnit = nullptr;\n                }\n\n                // put it in the under construction vector\n                b.status = BuildingStatus::UnderConstruction;\n\n                // free this space\n                m_buildingPlacer.freeTiles(b.finalPosition,b.type.tileWidth(),b.type.tileHeight());\n\n                // only one building will match\n                break;\n            }\n        }\n    }\n}\n\n// STEP 5: IF WE ARE TERRAN, THIS MATTERS, SO: LOL\nvoid BuildingManager::checkForDeadTerranBuilders() {}\n\n// STEP 6: CHECK FOR COMPLETED BUILDINGS\nvoid BuildingManager::checkForCompletedBuildings()\n{\n    PROFILE_FUNCTION();\n\n    std::vector<Building> toRemove;\n\n    // for each of our buildings under construction\n    for (auto & b : m_buildings)\n    {\n        if (b.status != BuildingStatus::UnderConstruction)\n        {\n            continue;       \n        }\n\n        // if the unit has completed\n        if (b.buildingUnit->isCompleted())\n        {\n            // if we are terran, give the worker back to worker manager\n            if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran)\n            {\n                if (b.isGasSteal)\n                {\n                    Global::Scout().setWorkerScout(b.builderUnit);\n                }\n                // otherwise tell the worker manager we're finished with this unit\n                else\n                {\n                    Global::Workers().finishedWithWorker(b.builderUnit);\n                }\n            }\n\n            // remove this unit from the under construction vector\n            toRemove.push_back(b);\n        }\n    }\n\n    removeBuildings(toRemove);\n}\n\n// COMPLETED\nbool BuildingManager::isEvolvedBuilding(BWAPI::UnitType type) \n{\n    if (type == BWAPI::UnitTypes::Zerg_Sunken_Colony ||\n        type == BWAPI::UnitTypes::Zerg_Spore_Colony ||\n        type == BWAPI::UnitTypes::Zerg_Lair ||\n        type == BWAPI::UnitTypes::Zerg_Hive ||\n        type == BWAPI::UnitTypes::Zerg_Greater_Spire)\n    {\n        return true;\n    }\n\n    return false;\n}\n\n// add a new building to be constructed\nvoid BuildingManager::addBuildingTask(BWAPI::UnitType type, BWAPI::TilePosition desiredLocation, bool isGasSteal)\n{\n    m_reservedMinerals += type.mineralPrice();\n    m_reservedGas\t     += type.gasPrice();\n\n    Building b(type, desiredLocation);\n    b.isGasSteal = isGasSteal;\n    b.status = BuildingStatus::Unassigned;\n\n    m_buildings.push_back(b);\n}\n\nbool BuildingManager::isBuildingPositionExplored(const Building & b) const\n{\n    BWAPI::TilePosition tile = b.finalPosition;\n\n    // for each tile where the building will be built\n    for (int x=0; x<b.type.tileWidth(); ++x)\n    {\n        for (int y=0; y<b.type.tileHeight(); ++y)\n        {\n            if (!BWAPI::Broodwar->isExplored(tile.x + x,tile.y + y))\n            {\n                return false;\n            }\n        }\n    }\n\n    return true;\n}\n\n\nchar BuildingManager::getBuildingWorkerCode(const Building & b) const\n{\n    return b.builderUnit == nullptr ? 'X' : 'W';\n}\n\nint BuildingManager::getReservedMinerals() \n{\n    return m_reservedMinerals;\n}\n\nint BuildingManager::getReservedGas() \n{\n    return m_reservedGas;\n}\n\nvoid BuildingManager::drawBuildingInformation(int x,int y)\n{\n    if (!Config::Debug::DrawBuildingInfo)\n    {\n        return;\n    }\n\n    PROFILE_FUNCTION();\n\n    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        BWAPI::Broodwar->drawTextMap(unit->getPosition().x,unit->getPosition().y+5,\"\\x07%d\",unit->getID());\n    }\n\n    BWAPI::Broodwar->drawTextScreen(x,y,\"\\x04 Building Information:\");\n    BWAPI::Broodwar->drawTextScreen(x,y+20,\"\\x04 Name\");\n    BWAPI::Broodwar->drawTextScreen(x+150,y+20,\"\\x04 State\");\n\n    int yspace = 0;\n\n    for (const auto & b : m_buildings)\n    {\n        if (b.status == BuildingStatus::Unassigned)\n        {\n            BWAPI::Broodwar->drawTextScreen(x,y+40+((yspace)*10),\"\\x03 %s\",b.type.getName().c_str());\n            BWAPI::Broodwar->drawTextScreen(x+150,y+40+((yspace++)*10),\"\\x03 Need %c\",getBuildingWorkerCode(b));\n        }\n        else if (b.status == BuildingStatus::Assigned)\n        {\n            BWAPI::Broodwar->drawTextScreen(x,y+40+((yspace)*10),\"\\x03 %s %d\",b.type.getName().c_str(),b.builderUnit->getID());\n            BWAPI::Broodwar->drawTextScreen(x+150,y+40+((yspace++)*10),\"\\x03 A %c (%d,%d)\",getBuildingWorkerCode(b),b.finalPosition.x,b.finalPosition.y);\n\n            int x1 = b.finalPosition.x*32;\n            int y1 = b.finalPosition.y*32;\n            int x2 = (b.finalPosition.x + b.type.tileWidth())*32;\n            int y2 = (b.finalPosition.y + b.type.tileHeight())*32;\n\n            BWAPI::Broodwar->drawLineMap(b.builderUnit->getPosition().x,b.builderUnit->getPosition().y,(x1+x2)/2,(y1+y2)/2,BWAPI::Colors::Orange);\n            BWAPI::Broodwar->drawBoxMap(x1,y1,x2,y2,BWAPI::Colors::Red,false);\n        }\n        else if (b.status == BuildingStatus::UnderConstruction)\n        {\n            BWAPI::Broodwar->drawTextScreen(x,y+40+((yspace)*10),\"\\x03 %s %d\",b.type.getName().c_str(),b.buildingUnit->getID());\n            BWAPI::Broodwar->drawTextScreen(x+150,y+40+((yspace++)*10),\"\\x03 Const %c\",getBuildingWorkerCode(b));\n        }\n    }\n}\n\nstd::vector<BWAPI::UnitType> BuildingManager::buildingsQueued()\n{\n    std::vector<BWAPI::UnitType> buildingsQueued;\n\n    for (const auto & b : m_buildings)\n    {\n        if (b.status == BuildingStatus::Unassigned || b.status == BuildingStatus::Assigned)\n        {\n            buildingsQueued.push_back(b.type);\n        }\n    }\n\n    return buildingsQueued;\n}\n\n\nBWAPI::TilePosition BuildingManager::getBuildingLocation(const Building & b)\n{\n    int numPylons = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Pylon);\n\n    if (b.isGasSteal)\n    {\n\t\tauto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n        UAB_ASSERT(enemyBaseLocation,\"Should have enemy base location before attempting gas steal\");\n        UAB_ASSERT(enemyBaseLocation->getGeysers().size() > 0,\"Should have spotted an enemy geyser\");\n\n        for (auto & unit : enemyBaseLocation->getGeysers())\n        {\n            BWAPI::TilePosition tp(unit->getInitialTilePosition());\n            return tp;\n        }\n    }\n\n    if (b.type.requiresPsi() && numPylons == 0)\n    {\n        return BWAPI::TilePositions::None;\n    }\n\n    if (b.type.isRefinery())\n    {\n        return m_buildingPlacer.getRefineryPosition();\n    }\n\n    if (b.type.isResourceDepot())\n    {\n        // get the location \n\t\tauto tile = Global::Bases().getNextExpansion(BWAPI::Broodwar->self());\n\n        return tile;\n    }\n\n    // set the building padding specifically\n    int distance = b.type == BWAPI::UnitTypes::Protoss_Photon_Cannon ? 0 : Config::Macro::BuildingSpacing;\n    if (b.type == BWAPI::UnitTypes::Protoss_Pylon && (numPylons < 3))\n    {\n        distance = Config::Macro::PylonSpacing;\n    }\n\n    // get a position within our region\n    return m_buildingPlacer.getBuildLocationNear(b,distance,false);\n}\n\nvoid BuildingManager::removeBuildings(const std::vector<Building> & toRemove)\n{\n    for (auto & b : toRemove)\n    {\n        auto & it = std::find(m_buildings.begin(), m_buildings.end(), b);\n\n        if (it != m_buildings.end())\n        {\n            m_buildings.erase(it);\n        }\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/BuildingManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BuildingData.h\"\n#include \"BuildingPlacerManager.h\"\n\nnamespace UAlbertaBot\n{\n\nclass BuildingManager\n{\n    BuildingPlacerManager m_buildingPlacer;\n    std::vector<Building> m_buildings;\n\n    bool m_debugMode        = false;\n    int  m_reservedMinerals = 0;        // minerals reserved for planned buildings\n    int  m_reservedGas      = 0;        // gas reserved for planned buildings\n\n    bool isEvolvedBuilding(BWAPI::UnitType type);\n    bool isBuildingPositionExplored(const Building & b) const;\n    void removeBuildings(const std::vector<Building> & toRemove);\n\n    void validateWorkersAndBuildings();\t\t    // STEP 1\n    void assignWorkersToUnassignedBuildings();\t// STEP 2\n    void constructAssignedBuildings();\t\t\t// STEP 3\n    void checkForStartedConstruction();\t\t\t// STEP 4\n    void checkForDeadTerranBuilders();\t\t\t// STEP 5\n    void checkForCompletedBuildings();\t\t\t// STEP 6\n\n    char getBuildingWorkerCode(const Building & b) const;\n    \n\npublic:\n    \n    BuildingManager();\n\n    void update();\n    void addBuildingTask(BWAPI::UnitType type,BWAPI::TilePosition desiredLocation,bool isGasSteal);\n    void drawBuildingInformation(int x,int y);\n    int  getReservedMinerals();\n    int  getReservedGas();\n    bool isBeingBuilt(BWAPI::UnitType type);\n\n    BWAPI::TilePosition getBuildingLocation(const Building & b);\n    std::vector<BWAPI::UnitType> buildingsQueued();\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/BuildingPlacerManager.cpp",
    "content": "#include \"Common.h\"\n#include \"BuildingPlacerManager.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n#include \"BuildingData.h\"\n#include \"Global.h\"\n#include \"MapTools.h\"\n\nusing namespace UAlbertaBot;\n\nBuildingPlacerManager::BuildingPlacerManager()\n{\n    m_reserveMap = Grid<int>(BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight(), 0);\n\n    computeResourceBox();\n}\n\nbool BuildingPlacerManager::isInResourceBox(int x, int y) const\n{\n    int posX(x * 32);\n    int posY(y * 32);\n\n    return (posX >= m_boxLeft) && (posX < m_boxRight) && (posY >= m_boxTop) && (posY < m_boxBottom);\n}\n\nvoid BuildingPlacerManager::computeResourceBox()\n{\n    PROFILE_FUNCTION();\n\n    BWAPI::Position start(BWAPI::Broodwar->self()->getStartLocation());\n    BWAPI::Unitset unitsAroundNexus;\n\n    for (auto & unit : BWAPI::Broodwar->getAllUnits())\n    {\n        // if the units are less than 400 away add them if they are resources\n        if (unit->getDistance(start) < 300 && unit->getType().isMineralField())\n        {\n            unitsAroundNexus.insert(unit);\n        }\n    }\n\n    for (auto & unit : unitsAroundNexus)\n    {\n        int x = unit->getPosition().x;\n        int y = unit->getPosition().y;\n\n        int left = x - unit->getType().dimensionLeft();\n        int right = x + unit->getType().dimensionRight() + 1;\n        int top = y - unit->getType().dimensionUp();\n        int bottom = y + unit->getType().dimensionDown() + 1;\n\n        m_boxTop     = top < m_boxTop       ? top    : m_boxTop;\n        m_boxBottom  = bottom > m_boxBottom ? bottom : m_boxBottom;\n        m_boxLeft    = left < m_boxLeft     ? left   : m_boxLeft;\n        m_boxRight   = right > m_boxRight   ? right  : m_boxRight;\n    }\n\n    //BWAPI::Broodwar->printf(\"%d %d %d %d\", boxTop, boxBottom, boxLeft, boxRight);\n}\n\n// makes final checks to see if a building can be built at a certain location\nbool BuildingPlacerManager::canBuildHere(BWAPI::TilePosition position, const Building & b) const\n{\n    /*if (!b.type.isRefinery() && !Global::Info().tileContainsUnit(position))\n    {\n    return false;\n    }*/\n\n    //returns true if we can build this type of unit here. Takes into account reserved tiles.\n    if (!BWAPI::Broodwar->canBuildHere(position, b.type, b.builderUnit))\n    {\n        return false;\n    }\n\n    // check the reserve map\n    for (int x = position.x; x < position.x + b.type.tileWidth(); x++)\n    {\n        for (int y = position.y; y < position.y + b.type.tileHeight(); y++)\n        {\n            if (m_reserveMap.get(x, y) == 1)\n            {\n                return false;\n            }\n        }\n    }\n\n    // if it overlaps a base location return false\n    if (tileOverlapsBaseLocation(position, b.type))\n    {\n        return false;\n    }\n\n    return true;\n}\n\nbool BuildingPlacerManager::tileBlocksAddon(BWAPI::TilePosition position) const\n{\n\n    for (int i=0; i<=2; ++i)\n    {\n        for (auto & unit : BWAPI::Broodwar->getUnitsOnTile(position.x - i, position.y))\n        {\n            if (unit->getType() == BWAPI::UnitTypes::Terran_Command_Center ||\n                unit->getType() == BWAPI::UnitTypes::Terran_Factory ||\n                unit->getType() == BWAPI::UnitTypes::Terran_Starport ||\n                unit->getType() == BWAPI::UnitTypes::Terran_Science_Facility)\n            {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\n//returns true if we can build this type of unit here with the specified amount of space.\n//space value is stored in this->buildDistance.\nbool BuildingPlacerManager::canBuildHereWithSpace(BWAPI::TilePosition position, const Building & b, int buildDist, bool horizontalOnly) const\n{\n    PROFILE_FUNCTION();\n\n    BWAPI::UnitType type = b.type;\n\n    //if we can't build here, we of course can't build here with space\n    if (!canBuildHere(position, b))\n    {\n        return false;\n    }\n\n    // height and width of the building\n    int width(b.type.tileWidth());\n    int height(b.type.tileHeight());\n\n    //make sure we leave space for add-ons. These types of units can have addons:\n    if (b.type==BWAPI::UnitTypes::Terran_Command_Center ||\n        b.type==BWAPI::UnitTypes::Terran_Factory ||\n        b.type==BWAPI::UnitTypes::Terran_Starport ||\n        b.type==BWAPI::UnitTypes::Terran_Science_Facility)\n    {\n        width += 2;\n    }\n\n    // define the rectangle of the building spot\n    int startx = position.x - buildDist;\n    int starty = position.y - buildDist;\n    int endx   = position.x + width + buildDist;\n    int endy   = position.y + height + buildDist;\n\n    if (b.type.isAddon())\n    {\n        const BWAPI::UnitType builderType = type.whatBuilds().first;\n\n        BWAPI::TilePosition builderTile(position.x - builderType.tileWidth(), position.y + 2 - builderType.tileHeight());\n\n        startx = builderTile.x - buildDist;\n        starty = builderTile.y - buildDist;\n        endx = position.x + width + buildDist;\n        endy = position.y + height + buildDist;\n    }\n\n    if (horizontalOnly)\n    {\n        starty += buildDist;\n        endy -= buildDist;\n    }\n\n    // if this rectangle doesn't fit on the map we can't build here\n    if (startx < 0 || starty < 0 || endx > BWAPI::Broodwar->mapWidth() || endx < position.x + width || endy > BWAPI::Broodwar->mapHeight())\n    {\n        return false;\n    }\n\n    // if we can't build here, or space is reserved, or it's in the resource box, we can't build here\n    for (int x = startx; x < endx; x++)\n    {\n        for (int y = starty; y < endy; y++)\n        {\n            if (!b.type.isRefinery())\n            {\n                if (!buildable(b, x, y) || m_reserveMap.get(x, y) || ((b.type != BWAPI::UnitTypes::Protoss_Photon_Cannon) && isInResourceBox(x, y)))\n                {\n                    return false;\n                }\n            }\n        }\n    }\n\n    return true;\n}\n\nBWAPI::TilePosition BuildingPlacerManager::GetBuildLocation(const Building & b, int padding) const\n{\n    return BWAPI::TilePosition(0, 0);\n}\n\nBWAPI::TilePosition BuildingPlacerManager::getBuildLocationNear(const Building & b, int buildDist, bool horizontalOnly) const\n{\n    PROFILE_FUNCTION();\n\n    // get the precomputed vector of tile positions which are sorted closes to this location\n    const std::vector<BWAPI::TilePosition> & closestToBuilding = Global::Map().getClosestTilesTo(b.desiredPosition);\n\n    // special easy case of having no pylons\n    int numPylons = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Pylon);\n    if (b.type.requiresPsi() && numPylons == 0)\n    {\n        return BWAPI::TilePositions::None;\n    }\n\n    // iterate through the list until we've found a suitable location\n    for (size_t i(0); i < closestToBuilding.size(); ++i)\n    {\n        if (canBuildHereWithSpace(closestToBuilding[i], b, buildDist, horizontalOnly))\n        {\n            //BWAPI::Broodwar->printf(\"Building Placer Took %d iterations, lasting %lf ms @ %lf iterations/ms, %lf setup ms\", i, ms, (i / ms), ms1);\n\n            return closestToBuilding[i];\n        }\n    }\n\n    return  BWAPI::TilePositions::None;\n}\n\nbool BuildingPlacerManager::tileOverlapsBaseLocation(BWAPI::TilePosition tile, BWAPI::UnitType type) const\n{\n    // if it's a resource depot we don't care if it overlaps\n    if (type.isResourceDepot())\n    {\n        return false;\n    }\n\n    // dimensions of the proposed location\n    int tx1 = tile.x;\n    int ty1 = tile.y;\n    int tx2 = tx1 + type.tileWidth();\n    int ty2 = ty1 + type.tileHeight();\n\n    // for each base location\n    for (auto base : Global::Bases().getBaseLocations())\n    {\n        // dimensions of the base location\n        int bx1 = base->getDepotPosition().x;\n        int by1 = base->getDepotPosition().y;\n        int bx2 = bx1 + BWAPI::Broodwar->self()->getRace().getResourceDepot().tileWidth();\n        int by2 = by1 + BWAPI::Broodwar->self()->getRace().getResourceDepot().tileHeight();\n\n        // conditions for non-overlap are easy\n        bool noOverlap = (tx2 < bx1) || (tx1 > bx2) || (ty2 < by1) || (ty1 > by2);\n\n        // if the reverse is true, return true\n        if (!noOverlap)\n        {\n            return true;\n        }\n    }\n\n    // otherwise there is no overlap\n    return false;\n}\n\nbool BuildingPlacerManager::buildable(const Building & b, int x, int y) const\n{\n    BWAPI::TilePosition tp(x, y);\n\n    //returns true if this tile is currently buildable, takes into account units on tile\n    if (!BWAPI::Broodwar->isBuildable(x, y))\n    {\n        return false;\n    }\n\n    if ((BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran) && tileBlocksAddon(BWAPI::TilePosition(x, y)))\n    {\n        return false;\n    }\n\n    for (auto & unit : BWAPI::Broodwar->getUnitsOnTile(x, y))\n    {\n        if ((b.builderUnit != nullptr) && (unit != b.builderUnit))\n        {\n            return false;\n        }\n    }\n\n    if (!tp.isValid())\n    {\n        return false;\n    }\n\n    return true;\n}\n\nvoid BuildingPlacerManager::reserveTiles(BWAPI::TilePosition position, int width, int height)\n{\n    for (int x = position.x; x < position.x + width && x < (int)m_reserveMap.width(); x++)\n    {\n        for (int y = position.y; y < position.y + height && y < (int)m_reserveMap.height(); y++)\n        {\n            m_reserveMap.set(x, y, 1);\n        }\n    }\n}\n\nvoid BuildingPlacerManager::drawReservedTiles()\n{\n    if (!Config::Debug::DrawReservedBuildingTiles)\n    {\n        return;\n    }\n\n    PROFILE_FUNCTION();\n\n    for (int x = 0; x < (int)m_reserveMap.width(); ++x)\n    {\n        for (int y = 0; y < (int)m_reserveMap.height(); ++y)\n        {\n            if (m_reserveMap.get(x, y) || isInResourceBox(x, y))\n            {\n                int x1 = x*32 + 8;\n                int y1 = y*32 + 8;\n                int x2 = (x+1)*32 - 8;\n                int y2 = (y+1)*32 - 8;\n\n                BWAPI::Broodwar->drawBoxMap(x1, y1, x2, y2, BWAPI::Colors::Yellow, false);\n            }\n        }\n    }\n}\n\nvoid BuildingPlacerManager::freeTiles(BWAPI::TilePosition position, int width, int height)\n{\n    for (int x = position.x; x < position.x + width && x < (int)m_reserveMap.width(); x++)\n    {\n        for (int y = position.y; y < position.y + height && y < (int)m_reserveMap.height(); y++)\n        {\n            m_reserveMap.set(x, y, 0);\n        }\n    }\n}\n\nBWAPI::TilePosition BuildingPlacerManager::getRefineryPosition()\n{\n    BWAPI::TilePosition closestGeyser = BWAPI::TilePositions::None;\n    double minGeyserDistanceFromHome = std::numeric_limits<double>::max();\n    BWAPI::Position homePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n\n    // for each geyser\n    for (auto & geyser : BWAPI::Broodwar->getStaticGeysers())\n    {\n        if (geyser->getType() != BWAPI::UnitTypes::Resource_Vespene_Geyser)\n        {\n            continue;\n        }\n\n        BWAPI::Position geyserPos = geyser->getInitialPosition();\n        BWAPI::TilePosition geyserTilePos = geyser->getInitialTilePosition();\n\n        // check to see if it's next to one of our depots\n        bool nearDepot = false;\n        for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n        {\n            if (unit->getType().isResourceDepot() && unit->getDistance(geyserPos) < 300)\n            {\n                nearDepot = true;\n            }\n        }\n\n        if (nearDepot)\n        {\n            double homeDistance = geyser->getDistance(homePosition);\n\n            if (homeDistance < minGeyserDistanceFromHome)\n            {\n                minGeyserDistanceFromHome = homeDistance;\n                closestGeyser = geyser->getInitialTilePosition();\n            }\n        }\n    }\n\n    return closestGeyser;\n}\n\nbool BuildingPlacerManager::isReserved(int x, int y) const\n{\n    if (x < 0 || y < 0 || x >= (int)m_reserveMap.width() || y >= (int)m_reserveMap.height())\n    {\n        return false;\n    }\n\n    return m_reserveMap.get(x, y);\n}\n\n"
  },
  {
    "path": "UAlbertaBot/Source/BuildingPlacerManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Grid.hpp\"\n\nnamespace UAlbertaBot\n{\n\nclass Building;\nclass BuildingPlacerManager\n{\n    Grid<int> m_reserveMap;\n\n    int m_boxTop     = std::numeric_limits<int>::max();\n    int m_boxBottom  = std::numeric_limits<int>::lowest();\n    int m_boxLeft    = std::numeric_limits<int>::max();\n    int m_boxRight   = std::numeric_limits<int>::lowest();\n\npublic:\n    \n    BuildingPlacerManager();\n\n    // queries for various BuildingPlacer data\n    bool buildable(const Building & b,int x,int y) const;\n    bool isReserved(int x,int y) const;\n    bool isInResourceBox(int x,int y) const;\n    bool tileOverlapsBaseLocation(BWAPI::TilePosition tile,BWAPI::UnitType type) const;\n    bool tileBlocksAddon(BWAPI::TilePosition position) const;\n\n    BWAPI::TilePosition GetBuildLocation(const Building & b,int padding) const;\n\n    // determines whether we can build at a given location\n    bool canBuildHere(BWAPI::TilePosition position,const Building & b) const;\n    bool canBuildHereWithSpace(BWAPI::TilePosition position,const Building & b,int buildDist,bool horizontalOnly = false) const;\n\n    // returns a build location near a building's desired location\n    BWAPI::TilePosition getBuildLocationNear(const Building & b,int buildDist,bool horizontalOnly = false) const;\n\n    void reserveTiles(BWAPI::TilePosition position,int width,int height);\n    void freeTiles(BWAPI::TilePosition position,int width,int height);\n\n    void drawReservedTiles();\n    void computeResourceBox();\n\n    BWAPI::TilePosition getRefineryPosition();\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/CombatCommander.cpp",
    "content": "#include \"CombatCommander.h\"\n#include \"UnitUtil.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n#include \"WorkerManager.h\"\n#include \"UnitData.h\"\n#include \"MapTools.h\"\n#include \"InformationManager.h\"\n#include \"StrategyManager.h\"\n#include \"Squad.h\"\n#include \"SquadData.h\"\n\nusing namespace UAlbertaBot;\n\nconst size_t IdlePriority = 0;\nconst size_t AttackPriority = 1;\nconst size_t BaseDefensePriority = 2;\nconst size_t ScoutDefensePriority = 3;\nconst size_t DropPriority = 4;\n\nCombatCommander::CombatCommander()\n{\n\n}\n\nvoid CombatCommander::initializeSquads()\n{\n    SquadOrder idleOrder(SquadOrderTypes::Idle, BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()), 100, \"Chill Out\");\n    m_squadData.addSquad(\"Idle\", Squad(\"Idle\", idleOrder, IdlePriority));\n\n    // the main attack squad that will pressure the enemy's closest base location\n    SquadOrder mainAttackOrder(SquadOrderTypes::Attack, getMainAttackLocation(), 800, \"Attack Enemy Base\");\n    m_squadData.addSquad(\"MainAttack\", Squad(\"MainAttack\", mainAttackOrder, AttackPriority));\n\n    BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n\n    // the scout defense squad will handle chasing the enemy worker scout\n    SquadOrder enemyScoutDefense(SquadOrderTypes::Defend, ourBasePosition, 900, \"Get the scout\");\n    m_squadData.addSquad(\"ScoutDefense\", Squad(\"ScoutDefense\", enemyScoutDefense, ScoutDefensePriority));\n\n    // add a drop squad if we are using a drop strategy\n    if (Config::Strategy::StrategyName == \"Protoss_Drop\")\n    {\n        SquadOrder zealotDrop(SquadOrderTypes::Drop, ourBasePosition, 900, \"Wait for transport\");\n        m_squadData.addSquad(\"Drop\", Squad(\"Drop\", zealotDrop, DropPriority));\n    }\n\n    m_initialized = true;\n}\n\nbool CombatCommander::isSquadUpdateFrame()\n{\n    return BWAPI::Broodwar->getFrameCount() % 10 == 0;\n}\n\nvoid CombatCommander::update(const BWAPI::Unitset & combatUnits)\n{\n    PROFILE_FUNCTION();\n\n    if (!Config::Modules::UsingCombatCommander)\n    {\n        return;\n    }\n\n    if (!m_initialized)\n    {\n        initializeSquads();\n    }\n\n    m_combatUnits = combatUnits;\n\n\n    if (isSquadUpdateFrame())\n    {\n        updateIdleSquad();\n        updateDropSquads();\n        updateScoutDefenseSquad();\n        updateDefenseSquads();\n        updateAttackSquads();\n    }\n\n    m_squadData.update();\n}\n\nvoid CombatCommander::updateIdleSquad()\n{\n    Squad & idleSquad = m_squadData.getSquad(\"Idle\");\n    for (auto & unit : m_combatUnits)\n    {\n        // if it hasn't been assigned to a squad yet, put it in the low priority idle squad\n        if (m_squadData.canAssignUnitToSquad(unit, idleSquad))\n        {\n            idleSquad.addUnit(unit);\n        }\n    }\n}\n\nvoid CombatCommander::updateAttackSquads()\n{\n    Squad & mainAttackSquad = m_squadData.getSquad(\"MainAttack\");\n\n    for (auto & unit : m_combatUnits)\n    {\n        if (unit->getType() == BWAPI::UnitTypes::Zerg_Scourge && UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hydralisk) < 30)\n        {\n            continue;\n        }\n\n        // get every unit of a lower priority and put it into the attack squad\n        if (!unit->getType().isWorker() && (unit->getType() != BWAPI::UnitTypes::Zerg_Overlord) && m_squadData.canAssignUnitToSquad(unit, mainAttackSquad))\n        {\n            m_squadData.assignUnitToSquad(unit, mainAttackSquad);\n        }\n    }\n\n    SquadOrder mainAttackOrder(SquadOrderTypes::Attack, getMainAttackLocation(), 800, \"Attack Enemy Base\");\n    mainAttackSquad.setSquadOrder(mainAttackOrder);\n}\n\nvoid CombatCommander::updateDropSquads()\n{\n    if (Config::Strategy::StrategyName != \"Protoss_Drop\")\n    {\n        return;\n    }\n\n    Squad & dropSquad = m_squadData.getSquad(\"Drop\");\n\n    // figure out how many units the drop squad needs\n    bool dropSquadHasTransport = false;\n    int transportSpotsRemaining = 8;\n    auto & dropUnits = dropSquad.getUnits();\n\n    for (auto & unit : dropUnits)\n    {\n        if (unit->isFlying() && unit->getType().spaceProvided() > 0)\n        {\n            dropSquadHasTransport = true;\n        }\n        else\n        {\n            transportSpotsRemaining -= unit->getType().spaceRequired();\n        }\n    }\n\n    // if there are still units to be added to the drop squad, do it\n    if (transportSpotsRemaining > 0 || !dropSquadHasTransport)\n    {\n        // take our first amount of combat units that fill up a transport and add them to the drop squad\n        for (auto & unit : m_combatUnits)\n        {\n            // if this is a transport unit and we don't have one in the squad yet, add it\n            if (!dropSquadHasTransport && (unit->getType().spaceProvided() > 0 && unit->isFlying()))\n            {\n                m_squadData.assignUnitToSquad(unit, dropSquad);\n                dropSquadHasTransport = true;\n                continue;\n            }\n\n            if (unit->getType().spaceRequired() > transportSpotsRemaining)\n            {\n                continue;\n            }\n\n            // get every unit of a lower priority and put it into the attack squad\n            if (!unit->getType().isWorker() && m_squadData.canAssignUnitToSquad(unit, dropSquad))\n            {\n                m_squadData.assignUnitToSquad(unit, dropSquad);\n                transportSpotsRemaining -= unit->getType().spaceRequired();\n            }\n        }\n    }\n    // otherwise the drop squad is full, so execute the order\n    else\n    {\n        SquadOrder dropOrder(SquadOrderTypes::Drop, getMainAttackLocation(), 800, \"Attack Enemy Base\");\n        dropSquad.setSquadOrder(dropOrder);\n    }\n}\n\nvoid CombatCommander::updateScoutDefenseSquad()\n{\n    if (m_combatUnits.empty())\n    {\n        return;\n    }\n\n    // if the current squad has units in it then we can ignore this\n    Squad & scoutDefenseSquad = m_squadData.getSquad(\"ScoutDefense\");\n\n    // get the region that our base is located in\n\n    auto myBase = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->self());\n\n    // get all of the enemy units in this region\n    BWAPI::Unitset enemyUnitsInRegion;\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        if (myBase->containsPosition(unit->getPosition()))\n        {\n            enemyUnitsInRegion.insert(unit);\n        }\n    }\n\n    // if there's an enemy worker in our region then assign someone to chase him\n    bool assignScoutDefender = enemyUnitsInRegion.size() == 1 && (*enemyUnitsInRegion.begin())->getType().isWorker();\n\n    // if our current squad is empty and we should assign a worker, do it\n    if (scoutDefenseSquad.isEmpty() && assignScoutDefender)\n    {\n        // the enemy worker that is attacking us\n        BWAPI::Unit enemyWorker = *enemyUnitsInRegion.begin();\n\n        // get our worker unit that is mining that is closest to it\n        BWAPI::Unit workerDefender = findClosestWorkerToTarget(m_combatUnits, enemyWorker);\n\n        if (enemyWorker && workerDefender)\n        {\n            // grab it from the worker manager and put it in the squad\n            if (m_squadData.canAssignUnitToSquad(workerDefender, scoutDefenseSquad))\n            {\n                Global::Workers().setCombatWorker(workerDefender);\n                m_squadData.assignUnitToSquad(workerDefender, scoutDefenseSquad);\n            }\n        }\n    }\n    // if our squad is not empty and we shouldn't have a worker chasing then take him out of the squad\n    else if (!scoutDefenseSquad.isEmpty() && !assignScoutDefender)\n    {\n        for (auto & unit : scoutDefenseSquad.getUnits())\n        {\n            unit->stop();\n            if (unit->getType().isWorker())\n            {\n                Global::Workers().finishedWithWorker(unit);\n            }\n        }\n\n        scoutDefenseSquad.clear();\n    }\n}\n\nvoid CombatCommander::updateDefenseSquads()\n{\n    if (m_combatUnits.empty())\n    {\n        return;\n    }\n\n    // for each of our occupied regions\n    const BaseLocation * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n    for (const BaseLocation * myBaseLocation : Global::Bases().getOccupiedBaseLocations(BWAPI::Broodwar->self()))\n    {\n        // don't defend inside the enemy region, this will end badly when we are stealing gas or cannon rushing\n        if (myBaseLocation == enemyBaseLocation)\n        {\n            continue;\n        }\n\n        BWAPI::Position basePosition = myBaseLocation->getPosition();\n\n        // start off assuming all enemy units in region are just workers\n        int numDefendersPerEnemyUnit = 2;\n\n        // all of the enemy units in this region\n        std::vector<BWAPI::Unit> enemyUnitsInRegion;\n        for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n        {\n            // if it's an overlord, don't worry about it for defense, we don't care what they see\n            if (unit->getType() == BWAPI::UnitTypes::Zerg_Overlord)\n            {\n                continue;\n            }\n\n            if (myBaseLocation->containsPosition(unit->getPosition()))\n            {\n                enemyUnitsInRegion.push_back(unit);\n            }\n        }\n\n        // we can ignore the first enemy worker in our region since we assume it is a scout\n        for (auto unit : enemyUnitsInRegion)\n        {\n            if (unit->getType().isWorker())\n            {\n                enemyUnitsInRegion.erase(std::remove(enemyUnitsInRegion.begin(), enemyUnitsInRegion.end(), unit), enemyUnitsInRegion.end());\n                break;\n            }\n        }\n\n        // calculate how many units are flying / ground units\n        int numEnemyFlyingInRegion = 0;\n        int numEnemyGroundInRegion = 0;\n        for (auto & unit : enemyUnitsInRegion)\n        {\n            if (unit->isFlying())\n            {\n                numEnemyFlyingInRegion++;\n            }\n            else\n            {\n                numEnemyGroundInRegion++;\n            }\n        }\n\n\n        std::stringstream squadName;\n        squadName << \"Base Defense \" << basePosition.x << \" \" << basePosition.y;\n\n        // if there's nothing in this region to worry about\n        if (enemyUnitsInRegion.empty())\n        {\n            // if a defense squad for this region exists, remove it\n            if (m_squadData.squadExists(squadName.str()))\n            {\n                m_squadData.getSquad(squadName.str()).clear();\n            }\n\n            // and return, nothing to defend here\n            continue;\n        }\n        else\n        {\n            // if we don't have a squad assigned to this region already, create one\n            if (!m_squadData.squadExists(squadName.str()))\n            {\n                SquadOrder defendRegion(SquadOrderTypes::Defend, basePosition, 32 * 25, \"Defend Region!\");\n                m_squadData.addSquad(squadName.str(), Squad(squadName.str(), defendRegion, BaseDefensePriority));\n            }\n        }\n\n        // assign units to the squad\n        if (m_squadData.squadExists(squadName.str()))\n        {\n            Squad & defenseSquad = m_squadData.getSquad(squadName.str());\n\n            // figure out how many units we need on defense\n            int flyingDefendersNeeded = numDefendersPerEnemyUnit * numEnemyFlyingInRegion;\n            int groundDefensersNeeded = numDefendersPerEnemyUnit * numEnemyGroundInRegion;\n\n            updateDefenseSquadUnits(defenseSquad, flyingDefendersNeeded, groundDefensersNeeded);\n        }\n        else\n        {\n            UAB_ASSERT(false, \"Squad should have existed: %s\", squadName.str().c_str());\n        }\n    }\n\n    // for each of our defense squads, if there aren't any enemy units near the position, remove the squad\n    std::set<std::string> uselessDefenseSquads;\n    for (const auto & kv : m_squadData.getSquads())\n    {\n        const Squad & squad = kv.second;\n        const SquadOrder & order = squad.getSquadOrder();\n\n        if (order.getType() != SquadOrderTypes::Defend)\n        {\n            continue;\n        }\n\n        bool enemyUnitInRange = false;\n        for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n        {\n            if (unit->getDistance(order.getPosition()) < order.getRadius())\n            {\n                enemyUnitInRange = true;\n                break;\n            }\n        }\n\n        if (!enemyUnitInRange)\n        {\n            m_squadData.getSquad(squad.getName()).clear();\n        }\n    }\n}\n\nvoid CombatCommander::updateDefenseSquadUnits(Squad & defenseSquad, const size_t & flyingDefendersNeeded, const size_t & groundDefendersNeeded)\n{\n    const BWAPI::Unitset & squadUnits = defenseSquad.getUnits();\n    size_t flyingDefendersInSquad = std::count_if(squadUnits.begin(), squadUnits.end(), UnitUtil::CanAttackAir);\n    size_t groundDefendersInSquad = std::count_if(squadUnits.begin(), squadUnits.end(), UnitUtil::CanAttackGround);\n\n    // if there's nothing left to defend, clear the squad\n    if (flyingDefendersNeeded == 0 && groundDefendersNeeded == 0)\n    {\n        defenseSquad.clear();\n        return;\n    }\n\n    // add flying defenders if we still need them\n    size_t flyingDefendersAdded = 0;\n    while (flyingDefendersNeeded > flyingDefendersInSquad + flyingDefendersAdded)\n    {\n        BWAPI::Unit defenderToAdd = findClosestDefender(defenseSquad, defenseSquad.getSquadOrder().getPosition(), true);\n\n        // if we find a valid flying defender, add it to the squad\n        if (defenderToAdd)\n        {\n            m_squadData.assignUnitToSquad(defenderToAdd, defenseSquad);\n            ++flyingDefendersAdded;\n        }\n        // otherwise we'll never find another one so break out of this loop\n        else\n        {\n            break;\n        }\n    }\n\n    // add ground defenders if we still need them\n    size_t groundDefendersAdded = 0;\n    while (groundDefendersNeeded > groundDefendersInSquad + groundDefendersAdded)\n    {\n        BWAPI::Unit defenderToAdd = findClosestDefender(defenseSquad, defenseSquad.getSquadOrder().getPosition(), false);\n\n        // if we find a valid ground defender add it\n        if (defenderToAdd)\n        {\n            m_squadData.assignUnitToSquad(defenderToAdd, defenseSquad);\n            ++groundDefendersAdded;\n        }\n        // otherwise we'll never find another one so break out of this loop\n        else\n        {\n            break;\n        }\n    }\n}\n\nBWAPI::Unit CombatCommander::findClosestDefender(const Squad & defenseSquad, BWAPI::Position pos, bool flyingDefender)\n{\n    BWAPI::Unit closestDefender = nullptr;\n    double minDistance = std::numeric_limits<double>::max();\n\n    int zerglingsInOurBase = numZerglingsInOurBase();\n    bool zerglingRush = zerglingsInOurBase > 0 && BWAPI::Broodwar->getFrameCount() < 5000;\n\n    for (auto & unit : m_combatUnits)\n    {\n        if ((flyingDefender && !UnitUtil::CanAttackAir(unit)) || (!flyingDefender && !UnitUtil::CanAttackGround(unit)))\n        {\n            continue;\n        }\n\n        if (!m_squadData.canAssignUnitToSquad(unit, defenseSquad))\n        {\n            continue;\n        }\n\n        // add workers to the defense squad if we are being rushed very quickly\n        if (!Config::Micro::WorkersDefendRush || (unit->getType().isWorker() && !zerglingRush && !beingBuildingRushed()))\n        {\n            continue;\n        }\n\n        double dist = unit->getDistance(pos);\n        if (!closestDefender || (dist < minDistance))\n        {\n            closestDefender = unit;\n            minDistance = dist;\n        }\n    }\n\n    return closestDefender;\n}\n\nBWAPI::Position CombatCommander::getDefendLocation()\n{\n    return BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n}\n\nvoid CombatCommander::drawSquadInformation(int x, int y)\n{\n    m_squadData.drawSquadInformation(x, y);\n}\n\nBWAPI::Position CombatCommander::getMainAttackLocation()\n{\n    const BaseLocation * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n\n    // First choice: Attack an enemy region if we can see units inside it\n    if (enemyBaseLocation)\n    {\n        BWAPI::Position enemyBasePosition = enemyBaseLocation->getPosition();\n\n        // get all known enemy units in the area\n        BWAPI::Unitset enemyUnitsInArea;\n        Global::Map().getUnits(enemyUnitsInArea, enemyBasePosition, 800, false, true);\n\n        bool onlyOverlords = true;\n        for (auto & unit : enemyUnitsInArea)\n        {\n            if (unit->getType() != BWAPI::UnitTypes::Zerg_Overlord)\n            {\n                onlyOverlords = false;\n            }\n        }\n\n        if (!BWAPI::Broodwar->isExplored(BWAPI::TilePosition(enemyBasePosition)) || !enemyUnitsInArea.empty())\n        {\n            if (!onlyOverlords)\n            {\n                return enemyBaseLocation->getPosition();\n            }\n        }\n    }\n\n    // Second choice: Attack known enemy buildings\n    for (const auto & kv : Global::Info().getUnitInfo(BWAPI::Broodwar->enemy()))\n    {\n        const UnitInfo & ui = kv.second;\n\n        if (ui.type.isBuilding() && ui.lastPosition != BWAPI::Positions::None)\n        {\n            return ui.lastPosition;\n        }\n    }\n\n    // Third choice: Attack visible enemy units that aren't overlords\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        if (unit->getType() == BWAPI::UnitTypes::Zerg_Overlord)\n        {\n            continue;\n        }\n\n        if (UnitUtil::IsValidUnit(unit) && unit->isVisible())\n        {\n            return unit->getPosition();\n        }\n    }\n\n    // Fourth choice: We can't see anything so explore the map attacking along the way\n    return BWAPI::Position(Global::Map().getLeastRecentlySeenTile());\n}\n\nBWAPI::Unit CombatCommander::findClosestWorkerToTarget(BWAPI::Unitset & unitsToAssign, BWAPI::Unit target)\n{\n    UAB_ASSERT(target != nullptr, \"target was null\");\n\n    if (!target)\n    {\n        return nullptr;\n    }\n\n    BWAPI::Unit closestMineralWorker = nullptr;\n    double closestDist = 100000;\n\n    // for each of our workers\n    for (auto & unit : unitsToAssign)\n    {\n        if (!unit->getType().isWorker())\n        {\n            continue;\n        }\n\n        // if it is a move worker\n        if (Global::Workers().isFree(unit))\n        {\n            double dist = unit->getDistance(target);\n\n            if (!closestMineralWorker || dist < closestDist)\n            {\n                closestMineralWorker = unit;\n                dist = closestDist;\n            }\n        }\n    }\n\n    return closestMineralWorker;\n}\n\n// when do we want to defend with our workers?\n// this function can only be called if we have no fighters to defend with\nint CombatCommander::defendWithWorkers()\n{\n    // our home nexus position\n    BWAPI::Position homePosition(BWAPI::Broodwar->self()->getStartLocation());\n\n    // enemy units near our workers\n    int enemyUnitsNearWorkers = 0;\n\n    // defense radius of nexus\n    int defenseRadius = 300;\n\n    // fill the set with the types of units we're concerned about\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        // if it's a zergling or a worker we want to defend\n        if (unit->getType() == BWAPI::UnitTypes::Zerg_Zergling)\n        {\n            if (unit->getDistance(homePosition) < defenseRadius)\n            {\n                enemyUnitsNearWorkers++;\n            }\n        }\n    }\n\n    // if there are enemy units near our workers, we want to defend\n    return enemyUnitsNearWorkers;\n}\n\nint CombatCommander::numZerglingsInOurBase()\n{\n    int concernRadius = 600;\n    int zerglings = 0;\n    BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n\n    // check to see if the enemy has zerglings as the only attackers in our base\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        if (unit->getType() != BWAPI::UnitTypes::Zerg_Zergling)\n        {\n            continue;\n        }\n\n        if (unit->getDistance(ourBasePosition) < concernRadius)\n        {\n            zerglings++;\n        }\n    }\n\n    return zerglings;\n}\n\nbool CombatCommander::beingBuildingRushed()\n{\n    int concernRadius = 1200;\n    BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n\n    // check to see if the enemy has zerglings as the only attackers in our base\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        if (unit->getType().isBuilding())\n        {\n            return true;\n        }\n    }\n\n    return false;\n}"
  },
  {
    "path": "UAlbertaBot/Source/CombatCommander.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"SquadData.h\"\n\nnamespace UAlbertaBot\n{\n\nclass Squad;\nclass CombatCommander\n{\n    SquadData       m_squadData;\n    BWAPI::Unitset  m_combatUnits;\n    bool            m_initialized = false;\n\n    void updateScoutDefenseSquad();\n    void updateDefenseSquads();\n    void updateAttackSquads();\n    void updateDropSquads();\n    void updateIdleSquad();\n    void initializeSquads();\n    void updateDefenseSquadUnits(Squad & defenseSquad, const size_t & flyingDefendersNeeded, const size_t & groundDefendersNeeded);\n\n    int  defendWithWorkers();\n    int  numZerglingsInOurBase();\n    bool beingBuildingRushed();\n    bool isSquadUpdateFrame();\n\n    BWAPI::Unit     findClosestDefender(const Squad & defenseSquad, BWAPI::Position pos, bool flyingDefender);\n    BWAPI::Unit     findClosestWorkerToTarget(BWAPI::Unitset & unitsToAssign, BWAPI::Unit target);\n    BWAPI::Position getDefendLocation();\n    BWAPI::Position getMainAttackLocation();\n\npublic:\n\n    CombatCommander();\n\n    void update(const BWAPI::Unitset & combatUnits);\n\n    void drawSquadInformation(int x, int y);\n};\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/CombatSimulation.cpp",
    "content": "#include \"CombatSimulation.h\"\n#include \"Global.h\"\n#include \"MapTools.h\"\n#include \"UnitData.h\"\n#include \"InformationManager.h\"\n\nusing namespace UAlbertaBot;\n\nCombatSimulation::CombatSimulation()\n{\n\n}\n\n// sets the starting states based on the combat units within a radius of a given position\n// this center will most likely be the position of the forwardmost combat unit we control\nvoid CombatSimulation::setCombatUnits(const BWAPI::Position & center, const int radius)\n{\n    SparCraft::GameState s;\n\n    BWAPI::Broodwar->drawCircleMap(center.x, center.y, 10, BWAPI::Colors::Red, true);\n\n    BWAPI::Unitset ourCombatUnits;\n    std::vector<UnitInfo> enemyCombatUnits;\n\n    Global::Map().getUnits(ourCombatUnits, center, Config::Micro::CombatRegroupRadius, true, false);\n    Global::Info().getNearbyForce(enemyCombatUnits, center, BWAPI::Broodwar->enemy(), Config::Micro::CombatRegroupRadius);\n\n    for (auto & unit : ourCombatUnits)\n    {\n        if (unit->getType().isWorker())\n        {\n            continue;\n        }\n\n        if (Global::Info().isCombatUnit(unit->getType()) && SparCraft::System::isSupportedUnitType(unit->getType()))\n        {\n            try\n            {\n                s.addUnit(getSparCraftUnit(unit));\n            }\n            catch (int e)\n            {\n                e=1;\n                BWAPI::Broodwar->printf(\"Problem Adding Self Unit with ID: %d\", unit->getID());\n            }\n        }\n    }\n\n    for (UnitInfo & ui : enemyCombatUnits)\n    {\n        if (ui.type.isWorker())\n        {\n            continue;\n        }\n\n\n        if (ui.type == BWAPI::UnitTypes::Terran_Bunker)\n        {\n            double hpRatio = static_cast<double>(ui.lastHealth) / ui.type.maxHitPoints();\n\n            SparCraft::Unit marine(BWAPI::UnitTypes::Terran_Marine,\n                SparCraft::Position(ui.lastPosition),\n                ui.unitID,\n                getSparCraftPlayerID(ui.player),\n                static_cast<int>(BWAPI::UnitTypes::Terran_Marine.maxHitPoints() * hpRatio),\n                0,\n                BWAPI::Broodwar->getFrameCount(),\n                BWAPI::Broodwar->getFrameCount());\n\n            for (size_t i(0); i < 5; ++i)\n            {\n                s.addUnit(marine);\n            }\n\n            continue;\n        }\n\n        if (!ui.type.isFlyer() && SparCraft::System::isSupportedUnitType(ui.type) && ui.completed)\n        {\n            try\n            {\n                s.addUnit(getSparCraftUnit(ui));\n            }\n            catch (int e)\n            {\n                BWAPI::Broodwar->printf(\"Problem Adding Enemy Unit with ID: %d %d\", ui.unitID, e);\n            }\n        }\n    }\n\n    s.finishedMoving();\n\n    m_state = s;\n}\n\n// Gets a SparCraft unit from a BWAPI::Unit, used for our own units since we have all their info\nconst SparCraft::Unit CombatSimulation::getSparCraftUnit(BWAPI::Unit unit) const\n{\n    return SparCraft::Unit(unit->getType(),\n        SparCraft::Position(unit->getPosition()),\n        unit->getID(),\n        getSparCraftPlayerID(unit->getPlayer()),\n        unit->getHitPoints() + unit->getShields(),\n        0,\n        BWAPI::Broodwar->getFrameCount(),\n        BWAPI::Broodwar->getFrameCount());\n}\n\n// Gets a SparCraft unit from a UnitInfo struct, needed to get units of enemy behind FoW\nconst SparCraft::Unit CombatSimulation::getSparCraftUnit(const UnitInfo & ui) const\n{\n    BWAPI::UnitType type = ui.type;\n\n    // this is a hack, treat medics as a marine for now\n    if (type == BWAPI::UnitTypes::Terran_Medic)\n    {\n        type = BWAPI::UnitTypes::Terran_Marine;\n    }\n\n    return SparCraft::Unit(ui.type,\n        SparCraft::Position(ui.lastPosition),\n        ui.unitID,\n        getSparCraftPlayerID(ui.player),\n        ui.lastHealth,\n        0,\n        BWAPI::Broodwar->getFrameCount(),\n        BWAPI::Broodwar->getFrameCount());\n}\n\nSparCraft::ScoreType CombatSimulation::simulateCombat()\n{\n    PROFILE_FUNCTION();\n\n    try\n    {\n        SparCraft::GameState s1(m_state);\n\n        SparCraft::PlayerPtr selfNOK(new SparCraft::Player_NOKDPS(getSparCraftPlayerID(BWAPI::Broodwar->self())));\n\n        SparCraft::PlayerPtr enemyNOK(new SparCraft::Player_NOKDPS(getSparCraftPlayerID(BWAPI::Broodwar->enemy())));\n\n        SparCraft::Game g (s1, selfNOK, enemyNOK, 2000);\n\n        g.play();\n\n        SparCraft::ScoreType eval =  g.getState().eval(SparCraft::Players::Player_One, SparCraft::EvaluationMethods::LTD2).val();\n\n        if (Config::Debug::DrawCombatSimulationInfo)\n        {\n            std::stringstream ss1;\n            ss1 << \"Initial State:\\n\";\n            ss1 << s1.toStringCompact() << \"\\n\\n\";\n\n            std::stringstream ss2;\n\n            ss2 << \"Predicted Outcome: \" << eval << \"\\n\";\n            ss2 << g.getState().toStringCompact() << \"\\n\";\n\n            BWAPI::Broodwar->drawTextScreen(150, 200, \"%s\", ss1.str().c_str());\n            BWAPI::Broodwar->drawTextScreen(300, 200, \"%s\", ss2.str().c_str());\n\n            BWAPI::Broodwar->drawTextScreen(240, 280, \"Combat Sim : %d\", eval);\n        }\n\n        return eval;\n    }\n    catch (int e)\n    {\n        BWAPI::Broodwar->printf(\"SparCraft FatalError, simulateCombat() threw\");\n\n        return e;\n    }\n}\n\nconst SparCraft::GameState & CombatSimulation::getSparCraftState() const\n{\n    return m_state;\n}\n\nconst size_t CombatSimulation::getSparCraftPlayerID(BWAPI::Player player) const\n{\n    if (player == BWAPI::Broodwar->self())\n    {\n        return SparCraft::Players::Player_One;\n    }\n    else if (player == BWAPI::Broodwar->enemy())\n    {\n        return SparCraft::Players::Player_Two;\n    }\n\n    return SparCraft::Players::Player_None;\n}"
  },
  {
    "path": "UAlbertaBot/Source/CombatSimulation.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\n#ifdef USING_VISUALIZATION_LIBRARIES\n\t#include \"Visualizer.h\"\n#endif\n\n#include \"..\\..\\SparCraft\\source\\GameState.h\"\n#include \"..\\..\\SparCraft\\source\\Game.h\"\n#include \"..\\..\\SparCraft\\source\\Unit.h\"\n#include \"..\\..\\SparCraft\\source\\AllPlayers.h\"\n\nnamespace UAlbertaBot\n{\nstruct UnitInfo;\nclass CombatSimulation\n{\n\tSparCraft::GameState m_state;\n\npublic:\n\n\tCombatSimulation();\n\n\tvoid setCombatUnits(const BWAPI::Position & center, const int radius);\n\n\tSparCraft::ScoreType            simulateCombat();\n\tconst SparCraft::Unit\t\t\tgetSparCraftUnit(const UnitInfo & ui) const;\n    const SparCraft::Unit\t\t\tgetSparCraftUnit(BWAPI::Unit unit) const;\n\tconst SparCraft::GameState &\tgetSparCraftState() const;\n\tconst size_t                    getSparCraftPlayerID(BWAPI::Player player) const;\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/Common.cpp",
    "content": "#include \"Common.h\"\n"
  },
  {
    "path": "UAlbertaBot/Source/Common.h",
    "content": "#pragma once\n\n#define _USE_MATH_DEFINES\n#include <cmath>\n#include <math.h>\n#include <cstdlib>\n\n#include <stdexcept>\n#include <string>\n#include <sstream>\n#include <algorithm>\n#include <vector>\n#include <deque>\n#include <list>\n#include <set>\n#include <map>\n#include <array>\n\n#include <BWAPI.h>\n\n#include \"Config.h\"\n#include \"UABAssert.h\"\n#include \"Profiler.hpp\"\n"
  },
  {
    "path": "UAlbertaBot/Source/Config.cpp",
    "content": "#include \"Config.h\"\n#include \"UABAssert.h\"\n\nnamespace Bot\n{\n\n}\n\nnamespace Config\n{\n    namespace ConfigFile\n    {\n        bool ConfigFileFound                = false;\n        bool ConfigFileParsed               = false;\n        std::string ConfigFileLocation      = \"UAlbertaBot_Config.txt\";\n    }\n\n    namespace Strategy\n    {\n        std::string ProtossStrategyName     = \"Protoss_ZealotRush\";\n        std::string TerranStrategyName      = \"Terran_MarineRush\";\n        std::string ZergStrategyName        = \"Zerg_3HatchMuta\";\n        std::string StrategyName            = \"Protoss_ZealotRush\";\n        std::string ReadDir                 = \"bwapi-data/read/\";\n        std::string WriteDir                = \"bwapi-data/write/\";\n        bool GasStealWithScout              = false;\n        bool ScoutHarassEnemy               = true;\n        bool UseEnemySpecificStrategy       = false;\n        bool FoundEnemySpecificStrategy     = false;\n    }\n\n    namespace Modules\t\t\t\t\t\t\t    \n    {\n        // the default tournament bot modules\n        bool UsingGameCommander             = true;     // toggle GameCommander, effectively UAlbertaBot\n        bool UsingScoutManager              = true;\n        bool UsingCombatCommander           = true;\n        bool UsingBuildOrderSearch          = true;     // toggle use of Build Order Search, currently no backup\n        bool UsingAutoObserver              = false;\n        bool UsingStrategyIO                = false;    // toggle the use of file io for strategy\n        bool UsingUnitCommandManager        = false;    // handles all unit commands\n\t\t\n        // extra things, don't enable unless you know what they are\n        bool UsingBuildOrderDemo            = false;\n    }\n\n    namespace BotInfo\n    {\n        std::string BotName                 = \"UAlbertaBot\";\n        std::string Authors                 = \"Dave Churchill\";\n        bool PrintInfoOnStart               = false;\n    }\n\n    namespace BWAPIOptions\n    {\n        int SetLocalSpeed                   = 42;\n        int SetFrameSkip                    = 0;\n        bool EnableUserInput                = true;\n        bool EnableCompleteMapInformation   = false;\n    }\n    \n    namespace Tournament\t\t\t\t\t\t\n    {\n        int GameEndFrame                    = 86400;\t\n    }\n    \n    namespace Debug\t\t\t\t\t\t\t\t\n    {\n        bool DrawGameInfo                   = true;\n        bool DrawUnitHealthBars             = true;\n        bool DrawProductionInfo             = true;\n        bool DrawBuildOrderSearchInfo       = false;\n        bool DrawScoutInfo                  = false;\n        bool DrawResourceInfo               = false;\n        bool DrawWorkerInfo                 = false;\n        bool DrawModuleTimers               = false;\n        bool DrawReservedBuildingTiles      = false;\n        bool DrawCombatSimulationInfo       = false;\n        bool DrawBuildingInfo               = false;\n        bool DrawMouseCursorInfo            = false;\n        bool DrawEnemyUnitInfo              = false;\n        bool DrawBWTAInfo                   = false;\n        bool DrawMapGrid                    = false;\n        bool DrawUnitTargetInfo             = false;\n        bool DrawSquadInfo                  = false;\n        bool DrawBOSSStateInfo              = false;\n        bool DrawWalkableSectors            = false;\n        bool DrawTileInfo                   = false;\n        bool PrintModuleTimeout             = false;\t\n\n        std::string ErrorLogFilename        = \"UAB_ErrorLog.txt\";\n        bool LogAssertToErrorFile           = false;\n\n        BWAPI::Color ColorLineTarget        = BWAPI::Colors::White;\n        BWAPI::Color ColorLineMineral       = BWAPI::Colors::Cyan;\n        BWAPI::Color ColorUnitNearEnemy     = BWAPI::Colors::Red;\n        BWAPI::Color ColorUnitNotNearEnemy  = BWAPI::Colors::Green;\n    }\n\n    namespace Micro\t\t\t\t\t\t\t\t\n    {\n        bool UseSparcraftSimulation         = true;\n        bool KiteWithRangedUnits            = true;\n        std::set<BWAPI::UnitType> KiteLongerRangedUnits;\n        bool WorkersDefendRush              = false; \n\t\tint RetreatMeleeUnitShields         = 0;\n        int RetreatMeleeUnitHP              = 0;\n        int CombatRadius                    = 1000;     // radius of combat to consider units for Micro Search\n        int CombatRegroupRadius             = 300;      // radius of units around frontmost unit we consider in regroup calculation\n        int UnitNearEnemyRadius             = 600;      // radius to consider a unit 'near' to an enemy unit\n    }\n\n    namespace Macro\n    {\n        int BOSSFrameLimit                  = 160;\n        int BOSSTimePerFrame                = 30;\n        int WorkersPerRefinery              = 3;\n        int BuildingSpacing                 = 1;\n        int PylonSpacing                    = 3;\n    }\n\n    namespace Tools\t\t\t\t\t\t\t\t\n    {\n        extern int MAP_GRID_SIZE            = 320;      // size of grid spacing in MapGrid\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/Config.h",
    "content": "#pragma once\n\n#include \"BWAPI.h\"\n#include <set>\n#include <cassert>\n\nnamespace Config\n{\n    namespace ConfigFile\n    {\n        extern bool ConfigFileFound;\n        extern bool ConfigFileParsed;\n        extern std::string ConfigFileLocation;\n    }\n\n    namespace Modules\n    {\n        extern bool UsingGameCommander;\t\t\t\n        extern bool UsingScoutManager;\n        extern bool UsingCombatCommander;\n        extern bool UsingUnitCommandManager;\n        extern bool UsingBuildOrderSearch;  \n        extern bool UsingAutoObserver;\n        extern bool UsingStrategyIO;\t\t\t\n    }\n    \n    namespace BotInfo\n    {\n        extern std::string BotName;\n        extern std::string Authors;\n        extern bool PrintInfoOnStart;\n    }\n\n    namespace Strategy\n    {\n        extern std::string StrategyName;\n        extern std::string ReadDir;\n        extern std::string WriteDir;\n        extern bool GasStealWithScout;\n        extern bool ScoutHarassEnemy;\n        extern bool UseEnemySpecificStrategy;\n        extern bool FoundEnemySpecificStrategy;\n    }\n\n    namespace BWAPIOptions\n    {\n        extern int SetLocalSpeed;\n        extern int SetFrameSkip;\n        extern bool EnableUserInput;\n        extern bool EnableCompleteMapInformation;\n    }\n\n    namespace Tournament\n    {\n        extern int GameEndFrame;\t\n    }\n\n    namespace Debug\n    {\n        extern bool DrawGameInfo;\n        extern bool DrawBuildOrderSearchInfo;\n        extern bool DrawUnitHealthBars;\n        extern bool DrawResourceInfo;\n        extern bool DrawProductionInfo;\n        extern bool DrawScoutInfo;\n        extern bool DrawWorkerInfo;\n        extern bool DrawModuleTimers;\n        extern bool DrawReservedBuildingTiles;\n        extern bool DrawCombatSimulationInfo;\n        extern bool DrawBuildingInfo;\n        extern bool DrawMouseCursorInfo;\n        extern bool DrawEnemyUnitInfo;\n        extern bool DrawBWTAInfo;\n        extern bool DrawMapGrid;\n        extern bool DrawUnitTargetInfo;\n        extern bool DrawSquadInfo;\n        extern bool DrawBOSSStateInfo;\n        extern bool DrawWalkableSectors;\n        extern bool DrawTileInfo;\n        extern bool PrintModuleTimeout;\t\n        \n        extern std::string ErrorLogFilename;\n        extern bool LogAssertToErrorFile;\n\n        extern BWAPI::Color ColorLineTarget;\n        extern BWAPI::Color ColorLineMineral;\n        extern BWAPI::Color ColorUnitNearEnemy;\n        extern BWAPI::Color ColorUnitNotNearEnemy;\n    }\n\n    namespace Micro\n    {\n        extern bool UseSparcraftSimulation;\n        extern bool KiteWithRangedUnits;\n        extern std::set<BWAPI::UnitType> KiteLongerRangedUnits;\n        extern bool WorkersDefendRush;\n        extern int RetreatMeleeUnitShields;\n        extern int RetreatMeleeUnitHP;\n        extern int CombatRadius;                \n        extern int CombatRegroupRadius;         \n        extern int UnitNearEnemyRadius;         \n    }\n\n    namespace Macro\n    {\n        extern int BOSSFrameLimit;\n        extern int BOSSTimePerFrame;\n        extern int WorkersPerRefinery;\n        extern int BuildingSpacing;\n        extern int PylonSpacing;\n    }\n\n    namespace Tools\n    {\n        extern int MAP_GRID_SIZE;\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/DetectorManager.cpp",
    "content": "#include \"Common.h\"\n#include \"DetectorManager.h\"\n#include \"Global.h\"\n#include \"Micro.h\"\n#include \"MapTools.h\"\n\nusing namespace UAlbertaBot;\n\nDetectorManager::DetectorManager()\n{ \n\n}\n\nvoid DetectorManager::executeMicro(const BWAPI::Unitset & targets)\n{\n    const BWAPI::Unitset & detectorUnits = getUnits();\n\n    if (detectorUnits.empty())\n    {\n        return;\n    }\n\n    for (size_t i(0); i<targets.size(); ++i)\n    {\n        // do something here if there's targets\n    }\n\n    m_cloakedUnitMap.clear();\n    BWAPI::Unitset cloakedUnits;\n\n    // figure out targets\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        // conditions for targeting\n        if (unit->getType() == BWAPI::UnitTypes::Zerg_Lurker ||\n            unit->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar ||\n            unit->getType() == BWAPI::UnitTypes::Terran_Wraith)\n        {\n            cloakedUnits.insert(unit);\n            m_cloakedUnitMap[unit] = false;\n        }\n    }\n\n    bool detectorUnitInBattle = false;\n\n    // for each detectorUnit\n    for (auto & detectorUnit : detectorUnits)\n    {\n        // if we need to regroup, move the detectorUnit to that location\n        if (!detectorUnitInBattle && unitClosestToEnemy && unitClosestToEnemy->getPosition().isValid())\n        {\n            Micro::SmartMove(detectorUnit, unitClosestToEnemy->getPosition());\n            detectorUnitInBattle = true;\n        }\n        // otherwise there is no battle or no closest to enemy so we don't want our detectorUnit to die\n        // send him to scout around the map\n        else\n        {\n            BWAPI::Position explorePosition = BWAPI::Position(Global::Map().getLeastRecentlySeenTile());\n            Micro::SmartMove(detectorUnit, explorePosition);\n        }\n    }\n}\n\n\nBWAPI::Unit DetectorManager::closestCloakedUnit(const BWAPI::Unitset & cloakedUnits, BWAPI::Unit detectorUnit)\n{\n    BWAPI::Unit closestCloaked = nullptr;\n    double closestDist = 100000;\n\n    for (auto & unit : cloakedUnits)\n    {\n        // if we haven't already assigned an detectorUnit to this cloaked unit\n        if (!m_cloakedUnitMap[unit])\n        {\n            double dist = unit->getDistance(detectorUnit);\n\n            if (!closestCloaked || (dist < closestDist))\n            {\n                closestCloaked = unit;\n                closestDist = dist;\n            }\n        }\n    }\n\n    return closestCloaked;\n}"
  },
  {
    "path": "UAlbertaBot/Source/DetectorManager.h",
    "content": "#pragma once\n\n#include \"MicroManager.h\"\n\nnamespace UAlbertaBot\n{\nclass DetectorManager : public MicroManager\n{\n    std::map<BWAPI::Unit, bool>\tm_cloakedUnitMap;\n    BWAPI::Unit unitClosestToEnemy = nullptr;\n\n    bool isAssigned(BWAPI::Unit unit);\n\npublic:\n\n    DetectorManager();\n\n    void setUnitClosestToEnemy(BWAPI::Unit unit) { unitClosestToEnemy = unit; }\n    void executeMicro(const BWAPI::Unitset & targets);\n\n    BWAPI::Unit closestCloakedUnit(const BWAPI::Unitset & cloakedUnits, BWAPI::Unit detectorUnit);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/DistanceMap.cpp",
    "content": "#include \"DistanceMap.h\"\n#include \"MapTools.h\"\n#include \"Global.h\"\n\nusing namespace UAlbertaBot;\n\nconst size_t LegalActions = 4;\nconst int actionX[LegalActions] ={1, -1, 0, 0};\nconst int actionY[LegalActions] ={0, 0, 1, -1};\n\nDistanceMap::DistanceMap()\n{\n\n}\n\nint DistanceMap::getDistance(int tileX, int tileY) const\n{\n    UAB_ASSERT(tileX < m_width && tileY < m_height, \"Index out of range: X = %d, Y = %d\", tileX, tileY);\n\n    return m_dist.get(tileX, tileY);\n}\n\nint DistanceMap::getDistance(const BWAPI::TilePosition & pos) const\n{\n    return getDistance(pos.x, pos.y);\n}\n\nint DistanceMap::getDistance(const BWAPI::Position & pos) const\n{\n    return getDistance(BWAPI::TilePosition(pos));\n}\n\nconst std::vector<BWAPI::TilePosition> & DistanceMap::getSortedTiles() const\n{\n    return m_sortedTiles;\n}\n\n// Computes m_dist[x][y] = ground distance from (startX, startY) to (x,y)\n// Uses BFS, since the map is quite large and DFS may cause a stack overflow\nvoid DistanceMap::computeDistanceMap(const BWAPI::TilePosition & startTile)\n{\n    PROFILE_FUNCTION();\n\n    m_startTile = startTile;\n    m_width     = BWAPI::Broodwar->mapWidth();\n    m_height    = BWAPI::Broodwar->mapHeight();\n    m_dist      = Grid<int>(m_width, m_height, -1);\n    m_sortedTiles.reserve(m_width * m_height);\n\n    // the fringe for the BFS we will perform to calculate distances\n    std::vector<BWAPI::TilePosition> fringe;\n    fringe.reserve(m_width * m_height);\n    fringe.push_back(startTile);\n    m_sortedTiles.push_back(startTile);\n\n    m_dist.set(startTile.x, startTile.y, 0);\n\n    for (size_t fringeIndex=0; fringeIndex<fringe.size(); ++fringeIndex)\n    {\n        const auto & tile = fringe[fringeIndex];\n\n        // check every possible child of this tile\n        for (size_t a=0; a<LegalActions; ++a)\n        {\n            const BWAPI::TilePosition nextTile(tile.x + actionX[a], tile.y + actionY[a]);\n\n            // if the new tile is inside the map bounds, is walkable, and has not been visited yet, set the distance of its parent + 1\n            if (Global::Map().isWalkable(nextTile) && getDistance(nextTile) == -1)\n            {\n                m_dist.set(nextTile.x, nextTile.y, m_dist.get(tile.x, tile.y) + 1);\n                fringe.push_back(nextTile);\n                m_sortedTiles.push_back(nextTile);\n            }\n        }\n    }\n}\n\nvoid DistanceMap::draw() const\n{\n    const int tilesToDraw = 200;\n    for (size_t i(0); i < tilesToDraw && i < m_sortedTiles.size(); ++i)\n    {\n        const auto & tile = m_sortedTiles[i];\n        const int dist = getDistance(tile);\n\n        const BWAPI::Position textPos(tile);\n        std::stringstream ss;\n        ss << dist;\n\n        BWAPI::Broodwar->drawTextMap(textPos, ss.str().c_str(), BWAPI::Colors::White);\n    }\n}\n\nconst BWAPI::TilePosition & DistanceMap::getStartTile() const\n{\n    return m_startTile;\n}"
  },
  {
    "path": "UAlbertaBot/Source/DistanceMap.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Grid.hpp\"\n\nnamespace UAlbertaBot\n{\nclass DistanceMap\n{\n    int                             m_width = 0;\n    int                             m_height = 0;\n    Grid<int>                       m_dist;\n    BWAPI::TilePosition             m_startTile;\n    std::vector<BWAPI::TilePosition> m_sortedTiles;\n\npublic:\n\n    DistanceMap();\n    void computeDistanceMap(const BWAPI::TilePosition & startTile);\n\n    int getDistance(int tileX, int tileY) const;\n    int getDistance(const BWAPI::TilePosition & pos) const;\n    int getDistance(const BWAPI::Position & pos) const;\n\n    // given a position, get the position we should move to to minimize distance\n    const std::vector<BWAPI::TilePosition> & getSortedTiles() const;\n    const BWAPI::TilePosition & getStartTile() const;\n\n    void draw() const;\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/GameCommander.cpp",
    "content": "#include \"Common.h\"\n#include \"GameCommander.h\"\n#include \"UnitUtil.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n#include \"BuildingPlacerManager.h\"\n#include \"BOSSManager.h\"\n#include \"MapTools.h\"\n#include \"InformationManager.h\"\n#include \"WorkerManager.h\"\n#include \"ProductionManager.h\"\n#include \"BuildingManager.h\"\n#include \"ScoutManager.h\"\n#include \"StrategyManager.h\"\n#include \"Squad.h\"\n\nusing namespace UAlbertaBot;\n\nGameCommander::GameCommander() \n    : m_initialScoutSet(false)\n{\n\n}\n\nvoid GameCommander::update()\n{\n    PROFILE_FUNCTION();\n\n\tm_timerManager.startTimer(TimerManager::All);\n\n\t// populate the unit vectors we will pass into various managers\n\thandleUnitAssignments();\n\n\t// utility managers\n\tm_timerManager.startTimer(TimerManager::InformationManager);\n\tGlobal::Info().update();\n\tm_timerManager.stopTimer(TimerManager::InformationManager);\n\n\tm_timerManager.startTimer(TimerManager::MapTools);\n\tGlobal::Map().onFrame();\n\tm_timerManager.stopTimer(TimerManager::MapTools);\n\n\t// economy and base managers\n\tm_timerManager.startTimer(TimerManager::Worker);\n\tGlobal::Workers().onFrame();\n\tm_timerManager.stopTimer(TimerManager::Worker);\n\n\tm_timerManager.startTimer(TimerManager::Production);\n\tGlobal::Production().update();\n\tm_timerManager.stopTimer(TimerManager::Production);\n\n\t// combat and scouting managers\n\tm_timerManager.startTimer(TimerManager::Combat);\n\tm_combatCommander.update(m_combatUnits);\n\tm_timerManager.stopTimer(TimerManager::Combat);\n\n\tm_timerManager.startTimer(TimerManager::Scout);\n    Global::Scout().update();\n\tm_timerManager.stopTimer(TimerManager::Scout);\n\n\tm_timerManager.stopTimer(TimerManager::All);\n\n\tGlobal::Bases().onFrame();\n\n\tdrawDebugInterface();\n}\n\nvoid GameCommander::drawDebugInterface()\n{\n\tGlobal::Info().drawExtendedInterface();\n\tGlobal::Info().drawUnitInformation(425,30);\n\tGlobal::Info().drawMapInformation();\n\t\n\tGlobal::Production().drawProductionInformation(30, 50);\n    \n\tm_combatCommander.drawSquadInformation(200, 30);\n    m_timerManager.displayTimers(490, 225);\n    drawGameInformation(4, 1);\n\n\t// draw position of mouse cursor\n\tif (Config::Debug::DrawMouseCursorInfo)\n\t{\n\t\tint mouseX = BWAPI::Broodwar->getMousePosition().x + BWAPI::Broodwar->getScreenPosition().x;\n\t\tint mouseY = BWAPI::Broodwar->getMousePosition().y + BWAPI::Broodwar->getScreenPosition().y;\n\t\tBWAPI::Broodwar->drawTextMap(mouseX + 20, mouseY, \" %d %d\", mouseX, mouseY);\n\t}\n}\n\nvoid GameCommander::drawGameInformation(int x, int y)\n{\n    BWAPI::Broodwar->drawTextScreen(x, y, \"\\x04Players:\");\n\tBWAPI::Broodwar->drawTextScreen(x+50, y, \"%c%s \\x04vs. %c%s\", BWAPI::Broodwar->self()->getTextColor(), BWAPI::Broodwar->self()->getName().c_str(), \n                                                                  BWAPI::Broodwar->enemy()->getTextColor(), BWAPI::Broodwar->enemy()->getName().c_str());\n\ty += 12;\n\t\t\n    BWAPI::Broodwar->drawTextScreen(x, y, \"\\x04Strategy:\");\n\tBWAPI::Broodwar->drawTextScreen(x+50, y, \"\\x03%s %s\", Config::Strategy::StrategyName.c_str(), Config::Strategy::FoundEnemySpecificStrategy ? \"(enemy specific)\" : \"\");\n\tBWAPI::Broodwar->setTextSize();\n\ty += 12;\n\n    BWAPI::Broodwar->drawTextScreen(x, y, \"\\x04Map:\");\n\tBWAPI::Broodwar->drawTextScreen(x+50, y, \"\\x03%s\", BWAPI::Broodwar->mapFileName().c_str());\n\tBWAPI::Broodwar->setTextSize();\n\ty += 12;\n\n    BWAPI::Broodwar->drawTextScreen(x, y, \"\\x04Time:\");\n    BWAPI::Broodwar->drawTextScreen(x+50, y, \"\\x04%d %4dm %3ds\", BWAPI::Broodwar->getFrameCount(), (int)(BWAPI::Broodwar->getFrameCount()/(23.8*60)), (int)((int)(BWAPI::Broodwar->getFrameCount()/23.8)%60));\n}\n\n// assigns units to various managers\nvoid GameCommander::handleUnitAssignments()\n{\n\tm_validUnits.clear();\n    m_combatUnits.clear();\n\n\t// filter our units for those which are valid and usable\n\tsetValidUnits();\n\n\t// set each type of unit\n\tsetScoutUnits();\n\tsetCombatUnits();\n}\n\nbool GameCommander::isAssigned(BWAPI::Unit unit) const\n{\n\treturn m_combatUnits.contains(unit) || m_scoutUnits.contains(unit);\n}\n\n// validates units as usable for distribution to various managers\nvoid GameCommander::setValidUnits()\n{\n\t// make sure the unit is completed and alive and usable\n\tfor (auto & unit : BWAPI::Broodwar->self()->getUnits())\n\t{\n\t\tif (UnitUtil::IsValidUnit(unit))\n\t\t{\t\n\t\t\tm_validUnits.insert(unit);\n\t\t}\n\t}\n}\n\nvoid GameCommander::setScoutUnits()\n{\n    // if we haven't set a scout unit, do it\n    if (m_scoutUnits.empty() && !m_initialScoutSet)\n    {\n        BWAPI::Unit supplyProvider = getFirstSupplyProvider();\n\n\t\t// if it exists\n\t\tif (supplyProvider)\n\t\t{\n\t\t\t// grab the closest worker to the supply provider to send to scout\n\t\t\tBWAPI::Unit workerScout = getClosestWorkerToTarget(supplyProvider->getPosition());\n\n\t\t\t// if we find a worker (which we should) add it to the scout units\n\t\t\tif (workerScout)\n\t\t\t{\n                Global::Scout().setWorkerScout(workerScout);\n\t\t\t\tassignUnit(workerScout, m_scoutUnits);\n                m_initialScoutSet = true;\n\t\t\t}\n\t\t}\n    }\n}\n\n// sets combat units to be passed to CombatCommander\nvoid GameCommander::setCombatUnits()\n{\n\tfor (auto & unit : m_validUnits)\n\t{\n\t\tif (!isAssigned(unit) && UnitUtil::IsCombatUnit(unit) || unit->getType().isWorker())\t\t\n\t\t{\t\n\t\t\tassignUnit(unit, m_combatUnits);\n\t\t}\n\t}\n}\n\nBWAPI::Unit GameCommander::getFirstSupplyProvider()\n{\n\tBWAPI::Unit supplyProvider = nullptr;\n\n\tif (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg)\n\t{\n\t\tfor (auto & unit : BWAPI::Broodwar->self()->getUnits())\n\t\t{\n\t\t\tif (unit->getType() == BWAPI::UnitTypes::Zerg_Spawning_Pool)\n\t\t\t{\n\t\t\t\tsupplyProvider = unit;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t\n\t\tfor (auto & unit : BWAPI::Broodwar->self()->getUnits())\n\t\t{\n\t\t\tif (unit->getType() == BWAPI::Broodwar->self()->getRace().getSupplyProvider())\n\t\t\t{\n\t\t\t\tsupplyProvider = unit;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn supplyProvider;\n}\n\nvoid GameCommander::onUnitShow(BWAPI::Unit unit)\t\t\t\n{ \n\tGlobal::Info().onUnitShow(unit); \n\tGlobal::Workers().onUnitShow(unit);\n}\n\nvoid GameCommander::onUnitHide(BWAPI::Unit unit)\t\t\t\n{ \n\tGlobal::Info().onUnitHide(unit); \n}\n\nvoid GameCommander::onUnitCreate(BWAPI::Unit unit)\t\t\n{ \n\tGlobal::Info().onUnitCreate(unit); \n}\n\nvoid GameCommander::onUnitComplete(BWAPI::Unit unit)\n{\n\tGlobal::Info().onUnitComplete(unit);\n}\n\nvoid GameCommander::onUnitRenegade(BWAPI::Unit unit)\t\t\n{ \n\tGlobal::Info().onUnitRenegade(unit); \n}\n\nvoid GameCommander::onUnitDestroy(BWAPI::Unit unit)\t\t\n{ \t\n\tGlobal::Production().onUnitDestroy(unit);\n\tGlobal::Workers().onUnitDestroy(unit);\n\tGlobal::Info().onUnitDestroy(unit); \n}\n\nvoid GameCommander::onUnitMorph(BWAPI::Unit unit)\t\t\n{ \n\tGlobal::Info().onUnitMorph(unit);\n\tGlobal::Workers().onUnitMorph(unit);\n}\n\nBWAPI::Unit GameCommander::getClosestUnitToTarget(BWAPI::UnitType type, BWAPI::Position target)\n{\n\tBWAPI::Unit closestUnit = nullptr;\n\tdouble closestDist = 100000;\n\n\tfor (auto & unit : m_validUnits)\n\t{\n\t\tif (unit->getType() == type)\n\t\t{\n\t\t\tdouble dist = unit->getDistance(target);\n\t\t\tif (!closestUnit || dist < closestDist)\n\t\t\t{\n\t\t\t\tclosestUnit = unit;\n\t\t\t\tclosestDist = dist;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn closestUnit;\n}\n\nBWAPI::Unit GameCommander::getClosestWorkerToTarget(BWAPI::Position target)\n{\n\tBWAPI::Unit closestUnit = nullptr;\n\tdouble closestDist = 100000;\n\n\tfor (auto & unit : m_validUnits)\n\t{\n\t\tif (!isAssigned(unit) && unit->getType().isWorker() && Global::Workers().isFree(unit))\n\t\t{\n\t\t\tdouble dist = unit->getDistance(target);\n\t\t\tif (!closestUnit || dist < closestDist)\n\t\t\t{\n\t\t\t\tclosestUnit = unit;\n\t\t\t\tclosestDist = dist;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn closestUnit;\n}\n\nvoid GameCommander::assignUnit(BWAPI::Unit unit, BWAPI::Unitset & set)\n{\n    if (m_scoutUnits.contains(unit)) { m_scoutUnits.erase(unit); }\n    else if (m_combatUnits.contains(unit)) { m_combatUnits.erase(unit); }\n\n    set.insert(unit);\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/GameCommander.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"CombatCommander.h\"\n#include \"TimerManager.h\"\n\nnamespace UAlbertaBot\n{\n\n\nclass UnitToAssign\n{\npublic:\n\n\tBWAPI::Unit unit;\n\tbool isAssigned = false;\n\n\tUnitToAssign(BWAPI::Unit u)\n        : unit(u)\n\t{\n\t\t\n\t}\n};\n\nclass GameCommander \n{\n\tCombatCommander m_combatCommander;\n\tTimerManager    m_timerManager;\n\n\tBWAPI::Unitset  m_validUnits;\n\tBWAPI::Unitset  m_combatUnits;\n\tBWAPI::Unitset  m_scoutUnits;\n\n    bool            m_initialScoutSet = false;\n\n    void assignUnit(BWAPI::Unit unit, BWAPI::Unitset & set);\n\tbool isAssigned(BWAPI::Unit unit) const;\n\npublic:\n\n\tGameCommander();\n\n\tvoid update();\n\n\tvoid handleUnitAssignments();\n\tvoid setValidUnits();\n\tvoid setScoutUnits();\n\tvoid setCombatUnits();\n\n\tvoid drawDebugInterface();\n    void drawGameInformation(int x, int y);\n\n\tBWAPI::Unit getFirstSupplyProvider();\n\tBWAPI::Unit getClosestUnitToTarget(BWAPI::UnitType type, BWAPI::Position target);\n\tBWAPI::Unit getClosestWorkerToTarget(BWAPI::Position target);\n\n\tvoid onUnitShow(BWAPI::Unit unit);\n\tvoid onUnitHide(BWAPI::Unit unit);\n\tvoid onUnitCreate(BWAPI::Unit unit);\n\tvoid onUnitComplete(BWAPI::Unit unit);\n\tvoid onUnitRenegade(BWAPI::Unit unit);\n\tvoid onUnitDestroy(BWAPI::Unit unit);\n\tvoid onUnitMorph(BWAPI::Unit unit);\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/Global.cpp",
    "content": "#include \"Global.h\"\n\n#include \"MapTools.h\"\n#include \"InformationManager.h\"\n#include \"BaseLocationManager.h\"\n#include \"WorkerManager.h\"\n#include \"StrategyManager.h\"\n#include \"BOSSManager.h\"\n#include \"ProductionManager.h\"\n#include \"BuildingManager.h\"\n#include \"ScoutManager.h\"\n#include \"BuildingPlacerManager.h\"\n\nusing namespace UAlbertaBot;\n\nGlobal::Global()\n{\n    init();\n}\n\nGlobal & Global::Instance()\n{\n    static Global instance;\n    return instance;\n}\n\nvoid Global::init()\n{\n    reset(m_mapTools);\n    reset(m_informationManager);\n    reset(m_workerManager);\n    reset(m_productionManager);\n    reset(m_baseLocationManager);\n    reset(m_strategyManager);\n    reset(m_scoutManager);\n}\n\nvoid Global::GameStart()\n{\n    Instance().init();\n}\n\nMapTools &              Global::Map()            { return *get(Instance().m_mapTools);            }\nBaseLocationManager &   Global::Bases()          { return *get(Instance().m_baseLocationManager); }\nInformationManager &    Global::Info()           { return *get(Instance().m_informationManager);  }\nStrategyManager &       Global::Strategy()       { return *get(Instance().m_strategyManager);     }\nWorkerManager &         Global::Workers()        { return *get(Instance().m_workerManager);       }\nProductionManager &     Global::Production()     { return *get(Instance().m_productionManager);   }\nScoutManager &          Global::Scout()          { return *get(Instance().m_scoutManager);        }"
  },
  {
    "path": "UAlbertaBot/Source/Global.h",
    "content": "#pragma once\n\n#include <memory>\n\nnamespace UAlbertaBot\n{\n\nclass MapTools;\nclass BaseLocationManager;\nclass InformationManager;\nclass StrategyManager;\nclass WorkerManager;\nclass ProductionManager;\nclass ScoutManager;\n\n\nclass Global\n{\n    MapTools *            m_mapTools            = nullptr;\n    BaseLocationManager * m_baseLocationManager = nullptr;\n    InformationManager *  m_informationManager  = nullptr;\n    StrategyManager *     m_strategyManager     = nullptr;\n    WorkerManager *       m_workerManager       = nullptr;\n    ProductionManager *   m_productionManager   = nullptr;\n    ScoutManager *        m_scoutManager        = nullptr;\n    \n    template <class T>\n    void reset(T *& ptr)\n    {\n        delete ptr;\n        ptr = nullptr;\n    }\n\n    template <class T>\n    static T * get(T *& ptr)\n    {\n        if (ptr == nullptr) { ptr = new T(); }\n        return ptr;\n    }\n\n    Global();\n    static Global & Instance();\n    void init();\n\npublic:\n    \n    static void GameStart();\n    static MapTools & Map();\n    static BaseLocationManager & Bases();\n    static InformationManager & Info();\n    static StrategyManager & Strategy();\n    static WorkerManager & Workers();\n    static ProductionManager & Production();\n    static ScoutManager & Scout();\n};\n\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/Grid.hpp",
    "content": "#pragma once\n\n#include <vector>\n\n// WARNING: ONLY USE THIS FOR BASE TYPES, IT COPIES\n\nnamespace UAlbertaBot\n{\n\ntemplate <class T>\nclass Grid\n{\n    size_t m_width = 0;\n    size_t m_height = 0;\n\n    std::vector<std::vector<T>> m_grid;\n\npublic:\n\n    Grid() {}\n\n    Grid(size_t width, size_t height, T val)\n        : m_width(width)\n        , m_height(height)\n        , m_grid(width, std::vector<T>(height, val))\n    {\n\n    }\n\n    inline T get(size_t x, size_t y)\n    {\n        return m_grid[x][y];\n    }\n\n    inline const T get(size_t x, size_t y) const\n    {\n        return m_grid[x][y];\n    }\n\n    inline void set(size_t x, size_t y, T val)\n    {\n        m_grid[x][y] = val;\n    }\n\n    inline size_t width() const\n    {\n        return m_width;\n    }\n\n    inline size_t height() const\n    {\n        return m_height;\n    }\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/InformationManager.cpp",
    "content": "#include \"Common.h\"\n#include \"InformationManager.h\"\n#include \"UnitData.h\"\n\nusing namespace UAlbertaBot;\n\nInformationManager::InformationManager()\n{\n\tupdate();\n}\n\nvoid InformationManager::update() \n{\n\tupdateUnitInfo();\n}\n\nvoid InformationManager::updateUnitInfo() \n{\n    PROFILE_FUNCTION();\n\n\tfor (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n\t{\n\t\tupdateUnit(unit);\n\t}\n\n\tfor (auto & unit : BWAPI::Broodwar->self()->getUnits())\n\t{\n\t\tupdateUnit(unit);\n\t}\n\n\t// remove bad enemy units\n\tm_unitData[BWAPI::Broodwar->enemy()].removeBadUnits();\n\tm_unitData[BWAPI::Broodwar->self()].removeBadUnits();\n}\n\nconst UIMap & InformationManager::getUnitInfo(BWAPI::Player player) const\n{\n\treturn getUnitData(player).getUnits();\n}\n\nvoid InformationManager::drawExtendedInterface()\n{\n    if (!Config::Debug::DrawUnitHealthBars)\n    {\n        return;\n    }\n\n    int verticalOffset = -10;\n\n    // draw enemy units\n    for (const auto & kv : getUnitData(BWAPI::Broodwar->enemy()).getUnits())\n\t{\n        const UnitInfo & ui(kv.second);\n\n\t\tBWAPI::UnitType type(ui.type);\n        int hitPoints = ui.lastHealth;\n        int shields = ui.lastShields;\n\n        const BWAPI::Position & pos = ui.lastPosition;\n\n        int left    = pos.x - type.dimensionLeft();\n        int right   = pos.x + type.dimensionRight();\n        int top     = pos.y - type.dimensionUp();\n        int bottom  = pos.y + type.dimensionDown();\n\n        if (!BWAPI::Broodwar->isVisible(BWAPI::TilePosition(ui.lastPosition)))\n        {\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, top), BWAPI::Position(right, bottom), BWAPI::Colors::Grey, false);\n            BWAPI::Broodwar->drawTextMap(BWAPI::Position(left + 3, top + 4), \"%s\", ui.type.getName().c_str());\n        }\n        \n        if (!type.isResourceContainer() && type.maxHitPoints() > 0)\n        {\n            double hpRatio = (double)hitPoints / (double)type.maxHitPoints();\n        \n            BWAPI::Color hpColor = BWAPI::Colors::Green;\n            if (hpRatio < 0.66) hpColor = BWAPI::Colors::Orange;\n            if (hpRatio < 0.33) hpColor = BWAPI::Colors::Red;\n\n            int ratioRight = left + (int)((right-left) * hpRatio);\n            int hpTop = top + verticalOffset;\n            int hpBottom = top + 4 + verticalOffset;\n\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), hpColor, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);\n\n            int ticWidth = 3;\n\n            for (int i(left); i < right-1; i+=ticWidth)\n            {\n                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);\n            }\n        }\n\n        if (!type.isResourceContainer() && type.maxShields() > 0)\n        {\n            double shieldRatio = (double)shields / (double)type.maxShields();\n        \n            int ratioRight = left + (int)((right-left) * shieldRatio);\n            int hpTop = top - 3 + verticalOffset;\n            int hpBottom = top + 1 + verticalOffset;\n\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), BWAPI::Colors::Blue, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);\n\n            int ticWidth = 3;\n\n            for (int i(left); i < right-1; i+=ticWidth)\n            {\n                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);\n            }\n        }\n\n    }\n\n    // draw neutral units and our units\n    for (auto & unit : BWAPI::Broodwar->getAllUnits())\n    {\n        if (unit->getPlayer() == BWAPI::Broodwar->enemy())\n        {\n            continue;\n        }\n\n        const BWAPI::Position & pos = unit->getPosition();\n\n        int left    = pos.x - unit->getType().dimensionLeft();\n        int right   = pos.x + unit->getType().dimensionRight();\n        int top     = pos.y - unit->getType().dimensionUp();\n        int bottom  = pos.y + unit->getType().dimensionDown();\n\n        //BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, top), BWAPI::Position(right, bottom), BWAPI::Colors::Grey, false);\n\n        if (!unit->getType().isResourceContainer() && unit->getType().maxHitPoints() > 0)\n        {\n            double hpRatio = (double)unit->getHitPoints() / (double)unit->getType().maxHitPoints();\n        \n            BWAPI::Color hpColor = BWAPI::Colors::Green;\n            if (hpRatio < 0.66) hpColor = BWAPI::Colors::Orange;\n            if (hpRatio < 0.33) hpColor = BWAPI::Colors::Red;\n\n            int ratioRight = left + (int)((right-left) * hpRatio);\n            int hpTop = top + verticalOffset;\n            int hpBottom = top + 4 + verticalOffset;\n\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), hpColor, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);\n\n            int ticWidth = 3;\n\n            for (int i(left); i < right-1; i+=ticWidth)\n            {\n                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);\n            }\n        }\n\n        if (!unit->getType().isResourceContainer() && unit->getType().maxShields() > 0)\n        {\n            double shieldRatio = (double)unit->getShields() / (double)unit->getType().maxShields();\n        \n            int ratioRight = left + (int)((right-left) * shieldRatio);\n            int hpTop = top - 3 + verticalOffset;\n            int hpBottom = top + 1 + verticalOffset;\n\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), BWAPI::Colors::Blue, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);\n\n            int ticWidth = 3;\n\n            for (int i(left); i < right-1; i+=ticWidth)\n            {\n                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);\n            }\n        }\n\n        if (unit->getType().isResourceContainer() && unit->getInitialResources() > 0)\n        {\n            \n            double mineralRatio = (double)unit->getResources() / (double)unit->getInitialResources();\n        \n            int ratioRight = left + (int)((right-left) * mineralRatio);\n            int hpTop = top + verticalOffset;\n            int hpBottom = top + 4 + verticalOffset;\n\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), BWAPI::Colors::Cyan, true);\n            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);\n\n            int ticWidth = 3;\n\n            for (int i(left); i < right-1; i+=ticWidth)\n            {\n                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);\n            }\n        }\n    }\n}\n\nvoid InformationManager::drawUnitInformation(int x, int y) \n{\n\tif (!Config::Debug::DrawEnemyUnitInfo)\n    {\n        return;\n    }\n\n\tstd::string prefix = \"\\x04\";\n\n\tBWAPI::Broodwar->drawTextScreen(x, y-10, \"\\x03 Self Loss:\\x04 Minerals: \\x1f%d \\x04Gas: \\x07%d\", \n        m_unitData[BWAPI::Broodwar->self()].getMineralsLost(), \n        m_unitData[BWAPI::Broodwar->self()].getGasLost());\n    BWAPI::Broodwar->drawTextScreen(x, y, \"\\x03 Enemy Loss:\\x04 Minerals: \\x1f%d \\x04Gas: \\x07%d\", \n        m_unitData[BWAPI::Broodwar->enemy()].getMineralsLost(), \n        m_unitData[BWAPI::Broodwar->enemy()].getGasLost());\n\tBWAPI::Broodwar->drawTextScreen(x, y+10, \"\\x04 Enemy: %s\", BWAPI::Broodwar->enemy()->getName().c_str());\n\tBWAPI::Broodwar->drawTextScreen(x, y+20, \"\\x04 UNIT NAME\");\n\tBWAPI::Broodwar->drawTextScreen(x+140, y+20, \"\\x04#\");\n\tBWAPI::Broodwar->drawTextScreen(x+160, y+20, \"\\x04X\");\n\n\tint yspace = 0;\n\n\t// for each unit in the queue\n\tfor (BWAPI::UnitType t : BWAPI::UnitTypes::allUnitTypes()) \n\t{\n\t\tint numUnits = m_unitData[BWAPI::Broodwar->enemy()].getNumUnits(t);\n\t\tint numDeadUnits = m_unitData[BWAPI::Broodwar->enemy()].getNumDeadUnits(t);\n\n\t\t// if there exist units in the vector\n\t\tif (numUnits > 0) \n\t\t{\n\t\t\tif (t.isDetector())\t\t\t{ prefix = \"\\x10\"; }\t\t\n\t\t\telse if (t.canAttack())\t\t{ prefix = \"\\x08\"; }\t\t\n\t\t\telse if (t.isBuilding())\t{ prefix = \"\\x03\"; }\n\t\t\telse\t\t\t\t\t\t{ prefix = \"\\x04\"; }\n\n\t\t\tBWAPI::Broodwar->drawTextScreen(x, y+40+((yspace)*10), \" %s%s\", prefix.c_str(), t.getName().c_str());\n\t\t\tBWAPI::Broodwar->drawTextScreen(x+140, y+40+((yspace)*10), \"%s%d\", prefix.c_str(), numUnits);\n\t\t\tBWAPI::Broodwar->drawTextScreen(x+160, y+40+((yspace++)*10), \"%s%d\", prefix.c_str(), numDeadUnits);\n\t\t}\n\t}\n}\n\nvoid InformationManager::drawMapInformation()\n{\n    if (!Config::Debug::DrawBWTAInfo)\n    {\n        return;\n    }\n\n\t\n}\n\nvoid InformationManager::updateUnit(BWAPI::Unit unit)\n{\n    if (!(unit->getPlayer() == BWAPI::Broodwar->self() || unit->getPlayer() == BWAPI::Broodwar->enemy()))\n    {\n        return;\n    }\n\n    m_unitData[unit->getPlayer()].updateUnit(unit);\n}\n\n// is the unit valid?\nbool InformationManager::isValidUnit(BWAPI::Unit unit) \n{\n\t// we only care about our units and enemy units\n\tif (unit->getPlayer() != BWAPI::Broodwar->self() && unit->getPlayer() != BWAPI::Broodwar->enemy()) \n\t{\n\t\treturn false;\n\t}\n\n\t// if it's a weird unit, don't bother\n\tif (unit->getType() == BWAPI::UnitTypes::None || unit->getType() == BWAPI::UnitTypes::Unknown ||\n\t\tunit->getType() == BWAPI::UnitTypes::Zerg_Larva || unit->getType() == BWAPI::UnitTypes::Zerg_Egg) \n\t{\n\t\treturn false;\n\t}\n\n\t// if the position isn't valid throw it out\n\tif (!unit->getPosition().isValid()) \n\t{\n\t\treturn false;\t\n\t}\n\n\t// s'all good baby baby\n\treturn true;\n}\n\nvoid InformationManager::onUnitDestroy(BWAPI::Unit unit) \n{ \n    if (unit->getType().isNeutral())\n    {\n        return;\n    }\n\n    m_unitData[unit->getPlayer()].removeUnit(unit);\n}\n\nbool InformationManager::isCombatUnit(BWAPI::UnitType type) const\n{\n\tif (type == BWAPI::UnitTypes::Zerg_Lurker/* || type == BWAPI::UnitTypes::Protoss_Dark_Templar*/)\n\t{\n\t\treturn false;\n\t}\n\n\t// check for various types of combat units\n\tif (type.canAttack() || \n\t\ttype == BWAPI::UnitTypes::Terran_Medic || \n\t\ttype == BWAPI::UnitTypes::Protoss_Observer ||\n        type == BWAPI::UnitTypes::Terran_Bunker)\n\t{\n\t\treturn true;\n\t}\n\t\t\n\treturn false;\n}\n\nvoid InformationManager::getNearbyForce(std::vector<UnitInfo> & unitInfo, BWAPI::Position p, BWAPI::Player player, int radius) \n{\n\tbool hasBunker = false;\n\t// for each unit we know about for that player\n\tfor (const auto & kv : getUnitData(player).getUnits())\n\t{\n\t\tconst UnitInfo & ui(kv.second);\n\n\t\t// if it's a combat unit we care about\n\t\t// and it's finished! \n\t\tif (isCombatUnit(ui.type) && ui.completed)\n\t\t{\n\t\t\t// determine its attack range\n\t\t\tint range = 0;\n\t\t\tif (ui.type.groundWeapon() != BWAPI::WeaponTypes::None)\n\t\t\t{\n\t\t\t\trange = ui.type.groundWeapon().maxRange() + 40;\n\t\t\t}\n\n\t\t\t// if it can attack into the radius we care about\n\t\t\tif (ui.lastPosition.getDistance(p) <= (radius + range))\n\t\t\t{\n\t\t\t\t// add it to the vector\n\t\t\t\tunitInfo.push_back(ui);\n\t\t\t}\n\t\t}\n\t\telse if (ui.type.isDetector() && ui.lastPosition.getDistance(p) <= (radius + 250))\n        {\n\t\t\t// add it to the vector\n\t\t\tunitInfo.push_back(ui);\n        }\n\t}\n}\n\nint InformationManager::getNumUnits(BWAPI::UnitType t, BWAPI::Player player)\n{\n\treturn getUnitData(player).getNumUnits(t);\n}\n\nconst UnitData & InformationManager::getUnitData(BWAPI::Player player) const\n{\n    return m_unitData.find(player)->second;\n}\n\nbool InformationManager::enemyHasCloakedUnits()\n{\n    for (const auto & kv : getUnitData(BWAPI::Broodwar->enemy()).getUnits())\n\t{\n\t\tconst UnitInfo & ui(kv.second);\n\n        if (ui.type.isCloakable())\n        {\n            return true;\n        }\n\n        // assume they're going dts\n        if (ui.type == BWAPI::UnitTypes::Protoss_Citadel_of_Adun)\n        {\n            return true;\n        }\n\n        if (ui.type == BWAPI::UnitTypes::Protoss_Observatory)\n        {\n            return true;\n        }\n    }\n\n\treturn false;\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/InformationManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"UnitData.h\"\n\nnamespace UAlbertaBot\n{\nstruct BaseInfo;\n\ntypedef std::vector<BaseInfo> BaseInfoVector;\n\nclass InformationManager\n{\n    friend class Global;\n\n    std::map<BWAPI::Player, UnitData> m_unitData;\n\n    void updateUnit(BWAPI::Unit unit);\n    void updateUnitInfo();\n    bool isValidUnit(BWAPI::Unit unit);\n\n    InformationManager();\n\npublic:\n\n    void update();\n\n    // event driven stuff\n    void onUnitShow(BWAPI::Unit unit)       { updateUnit(unit); }\n    void onUnitHide(BWAPI::Unit unit)       { updateUnit(unit); }\n    void onUnitCreate(BWAPI::Unit unit)     { updateUnit(unit); }\n    void onUnitComplete(BWAPI::Unit unit)   { updateUnit(unit); }\n    void onUnitMorph(BWAPI::Unit unit)      { updateUnit(unit); }\n    void onUnitRenegade(BWAPI::Unit unit)   { updateUnit(unit); }\n    void onUnitDestroy(BWAPI::Unit unit);\n\n    int  getNumUnits(BWAPI::UnitType type, BWAPI::Player player);\n    bool isCombatUnit(BWAPI::UnitType type) const;\n    void getNearbyForce(std::vector<UnitInfo> & unitInfo, BWAPI::Position p, BWAPI::Player player, int radius);\n    bool enemyHasCloakedUnits();\n    void drawExtendedInterface();\n    void drawUnitInformation(int x, int y);\n    void drawMapInformation();\n\n    const UIMap &    getUnitInfo(BWAPI::Player player) const;\n    const UnitData & getUnitData(BWAPI::Player player) const;\n};\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/JSONTools.cpp",
    "content": "#include \"Common.h\"\n#include \"JSONTools.h\"\n\nnamespace UAlbertaBot\n{\nnamespace JSONTools\n{\n    void ReadBool(const char * key, const rapidjson::Value & value, bool & dest)\n    {\n        if (value.HasMember(key))\n        {\n            UAB_ASSERT(value[key].IsBool(), \"%s should be a bool\", key);\n            dest = value[key].GetBool();\n        }\n    }\n\n    void ReadString(const char * key, const rapidjson::Value & value, std::string & dest)\n    {\n        if (value.HasMember(key))\n        {\n            UAB_ASSERT(value[key].IsString(), \"%s should be a string\", key);\n            dest = value[key].GetString();\n        }\n    }\n}\n}\n\n"
  },
  {
    "path": "UAlbertaBot/Source/JSONTools.h",
    "content": "#pragma once\n\n#include \"rapidjson/rapidjson.h\"\n#include \"rapidjson/document.h\"\n\nnamespace UAlbertaBot\n{\nnamespace JSONTools\n{\n    template <class T>\n    void ReadInt(const char * key, const rapidjson::Value & value, T & dest)\n    {\n        if (value.HasMember(key))\n        {\n            UAB_ASSERT(value[key].IsInt(), \"%s should be an int\", key);\n            dest = (T)value[key].GetInt();\n        }\n    }\n\n    void ReadBool(const char * key, const rapidjson::Value & value, bool & dest);\n    void ReadString(const char * key, const rapidjson::Value & value, std::string & dest);\n}\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/Logger.cpp",
    "content": "#include \"Common.h\"\n#include \"Logger.h\"\n#include \"UABAssert.h\"\n#include <stdarg.h>\n#include <cstdio>\n#include <sstream>\n\nusing namespace UAlbertaBot;\n\nvoid Logger::LogAppendToFile(const std::string & logFile, const std::string & msg)\n{\n    std::ofstream logStream;\n    logStream.open(logFile.c_str(), std::ofstream::app);\n    logStream << msg;\n    logStream.flush();\n    logStream.close();\n}\n\nvoid Logger::LogAppendToFile(const std::string & logFile, const char *fmt, ...)\n{\n\tva_list arg;\n\t\t\n\tva_start(arg, fmt);\n\t//vfprintf(log_file, fmt, arg);\n\tchar buff[256];\n\tvsnprintf_s(buff, 256, fmt, arg);\n\tva_end(arg);\n\t\t\n\tstd::ofstream logStream;\n\tlogStream.open(logFile.c_str(), std::ofstream::app);\n\tlogStream << buff;\n\tlogStream.flush();\n\tlogStream.close();\n}\n\nvoid Logger::LogOverwriteToFile(const std::string & logFile, const std::string & msg)\n{\n    std::ofstream logStream(logFile.c_str());\n    logStream << msg;\n    logStream.flush();\n    logStream.close();\n}\n\n\nstd::string FileUtils::ReadFile(const std::string & filename)\n{\n    std::stringstream ss;\n\n    FILE *file = fopen ( filename.c_str(), \"r\" );\n    if ( file != nullptr )\n    {\n        char line [ 4096 ]; /* or other suitable maximum line size */\n        while ( fgets ( line, sizeof line, file ) != nullptr ) /* read a line */\n        {\n            ss << line;\n        }\n        fclose ( file );\n    }\n    else\n    {\n        BWAPI::Broodwar->printf(\"Could not open file: %s\", filename.c_str());\n    }\n\n    return ss.str();\n}"
  },
  {
    "path": "UAlbertaBot/Source/Logger.h",
    "content": "#pragma once\n\n#include <string>\n#include <iostream>\n#include <fstream>\n\nnamespace UAlbertaBot\n{\nnamespace Logger \n{\n    void LogAppendToFile(const std::string & logFile, const std::string & msg);\n\tvoid LogAppendToFile(const std::string & logFile, const char *fmt, ...);\n    void LogOverwriteToFile(const std::string & logFile, const std::string & msg);\n};\n\nnamespace FileUtils\n{\n    std::string ReadFile(const std::string & filename);\n}\n}"
  },
  {
    "path": "UAlbertaBot/Source/MapTools.cpp",
    "content": "#include \"MapTools.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n\n#include <iostream>\n#include <sstream>\n#include <fstream>\n#include <array>\n\nusing namespace UAlbertaBot;\n\nconst size_t LegalActions = 4;\nconst int actionX[LegalActions] ={1, -1, 0, 0};\nconst int actionY[LegalActions] ={0, 0, 1, -1};\n\n// constructor for MapTools\nMapTools::MapTools()\n{\n    onStart();\n}\n\nvoid MapTools::onStart()\n{\n    PROFILE_FUNCTION();\n\n    m_width          = BWAPI::Broodwar->mapWidth();\n    m_height         = BWAPI::Broodwar->mapHeight();\n    m_walkable       = Grid<int>(m_width, m_height, 1);\n    m_buildable      = Grid<int>(m_width, m_height, 0);\n    m_depotBuildable = Grid<int>(m_width, m_height, 0);\n    m_lastSeen       = Grid<int>(m_width, m_height, 0);\n    m_sectorNumber   = Grid<int>(m_width, m_height, 0);\n\n    // Set the boolean grid data from the Map\n    for (int x(0); x < m_width; ++x)\n    {\n        for (int y(0); y < m_height; ++y)\n        {\n            m_buildable.set(x, y, canBuild(x, y));\n            m_depotBuildable.set(x, y, canBuild(x, y));\n            m_walkable.set(x, y, m_buildable.get(x,y) || canWalk(x, y));\n        }\n    }\n\n    // set tiles that static resources are on as unbuildable\n    for (auto & resource : BWAPI::Broodwar->getStaticNeutralUnits())\n    {\n        if (!resource->getType().isResourceContainer())\n        {\n            continue;\n        }\n\n        const int tileX = resource->getTilePosition().x;\n        const int tileY = resource->getTilePosition().y;\n\n        for (int x=tileX; x<tileX+resource->getType().tileWidth(); ++x)\n        {\n            for (int y=tileY; y<tileY+resource->getType().tileHeight(); ++y)\n            {\n                m_buildable.set(x, y, false);\n\n                // depots can't be built within 3 tiles of any resource\n                for (int rx=-3; rx<=3; rx++)\n                {\n                    for (int ry=-3; ry<=3; ry++)\n                    {\n                        if (!BWAPI::TilePosition(x+rx, y+ry).isValid())\n                        {\n                            continue;\n                        }\n\n                        m_depotBuildable.set(x+rx, y+ry, 0);\n                    }\n                }\n            }\n        }\n    }\n\n    // compute the map connectivity\n    computeConnectivity();\n    computeMap();\n}\n\nvoid MapTools::onFrame()\n{\n    PROFILE_FUNCTION();\n\n    for (int x=0; x<m_width; ++x)\n    {\n        for (int y=0; y<m_height; ++y)\n        {\n            if (isVisible(x, y))\n            {\n                m_lastSeen.set(x, y, m_frame);\n            }\n        }\n    }\n    \n    m_frame++;\n    draw();\n}\n\nvoid MapTools::computeMap()\n{\n    if (m_map.width() > 0) { return; }\n\n    m_map = StarDraftMap(BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight());\n\n    for (size_t x = 0; x < m_map.width(); x++)\n    {\n        for (size_t y = 0; y < m_map.height(); y++)\n        {\n            if      (isDepotBuildableTile(x, y)) { m_map.set(x, y, TileType::BuildAll);   }\n            else if (isBuildable(x, y))          { m_map.set(x, y, TileType::NoDepot);    }\n            else if (isWalkable(x, y))           { m_map.set(x, y, TileType::Walk);       }\n            else                                 { m_map.set(x, y, TileType::Unwalkable); }\n        }\n    }\n\n    for (auto & mineral : BWAPI::Broodwar->getStaticMinerals())\n    {\n        const BWAPI::TilePosition mineralTile(mineral->getPosition());\n        m_map.set(mineralTile.x, mineralTile.y, TileType::Mineral);\n        m_map.set(mineralTile.x-1, mineralTile.y, TileType::Mineral);\n    }\n\n    for (auto & geyser : BWAPI::Broodwar->getStaticGeysers())\n    {\n        const BWAPI::TilePosition geyserTile(geyser->getPosition());\n        m_map.set(geyserTile.x, geyserTile.y, TileType::Gas);\n        m_map.set(geyserTile.x+1, geyserTile.y, TileType::Gas);\n        m_map.set(geyserTile.x-1, geyserTile.y, TileType::Gas);\n        m_map.set(geyserTile.x-2, geyserTile.y, TileType::Gas);\n        m_map.set(geyserTile.x, geyserTile.y-1, TileType::Gas);\n        m_map.set(geyserTile.x+1, geyserTile.y-1, TileType::Gas);\n        m_map.set(geyserTile.x-1, geyserTile.y-1, TileType::Gas);\n        m_map.set(geyserTile.x-2, geyserTile.y-1, TileType::Gas);\n    }\n\n    for (auto & tile : BWAPI::Broodwar->getStartLocations())\n    {\n        m_map.addStartTile(tile.x, tile.y);\n    }\n\n    for (size_t x=0; x<4*m_map.width(); x++)\n    {\n        for (size_t y=0; y<4*m_map.height(); y++)\n        {\n            m_map.setWalk(x, y, BWAPI::Broodwar->isWalkable(x,y));\n        }\n    }\n}\n\nvoid MapTools::computeConnectivity()\n{\n    PROFILE_FUNCTION();\n\n    // the fringe data structe we will use to do our BFS searches\n    std::vector<std::array<int, 2>> fringe;\n    fringe.reserve(m_width*m_height);\n    int sectorNumber = 0;\n\n    // for every tile on the map, do a connected flood fill using BFS\n    for (int x=0; x<m_width; ++x)\n    {\n        for (int y=0; y<m_height; ++y)\n        {\n            // if the sector is not currently 0, or the map isn't walkable here, then we can skip this tile\n            if (getSectorNumber(x, y) != 0 || !isWalkable(x, y))\n            {\n                continue;\n            }\n\n            // increase the sector number, so that walkable tiles have sectors 1-N\n            sectorNumber++;\n\n            // reset the fringe for the search and add the start tile to it\n            fringe.clear();\n            fringe.push_back({x,y});\n            m_sectorNumber.set(x, y, sectorNumber);\n\n            // do the BFS, stopping when we reach the last element of the fringe\n            for (size_t fringeIndex=0; fringeIndex<fringe.size(); ++fringeIndex)\n            {\n                auto & tile = fringe[fringeIndex];\n\n                // check every possible child of this tile\n                for (size_t a=0; a<LegalActions; ++a)\n                {\n                    const int nextX = tile[0] + actionX[a];\n                    const int nextY = tile[1] + actionY[a];\n\n                    // if the new tile is inside the map bounds, is walkable, and has not been assigned a sector, add it to the current sector and the fringe\n                    if (isValidTile(nextX, nextY) && isWalkable(nextX, nextY) && (getSectorNumber(nextX, nextY) == 0))\n                    {\n                        m_sectorNumber.set(nextX, nextY, sectorNumber);\n                        fringe.push_back({nextX, nextY});\n                    }\n                }\n            }\n        }\n    }\n}\n\nbool MapTools::isExplored(const BWAPI::TilePosition & pos) const\n{\n    return isExplored(pos.x, pos.y);\n}\n\nbool MapTools::isExplored(const BWAPI::Position & pos) const\n{\n    return isExplored(BWAPI::TilePosition(pos));\n}\n\nbool MapTools::isExplored(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY)) { return false; }\n\n    return BWAPI::Broodwar->isExplored(tileX, tileY);\n}\n\nbool MapTools::isVisible(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY)) { return false; }\n\n    return BWAPI::Broodwar->isVisible(BWAPI::TilePosition(tileX, tileY));\n}\n\nbool MapTools::isPowered(int tileX, int tileY) const\n{\n    return BWAPI::Broodwar->hasPower(BWAPI::TilePosition(tileX, tileY));\n}\n\nint MapTools::getGroundDistance(const BWAPI::Position & src, const BWAPI::Position & dest) const\n{\n    if (m_allMaps.size() > 50)\n    {\n        m_allMaps.clear();\n    }\n\n    return getDistanceMap(dest).getDistance(src);\n}\n\nconst DistanceMap & MapTools::getDistanceMap(const BWAPI::Position & pos) const\n{\n    return getDistanceMap(BWAPI::TilePosition(pos));\n}\n\nconst DistanceMap & MapTools::getDistanceMap(const BWAPI::TilePosition & tile) const\n{\n    std::pair<int,int> pairTile(tile.x, tile.y);\n\n    if (m_allMaps.find(pairTile) == m_allMaps.end())\n    {\n        m_allMaps[pairTile] = DistanceMap();\n        m_allMaps[pairTile].computeDistanceMap(tile);\n    }\n\n    return m_allMaps[pairTile];\n}\n\nint MapTools::getSectorNumber(int x, int y) const\n{\n    if (!isValidTile(x, y))\n    {\n        return 0;\n    }\n\n    return m_sectorNumber.get(x, y);\n}\n\nbool MapTools::isValidTile(int tileX, int tileY) const\n{\n    return tileX >= 0 && tileY >= 0 && tileX < m_width && tileY < m_height;\n}\n\nbool MapTools::isValidTile(const BWAPI::TilePosition & tile) const\n{\n    return isValidTile(tile.x, tile.y);\n}\n\nbool MapTools::isValidPosition(const BWAPI::Position & pos) const\n{\n    return isValidTile(BWAPI::TilePosition(pos));\n}\n\nbool MapTools::isConnected(int x1, int y1, int x2, int y2) const\n{\n    if (!isValidTile(x1, y1) || !isValidTile(x2, y2))\n    {\n        return false;\n    }\n\n    const int s1 = getSectorNumber(x1, y1);\n    const int s2 = getSectorNumber(x2, y2);\n\n    return s1 != 0 && (s1 == s2);\n}\n\nbool MapTools::isConnected(const BWAPI::TilePosition & p1, const BWAPI::TilePosition & p2) const\n{\n    return isConnected(p1.x, p1.y, p2.x, p2.y);\n}\n\nbool MapTools::isConnected(const BWAPI::Position & p1, const BWAPI::Position & p2) const\n{\n    return isConnected(BWAPI::TilePosition(p1), BWAPI::TilePosition(p2));\n}\n\nbool MapTools::isBuildable(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY))\n    {\n        return false;\n    }\n\n    return m_buildable.get(tileX, tileY);\n}\n\nbool MapTools::canBuildTypeAtPosition(int tileX, int tileY, const BWAPI::UnitType & type) const\n{\n    return BWAPI::Broodwar->canBuildHere(BWAPI::TilePosition(tileX, tileY), type);\n}\n\nbool MapTools::isBuildable(const BWAPI::TilePosition & tile) const\n{\n    return isBuildable(tile.x, tile.y);\n}\n\nvoid MapTools::printMap() const\n{\n    std::stringstream ss;\n    for (int y(0); y < m_height; ++y)\n    {\n        for (int x(0); x < m_width; ++x)\n        {\n            ss << isWalkable(x, y);\n        }\n\n        ss << \"\\n\";\n    }\n\n    std::ofstream out(\"map.txt\");\n    out << ss.str();\n    out.close();\n}\n\nbool MapTools::isDepotBuildableTile(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY))\n    {\n        return false;\n    }\n\n    return m_depotBuildable.get(tileX, tileY);\n}\n\nbool MapTools::isWalkable(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY))\n    {\n        return false;\n    }\n\n    return m_walkable.get(tileX, tileY);\n}\n\nbool MapTools::isWalkable(const BWAPI::TilePosition & tile) const\n{\n    return isWalkable(tile.x, tile.y);\n}\n\nint MapTools::width() const\n{\n    return m_width;\n}\n\nint MapTools::height() const\n{\n    return m_height;\n}\n\nvoid MapTools::drawTile(int tileX, int tileY, const BWAPI::Color & color) const\n{\n    const int padding   = 2;\n    const int px        = tileX*32 + padding;\n    const int py        = tileY*32 + padding;\n    const int d         = 32 - 2*padding;\n\n    BWAPI::Broodwar->drawLineMap(px,     py,     px + d, py,     color);\n    BWAPI::Broodwar->drawLineMap(px + d, py,     px + d, py + d, color);\n    BWAPI::Broodwar->drawLineMap(px + d, py + d, px,     py + d, color);\n    BWAPI::Broodwar->drawLineMap(px,     py + d, px,     py,     color);\n}\n\nconst std::vector<BWAPI::TilePosition> & MapTools::getClosestTilesTo(const BWAPI::TilePosition & tilePos) const\n{\n    return getDistanceMap(tilePos).getSortedTiles();\n}\n\nconst std::vector<BWAPI::TilePosition> & MapTools::getClosestTilesTo(const BWAPI::Position & pos) const\n{\n    return getClosestTilesTo(BWAPI::TilePosition(pos));\n}\n\nBWAPI::TilePosition MapTools::getLeastRecentlySeenTile() const\n{\n    int minSeen = std::numeric_limits<int>::max();\n    BWAPI::TilePosition leastSeen;\n    const BaseLocation * baseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->self());\n    UAB_ASSERT(baseLocation, \"Null self baselocation is insanely bad\");\n\n    for (auto & tile : baseLocation->getClosestTiles())\n    {\n        UAB_ASSERT(isValidTile(tile), \"How is this tile not valid?\");\n\n        const int lastSeen = m_lastSeen.get(tile.x, tile.y);\n        if (lastSeen < minSeen)\n        {\n            minSeen = lastSeen;\n            leastSeen = tile;\n        }\n    }\n\n    return leastSeen;\n}\n\nbool MapTools::canWalk(int tileX, int tileY) const\n{\n    for (int i=0; i<4; ++i)\n    {\n        for (int j=0; j<4; ++j)\n        {\n            if (!BWAPI::Broodwar->isWalkable(tileX*4 + i, tileY*4 + j))\n            {\n                return false;\n            }\n        }\n    }\n\n    return true;\n}\n\nbool MapTools::canBuild(int tileX, int tileY) const\n{\n    return BWAPI::Broodwar->isBuildable(BWAPI::TilePosition(tileX, tileY));\n}\n\nvoid MapTools::draw() const\n{\n    const BWAPI::TilePosition screen(BWAPI::Broodwar->getScreenPosition());\n    const int sx = screen.x;\n    const int sy = screen.y;\n    const int ex = sx + 20;\n    const int ey = sy + 15;\n    \n    for (int x = sx; x < ex; ++x)\n    {\n        for (int y = sy; y < ey; y++)\n        {\n            const BWAPI::TilePosition tilePos(x,y);\n            if (!tilePos.isValid()) { continue; }\n\n            if (Config::Debug::DrawWalkableSectors)\n            {\n                std::stringstream ss;\n                ss << getSectorNumber(x, y);\n                const BWAPI::Position pos = BWAPI::Position(tilePos) + BWAPI::Position(14,9);\n                BWAPI::Broodwar->drawTextMap(pos, ss.str().c_str());\n            }\n\n            if (Config::Debug::DrawTileInfo)\n            {\n                BWAPI::Color color = isWalkable(x, y) ? BWAPI::Color(0, 255, 0) : BWAPI::Color(255, 0, 0);\n                if (isWalkable(x, y) && !isBuildable(x, y)) { color = BWAPI::Color(255, 255, 0); }\n                if (isBuildable(x, y) && !isDepotBuildableTile(x, y)) { color = BWAPI::Color(127, 255, 255); }\n                drawTile(x, y, color);\n            }\n        }\n    }\n}\n\nvoid MapTools::getUnits(BWAPI::Unitset & units, BWAPI::Position center, int radius, bool ourUnits, bool oppUnits)\n{\n\tconst int radiusSq(radius * radius);\n\n\tif (ourUnits)\n\t{\n\t\tfor (auto & unit : BWAPI::Broodwar->self()->getUnits())\n\t\t{\n\t\t\tBWAPI::Position d(unit->getPosition() - center);\n\t\t\tif(d.x * d.x + d.y * d.y <= radiusSq)\n\t\t\t{\n\t\t\t\tif (!units.contains(unit)) \n\t\t\t\t{\n\t\t\t\t\tunits.insert(unit);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (oppUnits)\n\t{\n\t\tfor (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) \n\t\t{\n            if (unit->getType() == BWAPI::UnitTypes::Unknown || !unit->isVisible())\n            {\n                continue;\n            }\n\n\t\t\tBWAPI::Position d(unit->getPosition() - center);\n\t\t\tif(d.x * d.x + d.y * d.y <= radiusSq)\n\t\t\t{\n\t\t\t\tif (!units.contains(unit))\n\t\t\t\t{ \n\t\t\t\t\tunits.insert(unit); \n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst StarDraftMap & MapTools::getStarDraftMap() const\n{\n    return m_map;\n}\n    \nvoid MapTools::saveMapToFile(const std::string & path) const\n{\n    // replace spaces with underscores\n    std::string mapFile = BWAPI::Broodwar->mapFileName();\n    std::replace( mapFile.begin(), mapFile.end(), ' ', '_'); \n    getStarDraftMap().save(mapFile + \".txt\");\n}"
  },
  {
    "path": "UAlbertaBot/Source/MapTools.h",
    "content": "#pragma once\n\n#include <vector>\n#include \"DistanceMap.h\"\n#include \"Grid.hpp\"\n\n#include \"stardraft/StarDraft.h\"\n\nnamespace UAlbertaBot\n{\n\nclass MapTools\n{\n    friend class Global;\n    \n    StarDraftMap m_map;\n\n    int     m_width = 0;\n    int     m_height = 0;\n    int     m_frame = 0;\n    \n    // a cache of already computed distance maps, which is mutable since it only acts as a cache\n    mutable std::map<std::pair<int,int>, DistanceMap> m_allMaps;   \n\n    Grid<int> m_walkable;       // whether a tile is buildable (includes static resources)          \n    Grid<int> m_buildable;      // whether a tile is buildable (includes static resources)\n    Grid<int> m_depotBuildable; // whether a depot is buildable on a tile (illegal within 3 tiles of static resource)\n    Grid<int> m_lastSeen;       // the last time any of our units has seen this position on the map\n    Grid<int> m_sectorNumber;   // connectivity sector number, two tiles are ground connected if they have the same number\n    \n    void computeMap();\n\n    void computeConnectivity();\n    int  getSectorNumber(int x, int y) const;\n    void printMap() const;\n    bool canBuild(int tileX, int tileY) const;\n    bool canWalk(int tileX, int tileY) const;\n\n    MapTools();\n\npublic:\n    \n    void    onStart();\n    void    onFrame();\n    void    draw() const;\n\n    int     width() const;\n    int     height() const;\n\n    bool    isValidTile(int tileX, int tileY) const;\n    bool    isValidTile(const BWAPI::TilePosition & tile) const;\n    bool    isValidPosition(const BWAPI::Position & pos) const;\n    bool    isPowered(int tileX, int tileY) const;\n    bool    isExplored(int tileX, int tileY) const;\n    bool    isExplored(const BWAPI::Position & pos) const;\n    bool    isExplored(const BWAPI::TilePosition & pos) const;\n    bool    isVisible(int tileX, int tileY) const;\n    bool    canBuildTypeAtPosition(int tileX, int tileY, const BWAPI::UnitType & type) const;\n    void    drawTile(int tileX, int tileY, const BWAPI::Color & color) const;\n\n    const   DistanceMap & getDistanceMap(const BWAPI::TilePosition & tile) const;\n    const   DistanceMap & getDistanceMap(const BWAPI::Position & tile) const;\n    int     getGroundDistance(const BWAPI::Position & src, const BWAPI::Position & dest) const;\n    bool    isConnected(int x1, int y1, int x2, int y2) const;\n    bool    isConnected(const BWAPI::TilePosition & from, const BWAPI::TilePosition & to) const;\n    bool    isConnected(const BWAPI::Position & from, const BWAPI::Position & to) const;\n    bool    isWalkable(int tileX, int tileY) const;\n    bool    isWalkable(const BWAPI::TilePosition & tile) const;\n    \n    bool    isBuildable(int tileX, int tileY) const;\n    bool    isBuildable(const BWAPI::TilePosition & tile) const;\n    bool    isDepotBuildableTile(int tileX, int tileY) const;\n    \n    void    getUnits(BWAPI::Unitset & units, BWAPI::Position center, int radius, bool ourUnits, bool oppUnits);\n\n    const StarDraftMap & getStarDraftMap() const;\n    void saveMapToFile(const std::string & path) const;\n\n    BWAPI::TilePosition getLeastRecentlySeenTile() const;\n\n    // returns a list of all tiles on the map, sorted by 4-direcitonal walk distance from the given position\n    const std::vector<BWAPI::TilePosition> & getClosestTilesTo(const BWAPI::TilePosition & tilePos) const;\n    const std::vector<BWAPI::TilePosition> & getClosestTilesTo(const BWAPI::Position & pos) const;\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/MedicManager.cpp",
    "content": "#include \"Common.h\"\n#include \"MedicManager.h\"\n#include \"UnitUtil.h\"\n#include \"Micro.h\"\n\nusing namespace UAlbertaBot;\n\nMedicManager::MedicManager()\n{\n}\n\nvoid MedicManager::executeMicro(const BWAPI::Unitset & targets)\n{\n    const BWAPI::Unitset & medics = getUnits();\n\n    // create a set of all medic targets\n    BWAPI::Unitset medicTargets;\n    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        if (unit->getHitPoints() < unit->getInitialHitPoints() && !unit->getType().isMechanical() && !unit->getType().isBuilding())\n        {\n            medicTargets.insert(unit);\n        }\n    }\n\n    BWAPI::Unitset availableMedics(medics);\n\n    // for each target, send the closest medic to heal it\n    for (auto & target : medicTargets)\n    {\n        // only one medic can heal a target at a time\n        if (target->isBeingHealed())\n        {\n            continue;\n        }\n\n        double closestMedicDist = std::numeric_limits<double>::infinity();\n        BWAPI::Unit closestMedic = nullptr;\n\n        for (auto & medic : availableMedics)\n        {\n            double dist = medic->getDistance(target);\n\n            if (!closestMedic || (dist < closestMedicDist))\n            {\n                closestMedic = medic;\n                closestMedicDist = dist;\n            }\n        }\n\n        // if we found a medic, send it to heal the target\n        if (closestMedic)\n        {\n            closestMedic->useTech(BWAPI::TechTypes::Healing, target);\n\n            availableMedics.erase(closestMedic);\n        }\n        // otherwise we didn't find a medic which means they're all in use so break\n        else\n        {\n            break;\n        }\n    }\n\n    // the remaining medics should head to the squad order position\n    for (auto & medic : availableMedics)\n    {\n        Micro::SmartAttackMove(medic, m_order.getPosition());\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/MedicManager.h",
    "content": "#pragma once\n\n#include \"MicroManager.h\"\n\nnamespace UAlbertaBot\n{\nclass MedicManager : public MicroManager\n{\npublic:\n\n    MedicManager();\n    void executeMicro(const BWAPI::Unitset & targets);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/MeleeManager.cpp",
    "content": "#include \"MeleeManager.h\"\n#include \"UnitUtil.h\"\n#include \"Micro.h\"\n\nusing namespace UAlbertaBot;\n\nMeleeManager::MeleeManager()\n{\n\n}\n\nvoid MeleeManager::executeMicro(const BWAPI::Unitset & targets)\n{\n    assignTargetsOld(targets);\n}\n\nvoid MeleeManager::assignTargetsOld(const BWAPI::Unitset & targets)\n{\n    const BWAPI::Unitset & meleeUnits = getUnits();\n\n    // figure out targets\n    BWAPI::Unitset meleeUnitTargets;\n    for (auto & target : targets)\n    {\n        // conditions for targeting\n        if (!(target->getType().isFlyer()) &&\n            !(target->isLifted()) &&\n            !(target->getType() == BWAPI::UnitTypes::Zerg_Larva) &&\n            !(target->getType() == BWAPI::UnitTypes::Zerg_Egg) &&\n            target->isVisible())\n        {\n            meleeUnitTargets.insert(target);\n        }\n    }\n\n    // for each meleeUnit\n    for (auto & meleeUnit : meleeUnits)\n    {\n        // if the order is to attack or defend\n        if (m_order.getType() == SquadOrderTypes::Attack || m_order.getType() == SquadOrderTypes::Defend)\n        {\n            // run away if we meet the retreat critereon\n            if (meleeUnitShouldRetreat(meleeUnit, targets))\n            {\n                BWAPI::Position fleeTo(BWAPI::Broodwar->self()->getStartLocation());\n\n                Micro::SmartMove(meleeUnit, fleeTo);\n            }\n            // if there are targets\n            else if (!meleeUnitTargets.empty())\n            {\n                // find the best target for this meleeUnit\n                BWAPI::Unit target = getTarget(meleeUnit, meleeUnitTargets);\n\n                // attack it\n                Micro::SmartAttackUnit(meleeUnit, target);\n            }\n            // if there are no targets\n            else\n            {\n                // if we're not near the order position\n                if (meleeUnit->getDistance(m_order.getPosition()) > 100)\n                {\n                    // move to it\n                    Micro::SmartMove(meleeUnit, m_order.getPosition());\n                }\n            }\n        }\n\n        if (Config::Debug::DrawUnitTargetInfo)\n        {\n            BWAPI::Broodwar->drawLineMap(meleeUnit->getPosition().x, meleeUnit->getPosition().y,\n                meleeUnit->getTargetPosition().x, meleeUnit->getTargetPosition().y, Config::Debug::ColorLineTarget);\n        }\n    }\n}\n\nstd::pair<BWAPI::Unit, BWAPI::Unit> MeleeManager::findClosestUnitPair(const BWAPI::Unitset & attackers, const BWAPI::Unitset & targets)\n{\n    std::pair<BWAPI::Unit, BWAPI::Unit> closestPair(nullptr, nullptr);\n    double closestDistance = std::numeric_limits<double>::max();\n\n    for (auto & attacker : attackers)\n    {\n        BWAPI::Unit target = getTarget(attacker, targets);\n        double dist = attacker->getDistance(attacker);\n\n        if (!closestPair.first || (dist < closestDistance))\n        {\n            closestPair.first = attacker;\n            closestPair.second = target;\n            closestDistance = dist;\n        }\n    }\n\n    return closestPair;\n}\n\n// get a target for the meleeUnit to attack\nBWAPI::Unit MeleeManager::getTarget(BWAPI::Unit meleeUnit, const BWAPI::Unitset & targets)\n{\n    int highPriority = 0;\n    double closestDist = std::numeric_limits<double>::infinity();\n    BWAPI::Unit closestTarget = nullptr;\n\n    // for each target possiblity\n    for (auto & unit : targets)\n    {\n        int priority = getAttackPriority(meleeUnit, unit);\n        int distance = meleeUnit->getDistance(unit);\n\n        // if it's a higher priority, or it's closer, set it\n        if (!closestTarget || (priority > highPriority) || (priority == highPriority && distance < closestDist))\n        {\n            closestDist = distance;\n            highPriority = priority;\n            closestTarget = unit;\n        }\n    }\n\n    return closestTarget;\n}\n\n// get the attack priority of a type in relation to a zergling\nint MeleeManager::getAttackPriority(BWAPI::Unit attacker, BWAPI::Unit unit)\n{\n    BWAPI::UnitType type = unit->getType();\n\n    if (attacker->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar\n        && unit->getType() == BWAPI::UnitTypes::Terran_Missile_Turret\n        && (BWAPI::Broodwar->self()->deadUnitCount(BWAPI::UnitTypes::Protoss_Dark_Templar) == 0))\n    {\n        return 13;\n    }\n\n    if (attacker->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar && unit->getType().isWorker())\n    {\n        return 12;\n    }\n\n    // highest priority is something that can attack us or aid in combat\n    if (type ==  BWAPI::UnitTypes::Terran_Bunker)\n    {\n        return 11;\n    }\n    else if (type == BWAPI::UnitTypes::Terran_Medic ||\n        (type.groundWeapon() != BWAPI::WeaponTypes::None && !type.isWorker()) ||\n        type ==  BWAPI::UnitTypes::Terran_Bunker ||\n        type == BWAPI::UnitTypes::Protoss_High_Templar ||\n        type == BWAPI::UnitTypes::Protoss_Reaver ||\n        (type.isWorker() && unitNearChokepoint(unit)))\n    {\n        return 10;\n    }\n    // next priority is worker\n    else if (type.isWorker())\n    {\n        return 9;\n    }\n    // next is special buildings\n    else if (type == BWAPI::UnitTypes::Zerg_Spawning_Pool)\n    {\n        return 5;\n    }\n    // next is special buildings\n    else if (type == BWAPI::UnitTypes::Protoss_Pylon)\n    {\n        return 5;\n    }\n    // next is buildings that cost gas\n    else if (type.gasPrice() > 0)\n    {\n        return 4;\n    }\n    else if (type.mineralPrice() > 0)\n    {\n        return 3;\n    }\n    // then everything else\n    else\n    {\n        return 1;\n    }\n}\n\nBWAPI::Unit MeleeManager::closestMeleeUnit(BWAPI::Unit target, const BWAPI::Unitset & meleeUnitsToAssign)\n{\n    double minDistance = 0;\n    BWAPI::Unit closest = nullptr;\n\n    for (auto & meleeUnit : meleeUnitsToAssign)\n    {\n        double distance = meleeUnit->getDistance(target);\n        if (!closest || distance < minDistance)\n        {\n            minDistance = distance;\n            closest = meleeUnit;\n        }\n    }\n\n    return closest;\n}\n\nbool MeleeManager::meleeUnitShouldRetreat(BWAPI::Unit meleeUnit, const BWAPI::Unitset & targets)\n{\n    // terran don't regen so it doesn't make any sense to retreat\n    if (meleeUnit->getType().getRace() == BWAPI::Races::Terran)\n    {\n        return false;\n    }\n\n    // we don't want to retreat the melee unit if its shields or hit points are above the threshold set in the config file\n    // set those values to zero if you never want the unit to retreat from combat individually\n    if (meleeUnit->getShields() > Config::Micro::RetreatMeleeUnitShields || meleeUnit->getHitPoints() > Config::Micro::RetreatMeleeUnitHP)\n    {\n        return false;\n    }\n\n    // if there is a ranged enemy unit within attack range of this melee unit then we shouldn't bother retreating since it could fire and kill it anyway\n    for (auto & unit : targets)\n    {\n        int groundWeaponRange = unit->getType().groundWeapon().maxRange();\n        if (groundWeaponRange >= 64 && unit->getDistance(meleeUnit) < groundWeaponRange)\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\n\n// still has bug in it somewhere, use Old version\nvoid MeleeManager::assignTargetsNew(const BWAPI::Unitset & targets)\n{\n    const BWAPI::Unitset & meleeUnits = getUnits();\n\n    // figure out targets\n    BWAPI::Unitset meleeUnitTargets;\n    for (auto & target : targets)\n    {\n        // conditions for targeting\n        if (!(target->getType().isFlyer()) &&\n            !(target->isLifted()) &&\n            !(target->getType() == BWAPI::UnitTypes::Zerg_Larva) &&\n            !(target->getType() == BWAPI::UnitTypes::Zerg_Egg) &&\n            target->isVisible())\n        {\n            meleeUnitTargets.insert(target);\n        }\n    }\n\n    BWAPI::Unitset meleeUnitsToAssign(meleeUnits);\n    std::map<BWAPI::Unit, int> attackersAssigned;\n\n    for (auto & unit : meleeUnitTargets)\n    {\n        attackersAssigned[unit] = 0;\n    }\n\n    int smallThreshold = BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg ? 3 : 1;\n    int bigThreshold = BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg ? 12 : 3;\n\n    // keep assigning targets while we have attackers and targets remaining\n    while (!meleeUnitsToAssign.empty() && !meleeUnitTargets.empty())\n    {\n        auto attackerAssignment = findClosestUnitPair(meleeUnitsToAssign, meleeUnitTargets);\n        BWAPI::Unit & attacker = attackerAssignment.first;\n        BWAPI::Unit & target = attackerAssignment.second;\n\n        UAB_ASSERT_WARNING(attacker, \"We should have chosen an attacker!\");\n\n        if (!attacker)\n        {\n            break;\n        }\n\n        if (!target)\n        {\n            Micro::SmartMove(attacker, m_order.getPosition());\n            continue;\n        }\n\n        Micro::SmartAttackUnit(attacker, target);\n\n        // update the number of units assigned to attack the target we found\n        int & assigned = attackersAssigned[attackerAssignment.second];\n        assigned++;\n\n        // if it's a small / fast unit and there's more than 2 things attacking it already, don't assign more\n        if ((target->getType().isWorker() || target->getType() == BWAPI::UnitTypes::Zerg_Zergling) && (assigned >= smallThreshold))\n        {\n            meleeUnitTargets.erase(target);\n        }\n        // if it's a building and there's more than 10 things assigned to it already, don't assign more\n        else if (assigned > bigThreshold)\n        {\n            meleeUnitTargets.erase(target);\n        }\n\n        meleeUnitsToAssign.erase(attacker);\n    }\n\n    // if there's no targets left, attack move to the order destination\n    if (meleeUnitTargets.empty())\n    {\n        for (auto & unit : meleeUnitsToAssign)\n        {\n            if (unit->getDistance(m_order.getPosition()) > 100)\n            {\n                // move to it\n                Micro::SmartMove(unit, m_order.getPosition());\n                BWAPI::Broodwar->drawLineMap(unit->getPosition(), m_order.getPosition(), BWAPI::Colors::Yellow);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/MeleeManager.h",
    "content": "#pragma once\n\n#include \"MicroManager.h\"\n\nnamespace UAlbertaBot\n{\nclass MeleeManager : public MicroManager\n{\n\npublic:\n\n    MeleeManager();\n    void executeMicro(const BWAPI::Unitset & targets);\n    void assignTargetsNew(const BWAPI::Unitset & targets);\n    void assignTargetsOld(const BWAPI::Unitset & targets);\n\n    int getAttackPriority(BWAPI::Unit attacker, BWAPI::Unit unit);\n    bool meleeUnitShouldRetreat(BWAPI::Unit meleeUnit, const BWAPI::Unitset & targets);\n    BWAPI::Unit closestMeleeUnit(BWAPI::Unit target, const BWAPI::Unitset & meleeUnitToAssign);\n    BWAPI::Unit getTarget(BWAPI::Unit meleeUnit, const BWAPI::Unitset & targets);\n    std::pair<BWAPI::Unit, BWAPI::Unit> findClosestUnitPair(const BWAPI::Unitset & attackers, const BWAPI::Unitset & targets);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/MetaType.cpp",
    "content": "#include \"MetaType.h\"\n\nusing namespace UAlbertaBot;\n\nMetaType::MetaType ()\n{\n}\n\nMetaType::MetaType(const std::string & name)\n{\n    std::string inputName(name);\n    std::replace(inputName.begin(), inputName.end(), '_', ' ');\n\n    for (const BWAPI::UnitType & unitType : BWAPI::UnitTypes::allUnitTypes())\n    {\n        // check to see if the names match exactly\n        std::string typeName = unitType.getName();\n        std::replace(typeName.begin(), typeName.end(), '_', ' ');\n        if (typeName == inputName)\n        {\n            *this = MetaType(unitType);\n            return;\n        }\n\n        // check to see if the names match without the race prefix\n        const std::string & raceName = unitType.getRace().getName();\n        if ((typeName.length() > raceName.length()) && (typeName.compare(raceName.length() + 1, typeName.length(), inputName) == 0))\n        {\n            *this = MetaType(unitType);\n            return;\n        }\n    }\n\n    for (const BWAPI::TechType & techType : BWAPI::TechTypes::allTechTypes())\n    {\n        std::string typeName = techType.getName();\n        std::replace(typeName.begin(), typeName.end(), '_', ' ');\n        if (typeName == inputName)\n        {\n            *this = MetaType(techType);\n            return;\n        }\n    }\n\n    for (const BWAPI::UpgradeType & upgradeType : BWAPI::UpgradeTypes::allUpgradeTypes())\n    {\n        std::string typeName = upgradeType.getName();\n        std::replace(typeName.begin(), typeName.end(), '_', ' ');\n        if (typeName == inputName)\n        {\n            *this = MetaType(upgradeType);\n            return;\n        }\n    }\n\n    UAB_ASSERT_WARNING(false, \"Could not find MetaType with name: %s\", name.c_str());\n}\n\nMetaType::MetaType (BWAPI::UnitType t)\n    : m_unitType(t)\n    , m_type(MetaTypes::Unit)\n    , m_race(t.getRace())\n{\n}\n\nMetaType::MetaType (BWAPI::TechType t)\n    : m_techType(t)\n    , m_type(MetaTypes::Tech)\n    , m_race(t.getRace())\n{\n}\n\nMetaType::MetaType (BWAPI::UpgradeType t)\n    : m_upgradeType(t)\n    , m_type(MetaTypes::Upgrade)\n    , m_race(t.getRace())\n{\n}\n\nconst size_t & MetaType::type() const\n{\n    return m_type;\n}\n\nbool MetaType::isUnit() const\n{\n    return m_type == MetaTypes::Unit;\n}\n\nbool MetaType::isTech() const\n{\n    return m_type == MetaTypes::Tech;\n}\n\nbool MetaType::isUpgrade() const\n{\n    return m_type == MetaTypes::Upgrade;\n}\n\nbool MetaType::isCommand() const\n{\n    return m_type == MetaTypes::Command;\n}\n\nconst BWAPI::Race & MetaType::getRace() const\n{\n    return m_race;\n}\n\nbool MetaType::isBuilding()\tconst\n{\n    return m_type == MetaTypes::Unit && m_unitType.isBuilding();\n}\n\nbool MetaType::isRefinery()\tconst\n{\n    return isBuilding() && m_unitType.isRefinery();\n}\n\nconst BWAPI::UnitType & MetaType::getUnitType() const\n{\n    return m_unitType;\n}\n\nconst BWAPI::TechType & MetaType::getTechType() const\n{\n    return m_techType;\n}\n\nconst BWAPI::UpgradeType & MetaType::getUpgradeType() const\n{\n    return m_upgradeType;\n}\n\nint MetaType::supplyRequired()\n{\n    if (isUnit())\n    {\n        return m_unitType.supplyRequired();\n    }\n    else\n    {\n        return 0;\n    }\n}\n\nint MetaType::mineralPrice() const\n{\n    return isUnit() ? m_unitType.mineralPrice() : (isTech() ? m_techType.mineralPrice() : m_upgradeType.mineralPrice());\n}\n\nint MetaType::gasPrice() const\n{\n    return isUnit() ? m_unitType.gasPrice() : (isTech() ? m_techType.gasPrice() : m_upgradeType.gasPrice());\n}\n\nBWAPI::UnitType MetaType::whatBuilds() const\n{\n    return isUnit() ? m_unitType.whatBuilds().first : (isTech() ? m_techType.whatResearches() : m_upgradeType.whatUpgrades());\n}\n\nstd::string MetaType::getName() const\n{\n    if (isUnit())\n    {\n        return m_unitType.getName();\n    }\n    else if (isTech())\n    {\n        return m_techType.getName();\n    }\n    else if (isUpgrade())\n    {\n        return m_upgradeType.getName();\n    }\n    else\n    {\n        UAB_ASSERT(false, \"MetaType not found\");\n        return \"LOL\";\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/MetaType.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace UAlbertaBot\n{\n\nnamespace MetaTypes\n{\nenum { Unit, Tech, Upgrade, Command, Default };\n}\nclass MetaType\n{\n    size_t              m_type = MetaTypes::Default;\n    BWAPI::Race         m_race = BWAPI::Races::None;\n\n    BWAPI::UnitType     m_unitType;\n    BWAPI::TechType     m_techType;\n    BWAPI::UpgradeType  m_upgradeType;\n\npublic:\n\n    MetaType ();\n    MetaType (const std::string & name);\n    MetaType (BWAPI::UnitType t);\n    MetaType (BWAPI::TechType t);\n    MetaType (BWAPI::UpgradeType t);\n\n    bool isUnit()       const;\n    bool isTech()       const;\n    bool isUpgrade()    const;\n    bool isCommand()    const;\n    bool isBuilding()   const;\n    bool isRefinery()   const;\n\n    const size_t & type() const;\n    const BWAPI::Race & getRace() const;\n\n    const BWAPI::UnitType & getUnitType() const;\n    const BWAPI::TechType & getTechType() const;\n    const BWAPI::UpgradeType & getUpgradeType() const;\n\n    int supplyRequired();\n    int mineralPrice() const;\n    int gasPrice() const;\n\n    BWAPI::UnitType whatBuilds() const;\n    std::string getName() const;\n};\n\ntypedef std::pair<MetaType, size_t> MetaPair;\ntypedef std::vector<MetaPair> MetaPairVector;\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/Micro.cpp",
    "content": "#include \"Common.h\"\n#include \"Micro.h\"\n#include \"UnitUtil.h\"\n\nusing namespace UAlbertaBot;\n\nsize_t TotalCommands = 0;\n\nconst int dotRadius = 2;\n\nvoid Micro::SmartAttackUnit(BWAPI::Unit attacker, BWAPI::Unit target)\n{\n    UAB_ASSERT(attacker, \"SmartAttackUnit: Attacker not valid\");\n    UAB_ASSERT(target, \"SmartAttackUnit: Target not valid\");\n\n    if (!attacker || !target)\n    {\n        return;\n    }\n\n    // if we have issued a command to this unit already this frame, ignore this one\n    if (attacker->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || attacker->isAttackFrame())\n    {\n        return;\n    }\n\n    // get the unit's current command\n    BWAPI::UnitCommand currentCommand(attacker->getLastCommand());\n\n    // if we've already told this unit to attack this target, ignore this command\n    if (currentCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit &&\tcurrentCommand.getTarget() == target)\n    {\n        return;\n    }\n\n    // if nothing prevents it, attack the target\n    attacker->attack(target);\n    TotalCommands++;\n\n    if (Config::Debug::DrawUnitTargetInfo)\n    {\n        BWAPI::Broodwar->drawCircleMap(attacker->getPosition(), dotRadius, BWAPI::Colors::Red, true);\n        BWAPI::Broodwar->drawCircleMap(target->getPosition(), dotRadius, BWAPI::Colors::Red, true);\n        BWAPI::Broodwar->drawLineMap(attacker->getPosition(), target->getPosition(), BWAPI::Colors::Red);\n    }\n}\n\nvoid Micro::SmartAttackMove(BWAPI::Unit attacker, const BWAPI::Position & targetPosition)\n{\n    //UAB_ASSERT(attacker, \"SmartAttackMove: Attacker not valid\");\n    //UAB_ASSERT(targetPosition.isValid(), \"SmartAttackMove: targetPosition not valid\");\n\n    if (!attacker || !targetPosition.isValid())\n    {\n        return;\n    }\n\n    // if we have issued a command to this unit already this frame, ignore this one\n    if (attacker->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || attacker->isAttackFrame())\n    {\n        return;\n    }\n\n    // get the unit's current command\n    BWAPI::UnitCommand currentCommand(attacker->getLastCommand());\n\n    // if we've already told this unit to attack this target, ignore this command\n    if (currentCommand.getType() == BWAPI::UnitCommandTypes::Attack_Move &&\tcurrentCommand.getTargetPosition() == targetPosition)\n    {\n        return;\n    }\n\n    // if nothing prevents it, attack the target\n    attacker->attack(targetPosition);\n    TotalCommands++;\n\n    if (Config::Debug::DrawUnitTargetInfo)\n    {\n        BWAPI::Broodwar->drawCircleMap(attacker->getPosition(), dotRadius, BWAPI::Colors::Orange, true);\n        BWAPI::Broodwar->drawCircleMap(targetPosition, dotRadius, BWAPI::Colors::Orange, true);\n        BWAPI::Broodwar->drawLineMap(attacker->getPosition(), targetPosition, BWAPI::Colors::Orange);\n    }\n}\n\nvoid Micro::SmartMove(BWAPI::Unit attacker, const BWAPI::Position & targetPosition)\n{\n    //UAB_ASSERT(attacker, \"SmartAttackMove: Attacker not valid\");\n    //UAB_ASSERT(targetPosition.isValid(), \"SmartAttackMove: targetPosition not valid\");\n\n    if (!attacker || !targetPosition.isValid())\n    {\n        return;\n    }\n\n    // if we have issued a command to this unit already this frame, ignore this one\n    if (attacker->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || attacker->isAttackFrame())\n    {\n        return;\n    }\n\n    // get the unit's current command\n    BWAPI::UnitCommand currentCommand(attacker->getLastCommand());\n\n    // if we've already told this unit to move to this position, ignore this command\n    if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Move) && (currentCommand.getTargetPosition() == targetPosition) && attacker->isMoving())\n    {\n        return;\n    }\n\n    // if nothing prevents it, attack the target\n    attacker->move(targetPosition);\n    TotalCommands++;\n\n    if (Config::Debug::DrawUnitTargetInfo)\n    {\n        BWAPI::Broodwar->drawCircleMap(attacker->getPosition(), dotRadius, BWAPI::Colors::White, true);\n        BWAPI::Broodwar->drawCircleMap(targetPosition, dotRadius, BWAPI::Colors::White, true);\n        BWAPI::Broodwar->drawLineMap(attacker->getPosition(), targetPosition, BWAPI::Colors::White);\n    }\n}\n\nvoid Micro::SmartRightClick(BWAPI::Unit unit, BWAPI::Unit target)\n{\n    UAB_ASSERT(unit, \"SmartRightClick: Unit not valid\");\n    UAB_ASSERT(target, \"SmartRightClick: Target not valid\");\n\n    if (!unit || !target)\n    {\n        return;\n    }\n\n    // if we have issued a command to this unit already this frame, ignore this one\n    if (unit->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || unit->isAttackFrame())\n    {\n        return;\n    }\n\n    // get the unit's current command\n    BWAPI::UnitCommand currentCommand(unit->getLastCommand());\n\n    // if we've already told this unit to move to this position, ignore this command\n    if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Right_Click_Unit) && (currentCommand.getTargetPosition() == target->getPosition()))\n    {\n        return;\n    }\n\n    // if nothing prevents it, attack the target\n    unit->rightClick(target);\n    TotalCommands++;\n\n    if (Config::Debug::DrawUnitTargetInfo)\n    {\n        BWAPI::Broodwar->drawCircleMap(unit->getPosition(), dotRadius, BWAPI::Colors::Cyan, true);\n        BWAPI::Broodwar->drawCircleMap(target->getPosition(), dotRadius, BWAPI::Colors::Cyan, true);\n        BWAPI::Broodwar->drawLineMap(unit->getPosition(), target->getPosition(), BWAPI::Colors::Cyan);\n    }\n}\n\nvoid Micro::SmartLaySpiderMine(BWAPI::Unit unit, BWAPI::Position pos)\n{\n    if (!unit)\n    {\n        return;\n    }\n\n    if (!unit->canUseTech(BWAPI::TechTypes::Spider_Mines, pos))\n    {\n        return;\n    }\n\n    BWAPI::UnitCommand currentCommand(unit->getLastCommand());\n\n    // if we've already told this unit to move to this position, ignore this command\n    if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Use_Tech_Position) && (currentCommand.getTargetPosition() == pos))\n    {\n        return;\n    }\n\n    unit->canUseTechPosition(BWAPI::TechTypes::Spider_Mines, pos);\n}\n\nvoid Micro::SmartRepair(BWAPI::Unit unit, BWAPI::Unit target)\n{\n    UAB_ASSERT(unit, \"SmartRightClick: Unit not valid\");\n    UAB_ASSERT(target, \"SmartRightClick: Target not valid\");\n\n    if (!unit || !target)\n    {\n        return;\n    }\n\n    // if we have issued a command to this unit already this frame, ignore this one\n    if (unit->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || unit->isAttackFrame())\n    {\n        return;\n    }\n\n    // get the unit's current command\n    BWAPI::UnitCommand currentCommand(unit->getLastCommand());\n\n    // if we've already told this unit to move to this position, ignore this command\n    if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Repair) && (currentCommand.getTarget() == target))\n    {\n        return;\n    }\n\n    // if nothing prevents it, attack the target\n    unit->repair(target);\n    TotalCommands++;\n\n    if (Config::Debug::DrawUnitTargetInfo)\n    {\n        BWAPI::Broodwar->drawCircleMap(unit->getPosition(), dotRadius, BWAPI::Colors::Cyan, true);\n        BWAPI::Broodwar->drawCircleMap(target->getPosition(), dotRadius, BWAPI::Colors::Cyan, true);\n        BWAPI::Broodwar->drawLineMap(unit->getPosition(), target->getPosition(), BWAPI::Colors::Cyan);\n    }\n}\n\n\nvoid Micro::SmartKiteTarget(BWAPI::Unit rangedUnit, BWAPI::Unit target)\n{\n    UAB_ASSERT(rangedUnit, \"SmartKiteTarget: Unit not valid\");\n    UAB_ASSERT(target, \"SmartKiteTarget: Target not valid\");\n\n    if (!rangedUnit || !target)\n    {\n        return;\n    }\n\n    double range(rangedUnit->getType().groundWeapon().maxRange());\n    if (rangedUnit->getType() == BWAPI::UnitTypes::Protoss_Dragoon && BWAPI::Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Singularity_Charge))\n    {\n        range = 6*32;\n    }\n\n    // determine whether the target can be kited\n    bool kiteLonger = Config::Micro::KiteLongerRangedUnits.find(rangedUnit->getType()) != Config::Micro::KiteLongerRangedUnits.end();\n    if (!kiteLonger && (range <= target->getType().groundWeapon().maxRange()))\n    {\n        // if we can't kite it, there's no point\n        Micro::SmartAttackUnit(rangedUnit, target);\n        return;\n    }\n\n    bool    kite(true);\n    double  dist(rangedUnit->getDistance(target));\n    double  speed(rangedUnit->getType().topSpeed());\n\n\n    // if the unit can't attack back don't kite\n    if ((rangedUnit->isFlying() && !UnitUtil::CanAttackAir(target)) || (!rangedUnit->isFlying() && !UnitUtil::CanAttackGround(target)))\n    {\n        //kite = false;\n    }\n\n    double timeToEnter = std::max(0.0, (dist - range) / speed);\n    if ((timeToEnter >= rangedUnit->getGroundWeaponCooldown()))\n    {\n        kite = false;\n    }\n\n    if (target->getType().isBuilding())\n    {\n        kite = false;\n    }\n\n    // if we can't shoot, run away\n    if (kite)\n    {\n        BWAPI::Position fleePosition(rangedUnit->getPosition() - target->getPosition() + rangedUnit->getPosition());\n        //BWAPI::Broodwar->drawLineMap(rangedUnit->getPosition(), fleePosition, BWAPI::Colors::Cyan);\n        Micro::SmartMove(rangedUnit, fleePosition);\n    }\n    // otherwise shoot\n    else\n    {\n        Micro::SmartAttackUnit(rangedUnit, target);\n    }\n}\n\n\nvoid Micro::MutaDanceTarget(BWAPI::Unit muta, BWAPI::Unit target)\n{\n    UAB_ASSERT(muta, \"MutaDanceTarget: Muta not valid\");\n    UAB_ASSERT(target, \"MutaDanceTarget: Target not valid\");\n\n    if (!muta || !target)\n    {\n        return;\n    }\n\n    const int cooldown                  = muta->getType().groundWeapon().damageCooldown();\n    const int latency                   = BWAPI::Broodwar->getLatency();\n    const double speed                  = muta->getType().topSpeed();\n    const double range                  = muta->getType().groundWeapon().maxRange();\n    const double distanceToTarget       = muta->getDistance(target);\n    const double distanceToFiringRange  = std::max(distanceToTarget - range, 0.0);\n    const double timeToEnterFiringRange = distanceToFiringRange / speed;\n    const int framesToAttack            = static_cast<int>(timeToEnterFiringRange) + 2*latency;\n\n    // How many frames are left before we can attack?\n    const int currentCooldown = muta->isStartingAttack() ? cooldown : muta->getGroundWeaponCooldown();\n\n    BWAPI::Position fleeVector = GetKiteVector(target, muta);\n    BWAPI::Position moveToPosition(muta->getPosition() + fleeVector);\n\n    // If we can attack by the time we reach our firing range\n    if (currentCooldown <= framesToAttack)\n    {\n        // Move towards and attack the target\n        muta->attack(target);\n    }\n    else // Otherwise we cannot attack and should temporarily back off\n    {\n        // Determine direction to flee\n        // Determine point to flee to\n        if (moveToPosition.isValid())\n        {\n            muta->rightClick(moveToPosition);\n        }\n    }\n}\n\nBWAPI::Position Micro::GetKiteVector(BWAPI::Unit unit, BWAPI::Unit target)\n{\n    BWAPI::Position fleeVec(target->getPosition() - unit->getPosition());\n    double fleeAngle = atan2(fleeVec.y, fleeVec.x);\n    fleeVec = BWAPI::Position(static_cast<int>(64 * cos(fleeAngle)), static_cast<int>(64 * sin(fleeAngle)));\n    return fleeVec;\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/Micro.h",
    "content": "#pragma once\n\n#include <BWAPI.h>\n\nnamespace UAlbertaBot\n{\nnamespace Micro\n{      \n    void SmartAttackUnit(BWAPI::Unit attacker, BWAPI::Unit target);\n    void SmartAttackMove(BWAPI::Unit attacker, const BWAPI::Position & targetPosition);\n    void SmartMove(BWAPI::Unit attacker, const BWAPI::Position & targetPosition);\n    void SmartRightClick(BWAPI::Unit unit, BWAPI::Unit target);\n    void SmartLaySpiderMine(BWAPI::Unit unit, BWAPI::Position pos);\n    void SmartRepair(BWAPI::Unit unit, BWAPI::Unit target);\n    void SmartKiteTarget(BWAPI::Unit rangedUnit, BWAPI::Unit target);\n    void MutaDanceTarget(BWAPI::Unit muta, BWAPI::Unit target);\n    \n    BWAPI::Position GetKiteVector(BWAPI::Unit unit, BWAPI::Unit target);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/MicroManager.cpp",
    "content": "#include \"MicroManager.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n#include \"MapTools.h\"\n#include \"InformationManager.h\"\n#include \"Micro.h\"\n\nusing namespace UAlbertaBot;\n\nMicroManager::MicroManager()\n{\n}\n\nvoid MicroManager::setUnits(const BWAPI::Unitset & u)\n{\n    m_units = u;\n}\n\nBWAPI::Position MicroManager::calcCenter() const\n{\n    if (m_units.empty())\n    {\n        if (Config::Debug::DrawSquadInfo)\n        {\n            BWAPI::Broodwar->printf(\"Squad::calcCenter() called on empty squad\");\n        }\n        return BWAPI::Position(0, 0);\n    }\n\n    BWAPI::Position accum(0, 0);\n    for (auto & unit : m_units)\n    {\n        accum += unit->getPosition();\n    }\n    return BWAPI::Position(accum.x / m_units.size(), accum.y / m_units.size());\n}\n\nvoid MicroManager::execute(const SquadOrder & inputOrder)\n{\n    // Nothing to do if we have no units\n    if (m_units.empty() || !(inputOrder.getType() == SquadOrderTypes::Attack || inputOrder.getType() == SquadOrderTypes::Defend))\n    {\n        return;\n    }\n\n    m_order = inputOrder;\n    drawOrderText();\n\n    // Discover enemies within region of interest\n    BWAPI::Unitset nearbyEnemies;\n\n    // if the order is to defend, we only care about units in the radius of the defense\n    if (m_order.getType() == SquadOrderTypes::Defend)\n    {\n        Global::Map().getUnits(nearbyEnemies, m_order.getPosition(), m_order.getRadius(), false, true);\n\n    } // otherwise we want to see everything on the way\n    else if (m_order.getType() == SquadOrderTypes::Attack)\n    {\n        Global::Map().getUnits(nearbyEnemies, m_order.getPosition(), m_order.getRadius(), false, true);\n        for (auto & unit : m_units)\n        {\n            BWAPI::Unit u = unit;\n            BWAPI::UnitType t = u->getType();\n            Global::Map().getUnits(nearbyEnemies, unit->getPosition(), m_order.getRadius(), false, true);\n        }\n    }\n\n    // the following block of code attacks all units on the way to the order position\n    // we want to do this if the order is attack, defend, or harass\n    if (m_order.getType() == SquadOrderTypes::Attack || m_order.getType() == SquadOrderTypes::Defend)\n    {\n        // if this is a worker defense force\n        if (m_units.size() == 1 && (*m_units.begin())->getType().isWorker())\n        {\n            executeMicro(nearbyEnemies);\n        }\n        // otherwise it is a normal attack force\n        else\n        {\n            // if this is a defense squad then we care about all units in the area\n            if (m_order.getType() == SquadOrderTypes::Defend)\n            {\n                executeMicro(nearbyEnemies);\n            }\n            // otherwise we only care about workers if they are in their own region\n            else\n            {\n                // if this is the an attack squad\n                BWAPI::Unitset workersRemoved;\n\n                for (auto & enemyUnit : nearbyEnemies)\n                {\n                    // if its not a worker add it to the targets\n                    if (!enemyUnit->getType().isWorker())\n                    {\n                        workersRemoved.insert(enemyUnit);\n                    }\n                    // if it is a worker\n                    else\n                    {\n                        for (auto enemyBase : Global::Bases().getOccupiedBaseLocations(BWAPI::Broodwar->enemy()))\n                        {\n                            // only add it if it's in their region\n                            if (enemyBase->containsPosition(enemyUnit->getPosition()))\n                            {\n                                workersRemoved.insert(enemyUnit);\n                            }\n                        }\n                    }\n                }\n\n                // Allow micromanager to handle enemies\n                executeMicro(workersRemoved);\n            }\n        }\n    }\n}\n\nconst BWAPI::Unitset & MicroManager::getUnits() const\n{\n    return m_units;\n}\n\nvoid MicroManager::regroup(const BWAPI::Position & regroupPosition) const\n{\n    BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n    int regroupDistanceFromBase = Global::Map().getGroundDistance(regroupPosition, ourBasePosition);\n\n    // for each of the units we have\n    for (auto & unit : m_units)\n    {\n        int unitDistanceFromBase = Global::Map().getGroundDistance(unit->getPosition(), ourBasePosition);\n\n        // if the unit is outside the regroup area\n        if (unitDistanceFromBase > regroupDistanceFromBase)\n        {\n            Micro::SmartMove(unit, ourBasePosition);\n        }\n        else if (unit->getDistance(regroupPosition) > 100)\n        {\n            // regroup it\n            Micro::SmartMove(unit, regroupPosition);\n        }\n        else\n        {\n            Micro::SmartAttackMove(unit, unit->getPosition());\n        }\n    }\n}\n\nbool MicroManager::unitNearEnemy(BWAPI::Unit unit)\n{\n    assert(unit);\n\n    BWAPI::Unitset enemyNear;\n\n    Global::Map().getUnits(enemyNear, unit->getPosition(), 800, false, true);\n\n    return enemyNear.size() > 0;\n}\n\n// returns true if position:\n// a) is walkable\n// b) doesn't have buildings on it\n// c) doesn't have a unit on it that can attack ground\nbool MicroManager::checkPositionWalkable(BWAPI::Position pos)\n{\n    // get x and y from the position\n    int x(pos.x), y(pos.y);\n\n    // walkable tiles exist every 8 pixels\n    bool good = BWAPI::Broodwar->isWalkable(x/8, y/8);\n\n    // if it's not walkable throw it out\n    if (!good) return false;\n\n    // for each of those units, if it's a building or an attacking enemy unit we don't want to go there\n    for (auto & unit : BWAPI::Broodwar->getUnitsOnTile(x/32, y/32))\n    {\n        if (unit->getType().isBuilding() || unit->getType().isResourceContainer() ||\n            (unit->getPlayer() != BWAPI::Broodwar->self() && unit->getType().groundWeapon() != BWAPI::WeaponTypes::None))\n        {\n            return false;\n        }\n    }\n\n    // otherwise it's okay\n    return true;\n}\n\nvoid MicroManager::trainSubUnits(BWAPI::Unit unit) const\n{\n    if (unit->getType() == BWAPI::UnitTypes::Protoss_Reaver)\n    {\n        unit->train(BWAPI::UnitTypes::Protoss_Scarab);\n    }\n    else if (unit->getType() == BWAPI::UnitTypes::Protoss_Carrier)\n    {\n        unit->train(BWAPI::UnitTypes::Protoss_Interceptor);\n    }\n}\n\nbool MicroManager::unitNearChokepoint(BWAPI::Unit unit) const\n{\n    // TODO: Chokepoint\n    return false;\n}\n\nvoid MicroManager::drawOrderText()\n{\n    for (auto & unit : m_units)\n    {\n        if (Config::Debug::DrawUnitTargetInfo) BWAPI::Broodwar->drawTextMap(unit->getPosition().x, unit->getPosition().y, \"%s\", m_order.getStatus().c_str());\n    }\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/MicroManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"SquadOrder.h\"\n\nnamespace UAlbertaBot\n{\nstruct AirThreat\n{\n    BWAPI::Unit\tunit;\n    double      weight;\n};\n\nstruct GroundThreat\n{\n    BWAPI::Unit\tunit;\n    double      weight;\n};\n\nclass MicroManager\n{\n    BWAPI::Unitset  m_units;\n\nprotected:\n\n    SquadOrder m_order;\n\n    virtual void executeMicro(const BWAPI::Unitset & targets) = 0;\n    bool checkPositionWalkable(BWAPI::Position pos);\n    void drawOrderText();\n    bool unitNearEnemy(BWAPI::Unit unit);\n    bool unitNearChokepoint(BWAPI::Unit unit) const;\n    void trainSubUnits(BWAPI::Unit unit) const;\n\npublic:\n\n    MicroManager();\n    virtual ~MicroManager() {}\n\n    const BWAPI::Unitset & getUnits() const;\n    BWAPI::Position calcCenter() const;\n\n    void setUnits(const BWAPI::Unitset & u);\n    void execute(const SquadOrder & order);\n    void regroup(const BWAPI::Position & regroupPosition) const;\n\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/ParseUtils.cpp",
    "content": "#include \"ParseUtils.h\"\n#include \"rapidjson\\document.h\"\n#include \"JSONTools.h\"\n#include \"BuildOrder.h\"\n#include \"StrategyManager.h\"\n#include \"Global.h\"\n\nusing namespace UAlbertaBot;\n\nvoid ParseUtils::ParseConfigFile(const std::string & filename)\n{\n    PROFILE_FUNCTION();\n\n    rapidjson::Document doc;\n    BWAPI::Race race = BWAPI::Broodwar->self()->getRace();\n    const char * ourRace = race.getName().c_str();\n\n    std::string config = FileUtils::ReadFile(filename);\n\n    if (config.length() == 0)\n    {\n        return;\n    }\n\n    Config::ConfigFile::ConfigFileFound = true;\n\n    bool parsingFailed = doc.Parse(config.c_str()).HasParseError();\n    if (parsingFailed)\n    {\n        return;\n    }\n\n    // Parse the Bot Info\n    if (doc.HasMember(\"Bot Info\") && doc[\"Bot Info\"].IsObject())\n    {\n        const rapidjson::Value & info = doc[\"Bot Info\"];\n        JSONTools::ReadString(\"BotName\", info, Config::BotInfo::BotName);\n        JSONTools::ReadString(\"Authors\", info, Config::BotInfo::Authors);\n        JSONTools::ReadBool(\"PrintInfoOnStart\", info, Config::BotInfo::PrintInfoOnStart);\n    }\n\n    // Parse the BWAPI Options\n    if (doc.HasMember(\"BWAPI\") && doc[\"BWAPI\"].IsObject())\n    {\n        const rapidjson::Value & bwapi = doc[\"BWAPI\"];\n        JSONTools::ReadInt(\"SetLocalSpeed\", bwapi, Config::BWAPIOptions::SetLocalSpeed);\n        JSONTools::ReadInt(\"SetFrameSkip\", bwapi, Config::BWAPIOptions::SetFrameSkip);\n        JSONTools::ReadBool(\"UserInput\", bwapi, Config::BWAPIOptions::EnableUserInput);\n        JSONTools::ReadBool(\"CompleteMapInformation\", bwapi, Config::BWAPIOptions::EnableCompleteMapInformation);\n    }\n\n    // Parse the Micro Options\n    if (doc.HasMember(\"Micro\") && doc[\"Micro\"].IsObject())\n    {\n        const rapidjson::Value & micro = doc[\"Micro\"];\n        JSONTools::ReadBool(\"UseSparcraftSimulation\", micro, Config::Micro::UseSparcraftSimulation);\n        JSONTools::ReadBool(\"KiteWithRangedUnits\", micro, Config::Micro::KiteWithRangedUnits);\n        JSONTools::ReadBool(\"WorkersDefendRush\", micro, Config::Micro::WorkersDefendRush);\n        JSONTools::ReadInt(\"RetreatMeleeUnitShields\", micro, Config::Micro::RetreatMeleeUnitShields);\n        JSONTools::ReadInt(\"RetreatMeleeUnitHP\", micro, Config::Micro::RetreatMeleeUnitHP);\n        JSONTools::ReadInt(\"InCombatRadius\", micro, Config::Micro::CombatRadius);\n        JSONTools::ReadInt(\"RegroupRadius\", micro, Config::Micro::CombatRegroupRadius);\n        JSONTools::ReadInt(\"UnitNearEnemyRadius\", micro, Config::Micro::UnitNearEnemyRadius);\n\n        if (micro.HasMember(\"KiteLongerRangedUnits\") && micro[\"KiteLongerRangedUnits\"].IsArray())\n        {\n            const rapidjson::Value & kite = micro[\"KiteLongerRangedUnits\"];\n\n            for (size_t i(0); i < kite.Size(); ++i)\n            {\n                if (kite[i].IsString())\n                {\n                    MetaType type(kite[i].GetString());\n                    Config::Micro::KiteLongerRangedUnits.insert(type.getUnitType());\n                }\n            }\n        }\n    }\n\n    // Parse the Macro Options\n    if (doc.HasMember(\"Macro\") && doc[\"Macro\"].IsObject())\n    {\n        const rapidjson::Value & macro = doc[\"Macro\"];\n        JSONTools::ReadInt(\"BOSSFrameLimit\", macro, Config::Macro::BOSSFrameLimit);\n        JSONTools::ReadInt(\"BuildingSpacing\", macro, Config::Macro::BuildingSpacing);\n        JSONTools::ReadInt(\"PylongSpacing\", macro, Config::Macro::PylonSpacing);\n        JSONTools::ReadInt(\"WorkersPerRefinery\", macro, Config::Macro::WorkersPerRefinery);\n    }\n\n    // Parse the Debug Options\n    if (doc.HasMember(\"Debug\") && doc[\"Debug\"].IsObject())\n    {\n        const rapidjson::Value & debug = doc[\"Debug\"];\n        JSONTools::ReadString(\"ErrorLogFilename\", debug, Config::Debug::ErrorLogFilename);\n        JSONTools::ReadBool(\"LogAssertToErrorFile\", debug, Config::Debug::LogAssertToErrorFile);\n        JSONTools::ReadBool(\"DrawGameInfo\", debug, Config::Debug::DrawGameInfo);\n        JSONTools::ReadBool(\"DrawBuildOrderSearchInfo\", debug, Config::Debug::DrawBuildOrderSearchInfo);\n        JSONTools::ReadBool(\"DrawUnitHealthBars\", debug, Config::Debug::DrawUnitHealthBars);\n        JSONTools::ReadBool(\"DrawResourceInfo\", debug, Config::Debug::DrawResourceInfo);\n        JSONTools::ReadBool(\"DrawWorkerInfo\", debug, Config::Debug::DrawWorkerInfo);\n        JSONTools::ReadBool(\"DrawProductionInfo\", debug, Config::Debug::DrawProductionInfo);\n        JSONTools::ReadBool(\"DrawScoutInfo\", debug, Config::Debug::DrawScoutInfo);\n        JSONTools::ReadBool(\"DrawSquadInfo\", debug, Config::Debug::DrawSquadInfo);\n        JSONTools::ReadBool(\"DrawCombatSimInfo\", debug, Config::Debug::DrawCombatSimulationInfo);\n        JSONTools::ReadBool(\"DrawBuildingInfo\", debug, Config::Debug::DrawBuildingInfo);\n        JSONTools::ReadBool(\"DrawModuleTimers\", debug, Config::Debug::DrawModuleTimers);\n        JSONTools::ReadBool(\"DrawMouseCursorInfo\", debug, Config::Debug::DrawMouseCursorInfo);\n        JSONTools::ReadBool(\"DrawEnemyUnitInfo\", debug, Config::Debug::DrawEnemyUnitInfo);\n        JSONTools::ReadBool(\"DrawBWTAInfo\", debug, Config::Debug::DrawBWTAInfo);\n        JSONTools::ReadBool(\"DrawMapGrid\", debug, Config::Debug::DrawMapGrid);\n        JSONTools::ReadBool(\"DrawUnitTargetInfo\", debug, Config::Debug::DrawUnitTargetInfo);\n        JSONTools::ReadBool(\"DrawReservedBuildingTiles\", debug, Config::Debug::DrawReservedBuildingTiles);\n        JSONTools::ReadBool(\"DrawBOSSStateInfo\", debug, Config::Debug::DrawBOSSStateInfo); \n        JSONTools::ReadBool(\"DrawTileInfo\", debug, Config::Debug::DrawTileInfo); \n        JSONTools::ReadBool(\"DrawWalkableSectors\", debug, Config::Debug::DrawWalkableSectors); \n        JSONTools::ReadBool(\"PrintModuleTimeout\", debug, Config::Debug::PrintModuleTimeout);\n    }\n\n    // Parse the Module Options\n    if (doc.HasMember(\"Modules\") && doc[\"Modules\"].IsObject())\n    {\n        const rapidjson::Value & module = doc[\"Modules\"];\n\n        JSONTools::ReadBool(\"UseGameCommander\", module, Config::Modules::UsingGameCommander);\n        JSONTools::ReadBool(\"UseScoutManager\", module, Config::Modules::UsingScoutManager);\n        JSONTools::ReadBool(\"UseCombatCommander\", module, Config::Modules::UsingCombatCommander);\n        JSONTools::ReadBool(\"UseBuildOrderSearch\", module, Config::Modules::UsingBuildOrderSearch);\n        JSONTools::ReadBool(\"UseStrategyIO\", module, Config::Modules::UsingStrategyIO);\n        JSONTools::ReadBool(\"UseUnitCommandManager\", module, Config::Modules::UsingUnitCommandManager);\n        JSONTools::ReadBool(\"UseAutoObserver\", module, Config::Modules::UsingAutoObserver);\n    }\n\n    // Parse the Tool Options\n    if (doc.HasMember(\"Tools\") && doc[\"Tools\"].IsObject())\n    {\n        const rapidjson::Value & tool = doc[\"Tools\"];\n\n        JSONTools::ReadInt(\"MapGridSize\", tool, Config::Tools::MAP_GRID_SIZE);\n    }\n\n    // Parse the Strategy Options\n    if (doc.HasMember(\"Strategy\") && doc[\"Strategy\"].IsObject())\n    {\n        const rapidjson::Value & strategy = doc[\"Strategy\"];\n\n        // read in the various strategic elements\n        JSONTools::ReadBool(\"ScoutGasSteal\", strategy, Config::Strategy::GasStealWithScout);\n        JSONTools::ReadBool(\"ScoutHarassEnemy\", strategy, Config::Strategy::ScoutHarassEnemy);\n        JSONTools::ReadString(\"ReadDirectory\", strategy, Config::Strategy::ReadDir);\n        JSONTools::ReadString(\"WriteDirectory\", strategy, Config::Strategy::WriteDir);\n\n        // if we have set a strategy for the current race, use it\n        if (strategy.HasMember(race.c_str()) && strategy[race.c_str()].IsString())\n        {\n            Config::Strategy::StrategyName = strategy[race.c_str()].GetString();\n        }\n\n        // check if we are using an enemy specific strategy\n        JSONTools::ReadBool(\"UseEnemySpecificStrategy\", strategy, Config::Strategy::UseEnemySpecificStrategy);\n        if (Config::Strategy::UseEnemySpecificStrategy && strategy.HasMember(\"EnemySpecificStrategy\") && strategy[\"EnemySpecificStrategy\"].IsObject())\n        {\n            const std::string enemyName = BWAPI::Broodwar->enemy()->getName();\n            const rapidjson::Value & specific = strategy[\"EnemySpecificStrategy\"];\n\n            // check to see if our current enemy name is listed anywhere in the specific strategies\n            if (specific.HasMember(enemyName.c_str()) && specific[enemyName.c_str()].IsObject())\n            {\n                const rapidjson::Value & enemyStrategies = specific[enemyName.c_str()];\n\n                // if that enemy has a strategy listed for our current race, use it\n                if (enemyStrategies.HasMember(ourRace) && enemyStrategies[ourRace].IsString())\n                {\n                    Config::Strategy::StrategyName = enemyStrategies[ourRace].GetString();\n                    Config::Strategy::FoundEnemySpecificStrategy = true;\n                }\n            }\n        }\n\n        // Parse all the Strategies\n        if (strategy.HasMember(\"Strategies\") && strategy[\"Strategies\"].IsObject())\n        {\n            const rapidjson::Value & strategies = strategy[\"Strategies\"];\n            for (rapidjson::Value::ConstMemberIterator itr = strategies.MemberBegin(); itr != strategies.MemberEnd(); ++itr)\n            {\n                const std::string &         name = itr->name.GetString();\n                const rapidjson::Value &    val  = itr->value;\n        \n\n                BWAPI::Race strategyRace;\n                if (val.HasMember(\"Race\") && val[\"Race\"].IsString())\n                {\n                    strategyRace = GetRace(val[\"Race\"].GetString());\n                }\n                else\n                {\n                    UAB_ASSERT_WARNING(false, \"Strategy must have a Race string. Skipping strategy %s\", name.c_str());\n                    continue;\n                }\n\n                BuildOrder buildOrder(strategyRace);\n                if (val.HasMember(\"OpeningBuildOrder\") && val[\"OpeningBuildOrder\"].IsArray())\n                {\n                    const rapidjson::Value & build = val[\"OpeningBuildOrder\"];\n\n                    for (size_t b(0); b < build.Size(); ++b)\n                    {\n                        if (build[b].IsString())\n                        {\n                            MetaType type(build[b].GetString());\n\n                            if (type.getRace() != BWAPI::Races::None)\n                            {\n                                buildOrder.add(type);\n                            }\n                        }\n                        else\n                        {\n                            UAB_ASSERT_WARNING(false, \"Build order item must be a string %s\", name.c_str());\n                            continue;\n                        }\n                    }\n                }\n\n                Global::Strategy().addStrategy(name, Strategy(name, strategyRace, buildOrder));\n            }\n        }\n    }\n\n    Config::ConfigFile::ConfigFileParsed = true;\n}\n\n\nvoid ParseUtils::ParseTextCommand(const std::string & commandString)\n{\n    std::stringstream ss(commandString);\n\n    std::string command;\n    std::transform(command.begin(), command.end(), command.begin(), ::tolower);\n\n    std::string variableName;\n    std::transform(variableName.begin(), variableName.end(), variableName.begin(), ::tolower);\n\n    std::string val;\n\n    ss >> command;\n    ss >> variableName;\n    ss >> val;\n\n    if (command == \"/set\")\n    {\n        // BWAPI options\n        if (variableName == \"setlocalspeed\") { Config::BWAPIOptions::SetLocalSpeed = GetIntFromString(val); BWAPI::Broodwar->setLocalSpeed(Config::BWAPIOptions::SetLocalSpeed); }\n        else if (variableName == \"setframeskip\") { Config::BWAPIOptions::SetFrameSkip = GetIntFromString(val); BWAPI::Broodwar->setFrameSkip(Config::BWAPIOptions::SetFrameSkip); }\n        else if (variableName == \"userinput\") { Config::BWAPIOptions::EnableUserInput = GetBoolFromString(val); if (Config::BWAPIOptions::EnableUserInput) BWAPI::Broodwar->enableFlag(BWAPI::Flag::UserInput); }\n        else if (variableName == \"completemapinformation\") { Config::BWAPIOptions::EnableCompleteMapInformation = GetBoolFromString(val); if (Config::BWAPIOptions::EnableCompleteMapInformation) BWAPI::Broodwar->enableFlag(BWAPI::Flag::UserInput); }\n        \n        // Micro Options\n        else if (variableName == \"usesparcraftsimulation\") { Config::Micro::UseSparcraftSimulation = GetBoolFromString(val); }\n        else if (variableName == \"workersdefendrush\") { Config::Micro::WorkersDefendRush = GetBoolFromString(val); }\n        else if (variableName == \"incombatradius\") { Config::Micro::CombatRadius = GetIntFromString(val); }\n        else if (variableName == \"regroupradius\") { Config::Micro::CombatRegroupRadius = GetIntFromString(val); }\n        else if (variableName == \"unitnearenemyradius\") { Config::Micro::UnitNearEnemyRadius = GetIntFromString(val); }\n\n        // Macro Options\n        else if (variableName == \"buildingspacing\") { Config::Macro::BuildingSpacing = GetIntFromString(val); }\n        else if (variableName == \"pylonspacing\") { Config::Macro::PylonSpacing = GetIntFromString(val); }\n\n        // Debug Options\n        else if (variableName == \"errorlogfilename\") { Config::Debug::ErrorLogFilename = val; }\n        else if (variableName == \"printmoduletimeout\") { Config::Debug::PrintModuleTimeout = GetBoolFromString(val); }\n        else if (variableName == \"drawbuildordersearchinfo\") { Config::Debug::DrawBuildOrderSearchInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawunithealthbars\") { Config::Debug::DrawUnitHealthBars = GetBoolFromString(val); }\n        else if (variableName == \"drawproductioninfo\") { Config::Debug::DrawProductionInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawenemyunitinfo\") { Config::Debug::DrawEnemyUnitInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawmoduletimers\") { Config::Debug::DrawModuleTimers = GetBoolFromString(val); }\n        else if (variableName == \"drawresourceinfo\") { Config::Debug::DrawResourceInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawcombatsiminfo\") { Config::Debug::DrawCombatSimulationInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawunittargetinfo\") { Config::Debug::DrawUnitTargetInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawbwtainfo\") { Config::Debug::DrawBWTAInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawmapgrid\") { Config::Debug::DrawMapGrid = GetBoolFromString(val); }\n        else if (variableName == \"drawsquadinfo\") { Config::Debug::DrawSquadInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawworkerinfo\") { Config::Debug::DrawWorkerInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawmousecursorinfo\") { Config::Debug::DrawMouseCursorInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawbuildinginfo\") { Config::Debug::DrawBuildingInfo = GetBoolFromString(val); }\n        else if (variableName == \"drawreservedbuildingtiles\") { Config::Debug::DrawReservedBuildingTiles = GetBoolFromString(val); }\n\n        // Module Options\n        else if (variableName == \"usegamecommander\") { Config::Modules::UsingGameCommander = GetBoolFromString(val); }\n        else if (variableName == \"usescoutmanager\") { Config::Modules::UsingScoutManager = GetBoolFromString(val); }\n        else if (variableName == \"usecombatcommander\") { Config::Modules::UsingCombatCommander = GetBoolFromString(val); }\n        else if (variableName == \"usebuildordersearch\") { Config::Modules::UsingBuildOrderSearch = GetBoolFromString(val); }\n        else if (variableName == \"useautoobserver\") { Config::Modules::UsingAutoObserver = GetBoolFromString(val); }\n        else if (variableName == \"usestrategyio\") { Config::Modules::UsingStrategyIO = GetBoolFromString(val); }\n        else if (variableName == \"useunitcommandmanager\") { Config::Modules::UsingUnitCommandManager = GetBoolFromString(val); }\n\n        else { UAB_ASSERT_WARNING(false, \"Unknown variable name for /set: %s\", variableName.c_str()); }\n    }\n    else\n    {\n        UAB_ASSERT_WARNING(false, \"Unknown command: %s\", command.c_str());\n    }\n}\n\nBWAPI::Race ParseUtils::GetRace(const std::string & raceName)\n{\n    if (raceName == \"Protoss\")\n    {\n        return BWAPI::Races::Protoss;\n    }\n\n    if (raceName == \"Terran\")\n    {\n        return BWAPI::Races::Terran;\n    }\n\n    if (raceName == \"Zerg\")\n    {\n        return BWAPI::Races::Zerg;\n    }\n\n    if (raceName == \"Random\")\n    {\n        return BWAPI::Races::Random;\n    }\n\n    UAB_ASSERT_WARNING(false, \"Race not found: %s\", raceName.c_str());\n    return BWAPI::Races::None;\n}\n\nint ParseUtils::GetIntFromString(const std::string & str)\n{\n    std::stringstream ss(str);\n    int a = 0;\n    ss >> a;\n    return a;\n}\n\nbool ParseUtils::GetBoolFromString(const std::string & str)\n{\n    std::string boolStr(str);\n    std::transform(boolStr.begin(), boolStr.end(), boolStr.begin(), ::tolower);\n\n    if (boolStr == \"true\" || boolStr == \"t\")\n    {\n        return true;\n    }\n    else if (boolStr == \"false\" || boolStr == \"f\")\n    {\n        return false;\n    }\n    else\n    {\n        UAB_ASSERT_WARNING(false, \"Unknown bool from string: %s\", str.c_str());\n    }\n\n    return false;\n}"
  },
  {
    "path": "UAlbertaBot/Source/ParseUtils.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace UAlbertaBot\n{\n    namespace ParseUtils\n    {\n        void ParseConfigFile(const std::string & filename);\n        void ParseTextCommand(const std::string & commandLine);\n        BWAPI::Race GetRace(const std::string & raceName);\n\n        int GetIntFromString(const std::string & str);\n        bool GetBoolFromString(const std::string & str);\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/ProductionManager.cpp",
    "content": "#include \"ProductionManager.h\"\n#include \"Global.h\"\n#include \"BuildingData.h\"\n#include \"BuildingManager.h\"\n#include \"StrategyManager.h\"\n#include \"BOSSManager.h\"\n#include \"InformationManager.h\"\n#include \"WorkerManager.h\"\n\nusing namespace UAlbertaBot;\n\nProductionManager::ProductionManager()\n{\n    setBuildOrder(Global::Strategy().getOpeningBookBuildOrder());\n}\n\nvoid ProductionManager::setBuildOrder(const BuildOrder & buildOrder)\n{\n    m_queue.clearAll();\n\n    for (size_t i(0); i<buildOrder.size(); ++i)\n    {\n        m_queue.queueAsLowestPriority(buildOrder[i], true);\n    }\n}\n\nvoid ProductionManager::performBuildOrderSearch()\n{\n    if (!Config::Modules::UsingBuildOrderSearch || !canPlanBuildOrderNow())\n    {\n        return;\n    }\n\n    PROFILE_FUNCTION();\n\n    BuildOrder & buildOrder = m_bossManager.getBuildOrder();\n\n    if (buildOrder.size() > 0)\n    {\n        setBuildOrder(buildOrder);\n        m_bossManager.reset();\n    }\n    else\n    {\n        if (!m_bossManager.isSearchInProgress())\n        {\n            m_bossManager.startNewSearch(Global::Strategy().getBuildOrderGoal());\n        }\n    }\n}\n\nvoid ProductionManager::update()\n{\n    PROFILE_FUNCTION();\n\n    m_buildingManager.update();\n\n    // 30 ms per search update\n    m_bossManager.update(Config::Macro::BOSSTimePerFrame);\n\n    // check the _queue for stuff we can build\n    manageBuildOrderQueue();\n\n    // if nothing is currently building, get a new goal from the strategy manager\n    if ((m_queue.size() == 0) && (BWAPI::Broodwar->getFrameCount() > 10))\n    {\n        if (Config::Debug::DrawBuildOrderSearchInfo)\n        {\n            BWAPI::Broodwar->drawTextScreen(150, 10, \"Nothing left to build, new search!\");\n        }\n\n        performBuildOrderSearch();\n    }\n\n    // detect if there's a build order deadlock once per second\n    if ((BWAPI::Broodwar->getFrameCount() % 24 == 0) && detectBuildOrderDeadlock())\n    {\n        if (Config::Debug::DrawBuildOrderSearchInfo)\n        {\n            BWAPI::Broodwar->printf(\"Supply deadlock detected, building supply!\");\n        }\n        m_queue.queueAsHighestPriority(MetaType(BWAPI::Broodwar->self()->getRace().getSupplyProvider()), true);\n    }\n\n    // if they have cloaked units get a new goal asap\n    if (!m_enemyCloakedDetected && Global::Info().enemyHasCloakedUnits())\n    {\n        if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Protoss)\n        {\n            if (BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Protoss_Photon_Cannon) < 2)\n            {\n                m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Protoss_Photon_Cannon), true);\n                m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Protoss_Photon_Cannon), true);\n            }\n\n            if (BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Protoss_Forge) == 0)\n            {\n                m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Protoss_Forge), true);\n            }\n        }\n        else if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran)\n        {\n            if (BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Terran_Missile_Turret) < 2)\n            {\n                m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Terran_Missile_Turret), true);\n                m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Terran_Missile_Turret), true);\n            }\n\n            if (BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Terran_Engineering_Bay) == 0)\n            {\n                m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Terran_Engineering_Bay), true);\n            }\n        }\n\n        if (Config::Debug::DrawBuildOrderSearchInfo)\n        {\n            BWAPI::Broodwar->printf(\"Enemy Cloaked Unit Detected!\");\n        }\n\n        m_enemyCloakedDetected = true;\n    }\n\n    \n\tm_bossManager.drawSearchInformation(490, 100);\n    m_bossManager.drawStateInformation(250, 0);\n}\n\n// on unit destroy\nvoid ProductionManager::onUnitDestroy(BWAPI::Unit unit)\n{\n    // we don't care if it's not our unit\n    if (!unit || unit->getPlayer() != BWAPI::Broodwar->self())\n    {\n        return;\n    }\n\n    if (Config::Modules::UsingBuildOrderSearch)\n    {\n        // if it's a worker or a building, we need to re-search for the current goal\n        if ((unit->getType().isWorker() && !Global::Workers().isWorkerScout(unit)) || unit->getType().isBuilding())\n        {\n            if (unit->getType() != BWAPI::UnitTypes::Zerg_Drone)\n            {\n                performBuildOrderSearch();\n            }\n        }\n    }\n}\n\nvoid ProductionManager::manageBuildOrderQueue()\n{\n    PROFILE_FUNCTION();\n\n    // if there is nothing in the _queue, oh well\n    if (m_queue.isEmpty())\n    {\n        return;\n    }\n\n    // the current item to be used\n    BuildOrderItem & currentItem = m_queue.getHighestPriorityItem();\n\n    // while there is still something left in the _queue\n    while (!m_queue.isEmpty())\n    {\n        // this is the unit which can produce the currentItem\n        BWAPI::Unit producer = getProducer(currentItem.metaType);\n\n        // check to see if we can make it right now\n        bool canMake = canMakeNow(producer, currentItem.metaType);\n\n        // if we try to build too many refineries manually remove it\n        if (currentItem.metaType.isRefinery() && (BWAPI::Broodwar->self()->allUnitCount(BWAPI::Broodwar->self()->getRace().getRefinery() >= 3)))\n        {\n            m_queue.removeCurrentHighestPriorityItem();\n            break;\n        }\n\n        // if the next item in the list is a building and we can't yet make it\n        if (currentItem.metaType.isBuilding() && !(producer && canMake) && currentItem.metaType.whatBuilds().isWorker())\n        {\n            // construct a temporary building object\n            Building b(currentItem.metaType.getUnitType(), BWAPI::Broodwar->self()->getStartLocation());\n            b.isGasSteal = currentItem.isGasSteal;\n\n            // set the producer as the closest worker, but do not set its job yet\n            producer = Global::Workers().getBuilder(b, false);\n\n            // predict the worker movement to that building location\n            predictWorkerMovement(b);\n        }\n\n        // if we can make the current item\n        if (producer && canMake)\n        {\n            // create it\n            create(producer, currentItem);\n            m_assignedWorkerForThisBuilding = false;\n            m_haveLocationForThisBuilding = false;\n\n            // and remove it from the _queue\n            m_queue.removeCurrentHighestPriorityItem();\n\n            // don't actually loop around in here\n            break;\n        }\n        // otherwise, if we can skip the current item\n        else if (m_queue.canSkipItem())\n        {\n            // skip it\n            m_queue.skipItem();\n\n            // and get the next one\n            currentItem = m_queue.getNextHighestPriorityItem();\n        }\n        else\n        {\n            // so break out\n            break;\n        }\n    }\n}\n\nBWAPI::Unit ProductionManager::getProducer(MetaType t, BWAPI::Position closestTo)\n{\n    PROFILE_FUNCTION();\n\n    // get the type of unit that builds this\n    BWAPI::UnitType producerType = t.whatBuilds();\n\n    // make a set of all candidate producers\n    BWAPI::Unitset candidateProducers;\n    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n        // reasons a unit can not train the desired type\n        if (unit->getType() != producerType) { continue; }\n        if (!unit->isCompleted()) { continue; }\n        if (unit->isTraining()) { continue; }\n        if (unit->isLifted()) { continue; }\n        if (!unit->isPowered()) { continue; }\n\n        // if the type is an addon, some special cases\n        if (t.getUnitType().isAddon())\n        {\n            // if the unit already has an addon, it can't make one\n            if (unit->getAddon() != nullptr)\n            {\n                continue;\n            }\n\n            // if we just told this unit to build an addon, then it will not be building another one\n            // this deals with the frame-delay of telling a unit to build an addon and it actually starting to build\n            if (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Build_Addon\n                && (BWAPI::Broodwar->getFrameCount() - unit->getLastCommandFrame() < 10))\n            {\n                continue;\n            }\n\n            bool isBlocked = false;\n\n            // if the unit doesn't have space to build an addon, it can't make one\n            BWAPI::TilePosition addonPosition(unit->getTilePosition().x + unit->getType().tileWidth(), unit->getTilePosition().y + unit->getType().tileHeight() - t.getUnitType().tileHeight());\n            BWAPI::Broodwar->drawBoxMap(addonPosition.x*32, addonPosition.y*32, addonPosition.x*32 + 64, addonPosition.y*32 + 64, BWAPI::Colors::Red);\n\n            for (int i=0; i<unit->getType().tileWidth() + t.getUnitType().tileWidth(); ++i)\n            {\n                for (int j=0; j<unit->getType().tileHeight(); ++j)\n                {\n                    BWAPI::TilePosition tilePos(unit->getTilePosition().x + i, unit->getTilePosition().y + j);\n\n                    // if the map won't let you build here, we can't build it\n                    if (!BWAPI::Broodwar->isBuildable(tilePos))\n                    {\n                        isBlocked = true;\n                        BWAPI::Broodwar->drawBoxMap(tilePos.x*32, tilePos.y*32, tilePos.x*32 + 32, tilePos.y*32 + 32, BWAPI::Colors::Red);\n                    }\n\n                    // if there are any units on the addon tile, we can't build it\n                    BWAPI::Unitset uot = BWAPI::Broodwar->getUnitsOnTile(tilePos.x, tilePos.y);\n                    if (uot.size() > 0 && !(uot.size() == 1 && *(uot.begin()) == unit))\n                    {\n                        isBlocked = true;;\n                        BWAPI::Broodwar->drawBoxMap(tilePos.x*32, tilePos.y*32, tilePos.x*32 + 32, tilePos.y*32 + 32, BWAPI::Colors::Red);\n                    }\n                }\n            }\n\n            if (isBlocked)\n            {\n                continue;\n            }\n        }\n\n        // if the type requires an addon and the producer doesn't have one\n        typedef std::pair<BWAPI::UnitType, int> ReqPair;\n        for (const ReqPair & pair : t.getUnitType().requiredUnits())\n        {\n            BWAPI::UnitType requiredType = pair.first;\n            if (requiredType.isAddon())\n            {\n                if (!unit->getAddon() || (unit->getAddon()->getType() != requiredType))\n                {\n                    continue;\n                }\n            }\n        }\n\n        // if we haven't cut it, add it to the set of candidates\n        candidateProducers.insert(unit);\n    }\n\n    return getClosestUnitToPosition(candidateProducers, closestTo);\n}\n\nBWAPI::Unit ProductionManager::getClosestUnitToPosition(const BWAPI::Unitset & units, BWAPI::Position closestTo)\n{\n    if (units.size() == 0)\n    {\n        return nullptr;\n    }\n\n    // if we don't care where the unit is return the first one we have\n    if (closestTo == BWAPI::Positions::None)\n    {\n        return *(units.begin());\n    }\n\n    BWAPI::Unit closestUnit = nullptr;\n    double minDist(1000000);\n\n    for (auto & unit : units)\n    {\n        UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n        double distance = unit->getDistance(closestTo);\n        if (!closestUnit || distance < minDist)\n        {\n            closestUnit = unit;\n            minDist = distance;\n        }\n    }\n\n    return closestUnit;\n}\n\n// this function will check to see if all preconditions are met and then create a unit\nvoid ProductionManager::create(BWAPI::Unit producer, BuildOrderItem & item)\n{\n    if (!producer)\n    {\n        return;\n    }\n\n    PROFILE_FUNCTION();\n\n    MetaType t = item.metaType;\n\n    // if we're dealing with a building\n    if (t.isUnit() && t.getUnitType().isBuilding()\n        && t.getUnitType() != BWAPI::UnitTypes::Zerg_Lair\n        && t.getUnitType() != BWAPI::UnitTypes::Zerg_Hive\n        && t.getUnitType() != BWAPI::UnitTypes::Zerg_Greater_Spire\n        && !t.getUnitType().isAddon())\n    {\n        // send the building task to the building manager\n        m_buildingManager.addBuildingTask(t.getUnitType(), BWAPI::Broodwar->self()->getStartLocation(), item.isGasSteal);\n    }\n    else if (t.getUnitType().isAddon())\n    {\n        //BWAPI::TilePosition addonPosition(producer->getTilePosition().x + producer->getType().tileWidth(), producer->getTilePosition().y + producer->getType().tileHeight() - t.unitType.tileHeight());\n        producer->buildAddon(t.getUnitType());\n    }\n    // if we're dealing with a non-building unit\n    else if (t.isUnit())\n    {\n        // if the race is zerg, morph the unit\n        if (t.getUnitType().getRace() == BWAPI::Races::Zerg)\n        {\n            producer->morph(t.getUnitType());\n            // if not, train the unit\n        }\n        else\n        {\n            producer->train(t.getUnitType());\n        }\n    }\n    // if we're dealing with a tech research\n    else if (t.isTech())\n    {\n        producer->research(t.getTechType());\n    }\n    else if (t.isUpgrade())\n    {\n        //Logger::Instance().log(\"Produce Upgrade: \" + t.getName() + \"\\n\");\n        producer->upgrade(t.getUpgradeType());\n    }\n    else\n    {\n\n    }\n}\n\nbool ProductionManager::canMakeNow(BWAPI::Unit producer, MetaType t)\n{\n    //UAB_ASSERT(producer != nullptr, \"Producer was null\");\n\n    bool canMake = meetsReservedResources(t);\n    if (canMake)\n    {\n        if (t.isUnit())\n        {\n            canMake = BWAPI::Broodwar->canMake(t.getUnitType(), producer);\n        }\n        else if (t.isTech())\n        {\n            canMake = BWAPI::Broodwar->canResearch(t.getTechType(), producer);\n        }\n        else if (t.isUpgrade())\n        {\n            canMake = BWAPI::Broodwar->canUpgrade(t.getUpgradeType(), producer);\n        }\n        else\n        {\n            UAB_ASSERT(false, \"Unknown type\");\n        }\n    }\n\n    return canMake;\n}\n\nbool ProductionManager::detectBuildOrderDeadlock()\n{\n    // if the _queue is empty there is no deadlock\n    if (m_queue.size() == 0 || BWAPI::Broodwar->self()->supplyTotal() >= 390)\n    {\n        return false;\n    }\n\n    // are any supply providers being built currently\n    bool supplyInProgress =\tm_buildingManager.isBeingBuilt(BWAPI::Broodwar->self()->getRace().getSupplyProvider());\n\n    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        if (unit->getType() == BWAPI::UnitTypes::Zerg_Egg)\n        {\n            if (unit->getBuildType() == BWAPI::UnitTypes::Zerg_Overlord)\n            {\n                supplyInProgress = true;\n                break;\n            }\n        }\n    }\n\n    // does the current item being built require more supply\n\n    int supplyCost\t\t\t= m_queue.getHighestPriorityItem().metaType.supplyRequired();\n    int supplyAvailable\t\t= std::max(0, BWAPI::Broodwar->self()->supplyTotal() - BWAPI::Broodwar->self()->supplyUsed());\n\n    // if we don't have enough supply and none is being built, there's a deadlock\n    if ((supplyAvailable < supplyCost) && !supplyInProgress)\n    {\n        // if we're zerg, check to see if a building is planned to be built\n        if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg && m_buildingManager.buildingsQueued().size() > 0)\n        {\n            return false;\n        }\n        else\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n// When the next item in the _queue is a building, this checks to see if we should move to it\n// This function is here as it needs to access prodction manager's reserved resources info\nvoid ProductionManager::predictWorkerMovement(const Building & b)\n{\n    if (b.isGasSteal)\n    {\n        return;\n    }\n\n    // get a possible building location for the building\n    if (!m_haveLocationForThisBuilding)\n    {\n        m_predictedTilePosition = m_buildingManager.getBuildingLocation(b);\n    }\n\n    if (m_predictedTilePosition != BWAPI::TilePositions::None)\n    {\n        m_haveLocationForThisBuilding = true;\n    }\n    else\n    {\n        return;\n    }\n\n    // draw a box where the building will be placed\n    int x1 = m_predictedTilePosition.x * 32;\n    int x2 = x1 + (b.type.tileWidth()) * 32;\n    int y1 = m_predictedTilePosition.y * 32;\n    int y2 = y1 + (b.type.tileHeight()) * 32;\n    if (Config::Debug::DrawWorkerInfo)\n    {\n        BWAPI::Broodwar->drawBoxMap(x1, y1, x2, y2, BWAPI::Colors::Blue, false);\n    }\n\n    // where we want the worker to walk to\n    BWAPI::Position walkToPosition\t\t= BWAPI::Position(x1 + (b.type.tileWidth()/2)*32, y1 + (b.type.tileHeight()/2)*32);\n\n    // compute how many resources we need to construct this building\n    int mineralsRequired\t\t\t\t= std::max(0, b.type.mineralPrice() - getFreeMinerals());\n    int gasRequired\t\t\t\t\t\t= std::max(0, b.type.gasPrice() - getFreeGas());\n\n    // get a candidate worker to move to this location\n    BWAPI::Unit moveWorker\t\t\t= Global::Workers().getMoveWorker(walkToPosition);\n\n    // Conditions under which to move the worker: \n    //\t\t- there's a valid worker to move\n    //\t\t- we haven't yet assigned a worker to move to this location\n    //\t\t- the build position is valid\n    //\t\t- we will have the required resources by the time the worker gets there\n    if (moveWorker && m_haveLocationForThisBuilding && !m_assignedWorkerForThisBuilding && (m_predictedTilePosition != BWAPI::TilePositions::None) &&\n        Global::Workers().willHaveResources(mineralsRequired, gasRequired, moveWorker->getDistance(walkToPosition)))\n    {\n        // we have assigned a worker\n        m_assignedWorkerForThisBuilding = true;\n\n        // tell the worker manager to move this worker\n        Global::Workers().setMoveWorker(mineralsRequired, gasRequired, walkToPosition);\n    }\n}\n\nvoid ProductionManager::performCommand(BWAPI::UnitCommandType t)\n{\n    // if it is a cancel construction, it is probably the extractor trick\n    if (t == BWAPI::UnitCommandTypes::Cancel_Construction)\n    {\n        BWAPI::Unit extractor = nullptr;\n        for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n        {\n            if (unit->getType() == BWAPI::UnitTypes::Zerg_Extractor)\n            {\n                extractor = unit;\n            }\n        }\n\n        if (extractor)\n        {\n            extractor->cancelConstruction();\n        }\n    }\n}\n\nint ProductionManager::getFreeMinerals()\n{\n    return BWAPI::Broodwar->self()->minerals() - m_buildingManager.getReservedMinerals();\n}\n\nint ProductionManager::getFreeGas()\n{\n    return BWAPI::Broodwar->self()->gas() - m_buildingManager.getReservedGas();\n}\n\n// return whether or not we meet resources, including building reserves\nbool ProductionManager::meetsReservedResources(MetaType type)\n{\n    // return whether or not we meet the resources\n    return (type.mineralPrice() <= getFreeMinerals()) && (type.gasPrice() <= getFreeGas());\n}\n\n\n// selects a unit of a given type\nBWAPI::Unit ProductionManager::selectUnitOfType(BWAPI::UnitType type, BWAPI::Position closestTo)\n{\n    // if we have none of the unit type, return nullptr right away\n    if (BWAPI::Broodwar->self()->completedUnitCount(type) == 0)\n    {\n        return nullptr;\n    }\n\n    BWAPI::Unit unit = nullptr;\n\n    // if we are concerned about the position of the unit, that takes priority\n    if (closestTo != BWAPI::Positions::None)\n    {\n        double minDist(1000000);\n\n        for (auto & u : BWAPI::Broodwar->self()->getUnits())\n        {\n            if (u->getType() == type)\n            {\n                double distance = u->getDistance(closestTo);\n                if (!unit || distance < minDist) {\n                    unit = u;\n                    minDist = distance;\n                }\n            }\n        }\n\n        // if it is a building and we are worried about selecting the unit with the least\n        // amount of training time remaining\n    }\n    else if (type.isBuilding())\n    {\n        for (auto & u : BWAPI::Broodwar->self()->getUnits())\n        {\n            UAB_ASSERT(u != nullptr, \"Unit was null\");\n\n            if (u->getType() == type && u->isCompleted() && !u->isTraining() && !u->isLifted() &&u->isPowered()) {\n\n                return u;\n            }\n        }\n        // otherwise just return the first unit we come across\n    }\n    else\n    {\n        for (auto & u : BWAPI::Broodwar->self()->getUnits())\n        {\n            UAB_ASSERT(u != nullptr, \"Unit was null\");\n\n            if (u->getType() == type && u->isCompleted() && u->getHitPoints() > 0 && !u->isLifted() &&u->isPowered())\n            {\n                return u;\n            }\n        }\n    }\n\n    // return what we've found so far\n    return nullptr;\n}\n\nvoid ProductionManager::drawProductionInformation(int x, int y)\n{\n    if (!Config::Debug::DrawProductionInfo)\n    {\n        return;\n    }\n\n    // fill prod with each unit which is under construction\n    std::vector<BWAPI::Unit> prod;\n    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n        if (unit->isBeingConstructed())\n        {\n            prod.push_back(unit);\n        }\n    }\n\n    // sort it based on the time it was started\n    std::sort(prod.begin(), prod.end(), CompareWhenStarted());\n\n    BWAPI::Broodwar->drawTextScreen(x-30, y+20, \"\\x04 TIME\");\n    BWAPI::Broodwar->drawTextScreen(x, y+20, \"\\x04 UNIT NAME\");\n\n    size_t reps = prod.size() < 10 ? prod.size() : 10;\n\n    y += 30;\n    int yy = y;\n\n    // for each unit in the _queue\n    for (auto & unit : prod)\n    {\n        std::string prefix = \"\\x07\";\n\n        yy += 10;\n\n        BWAPI::UnitType t = unit->getType();\n        if (t == BWAPI::UnitTypes::Zerg_Egg)\n        {\n            t = unit->getBuildType();\n        }\n\n        BWAPI::Broodwar->drawTextScreen(x, yy, \" %s%s\", prefix.c_str(), t.getName().c_str());\n        BWAPI::Broodwar->drawTextScreen(x - 35, yy, \"%s%6d\", prefix.c_str(), unit->getRemainingBuildTime());\n    }\n\n    m_queue.drawQueueInformation(x, yy+10);\n}\n\nvoid ProductionManager::queueGasSteal()\n{\n    m_queue.queueAsHighestPriority(MetaType(BWAPI::Broodwar->self()->getRace().getRefinery()), true, true);\n}\n\n// this will return true if any unit is on the first frame if it's training time remaining\n// this can cause issues for the build order search system so don't plan a search on these frames\nbool ProductionManager::canPlanBuildOrderNow() const\n{\n    for (const auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        if (unit->getRemainingTrainTime() == 0)\n        {\n            continue;\n        }\n\n        BWAPI::UnitType trainType = unit->getLastCommand().getUnitType();\n\n        if (unit->getRemainingTrainTime() == trainType.buildTime())\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nstd::vector<BWAPI::UnitType> ProductionManager::buildingsQueued()\n{\n    return m_buildingManager.buildingsQueued();\n}"
  },
  {
    "path": "UAlbertaBot/Source/ProductionManager.h",
    "content": "#pragma once\n\n#include <Common.h>\n#include \"BuildOrderQueue.h\"\n#include \"BOSSManager.h\"\n#include \"BuildingManager.h\"\n\nnamespace UAlbertaBot\n{\ntypedef unsigned char Action;\n\nclass Building;\nclass BuildOrder;\n\nclass ProductionManager\n{\n    friend class Global;\n\n    BuildingManager     m_buildingManager;\n    BOSSManager         m_bossManager;\n    BuildOrderQueue     m_queue;\n    BWAPI::TilePosition m_predictedTilePosition;\n    bool                m_enemyCloakedDetected          = false;\n    bool                m_assignedWorkerForThisBuilding = false;\n    bool                m_haveLocationForThisBuilding   = false;\n\n    BWAPI::Unit         getClosestUnitToPosition(const BWAPI::Unitset & units, BWAPI::Position closestTo);\n    BWAPI::Unit         selectUnitOfType(BWAPI::UnitType type, BWAPI::Position closestTo = BWAPI::Position(0, 0));\n\n    void setBuildOrder(const BuildOrder & buildOrder);\n    void create(BWAPI::Unit producer, BuildOrderItem & item);\n    void manageBuildOrderQueue();\n    void performCommand(BWAPI::UnitCommandType t);\n    void predictWorkerMovement(const Building & b);\n\n    int  getFreeMinerals();\n    int  getFreeGas();\n    bool detectBuildOrderDeadlock();\n    bool canPlanBuildOrderNow() const;\n    bool canMakeNow(BWAPI::Unit producer, MetaType t);\n    bool meetsReservedResources(MetaType type);\n    \n    ProductionManager();\n\npublic:\n\n    void update();\n    void onUnitDestroy(BWAPI::Unit unit);\n    void performBuildOrderSearch();\n    void drawProductionInformation(int x, int y);\n    void queueGasSteal();\n    std::vector<BWAPI::UnitType> buildingsQueued();\n\n    BWAPI::Unit getProducer(MetaType t, BWAPI::Position closestTo = BWAPI::Positions::None);\n};\n\n\nclass CompareWhenStarted\n{\n\npublic:\n\n    CompareWhenStarted() {}\n\n    // the sorting operator\n    bool operator() (BWAPI::Unit u1, BWAPI::Unit u2)\n    {\n        int startedU1 = BWAPI::Broodwar->getFrameCount() - (u1->getType().buildTime() - u1->getRemainingBuildTime());\n        int startedU2 = BWAPI::Broodwar->getFrameCount() - (u2->getType().buildTime() - u2->getRemainingBuildTime());\n        return startedU1 > startedU2;\n    }\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/Profiler.hpp",
    "content": "#pragma once\n\n#include <chrono>\n#include <fstream>\n#include <mutex>\n#include <map>\n#include <algorithm>\n\n//#define PROFILING 1\n#ifdef PROFILING\n    #define PROFILE_SCOPE(name) \\\n        ProfileTimer timer##__LINE__(name)\n    #define PROFILE_FUNCTION() \\\n        PROFILE_SCOPE(__FUNCTION__)\n#else\n    #define PROFILE_FUNCTION()\n    #define PROFILE_SCOPE(name)\n#endif\n\nnamespace UAlbertaBot\n{\n\n\nstruct ProfileResult\n{\n    std::string name = \"Default\";\n    long long start  = 0;\n    long long end    = 0;\n    size_t threadID  = 0;\n};\n\nclass Profiler\n{\n    std::string     m_outputFile    = \"results.json\";\n    size_t          m_profileCount  = 0;\n    std::ofstream   m_outputStream;\n    std::mutex      m_lock;\n\n    Profiler()\n    { \n        m_outputStream = std::ofstream(m_outputFile);\n        writeHeader();\n    }\n\n    void writeHeader() { m_outputStream << \"{\\\"otherData\\\": {},\\\"traceEvents\\\":[\"; }\n    void writeFooter() { m_outputStream << \"]}\"; }\n\npublic:\n\n    static Profiler& Instance()\n    {\n        static Profiler instance;\n        return instance;\n    }\n\n    ~Profiler()\n    {\n        writeFooter();\n    }\n    \n    void writeProfile(const ProfileResult& result)\n    {\n        std::lock_guard<std::mutex> lock(m_lock);\n\n        if (m_profileCount++ > 0) { m_outputStream << \",\"; }\n\n        std::string name = result.name;\n        std::replace(name.begin(), name.end(), '\"', '\\'');\n\n        m_outputStream << \"\\n{\";\n        m_outputStream << \"\\\"cat\\\":\\\"function\\\",\";\n        m_outputStream << \"\\\"dur\\\":\" << (result.end - result.start) << ',';\n        m_outputStream << \"\\\"name\\\":\\\"\" << name << \"\\\",\";\n        m_outputStream << \"\\\"ph\\\":\\\"X\\\",\";\n        m_outputStream << \"\\\"pid\\\":0,\";\n        m_outputStream << \"\\\"tid\\\":\" << result.threadID << \",\";\n        m_outputStream << \"\\\"ts\\\":\" << result.start;\n        m_outputStream << \"}\";\n    }\n};\n\nclass ProfileTimer\n{\n    ProfileResult m_result;\n    bool m_stopped = false;\n\n    std::chrono::time_point<std::chrono::high_resolution_clock> m_startTimepoint;\n\npublic:\n\n    ProfileTimer(const std::string & name)\n    {\n        m_result.name = name;\n        m_startTimepoint = std::chrono::high_resolution_clock::now();\n    }\n\n    ~ProfileTimer()\n    {\n        stop();\n    }\n\n    void stop()\n    {\n        if (m_stopped) { return; }\n\n        auto endTimepoint = std::chrono::high_resolution_clock::now();\n\n        m_result.start = std::chrono::time_point_cast<std::chrono::microseconds>(m_startTimepoint).time_since_epoch().count();\n        m_result.end   = std::chrono::time_point_cast<std::chrono::microseconds>(endTimepoint).time_since_epoch().count();\n        m_result.threadID = std::hash<std::thread::id>{}(std::this_thread::get_id());\n        Profiler::Instance().writeProfile(m_result);\n\n        m_stopped = true;\n    }\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/RangedManager.cpp",
    "content": "#include \"RangedManager.h\"\n#include \"UnitUtil.h\"\n#include \"Micro.h\"\n\nusing namespace UAlbertaBot;\n\nRangedManager::RangedManager()\n{\n}\n\nvoid RangedManager::executeMicro(const BWAPI::Unitset & targets)\n{\n    assignTargetsOld(targets);\n}\n\n\nvoid RangedManager::assignTargetsOld(const BWAPI::Unitset & targets)\n{\n    const BWAPI::Unitset & rangedUnits = getUnits();\n\n    // figure out targets\n    BWAPI::Unitset rangedUnitTargets;\n    std::copy_if(targets.begin(), targets.end(), std::inserter(rangedUnitTargets, rangedUnitTargets.end()), [](BWAPI::Unit u) { return u->isVisible(); });\n\n    for (auto & rangedUnit : rangedUnits)\n    {\n        // train sub units such as scarabs or interceptors\n        //trainSubUnits(rangedUnit);\n\n        // if the order is to attack or defend\n        if (m_order.getType() == SquadOrderTypes::Attack || m_order.getType() == SquadOrderTypes::Defend)\n        {\n            // if there are targets\n            if (!rangedUnitTargets.empty())\n            {\n                // find the best target for this zealot\n                BWAPI::Unit target = getTarget(rangedUnit, rangedUnitTargets);\n\n                if (target && Config::Debug::DrawUnitTargetInfo)\n                {\n                    BWAPI::Broodwar->drawLineMap(rangedUnit->getPosition(), rangedUnit->getTargetPosition(), BWAPI::Colors::Purple);\n                }\n\n\n                // attack it\n                if (Config::Micro::KiteWithRangedUnits)\n                {\n                    if (rangedUnit->getType() == BWAPI::UnitTypes::Zerg_Mutalisk || rangedUnit->getType() == BWAPI::UnitTypes::Terran_Vulture)\n                    {\n                        Micro::MutaDanceTarget(rangedUnit, target);\n                    }\n                    else\n                    {\n                        Micro::SmartKiteTarget(rangedUnit, target);\n                    }\n                }\n                else\n                {\n                    Micro::SmartAttackUnit(rangedUnit, target);\n                }\n            }\n            // if there are no targets\n            else\n            {\n                // if we're not near the order position\n                if (rangedUnit->getDistance(m_order.getPosition()) > 100)\n                {\n                    // move to it\n                    Micro::SmartAttackMove(rangedUnit, m_order.getPosition());\n                }\n            }\n        }\n    }\n}\n\nstd::pair<BWAPI::Unit, BWAPI::Unit> RangedManager::findClosestUnitPair(const BWAPI::Unitset & attackers, const BWAPI::Unitset & targets)\n{\n    std::pair<BWAPI::Unit, BWAPI::Unit> closestPair(nullptr, nullptr);\n    double closestDistance = std::numeric_limits<double>::max();\n\n    for (auto & attacker : attackers)\n    {\n        BWAPI::Unit target = getTarget(attacker, targets);\n        double dist = attacker->getDistance(attacker);\n\n        if (!closestPair.first || (dist < closestDistance))\n        {\n            closestPair.first = attacker;\n            closestPair.second = target;\n            closestDistance = dist;\n        }\n    }\n\n    return closestPair;\n}\n\n// get a target for the zealot to attack\nBWAPI::Unit RangedManager::getTarget(BWAPI::Unit rangedUnit, const BWAPI::Unitset & targets)\n{\n    int bestPriorityDistance = 1000000;\n    int bestPriority = 0;\n\n    double bestLTD = 0;\n\n    int highPriority = 0;\n    double closestDist = std::numeric_limits<double>::infinity();\n    BWAPI::Unit closestTarget = nullptr;\n\n    for (const auto & target : targets)\n    {\n        double distance         = rangedUnit->getDistance(target);\n        double LTD              = UnitUtil::CalculateLTD(target, rangedUnit);\n        int priority            = getAttackPriority(rangedUnit, target);\n        bool targetIsThreat     = LTD > 0;\n\n        if (!closestTarget || (priority > highPriority) || (priority == highPriority && distance < closestDist))\n        {\n            closestDist = distance;\n            highPriority = priority;\n            closestTarget = target;\n        }\n    }\n\n    return closestTarget;\n}\n\n// get the attack priority of a type in relation to a zergling\nint RangedManager::getAttackPriority(BWAPI::Unit rangedUnit, BWAPI::Unit target)\n{\n    BWAPI::UnitType rangedType = rangedUnit->getType();\n    BWAPI::UnitType targetType = target->getType();\n\n\n    if (rangedUnit->getType() == BWAPI::UnitTypes::Zerg_Scourge)\n    {\n        if (target->getType() == BWAPI::UnitTypes::Protoss_Carrier)\n        {\n\n            return 100;\n        }\n\n        if (target->getType() == BWAPI::UnitTypes::Protoss_Corsair)\n        {\n            return 90;\n        }\n    }\n\n    bool isThreat = rangedType.isFlyer() ? targetType.airWeapon() != BWAPI::WeaponTypes::None : targetType.groundWeapon() != BWAPI::WeaponTypes::None;\n\n    if (target->getType().isWorker())\n    {\n        isThreat = false;\n    }\n\n    if (target->getType() == BWAPI::UnitTypes::Zerg_Larva || target->getType() == BWAPI::UnitTypes::Zerg_Egg)\n    {\n        return 0;\n    }\n\n    if (rangedUnit->isFlying() && target->getType() == BWAPI::UnitTypes::Protoss_Carrier)\n    {\n        return 101;\n    }\n\n    // if the target is building something near our base something is fishy\n    BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n    if (target->getType().isWorker() && (target->isConstructing() || target->isRepairing()) && target->getDistance(ourBasePosition) < 1200)\n    {\n        return 100;\n    }\n\n    if (target->getType().isBuilding() && (target->isCompleted() || target->isBeingConstructed()) && target->getDistance(ourBasePosition) < 1200)\n    {\n        return 90;\n    }\n\n    // highest priority is something that can attack us or aid in combat\n    if (targetType ==  BWAPI::UnitTypes::Terran_Bunker || isThreat)\n    {\n        return 11;\n    }\n    // next priority is worker\n    else if (targetType.isWorker())\n    {\n        if (rangedUnit->getType() == BWAPI::UnitTypes::Terran_Vulture)\n        {\n            return 11;\n        }\n\n        return 11;\n    }\n    // next is special buildings\n    else if (targetType == BWAPI::UnitTypes::Zerg_Spawning_Pool)\n    {\n        return 5;\n    }\n    // next is special buildings\n    else if (targetType == BWAPI::UnitTypes::Protoss_Pylon)\n    {\n        return 5;\n    }\n    // next is buildings that cost gas\n    else if (targetType.gasPrice() > 0)\n    {\n        return 4;\n    }\n    else if (targetType.mineralPrice() > 0)\n    {\n        return 3;\n    }\n    // then everything else\n    else\n    {\n        return 1;\n    }\n}\n\nBWAPI::Unit RangedManager::closestrangedUnit(BWAPI::Unit target, std::set<BWAPI::Unit> & rangedUnitsToAssign)\n{\n    double minDistance = 0;\n    BWAPI::Unit closest = nullptr;\n\n    for (auto & rangedUnit : rangedUnitsToAssign)\n    {\n        double distance = rangedUnit->getDistance(target);\n        if (!closest || distance < minDistance)\n        {\n            minDistance = distance;\n            closest = rangedUnit;\n        }\n    }\n\n    return closest;\n}\n\n\n// still has bug in it somewhere, use Old version\nvoid RangedManager::assignTargetsNew(const BWAPI::Unitset & targets)\n{\n    const BWAPI::Unitset & rangedUnits = getUnits();\n\n    // figure out targets\n    BWAPI::Unitset rangedUnitTargets;\n    std::copy_if(targets.begin(), targets.end(), std::inserter(rangedUnitTargets, rangedUnitTargets.end()), [](BWAPI::Unit u) { return u->isVisible(); });\n\n    BWAPI::Unitset rangedUnitsToAssign(rangedUnits);\n    std::map<BWAPI::Unit, int> attackersAssigned;\n\n    for (auto & unit : rangedUnitTargets)\n    {\n        attackersAssigned[unit] = 0;\n    }\n\n    // keep assigning targets while we have attackers and targets remaining\n    while (!rangedUnitsToAssign.empty() && !rangedUnitTargets.empty())\n    {\n        auto attackerAssignment = findClosestUnitPair(rangedUnitsToAssign, rangedUnitTargets);\n        BWAPI::Unit & attacker = attackerAssignment.first;\n        BWAPI::Unit & target = attackerAssignment.second;\n\n        UAB_ASSERT_WARNING(attacker, \"We should have chosen an attacker!\");\n\n        if (!attacker)\n        {\n            break;\n        }\n\n        if (!target)\n        {\n            Micro::SmartAttackMove(attacker, m_order.getPosition());\n            continue;\n        }\n\n        if (Config::Micro::KiteWithRangedUnits)\n        {\n            if (attacker->getType() == BWAPI::UnitTypes::Zerg_Mutalisk || attacker->getType() == BWAPI::UnitTypes::Terran_Vulture)\n            {\n                Micro::MutaDanceTarget(attacker, target);\n            }\n            else\n            {\n                Micro::SmartKiteTarget(attacker, target);\n            }\n        }\n        else\n        {\n            Micro::SmartAttackUnit(attacker, target);\n        }\n\n        // update the number of units assigned to attack the target we found\n        int & assigned = attackersAssigned[attackerAssignment.second];\n        assigned++;\n\n        // if it's a small / fast unit and there's more than 2 things attacking it already, don't assign more\n        if ((target->getType().isWorker() || target->getType() == BWAPI::UnitTypes::Zerg_Zergling) && (assigned > 2))\n        {\n            rangedUnitTargets.erase(target);\n        }\n        // if it's a building and there's more than 10 things assigned to it already, don't assign more\n        else if (target->getType().isBuilding() && (assigned > 10))\n        {\n            rangedUnitTargets.erase(target);\n        }\n\n        rangedUnitsToAssign.erase(attacker);\n    }\n\n    // if there's no targets left, attack move to the order destination\n    if (rangedUnitTargets.empty())\n    {\n        for (auto & unit : rangedUnitsToAssign)\n        {\n            if (unit->getDistance(m_order.getPosition()) > 100)\n            {\n                // move to it\n                Micro::SmartAttackMove(unit, m_order.getPosition());\n            }\n        }\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/RangedManager.h",
    "content": "#pragma once\n\n#include <Common.h>\n#include \"MicroManager.h\"\n\nnamespace UAlbertaBot\n{\nclass RangedManager : public MicroManager\n{\npublic:\n\n    RangedManager();\n    void executeMicro(const BWAPI::Unitset & targets);\n    void assignTargetsNew(const BWAPI::Unitset & targets);\n    void assignTargetsOld(const BWAPI::Unitset & targets);\n\n    int getAttackPriority(BWAPI::Unit rangedUnit, BWAPI::Unit target);\n    BWAPI::Unit closestrangedUnit(BWAPI::Unit target, std::set<BWAPI::Unit> & rangedUnitsToAssign);\n    BWAPI::Unit getTarget(BWAPI::Unit rangedUnit, const BWAPI::Unitset & targets);\n    std::pair<BWAPI::Unit, BWAPI::Unit> findClosestUnitPair(const BWAPI::Unitset & attackers, const BWAPI::Unitset & targets);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/ScoutManager.cpp",
    "content": "#include \"ScoutManager.h\"\n#include \"ProductionManager.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n#include \"MicroManager.h\"\n#include \"InformationManager.h\"\n#include \"Micro.h\"\n#include \"WorkerManager.h\"\n#include \"MapTools.h\"\n\nusing namespace UAlbertaBot;\n\nScoutManager::ScoutManager()\n{\n}\n\nvoid ScoutManager::update()\n{\n    PROFILE_FUNCTION();\n\n    if (!Config::Modules::UsingScoutManager)\n    {\n        return;\n    }\n\n    moveScouts();\n    drawScoutInformation(200, 320);\n}\n\nvoid ScoutManager::setWorkerScout(BWAPI::Unit unit)\n{\n    // if we have a previous worker scout, release it back to the worker manager\n    if (m_workerScout)\n    {\n        Global::Workers().finishedWithWorker(m_workerScout);\n    }\n\n    m_workerScout = unit;\n    Global::Workers().setScoutWorker(m_workerScout);\n}\n\nvoid ScoutManager::drawScoutInformation(int x, int y)\n{\n    if (!Config::Debug::DrawScoutInfo)\n    {\n        return;\n    }\n\n    BWAPI::Broodwar->drawTextScreen(x, y, \"ScoutInfo: %s\", m_scoutStatus.c_str());\n    BWAPI::Broodwar->drawTextScreen(x, y+10, \"GasSteal: %s\", m_gasStealStatus.c_str());\n}\n\nvoid ScoutManager::moveScouts()\n{\n    if (!m_workerScout || !m_workerScout->exists() || !(m_workerScout->getHitPoints() > 0))\n    {\n        return;\n    }\n\n    const int scoutHP = m_workerScout->getHitPoints() + m_workerScout->getShields();\n\n    gasSteal();\n\n    // get the enemy base location, if we have one\n    const BaseLocation * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n\n    const int scoutDistanceThreshold = 30;\n\n    if (m_workerScout->isCarryingGas())\n    {\n        BWAPI::Broodwar->drawCircleMap(m_workerScout->getPosition(), 10, BWAPI::Colors::Purple, true);\n    }\n\n    // if we initiated a gas steal and the worker isn't idle, \n    const bool finishedConstructingGasSteal = m_workerScout->isIdle() || m_workerScout->isCarryingGas();\n    if (!m_gasStealFinished && m_didGasSteal && !finishedConstructingGasSteal)\n    {\n        return;\n    }\n    // check to see if the gas steal is completed\n    else if (m_didGasSteal && finishedConstructingGasSteal)\n    {\n        m_gasStealFinished = true;\n    }\n\n    // for each start location in the level\n    if (!enemyBaseLocation)\n    {\n        m_scoutStatus = \"Enemy base unknown, exploring\";\n\n        for (auto startLocation : BWAPI::Broodwar->getStartLocations())\n        {\n            // if we haven't explored it yet, explore it\n            if (!BWAPI::Broodwar->isExplored(startLocation))\n            {\n                Micro::SmartMove(m_workerScout, BWAPI::Position(startLocation));\n                BWAPI::Broodwar->drawCircleMap(BWAPI::Position(startLocation), 32, BWAPI::Colors::Purple);\n                return;\n            }\n        }\n    }\n\n    // if we know where the enemy region is and where our scout is\n    if (enemyBaseLocation)\n    {\n        const int scoutDistanceToEnemy = Global::Map().getGroundDistance(m_workerScout->getPosition(), enemyBaseLocation->getPosition());\n        const bool scoutInRangeOfenemy = scoutDistanceToEnemy <= scoutDistanceThreshold;\n\n        // we only care if the scout is under attack within the enemy region\n        // this ignores if their scout worker attacks it on the way to their base\n        if (scoutHP < m_previousScoutHP)\n        {\n            m_scoutUnderAttack = true;\n        }\n\n        if (!m_workerScout->isUnderAttack() && !enemyWorkerInRadius())\n        {\n            m_scoutUnderAttack = false;\n        }\n\n        // if the scout is in the enemy region\n        if (scoutInRangeOfenemy)\n        {\n            // get the closest enemy worker\n            BWAPI::Unit closestWorker = closestEnemyWorker();\n\n            // if the worker scout is not under attack\n            if (!m_scoutUnderAttack)\n            {\n                // if there is a worker nearby, harass it\n                if (Config::Strategy::ScoutHarassEnemy && (!Config::Strategy::GasStealWithScout || m_gasStealFinished) && closestWorker && (m_workerScout->getDistance(closestWorker) < 800))\n                {\n                    m_scoutStatus = \"Harass enemy worker\";\n                    Micro::SmartAttackUnit(m_workerScout, closestWorker);\n                }\n                // otherwise keep moving to the enemy region\n                else\n                {\n                    m_scoutStatus = \"Following perimeter\";\n                    Micro::SmartMove(m_workerScout, BWAPI::Position(enemyBaseLocation->getPosition()));\n                }\n\n            }\n            // if the worker scout is under attack\n            else\n            {\n                m_scoutStatus = \"Under attack inside, fleeing\";\n                fleeScout();\n            }\n        }\n        // if the scout is not in the enemy region\n        else if (m_scoutUnderAttack)\n        {\n            m_scoutStatus = \"Under attack inside, fleeing\";\n\n            fleeScout();\n        }\n        else\n        {\n            m_scoutStatus = \"Enemy region known, going there\";\n\n            // move to the enemy region\n            Micro::SmartMove(m_workerScout, BWAPI::Position(enemyBaseLocation->getPosition()));\n        }\n\n    }\n\n    m_previousScoutHP = scoutHP;\n}\n\nvoid ScoutManager::fleeScout()\n{\n    const BWAPI::Position fleeTo = getFleePosition();\n\n    if (Config::Debug::DrawScoutInfo)\n    {\n        BWAPI::Broodwar->drawCircleMap(fleeTo, 5, BWAPI::Colors::Red, true);\n    }\n\n    Micro::SmartMove(m_workerScout, fleeTo);\n}\n\nvoid ScoutManager::gasSteal()\n{\n    if (!Config::Strategy::GasStealWithScout)\n    {\n        m_gasStealStatus = \"Not using gas steal\";\n        return;\n    }\n\n    if (m_didGasSteal)\n    {\n        return;\n    }\n\n    if (!m_workerScout)\n    {\n        m_gasStealStatus = \"No worker scout\";\n        return;\n    }\n\n    auto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n    if (!enemyBaseLocation)\n    {\n        m_gasStealStatus = \"No enemy base location found\";\n        return;\n    }\n\n    const BWAPI::Unit enemyGeyser = getEnemyGeyser();\n    if (!enemyGeyser)\n    {\n        m_gasStealStatus = \"No enemy geyser found\";\n        false;\n    }\n\n    if (!m_didGasSteal)\n    {\n        Global::Production().queueGasSteal();\n        m_didGasSteal = true;\n        Micro::SmartMove(m_workerScout, enemyGeyser->getPosition());\n        m_gasStealStatus = \"Did Gas Steal\";\n    }\n}\n\nBWAPI::Unit ScoutManager::closestEnemyWorker()\n{\n    BWAPI::Unit enemyWorker = nullptr;\n    BWAPI::Unit geyser      = getEnemyGeyser();\n    double      maxDist     = 0;\n\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        if (unit->getType().isWorker() && unit->isConstructing())\n        {\n            return unit;\n        }\n    }\n\n    // for each enemy worker\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        if (unit->getType().isWorker())\n        {\n            const double dist = unit->getDistance(geyser);\n\n            if (dist < 800 && dist > maxDist)\n            {\n                maxDist = dist;\n                enemyWorker = unit;\n            }\n        }\n    }\n\n    return enemyWorker;\n}\n\nBWAPI::Unit ScoutManager::getEnemyGeyser()\n{\n    BWAPI::Unit geyser = nullptr;\n    const auto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n\n    for (auto & unit : enemyBaseLocation->getGeysers())\n    {\n        geyser = unit;\n    }\n\n    return geyser;\n}\n\nbool ScoutManager::enemyWorkerInRadius()\n{\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        if (unit->getType().isWorker() && (unit->getDistance(m_workerScout) < 300))\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool ScoutManager::immediateThreat()\n{\n    BWAPI::Unitset enemyAttackingWorkers;\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        if (unit->getType().isWorker() && unit->isAttacking())\n        {\n            enemyAttackingWorkers.insert(unit);\n        }\n    }\n\n    if (m_workerScout->isUnderAttack())\n    {\n        return true;\n    }\n\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        const double dist = unit->getDistance(m_workerScout);\n        const double range = unit->getType().groundWeapon().maxRange();\n\n        if (unit->getType().canAttack() && !unit->getType().isWorker() && (dist <= range + 32))\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nBWAPI::Position ScoutManager::getFleePosition()\n{\n    return BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/ScoutManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace UAlbertaBot\n{\nclass ScoutManager\n{\n    friend class Global;\n\n    BWAPI::Unit\t\tm_workerScout       = nullptr;\n    std::string\t\tm_scoutStatus       = \"None\";\n    std::string\t\tm_gasStealStatus    = \"None\";\n    int\t\t\t\tm_numWorkerScouts   = 0;\n    int\t\t\t\tm_previousScoutHP   = 0;\n    bool\t\t\tm_scoutUnderAttack  = false;\n    bool\t\t\tm_didGasSteal       = false;\n    bool\t\t\tm_gasStealFinished  = false;\n\n    bool enemyWorkerInRadius();\n    bool immediateThreat();\n    void gasSteal();\n    void fleeScout();\n    void moveScouts();\n    void drawScoutInformation(int x, int y);\n    BWAPI::Position\tgetFleePosition();\n    BWAPI::Unit\t\tgetEnemyGeyser();\n    BWAPI::Unit\t\tclosestEnemyWorker();\n\n    ScoutManager();\n\npublic:\n\n    void update();\n\n    void setWorkerScout(BWAPI::Unit unit);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/Squad.cpp",
    "content": "#include \"Squad.h\"\n#include \"UnitUtil.h\"\n#include \"Global.h\"\n#include \"WorkerManager.h\"\n#include \"UnitData.h\"\n#include \"MapTools.h\"\n#include \"StrategyManager.h\"\n#include \"CombatSimulation.h\"\n#include \"InformationManager.h\"\n\nusing namespace UAlbertaBot;\n\nSquad::Squad()\n{\n    \n}\n\nSquad::Squad(const std::string & name, SquadOrder order, size_t priority)\n    : m_name(name)\n    , m_order(order)\n    , m_lastRetreatSwitch(0)\n    , m_lastRetreatSwitchVal(false)\n    , m_priority(priority)\n{\n}\n\nSquad::~Squad()\n{\n    clear();\n}\n\nvoid Squad::update()\n{\n    // update all necessary unit information within this squad\n    updateUnits();\n\n    // determine whether or not we should regroup\n    bool needToRegroup = needsToRegroup();\n\n    // draw some debug info\n    if (Config::Debug::DrawSquadInfo && m_order.getType() == SquadOrderTypes::Attack)\n    {\n        BWAPI::Broodwar->drawTextScreen(200, 350, \"%s\", m_regroupStatus.c_str());\n\n        BWAPI::Unit closest = unitClosestToEnemy();\n    }\n\n    // if we do need to regroup, do it\n    if (needToRegroup)\n    {\n        BWAPI::Position regroupPosition = calcRegroupPosition();\n\n        if (Config::Debug::DrawCombatSimulationInfo)\n        {\n            BWAPI::Broodwar->drawTextScreen(200, 150, \"REGROUP\");\n        }\n\n        BWAPI::Broodwar->drawCircleMap(regroupPosition.x, regroupPosition.y, 30, BWAPI::Colors::Purple, true);\n\n        m_meleeManager.regroup(regroupPosition);\n        m_rangedManager.regroup(regroupPosition);\n        m_tankManager.regroup(regroupPosition);\n        m_medicManager.regroup(regroupPosition);\n    }\n    else // otherwise, execute micro\n    {\n        m_meleeManager.execute(m_order);\n        m_rangedManager.execute(m_order);\n        m_tankManager.execute(m_order);\n        m_medicManager.execute(m_order);\n        m_transportManager.update();\n\n        m_detectorManager.setUnitClosestToEnemy(unitClosestToEnemy());\n        m_detectorManager.execute(m_order);\n    }\n}\n\nbool Squad::isEmpty() const\n{\n    return m_units.empty();\n}\n\nsize_t Squad::getPriority() const\n{\n    return m_priority;\n}\n\nvoid Squad::setPriority(const size_t & priority)\n{\n    m_priority = priority;\n}\n\nvoid Squad::updateUnits()\n{\n    setAllUnits();\n    setNearEnemyUnits();\n    addUnitsToMicroManagers();\n}\n\nvoid Squad::setAllUnits()\n{\n    // clean up the m_units vector just in case one of them died\n    BWAPI::Unitset goodUnits;\n    for (auto & unit : m_units)\n    {\n        if (unit->isCompleted() &&\n            unit->getHitPoints() > 0 &&\n            unit->exists() &&\n            unit->getPosition().isValid() &&\n            unit->getType() != BWAPI::UnitTypes::Unknown)\n        {\n            goodUnits.insert(unit);\n        }\n    }\n    m_units = goodUnits;\n}\n\nvoid Squad::setNearEnemyUnits()\n{\n    m_nearEnemy.clear();\n    for (auto & unit : m_units)\n    {\n        int x = unit->getPosition().x;\n        int y = unit->getPosition().y;\n\n        int left = unit->getType().dimensionLeft();\n        int right = unit->getType().dimensionRight();\n        int top = unit->getType().dimensionUp();\n        int bottom = unit->getType().dimensionDown();\n\n        m_nearEnemy[unit] = unitNearEnemy(unit);\n        if (m_nearEnemy[unit])\n        {\n            if (Config::Debug::DrawSquadInfo) BWAPI::Broodwar->drawBoxMap(x-left, y - top, x + right, y + bottom, Config::Debug::ColorUnitNearEnemy);\n        }\n        else\n        {\n            if (Config::Debug::DrawSquadInfo) BWAPI::Broodwar->drawBoxMap(x-left, y - top, x + right, y + bottom, Config::Debug::ColorUnitNotNearEnemy);\n        }\n    }\n}\n\nvoid Squad::addUnitsToMicroManagers()\n{\n    BWAPI::Unitset meleeUnits;\n    BWAPI::Unitset rangedUnits;\n    BWAPI::Unitset detectorUnits;\n    BWAPI::Unitset transportUnits;\n    BWAPI::Unitset tankUnits;\n    BWAPI::Unitset medicUnits;\n\n    // add m_units to micro managers\n    for (auto & unit : m_units)\n    {\n        if (unit->isCompleted() && unit->getHitPoints() > 0 && unit->exists())\n        {\n            // select dector m_units\n            if (unit->getType() == BWAPI::UnitTypes::Terran_Medic)\n            {\n                medicUnits.insert(unit);\n            }\n            else if (unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode || unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode)\n            {\n                tankUnits.insert(unit);\n            }\n            else if (unit->getType().isDetector() && !unit->getType().isBuilding())\n            {\n                detectorUnits.insert(unit);\n            }\n            // select transport m_units\n            else if (unit->getType() == BWAPI::UnitTypes::Protoss_Shuttle || unit->getType() == BWAPI::UnitTypes::Terran_Dropship)\n            {\n                transportUnits.insert(unit);\n            }\n            // select ranged m_units\n            else if ((unit->getType().groundWeapon().maxRange() > 32) || (unit->getType() == BWAPI::UnitTypes::Protoss_Reaver) || (unit->getType() == BWAPI::UnitTypes::Zerg_Scourge))\n            {\n                rangedUnits.insert(unit);\n            }\n            // select melee m_units\n            else if (unit->getType().groundWeapon().maxRange() <= 32)\n            {\n                meleeUnits.insert(unit);\n            }\n        }\n    }\n\n    m_meleeManager.setUnits(meleeUnits);\n    m_rangedManager.setUnits(rangedUnits);\n    m_detectorManager.setUnits(detectorUnits);\n    m_transportManager.setUnits(transportUnits);\n    m_tankManager.setUnits(tankUnits);\n    m_medicManager.setUnits(medicUnits);\n}\n\n// calculates whether or not to regroup\nbool Squad::needsToRegroup()\n{\n    if (!Config::Micro::UseSparcraftSimulation)\n    {\n        return false;\n    }\n\n    // if we are not attacking, never regroup\n    if (m_units.empty() || (m_order.getType() != SquadOrderTypes::Attack))\n    {\n        m_regroupStatus = std::string(\"\\x04 No combat units available\");\n        return false;\n    }\n\n    BWAPI::Unit unitClosest = unitClosestToEnemy();\n\n    if (!unitClosest)\n    {\n        m_regroupStatus = std::string(\"\\x04 No closest unit\");\n        return false;\n    }\n\n    // if none of our units are in attack range of any enemy units, don't retreat\n    std::vector<UnitInfo> enemyCombatUnits;\n    const auto & enemyUnitInfo = Global::Info().getUnitInfo(BWAPI::Broodwar->enemy());\n\n    bool anyInRange = false;\n    for (const auto & eui : enemyUnitInfo)\n    {\n        bool inRange = false;\n        for (const auto & u : m_units)\n        {\n            int range = UnitUtil::GetAttackRange(eui.second.type, u->getType());\n\n            if (range + 128 >= eui.second.lastPosition.getDistance(u->getPosition()))\n            {\n                inRange = true;\n                break;\n            }\n        }\n\n        if (inRange)\n        {\n            anyInRange = true;\n            break;\n        }\n    }\n\n    if (!anyInRange)\n    {\n        m_regroupStatus = std::string(\"\\x04 No enemy units in attack range\");\n        return false;\n    }\n\n    SparCraft::ScoreType score = 0;\n\n    //do the SparCraft Simulation!\n    CombatSimulation sim;\n\n    sim.setCombatUnits(unitClosest->getPosition(), Config::Micro::CombatRegroupRadius);\n    score = sim.simulateCombat();\n\n    // if we are DT rushing and we haven't lost a DT yet, no retreat!\n    if (Config::Strategy::StrategyName == \"Protoss_DTRush\" && (BWAPI::Broodwar->self()->deadUnitCount(BWAPI::UnitTypes::Protoss_Dark_Templar) == 0))\n    {\n        m_regroupStatus = std::string(\"\\x04 DARK TEMPLAR HOOOOO!\");\n        return false;\n    }\n\n    bool retreat = score < 0;\n    int switchTime = 100;\n    bool waiting = false;\n\n    // we should not attack unless 5 seconds have passed since a retreat\n    if (retreat != m_lastRetreatSwitchVal)\n    {\n        if (!retreat && (BWAPI::Broodwar->getFrameCount() - m_lastRetreatSwitch < switchTime))\n        {\n            waiting = true;\n            retreat = m_lastRetreatSwitchVal;\n        }\n        else\n        {\n            waiting = false;\n            m_lastRetreatSwitch = BWAPI::Broodwar->getFrameCount();\n            m_lastRetreatSwitchVal = retreat;\n        }\n    }\n\n    if (retreat)\n    {\n        m_regroupStatus = std::string(\"\\x04 Retreat - simulation predicts defeat\");\n    }\n    else\n    {\n        m_regroupStatus = std::string(\"\\x04 Attack - simulation predicts success\");\n    }\n\n    return retreat;\n}\n\nvoid Squad::setSquadOrder(const SquadOrder & so)\n{\n    m_order = so;\n}\n\nbool Squad::containsUnit(BWAPI::Unit u) const\n{\n    return m_units.contains(u);\n}\n\nvoid Squad::clear()\n{\n    for (auto & unit : getUnits())\n    {\n        if (unit->getType().isWorker())\n        {\n            Global::Workers().finishedWithWorker(unit);\n        }\n    }\n\n    m_units.clear();\n}\n\nbool Squad::unitNearEnemy(BWAPI::Unit unit)\n{\n    assert(unit);\n\n    BWAPI::Unitset enemyNear;\n\n    Global::Map().getUnits(enemyNear, unit->getPosition(), 400, false, true);\n\n    return enemyNear.size() > 0;\n}\n\nBWAPI::Position Squad::calcCenter()\n{\n    if (m_units.empty())\n    {\n        if (Config::Debug::DrawSquadInfo)\n        {\n            BWAPI::Broodwar->printf(\"Squad::calcCenter() called on empty squad\");\n        }\n        return BWAPI::Position(0, 0);\n    }\n\n    BWAPI::Position accum(0, 0);\n    for (auto & unit : m_units)\n    {\n        accum += unit->getPosition();\n    }\n    return BWAPI::Position(accum.x / m_units.size(), accum.y / m_units.size());\n}\n\nBWAPI::Position Squad::calcRegroupPosition()\n{\n    BWAPI::Position regroup(0, 0);\n\n    int minDist = 100000;\n\n    for (auto & unit : m_units)\n    {\n        if (!m_nearEnemy[unit])\n        {\n            int dist = unit->getDistance(m_order.getPosition());\n            if (dist < minDist)\n            {\n                minDist = dist;\n                regroup = unit->getPosition();\n            }\n        }\n    }\n\n    if (regroup == BWAPI::Position(0, 0))\n    {\n        return BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n    }\n    else\n    {\n        return regroup;\n    }\n}\n\nBWAPI::Unit Squad::unitClosestToEnemy()\n{\n    BWAPI::Unit closest = nullptr;\n    int closestDist = 100000;\n\n    for (auto & unit : m_units)\n    {\n        if (unit->getType() == BWAPI::UnitTypes::Protoss_Observer)\n        {\n            continue;\n        }\n\n        // the distance to the order position\n        int dist = Global::Map().getGroundDistance(unit->getPosition(), m_order.getPosition());\n\n        if (dist != -1 && (!closest || dist < closestDist))\n        {\n            closest = unit;\n            closestDist = dist;\n        }\n    }\n\n    if (!closest)\n    {\n        for (auto & unit : m_units)\n        {\n            if (unit->getType() == BWAPI::UnitTypes::Protoss_Observer)\n            {\n                continue;\n            }\n\n            // the distance to the order position\n            int dist = unit->getDistance(BWAPI::Position(BWAPI::Broodwar->enemy()->getStartLocation()));\n\n            if (dist != -1 && (!closest || dist < closestDist))\n            {\n                closest = unit;\n                closestDist = dist;\n            }\n        }\n    }\n\n    return closest;\n}\n\nint Squad::squadUnitsNear(BWAPI::Position p)\n{\n    int numUnits = 0;\n\n    for (auto & unit : m_units)\n    {\n        if (unit->getDistance(p) < 600)\n        {\n            numUnits++;\n        }\n    }\n\n    return numUnits;\n}\n\nconst BWAPI::Unitset & Squad::getUnits() const\n{\n    return m_units;\n}\n\nconst SquadOrder & Squad::getSquadOrder()\tconst\n{\n    return m_order;\n}\n\nvoid Squad::addUnit(BWAPI::Unit u)\n{\n    m_units.insert(u);\n}\n\nvoid Squad::removeUnit(BWAPI::Unit u)\n{\n    m_units.erase(u);\n}\n\nconst std::string & Squad::getName() const\n{\n    return m_name;\n}"
  },
  {
    "path": "UAlbertaBot/Source/Squad.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"MeleeManager.h\"\n#include \"RangedManager.h\"\n#include \"DetectorManager.h\"\n#include \"TransportManager.h\"\n#include \"SquadOrder.h\"\n#include \"TankManager.h\"\n#include \"MedicManager.h\"\n\nnamespace UAlbertaBot\n{\n\nclass Squad\n{\n    BWAPI::Unitset      m_units;\n    std::string         m_name                  = \"Default\";\n    std::string         m_regroupStatus         = \"Default\";\n    int                 m_lastRetreatSwitch     = 0;\n    bool                m_lastRetreatSwitchVal  = false;\n    size_t              m_priority              = 0;\n\n    SquadOrder          m_order;\n    MeleeManager        m_meleeManager;\n    RangedManager       m_rangedManager;\n    DetectorManager     m_detectorManager;\n    TransportManager    m_transportManager;\n    TankManager         m_tankManager;\n    MedicManager        m_medicManager;\n\n    std::map<BWAPI::Unit, bool>\tm_nearEnemy;\n\n    BWAPI::Unit unitClosestToEnemy();\n\n    void updateUnits();\n    void addUnitsToMicroManagers();\n    void setNearEnemyUnits();\n    void setAllUnits();\n\n    bool unitNearEnemy(BWAPI::Unit unit);\n    bool needsToRegroup();\n    int  squadUnitsNear(BWAPI::Position p);\n\npublic:\n\n    Squad(const std::string & name, SquadOrder order, size_t priority);\n    Squad();\n    ~Squad();\n\n    void update();\n    void setSquadOrder(const SquadOrder & so);\n    void addUnit(BWAPI::Unit u);\n    void removeUnit(BWAPI::Unit u);\n    bool containsUnit(BWAPI::Unit u) const;\n    bool isEmpty() const;\n    void clear();\n    size_t getPriority() const;\n    void setPriority(const size_t & priority);\n    const std::string & getName() const;\n\n    BWAPI::Position calcCenter();\n    BWAPI::Position calcRegroupPosition();\n\n    const BWAPI::Unitset & getUnits() const;\n    const SquadOrder & getSquadOrder()\tconst;\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/SquadData.cpp",
    "content": "#include \"SquadData.h\"\n#include \"Global.h\"\n#include \"WorkerManager.h\"\n#include \"Squad.h\"\n\nusing namespace UAlbertaBot;\n\nSquadData::SquadData()\n{\n\n}\n\nvoid SquadData::update()\n{\n    updateAllSquads();\n    verifySquadUniqueMembership();\n}\n\nvoid SquadData::clearSquadData()\n{\n    // give back workers who were in squads\n    for (auto & kv : m_squads)\n    {\n        Squad & squad = kv.second;\n\n        const BWAPI::Unitset & units = squad.getUnits();\n\n        for (auto & unit : units)\n        {\n            if (unit->getType().isWorker())\n            {\n                Global::Workers().finishedWithWorker(unit);\n            }\n        }\n    }\n\n    m_squads.clear();\n}\n\nvoid SquadData::removeSquad(const std::string & squadName)\n{\n    auto & squadPtr = m_squads.find(squadName);\n\n    UAB_ASSERT_WARNING(squadPtr != m_squads.end(), \"Trying to clear a squad that didn't exist: %s\", squadName.c_str());\n    if (squadPtr == m_squads.end())\n    {\n        return;\n    }\n\n    for (auto & unit : squadPtr->second.getUnits())\n    {\n        if (unit->getType().isWorker())\n        {\n            Global::Workers().finishedWithWorker(unit);\n        }\n    }\n\n    m_squads.erase(squadName);\n}\n\nconst std::map<std::string, Squad> & SquadData::getSquads() const\n{\n    return m_squads;\n}\n\nbool SquadData::squadExists(const std::string & squadName)\n{\n    return m_squads.find(squadName) != m_squads.end();\n}\n\nvoid SquadData::addSquad(const std::string & squadName, const Squad & squad)\n{\n    m_squads[squadName] = squad;\n}\n\nvoid SquadData::updateAllSquads()\n{\n    for (auto & kv : m_squads)\n    {\n        kv.second.update();\n    }\n}\n\nvoid SquadData::drawSquadInformation(int x, int y)\n{\n    if (!Config::Debug::DrawSquadInfo)\n    {\n        return;\n    }\n\n    BWAPI::Broodwar->drawTextScreen(x, y, \"\\x04Squads\");\n    BWAPI::Broodwar->drawTextScreen(x, y+20, \"\\x04NAME\");\n    BWAPI::Broodwar->drawTextScreen(x+150, y+20, \"\\x04SIZE\");\n    BWAPI::Broodwar->drawTextScreen(x+200, y+20, \"\\x04LOCATION\");\n\n    int yspace = 0;\n\n    for (auto & kv : m_squads)\n    {\n        const Squad & squad = kv.second;\n\n        const BWAPI::Unitset & units = squad.getUnits();\n        const SquadOrder & order = squad.getSquadOrder();\n\n        BWAPI::Broodwar->drawTextScreen(x, y+40+((yspace)*10), \"\\x03%s\", squad.getName().c_str());\n        BWAPI::Broodwar->drawTextScreen(x+150, y+40+((yspace)*10), \"\\x03%d\", units.size());\n        BWAPI::Broodwar->drawTextScreen(x+200, y+40+((yspace++)*10), \"\\x03(%d,%d)\", order.getPosition().x, order.getPosition().y);\n\n        BWAPI::Broodwar->drawCircleMap(order.getPosition(), 10, BWAPI::Colors::Green, true);\n        BWAPI::Broodwar->drawCircleMap(order.getPosition(), order.getRadius(), BWAPI::Colors::Red, false);\n        BWAPI::Broodwar->drawTextMap(order.getPosition() + BWAPI::Position(0, 12), \"%s\", squad.getName().c_str());\n\n        for (const BWAPI::Unit unit : units)\n        {\n            BWAPI::Broodwar->drawTextMap(unit->getPosition() + BWAPI::Position(0, 10), \"%s\", squad.getName().c_str());\n        }\n    }\n}\n\nvoid SquadData::verifySquadUniqueMembership()\n{\n    BWAPI::Unitset assigned;\n\n    for (const auto & kv : m_squads)\n    {\n        for (auto & unit : kv.second.getUnits())\n        {\n            if (assigned.contains(unit))\n            {\n                BWAPI::Broodwar->printf(\"Unit is in at least two squads: %s\", unit->getType().getName().c_str());\n            }\n\n            assigned.insert(unit);\n        }\n    }\n}\n\nbool SquadData::unitIsInSquad(BWAPI::Unit unit) const\n{\n    return getUnitSquad(unit) != nullptr;\n}\n\nconst Squad * SquadData::getUnitSquad(BWAPI::Unit unit) const\n{\n    for (const auto & kv : m_squads)\n    {\n        if (kv.second.getUnits().contains(unit))\n        {\n            return &kv.second;\n        }\n    }\n\n    return nullptr;\n}\n\nSquad * SquadData::getUnitSquad(BWAPI::Unit unit)\n{\n    for (auto & kv : m_squads)\n    {\n        if (kv.second.getUnits().contains(unit))\n        {\n            return &kv.second;\n        }\n    }\n\n    return nullptr;\n}\n\nvoid SquadData::assignUnitToSquad(BWAPI::Unit unit, Squad & squad)\n{\n    UAB_ASSERT_WARNING(canAssignUnitToSquad(unit, squad), \"We shouldn't be re-assigning this unit!\");\n\n    Squad * previousSquad = getUnitSquad(unit);\n\n    if (previousSquad)\n    {\n        previousSquad->removeUnit(unit);\n    }\n\n    squad.addUnit(unit);\n}\n\nbool SquadData::canAssignUnitToSquad(BWAPI::Unit unit, const Squad & squad) const\n{\n    const Squad * unitSquad = getUnitSquad(unit);\n\n    // make sure strictly less than so we don't reassign to the same squad etc\n    return !unitSquad || (unitSquad->getPriority() < squad.getPriority());\n}\n\nSquad & SquadData::getSquad(const std::string & squadName)\n{\n    UAB_ASSERT_WARNING(squadExists(squadName), \"Trying to access squad that doesn't exist: %s\", squadName);\n    \n    return m_squads[squadName];\n}"
  },
  {
    "path": "UAlbertaBot/Source/SquadData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"Squad.h\"\n\nnamespace UAlbertaBot\n{\n\nclass SquadData\n{\n    std::map<std::string, Squad> m_squads;\n\n    void updateAllSquads();\n    void verifySquadUniqueMembership();\n\npublic:\n\n    SquadData();\n\n    void update();\n    void clearSquadData();\n    void assignUnitToSquad(BWAPI::Unit unit, Squad & squad);\n    void addSquad(const std::string & squadName, const Squad & squad);\n    void removeSquad(const std::string & squadName);\n    void drawSquadInformation(int x, int y);\n\n    bool canAssignUnitToSquad(BWAPI::Unit unit, const Squad & squad) const;\n    bool squadExists(const std::string & squadName);\n    bool unitIsInSquad(BWAPI::Unit unit) const;\n    const Squad * getUnitSquad(BWAPI::Unit unit) const;\n    Squad * getUnitSquad(BWAPI::Unit unit);\n    Squad & getSquad(const std::string & squadName);\n    const std::map<std::string, Squad> & getSquads() const;\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/SquadOrder.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace UAlbertaBot\n{\n\nnamespace SquadOrderTypes\n{\n    enum { None, Idle, Attack, Defend, Regroup, Drop, SquadOrderTypes };\n}\n\nclass SquadOrder\n{\n    size_t              m_type       = SquadOrderTypes::None;\n    int                 m_radius     = 0;\n    BWAPI::Position     m_position;\n    std::string         m_status;\n\npublic:\n\n\tSquadOrder() \n\t{\n\t}\n\n\tSquadOrder(int type, BWAPI::Position position, int radius, std::string status = \"Default\") \n\t\t: m_type(type)\n\t\t, m_position(position)\n\t\t, m_radius(radius) \n\t\t, m_status(status)\n\t{\n\t}\n\n\tconst std::string & getStatus() const \n\t{\n\t\treturn m_status;\n\t}\n\n    const BWAPI::Position & getPosition() const\n    {\n        return m_position;\n    }\n\n    const int getRadius() const\n    {\n        return m_radius;\n    }\n\n    const size_t getType() const\n    {\n        return m_type;\n    }\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/StarDraftMap.hpp",
    "content": "#pragma once\n\n#include \"Grid.hpp\"\n#include <fstream>\n#include <iostream>\n\nnamespace UAlbertaBot\n{\n\nnamespace TileType\n{\n    enum \n    {\n        Unwalkable  = 'U',\n        Walk        = 'W',\n        BuildAll    = 'B',\n        NoDepot     = 'D',\n        Mineral     = 'M',\n        Gas         = 'G',\n        Neutral     = 'N'\n    };\n}\n\nstruct Tile { size_t x = 0, y = 0; };\n\nclass StarDraftMap\n{\n    Grid<char>          m_buildTiles;\n    Grid<char>          m_walkTiles;\n    std::vector<Tile>   m_minerals;\n    std::vector<Tile>   m_geysers;\n    std::vector<Tile>   m_startTiles;\n\n    inline bool isWalkable(char tile) const noexcept\n    {\n        return (tile == TileType::Walk) || (tile == TileType::BuildAll) || (tile == TileType::NoDepot);\n    }\n\n    inline bool canBuild(char tile) const noexcept\n    {\n        return tile == (TileType::BuildAll) || (tile == TileType::NoDepot);\n    }\n\n    inline bool canBuildDepot(char tile) const noexcept\n    {\n        return tile == TileType::BuildAll;\n    }\n\n\npublic:\n\n    StarDraftMap() {}\n\n    StarDraftMap(const std::string & path)\n    {\n        load(path);\n    }\n\n    StarDraftMap(size_t width, size_t height)\n        : m_buildTiles(width, height, 0)\n        , m_walkTiles(width*4, height*4, false)\n    {\n        \n    }\n\n    inline void set(size_t x, size_t y, char val)\n    {\n        m_buildTiles.set(x, y, val);\n\n        if (val == TileType::Mineral) { m_minerals.push_back({x, y}); }\n        else if (val == TileType::Gas) { m_geysers.push_back({x, y}); }\n    }\n\n    inline void setWalk(size_t x, size_t y, bool val)\n    {\n        m_walkTiles.set(x, y, val);\n    }\n\n    inline void addStartTile(size_t x, size_t y)\n    {\n        m_startTiles.push_back({x, y});\n    }\n    \n    inline size_t width() const\n    {\n        return m_buildTiles.width();\n    }\n\n    inline size_t height() const\n    {\n        return m_buildTiles.height();\n    }\n\n    inline char get(size_t x, size_t y) const\n    {\n        return m_buildTiles.get(x, y);\n    }\n\n    inline char getWalk(size_t x, size_t y) const\n    {\n        return m_walkTiles.get(x, y);\n    }\n\n    inline bool isWalkable(size_t x, size_t y) const\n    {\n        return isWalkable(get(x, y));\n    }\n\n    inline bool canBuild(size_t x, size_t y) const\n    {\n        return canBuild(get(x,y));\n    }\n\n    inline bool canBuildDepot(size_t x, size_t y) const\n    {\n        return canBuildDepot(get(x,y));\n    }\n\n    inline const std::vector<Tile> & startTiles() const\n    {\n        return m_startTiles;\n    }\n\n    inline void load(const std::string & path)\n    {\n        std::ifstream fin(path);\n        size_t w, h, n, sx, sy;\n        char c;\n\n        // first line is width height\n        fin >> w >> h; \n\n        m_buildTiles = Grid<char>(w, h, 0);\n        m_walkTiles  = Grid<char>(4*w, 4*h, 0);\n\n        // next line is the start tile locations\n        fin >> n;\n        for (size_t i=0; i<n; i++)\n        {\n            fin >> sx >> sy;\n            m_startTiles.push_back({sx, sy});\n        }\n\n        // followed by the int values in the grid\n        for (size_t y=0; y < m_buildTiles.height(); y++)\n        {\n            for (size_t x=0; x < m_buildTiles.width(); x++)\n            {\n                fin >> c;\n                m_buildTiles.set(x, y, c);\n            }   \n        }\n\n        // followed by the walk tiles\n        for (size_t y=0; y < m_walkTiles.height(); y++)\n        {\n            for (size_t x=0; x < m_walkTiles.width(); x++)\n            {\n                fin >> c;\n                m_walkTiles.set(x, y, c);\n            }   \n        }\n    }\n\n    inline void save(const std::string & path) const\n    {\n        std::ofstream fout(path);\n\n        // first line is width height\n        fout << m_buildTiles.width() << \" \" << m_buildTiles.height() << \"\\n\";\n        \n        // next line is the start tile locations\n        fout << m_startTiles.size();\n        for (auto & tile : m_startTiles)\n        {\n            fout << \" \" << tile.x << \" \" << tile.y;\n        }   fout << \"\\n\";\n\n        // followed by the int values in the grid\n        for (size_t y=0; y<m_buildTiles.height(); y++)\n        {\n            for (size_t x=0; x < m_buildTiles.width(); x++)\n            {\n                fout << m_buildTiles.get(x, y);\n            }   fout << \"\\n\";\n        }\n\n        // set the walk tiles\n        for (size_t y=0; y<m_walkTiles.height(); y++)\n        {\n            for (size_t x=0; x<m_walkTiles.width(); x++)   \n            {\n                fout << (m_walkTiles.get(x,y) ? '1' : '0');\n            }   fout << \"\\n\";\n        }\n    }\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/StrategyManager.cpp",
    "content": "#include \"Common.h\"\n#include \"StrategyManager.h\"\n#include \"UnitUtil.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n#include \"InformationManager.h\"\n#include \"WorkerManager.h\"\n#include \"Logger.h\"\n\nusing namespace UAlbertaBot;\n\n// constructor\nStrategyManager::StrategyManager()\n    : m_selfRace(BWAPI::Broodwar->self()->getRace())\n    , m_enemyRace(BWAPI::Broodwar->enemy()->getRace())\n    , m_emptyBuildOrder(BWAPI::Broodwar->self()->getRace())\n{\n\n}\n\n\n\nconst int StrategyManager::getScore(BWAPI::Player player) const\n{\n    return player->getBuildingScore() + player->getKillScore() + player->getRazingScore() + player->getUnitScore();\n}\n\nconst BuildOrder & StrategyManager::getOpeningBookBuildOrder() const\n{\n    auto buildOrderIt = m_strategies.find(Config::Strategy::StrategyName);\n\n    // look for the build order in the build order map\n    if (buildOrderIt != std::end(m_strategies))\n    {\n        return (*buildOrderIt).second.m_buildOrder;\n    }\n    else\n    {\n        UAB_ASSERT_WARNING(false, \"Strategy not found: %s, returning empty initial build order\", Config::Strategy::StrategyName.c_str());\n        return m_emptyBuildOrder;\n    }\n}\n\nconst bool StrategyManager::shouldExpandNow() const\n{\n    // if there is no place to expand to, we can't expand\n    if (Global::Bases().getNextExpansion(BWAPI::Broodwar->self()) == BWAPI::TilePositions::None)\n    {\n        BWAPI::Broodwar->printf(\"No valid expansion location\");\n        return false;\n    }\n\n    size_t numDepots    = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Command_Center)\n        + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Nexus)\n        + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hatchery)\n        + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Lair)\n        + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hive);\n    int frame           = BWAPI::Broodwar->getFrameCount();\n    int minute          = frame / (24*60);\n\n    // if we have a ton of idle workers then we need a new expansion\n    if (Global::Workers().getNumIdleWorkers() > 10)\n    {\n        return true;\n    }\n\n    // if we have a ridiculous stockpile of minerals, expand\n    if (BWAPI::Broodwar->self()->minerals() > 3000)\n    {\n        return true;\n    }\n\n    // we will make expansion N after array[N] minutes have passed\n    std::vector<int> expansionTimes ={5, 10, 20, 30, 40 , 50};\n\n    for (size_t i(0); i < expansionTimes.size(); ++i)\n    {\n        if (numDepots < (i+2) && minute > expansionTimes[i])\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid StrategyManager::addStrategy(const std::string & name, Strategy & strategy)\n{\n    m_strategies[name] = strategy;\n}\n\nconst MetaPairVector StrategyManager::getBuildOrderGoal()\n{\n    BWAPI::Race myRace = BWAPI::Broodwar->self()->getRace();\n\n    if (myRace == BWAPI::Races::Protoss)\n    {\n        return getProtossBuildOrderGoal();\n    }\n    else if (myRace == BWAPI::Races::Terran)\n    {\n        return getTerranBuildOrderGoal();\n    }\n    else if (myRace == BWAPI::Races::Zerg)\n    {\n        return getZergBuildOrderGoal();\n    }\n\n    return MetaPairVector();\n}\n\nconst MetaPairVector StrategyManager::getProtossBuildOrderGoal() const\n{\n    // the goal to return\n    MetaPairVector goal;\n\n    int numZealots          = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Zealot);\n    int numPylons           = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Pylon);\n    int numDragoons         = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Dragoon);\n    int numProbes           = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Probe);\n    int numNexusCompleted   = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Nexus);\n    int numNexusAll         = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Nexus);\n    int numCyber            = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Cybernetics_Core);\n    int numCannon           = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Photon_Cannon);\n    int numScout            = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Corsair);\n    int numReaver           = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Reaver);\n    int numDarkTeplar       = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Dark_Templar);\n\n    if (Config::Strategy::StrategyName == \"Protoss_ZealotRush\")\n    {\n        goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, numZealots + 8));\n\n        // once we have a 2nd nexus start making dragoons\n        if (numNexusAll >= 2)\n        {\n            goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, numDragoons + 4));\n        }\n    }\n    else if (Config::Strategy::StrategyName == \"Protoss_DragoonRush\")\n    {\n        goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, numDragoons + 6));\n    }\n    else if (Config::Strategy::StrategyName == \"Protoss_Drop\")\n    {\n        if (numZealots == 0)\n        {\n            goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, numZealots + 4));\n            goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Shuttle, 1));\n        }\n        else\n        {\n            goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, numZealots + 8));\n        }\n    }\n    else if (Config::Strategy::StrategyName == \"Protoss_DTRush\")\n    {\n        goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dark_Templar, numDarkTeplar + 2));\n\n        // if we have a 2nd nexus then get some goons out\n        if (numNexusAll >= 2)\n        {\n            goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, numDragoons + 4));\n        }\n    }\n    else\n    {\n        UAB_ASSERT_WARNING(false, \"Unknown Protoss Strategy Name: %s\", Config::Strategy::StrategyName.c_str());\n    }\n\n    // if we have 3 nexus, make an observer\n    if (numNexusCompleted >= 3)\n    {\n        goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n    }\n\n    // add observer to the goal if the enemy has cloaked units\n    if (Global::Info().enemyHasCloakedUnits())\n    {\n        goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1));\n\n        if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0)\n        {\n            goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1));\n        }\n        if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Observatory) > 0)\n        {\n            goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n        }\n    }\n\n    // if we want to expand, insert a nexus into the build order\n    if (shouldExpandNow())\n    {\n        goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1));\n    }\n\n    return goal;\n}\n\nconst MetaPairVector StrategyManager::getTerranBuildOrderGoal() const\n{\n    // the goal to return\n    std::vector<MetaPair> goal;\n\n    int numWorkers      = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_SCV);\n    int numCC           = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Command_Center);\n    int numMarines      = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Marine);\n    int numMedics       = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Medic);\n    int numWraith       = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Wraith);\n    int numVultures     = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Vulture);\n    int numGoliath      = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Goliath);\n    int numTanks        = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode)\n        + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode);\n    int numBay          = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Engineering_Bay);\n\n    if (Config::Strategy::StrategyName == \"Terran_MarineRush\")\n    {\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Marine, numMarines + 8));\n\n        if (numMarines > 5)\n        {\n            goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Engineering_Bay, 1));\n        }\n    }\n    else if (Config::Strategy::StrategyName == \"Terran_4RaxMarines\")\n    {\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Marine, numMarines + 8));\n    }\n    else if (Config::Strategy::StrategyName == \"Terran_VultureRush\")\n    {\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Vulture, numVultures + 8));\n\n        if (numVultures > 8)\n        {\n            goal.push_back(std::pair<MetaType, int>(BWAPI::TechTypes::Tank_Siege_Mode, 1));\n            goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode, 4));\n        }\n    }\n    else if (Config::Strategy::StrategyName == \"Terran_TankPush\")\n    {\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode, 6));\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Goliath, numGoliath + 6));\n        goal.push_back(std::pair<MetaType, int>(BWAPI::TechTypes::Tank_Siege_Mode, 1));\n    }\n    else\n    {\n        BWAPI::Broodwar->printf(\"Warning: No build order goal for Terran Strategy: %s\", Config::Strategy::StrategyName.c_str());\n    }\n\n\n\n    if (shouldExpandNow())\n    {\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Command_Center, numCC + 1));\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_SCV, numWorkers + 10));\n    }\n\n    return goal;\n}\n\nconst MetaPairVector StrategyManager::getZergBuildOrderGoal() const\n{\n    // the goal to return\n    std::vector<MetaPair> goal;\n\n    int numWorkers      = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Drone);\n    int numCC           = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hatchery)\n        + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Lair)\n        + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hive);\n    int numMutas        = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Mutalisk);\n    int numDrones       = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Drone);\n    int zerglings       = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Zergling);\n    int numHydras       = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hydralisk);\n    int numScourge      = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Scourge);\n    int numGuardians    = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Guardian);\n\n    int mutasWanted = numMutas + 6;\n    int hydrasWanted = numHydras + 6;\n\n    if (Config::Strategy::StrategyName == \"Zerg_ZerglingRush\")\n    {\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Zergling, zerglings + 6));\n    }\n    else if (Config::Strategy::StrategyName == \"Zerg_2HatchHydra\")\n    {\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Hydralisk, numHydras + 8));\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UpgradeTypes::Grooved_Spines, 1));\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Drone, numDrones + 4));\n    }\n    else if (Config::Strategy::StrategyName == \"Zerg_3HatchMuta\")\n    {\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Hydralisk, numHydras + 12));\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Drone, numDrones + 4));\n    }\n    else if (Config::Strategy::StrategyName == \"Zerg_3HatchScourge\")\n    {\n        if (numScourge > 40)\n        {\n            goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Hydralisk, numHydras + 12));\n        }\n        else\n        {\n            goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Scourge, numScourge + 12));\n        }\n\n\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Drone, numDrones + 4));\n    }\n\n    if (shouldExpandNow())\n    {\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Hatchery, numCC + 1));\n        goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Drone, numWorkers + 10));\n    }\n\n    return goal;\n}\n\nvoid StrategyManager::readResults()\n{\n    if (!Config::Modules::UsingStrategyIO)\n    {\n        return;\n    }\n\n    std::string enemyName = BWAPI::Broodwar->enemy()->getName();\n    std::replace(enemyName.begin(), enemyName.end(), ' ', '_');\n\n    std::string enemyResultsFile = Config::Strategy::ReadDir + enemyName + \".txt\";\n\n    std::string strategyName;\n    int wins = 0;\n    int losses = 0;\n\n    FILE *file = fopen (enemyResultsFile.c_str(), \"r\");\n    if (file != nullptr)\n    {\n        char line[4096]; /* or other suitable maximum line size */\n        while (fgets (line, sizeof line, file) != nullptr) /* read a line */\n        {\n            std::stringstream ss(line);\n\n            ss >> strategyName;\n            ss >> wins;\n            ss >> losses;\n\n            //BWAPI::Broodwar->printf(\"Results Found: %s %d %d\", strategyName.c_str(), wins, losses);\n\n            if (m_strategies.find(strategyName) == m_strategies.end())\n            {\n                //BWAPI::Broodwar->printf(\"Warning: Results file has unknown Strategy: %s\", strategyName.c_str());\n            }\n            else\n            {\n                m_strategies[strategyName].m_wins = wins;\n                m_strategies[strategyName].m_losses = losses;\n            }\n        }\n\n        fclose (file);\n    }\n    else\n    {\n        //BWAPI::Broodwar->printf(\"No results file found: %s\", enemyResultsFile.c_str());\n    }\n}\n\nvoid StrategyManager::writeResults()\n{\n    if (!Config::Modules::UsingStrategyIO)\n    {\n        return;\n    }\n\n    std::string enemyName = BWAPI::Broodwar->enemy()->getName();\n    std::replace(enemyName.begin(), enemyName.end(), ' ', '_');\n\n    std::string enemyResultsFile = Config::Strategy::WriteDir + enemyName + \".txt\";\n\n    std::stringstream ss;\n\n    for (auto & kv : m_strategies)\n    {\n        const Strategy & strategy = kv.second;\n\n        ss << strategy.m_name << \" \" << strategy.m_wins << \" \" << strategy.m_losses << \"\\n\";\n    }\n\n    Logger::LogOverwriteToFile(enemyResultsFile, ss.str());\n}\n\nvoid StrategyManager::onEnd(const bool isWinner)\n{\n    if (!Config::Modules::UsingStrategyIO)\n    {\n        return;\n    }\n\n    if (isWinner)\n    {\n        m_strategies[Config::Strategy::StrategyName].m_wins++;\n    }\n    else\n    {\n        m_strategies[Config::Strategy::StrategyName].m_losses++;\n    }\n\n    writeResults();\n}\n\nvoid StrategyManager::setLearnedStrategy()\n{\n    // we are currently not using this functionality for the competition so turn it off \n    return;\n\n    if (!Config::Modules::UsingStrategyIO)\n    {\n        return;\n    }\n\n    const std::string & strategyName = Config::Strategy::StrategyName;\n    Strategy & currentStrategy = m_strategies[strategyName];\n\n    int totalGamesPlayed = 0;\n    int strategyGamesPlayed = currentStrategy.m_wins + currentStrategy.m_losses;\n    double winRate = strategyGamesPlayed > 0 ? currentStrategy.m_wins / static_cast<double>(strategyGamesPlayed) : 0;\n\n    // if we are using an enemy specific strategy\n    if (Config::Strategy::FoundEnemySpecificStrategy)\n    {\n        return;\n    }\n\n    // if our win rate with the current strategy is super high don't explore at all\n    // also we're pretty confident in our base strategies so don't change if insufficient games have been played\n    if (strategyGamesPlayed < 5 || (strategyGamesPlayed > 0 && winRate > 0.49))\n    {\n        BWAPI::Broodwar->printf(\"Still using default strategy\");\n        return;\n    }\n\n    // get the total number of games played so far with this race\n    for (auto & kv : m_strategies)\n    {\n        Strategy & strategy = kv.second;\n        if (strategy.m_race == BWAPI::Broodwar->self()->getRace())\n        {\n            totalGamesPlayed += strategy.m_wins + strategy.m_losses;\n        }\n    }\n\n    // calculate the UCB value and store the highest\n    double C = 0.5;\n    std::string bestUCBStrategy;\n    double bestUCBStrategyVal = std::numeric_limits<double>::lowest();\n    for (auto & kv : m_strategies)\n    {\n        Strategy & strategy = kv.second;\n        if (strategy.m_race != BWAPI::Broodwar->self()->getRace())\n        {\n            continue;\n        }\n\n        int sGamesPlayed = strategy.m_wins + strategy.m_losses;\n        double sWinRate = sGamesPlayed > 0 ? currentStrategy.m_wins / static_cast<double>(strategyGamesPlayed) : 0;\n        double ucbVal = C * sqrt(log((double)totalGamesPlayed / sGamesPlayed));\n        double val = sWinRate + ucbVal;\n\n        if (val > bestUCBStrategyVal)\n        {\n            bestUCBStrategy = strategy.m_name;\n            bestUCBStrategyVal = val;\n        }\n    }\n\n    Config::Strategy::StrategyName = bestUCBStrategy;\n}"
  },
  {
    "path": "UAlbertaBot/Source/StrategyManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BuildOrder.h\"\n\nnamespace UAlbertaBot\n{\n\nstruct Strategy\n{\n    std::string m_name          = \"None\";\n    BWAPI::Race m_race          = BWAPI::Races::None;\n    int         m_wins          = 0;\n    int         m_losses        = 0;\n    BuildOrder  m_buildOrder;\n\n    Strategy()\n    {\n\n    }\n\n    Strategy(const std::string & name, const BWAPI::Race & race, const BuildOrder & buildOrder)\n        : m_name(name)\n        , m_race(race)\n        , m_wins(0)\n        , m_losses(0)\n        , m_buildOrder(buildOrder)\n    {\n\n    }\n};\n\nclass StrategyManager\n{\n    friend class Global;\n\n    StrategyManager();\n\n    BWAPI::Race\t\t\t\t\t    m_selfRace;\n    BWAPI::Race\t\t\t\t\t    m_enemyRace;\n    std::map<std::string, Strategy> m_strategies;\n    int                             m_totalGamesPlayed = 0;\n    BuildOrder                      m_emptyBuildOrder;\n\n    void                    writeResults();\n    const\tint             getScore(BWAPI::Player player) const;\n    const\tbool            shouldExpandNow() const;\n    const\tMetaPairVector  getProtossBuildOrderGoal() const;\n    const\tMetaPairVector  getTerranBuildOrderGoal() const;\n    const\tMetaPairVector  getZergBuildOrderGoal() const;\n\npublic:\n\n    void                    onEnd(const bool isWinner);\n    void                    addStrategy(const std::string & name, Strategy & strategy);\n    void                    setLearnedStrategy();\n    void\t                readResults();\n    const\tMetaPairVector  getBuildOrderGoal();\n    const\tBuildOrder &    getOpeningBookBuildOrder() const;\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/TankManager.cpp",
    "content": "#include \"TankManager.h\"\n#include \"UnitUtil.h\"\n#include \"Micro.h\"\n\nusing namespace UAlbertaBot;\n\nTankManager::TankManager()\n{\n}\n\nvoid TankManager::executeMicro(const BWAPI::Unitset & targets)\n{\n    const BWAPI::Unitset & tanks = getUnits();\n\n    // figure out targets\n    BWAPI::Unitset tankTargets;\n    std::copy_if(targets.begin(), targets.end(), std::inserter(tankTargets, tankTargets.end()),\n        [](BWAPI::Unit u) { return u->isVisible() && !u->isFlying(); });\n\n    int siegeTankRange = BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode.groundWeapon().maxRange() - 32;\n    bool haveSiege = BWAPI::Broodwar->self()->hasResearched(BWAPI::TechTypes::Tank_Siege_Mode);\n\n\n\n    // for each zealot\n    for (auto & tank : tanks)\n    {\n        // train sub units such as scarabs or interceptors\n        //trainSubUnits(rangedUnit);\n\n        bool tankNearChokepoint = false;\n        // TODO: chokepoint\n\n        // if the order is to attack or defend\n        if (m_order.getType() == SquadOrderTypes::Attack || m_order.getType() == SquadOrderTypes::Defend)\n        {\n            // if there are targets\n            if (!tankTargets.empty())\n            {\n                // find the best target for this zealot\n                BWAPI::Unit target = getTarget(tank, tankTargets);\n\n                if (target && Config::Debug::DrawUnitTargetInfo)\n                {\n                    BWAPI::Broodwar->drawLineMap(tank->getPosition(), tank->getTargetPosition(), BWAPI::Colors::Purple);\n                }\n\n                // if we are within siege range, siege up\n                if (tank->getDistance(target) < siegeTankRange && tank->canSiege() && !tankNearChokepoint)\n                {\n                    tank->siege();\n                }\n                // otherwise unsiege and move in\n                else if ((!target || tank->getDistance(target) > siegeTankRange) && tank->canUnsiege())\n                {\n                    tank->unsiege();\n                }\n\n\n                // if we're in siege mode just attack the target\n                if (tank->isSieged())\n                {\n                    Micro::SmartAttackUnit(tank, target);\n                }\n                // if we're not in siege mode kite the target\n                else\n                {\n                    Micro::SmartKiteTarget(tank, target);\n                }\n            }\n            // if there are no targets\n            else\n            {\n                // if we're not near the order position\n                if (tank->getDistance(m_order.getPosition()) > 100)\n                {\n                    if (tank->canUnsiege())\n                    {\n                        tank->unsiege();\n                    }\n                    else\n                    {\n                        // move to it\n                        Micro::SmartAttackMove(tank, m_order.getPosition());\n                    }\n                }\n            }\n        }\n    }\n}\n\n// get a target for the zealot to attack\nBWAPI::Unit TankManager::getTarget(BWAPI::Unit tank, const BWAPI::Unitset & targets)\n{\n    int bestPriorityDistance = 1000000;\n    int bestPriority = 0;\n\n    double bestLTD = 0;\n\n    BWAPI::Unit bestTargetThreatInRange = nullptr;\n    double bestTargetThreatInRangeLTD = 0;\n\n    int highPriority = 0;\n    double closestDist = std::numeric_limits<double>::infinity();\n    BWAPI::Unit closestTarget = nullptr;\n\n    int siegeTankRange = BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode.groundWeapon().maxRange() - 32;\n    BWAPI::Unitset targetsInSiegeRange;\n    for (auto & target : targets)\n    {\n        if (target->getDistance(tank) < siegeTankRange && UnitUtil::CanAttack(tank, target))\n        {\n            targetsInSiegeRange.insert(target);\n        }\n    }\n\n    const BWAPI::Unitset & newTargets = targetsInSiegeRange.empty() ? targets : targetsInSiegeRange;\n\n    // check first for units that are in range of our attack that can cause damage\n    // choose the highest priority one from them at the lowest health\n    for (const auto & target : newTargets)\n    {\n        if (!UnitUtil::CanAttack(tank, target))\n        {\n            continue;\n        }\n\n        double distance         = tank->getDistance(target);\n        double LTD              = UnitUtil::CalculateLTD(target, tank);\n        int priority            = getAttackPriority(tank, target);\n        bool targetIsThreat     = LTD > 0;\n        BWAPI::Broodwar->drawTextMap(target->getPosition(), \"%d\", priority);\n\n        if (!closestTarget || (priority > highPriority) || (priority == highPriority && distance < closestDist))\n        {\n            closestDist = distance;\n            highPriority = priority;\n            closestTarget = target;\n        }\n    }\n\n    if (bestTargetThreatInRange)\n    {\n        return bestTargetThreatInRange;\n    }\n\n    return closestTarget;\n}\n\n// get the attack priority of a type in relation to a zergling\nint TankManager::getAttackPriority(BWAPI::Unit rangedUnit, BWAPI::Unit target)\n{\n    BWAPI::UnitType rangedType = rangedUnit->getType();\n    BWAPI::UnitType targetType = target->getType();\n\n    bool isThreat = rangedType.isFlyer() ? targetType.airWeapon() != BWAPI::WeaponTypes::None : targetType.groundWeapon() != BWAPI::WeaponTypes::None;\n\n    if (target->getType().isWorker())\n    {\n        isThreat = false;\n    }\n\n    if (target->getType() == BWAPI::UnitTypes::Zerg_Larva || target->getType() == BWAPI::UnitTypes::Zerg_Egg)\n    {\n        return 0;\n    }\n\n    // if the target is building something near our base something is fishy\n    BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n    if (target->getType().isWorker() && (target->isConstructing() || target->isRepairing()) && target->getDistance(ourBasePosition) < 1200)\n    {\n        return 100;\n    }\n\n    if (target->getType().isBuilding() && (target->isCompleted() || target->isBeingConstructed()) && target->getDistance(ourBasePosition) < 1200)\n    {\n        return 90;\n    }\n\n    // highest priority is something that can attack us or aid in combat\n    if (targetType ==  BWAPI::UnitTypes::Terran_Bunker || isThreat)\n    {\n        return 11;\n    }\n    // next priority is worker\n    else if (targetType.isWorker())\n    {\n        return 9;\n    }\n    // next is special buildings\n    else if (targetType == BWAPI::UnitTypes::Zerg_Spawning_Pool)\n    {\n        return 5;\n    }\n    // next is special buildings\n    else if (targetType == BWAPI::UnitTypes::Protoss_Pylon)\n    {\n        return 5;\n    }\n    // next is buildings that cost gas\n    else if (targetType.gasPrice() > 0)\n    {\n        return 4;\n    }\n    else if (targetType.mineralPrice() > 0)\n    {\n        return 3;\n    }\n    // then everything else\n    else\n    {\n        return 1;\n    }\n}\n\nBWAPI::Unit TankManager::closestrangedUnit(BWAPI::Unit target, std::set<BWAPI::Unit> & rangedUnitsToAssign)\n{\n    double minDistance = 0;\n    BWAPI::Unit closest = nullptr;\n\n    for (auto & rangedUnit : rangedUnitsToAssign)\n    {\n        double distance = rangedUnit->getDistance(target);\n        if (!closest || distance < minDistance)\n        {\n            minDistance = distance;\n            closest = rangedUnit;\n        }\n    }\n\n    return closest;\n}"
  },
  {
    "path": "UAlbertaBot/Source/TankManager.h",
    "content": "#pragma once\n\n#include <Common.h>\n#include \"MicroManager.h\"\n\nnamespace UAlbertaBot\n{\nclass TankManager : public MicroManager\n{\npublic:\n\n\tTankManager();\n\tvoid executeMicro(const BWAPI::Unitset & targets);\n    \n\tint getAttackPriority(BWAPI::Unit rangedUnit, BWAPI::Unit target);\n\tBWAPI::Unit getTarget(BWAPI::Unit rangedUnit, const BWAPI::Unitset & targets);\n\tBWAPI::Unit closestrangedUnit(BWAPI::Unit target, std::set<BWAPI::Unit> & rangedUnitsToAssign);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/TimerManager.cpp",
    "content": "#include \"TimerManager.h\"\n#include \"Config.h\"\n\nusing namespace UAlbertaBot;\n\nTimerManager::TimerManager()\n    : m_timers(std::vector<BOSS::Timer>(NumTypes))\n    , m_barWidth(40)\n{\n    m_timerNames.push_back(\"Total\");\n    m_timerNames.push_back(\"Worker\");\n    m_timerNames.push_back(\"Production\");\n    m_timerNames.push_back(\"Building\");\n    m_timerNames.push_back(\"Combat\");\n    m_timerNames.push_back(\"Scout\");\n    m_timerNames.push_back(\"UnitInfo\");\n    m_timerNames.push_back(\"MapGrid\");\n    m_timerNames.push_back(\"MapTools\");\n    m_timerNames.push_back(\"Search\");\n}\n\nvoid TimerManager::startTimer(const TimerManager::Type t)\n{\n    m_timers[t].start();\n}\n\nvoid TimerManager::stopTimer(const TimerManager::Type t)\n{\n    m_timers[t].stop();\n}\n\ndouble TimerManager::getTotalElapsed()\n{\n    return m_timers[0].getElapsedTimeInMilliSec();\n}\n\nvoid TimerManager::displayTimers(int x, int y)\n{\n    if (!Config::Debug::DrawModuleTimers)\n    {\n        return;\n    }\n\n    BWAPI::Broodwar->drawBoxScreen(x-5, y-5, x+110+m_barWidth, y+5+(10*m_timers.size()), BWAPI::Colors::Black, true);\n\n    int yskip = 0;\n    double total = m_timers[0].getElapsedTimeInMilliSec();\n    for (size_t i(0); i<m_timers.size(); ++i)\n    {\n        double elapsed = m_timers[i].getElapsedTimeInMilliSec();\n        if (elapsed > 55)\n        {\n            BWAPI::Broodwar->printf(\"Timer Debug: %s %lf\", m_timerNames[i].c_str(), elapsed);\n        }\n\n        int width = (int)((elapsed == 0) ? 0 : (m_barWidth * (elapsed / total)));\n\n        BWAPI::Broodwar->drawTextScreen(x, y+yskip-3, \"\\x04 %s\", m_timerNames[i].c_str());\n        BWAPI::Broodwar->drawBoxScreen(x+60, y+yskip, x+60+width+1, y+yskip+8, BWAPI::Colors::White);\n        BWAPI::Broodwar->drawTextScreen(x+70+m_barWidth, y+yskip-3, \"%.4lf\", elapsed);\n        yskip += 10;\n    }\n}"
  },
  {
    "path": "UAlbertaBot/Source/TimerManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"../../BOSS/source/Timer.hpp\"\n\nnamespace UAlbertaBot\n{\n\nclass TimerManager\n{\n    std::vector<BOSS::Timer> m_timers;\n    std::vector<std::string> m_timerNames;\n    int                      m_barWidth = 0;\n\npublic:\n\n    enum Type { All, Worker, Production, Building, Combat, Scout, InformationManager, MapGrid, MapTools, Search, NumTypes };\n\n    TimerManager();\n\n    void startTimer(const TimerManager::Type t);\n    void stopTimer(const TimerManager::Type t);\n    void displayTimers(int x, int y);\n    double getTotalElapsed();\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/TransportManager.cpp",
    "content": "#include \"TransportManager.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n#include \"Micro.h\"\n#include \"MapTools.h\"\n\nusing namespace UAlbertaBot;\n\nTransportManager::TransportManager()\n{\n}\n\nvoid TransportManager::executeMicro(const BWAPI::Unitset & targets)\n{\n    const BWAPI::Unitset & transportUnits = getUnits();\n\n    if (transportUnits.empty())\n    {\n        return;\n    }\n}\n\nvoid TransportManager::calculateMapEdgeVertices()\n{\n    auto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n\n    if (!enemyBaseLocation)\n    {\n        return;\n    }\n\n    const BWAPI::Position basePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n    const std::vector<BWAPI::TilePosition> & closestTobase = Global::Map().getClosestTilesTo(basePosition);\n\n    std::set<BWAPI::Position> unsortedVertices;\n\n    int minX = std::numeric_limits<int>::max(); int minY = minX;\n    int maxX = std::numeric_limits<int>::min(); int maxY = maxX;\n\n    //compute mins and maxs\n    for (auto &tile : closestTobase)\n    {\n        if (tile.x > maxX) maxX = tile.x;\n        else if (tile.x < minX) minX = tile.x;\n\n        if (tile.y > maxY) maxY = tile.y;\n        else if (tile.y < minY) minY = tile.y;\n    }\n\n    m_minCorner = BWAPI::Position(minX, minY) * 32 + BWAPI::Position(16, 16);\n    m_maxCorner = BWAPI::Position(maxX, maxY) * 32 + BWAPI::Position(16, 16);\n\n    //add all(some) edge tiles! \n    for (int x = minX; x <= maxX; x += 5)\n    {\n        unsortedVertices.insert(BWAPI::Position(x, minY) * 32 + BWAPI::Position(16, 16));\n        unsortedVertices.insert(BWAPI::Position(x, maxY) * 32 + BWAPI::Position(16, 16));\n    }\n\n    for (int y = minY; y <= maxY; y += 5)\n    {\n        unsortedVertices.insert(BWAPI::Position(minX, y) * 32 + BWAPI::Position(16, 16));\n        unsortedVertices.insert(BWAPI::Position(maxX, y) * 32 + BWAPI::Position(16, 16));\n    }\n\n    std::vector<BWAPI::Position> sortedVertices;\n    BWAPI::Position current = *unsortedVertices.begin();\n\n    m_mapEdgeVertices.push_back(current);\n    unsortedVertices.erase(current);\n\n    // while we still have unsorted vertices left, find the closest one remaining to current\n    while (!unsortedVertices.empty())\n    {\n        double bestDist = 1000000;\n        BWAPI::Position bestPos;\n\n        for (const BWAPI::Position & pos : unsortedVertices)\n        {\n            double dist = pos.getDistance(current);\n\n            if (dist < bestDist)\n            {\n                bestDist = dist;\n                bestPos = pos;\n            }\n        }\n\n        current = bestPos;\n        sortedVertices.push_back(bestPos);\n        unsortedVertices.erase(bestPos);\n    }\n\n    m_mapEdgeVertices = sortedVertices;\n}\n\nvoid TransportManager::drawTransportInformation(int x = 0, int y = 0)\n{\n    if (!Config::Debug::DrawUnitTargetInfo)\n    {\n        return;\n    }\n\n    for (size_t i(0); i < m_mapEdgeVertices.size(); ++i)\n    {\n        BWAPI::Broodwar->drawCircleMap(m_mapEdgeVertices[i], 4, BWAPI::Colors::Green, false);\n        BWAPI::Broodwar->drawTextMap(m_mapEdgeVertices[i], \"%d\", i);\n    }\n}\n\nvoid TransportManager::update()\n{\n    if (!m_transportShip && getUnits().size() > 0)\n    {\n        m_transportShip = *getUnits().begin();\n    }\n\n    // calculate enemy region vertices if we haven't yet\n    if (m_mapEdgeVertices.empty())\n    {\n        calculateMapEdgeVertices();\n    }\n\n    moveTroops();\n    moveTransport();\n\n    drawTransportInformation();\n}\n\nvoid TransportManager::moveTransport()\n{\n    if (!m_transportShip || !m_transportShip->exists() || !(m_transportShip->getHitPoints() > 0))\n    {\n        return;\n    }\n\n    // If I didn't finish unloading the troops, wait\n    BWAPI::UnitCommand currentCommand(m_transportShip->getLastCommand());\n    if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Unload_All\n        || currentCommand.getType() == BWAPI::UnitCommandTypes::Unload_All_Position)\n        && m_transportShip->getLoadedUnits().size() > 0)\n    {\n        return;\n    }\n\n    if (m_to.isValid() && m_from.isValid())\n    {\n        followPerimeter(m_to, m_from);\n    }\n    else\n    {\n        followPerimeter();\n    }\n}\n\nvoid TransportManager::moveTroops()\n{\n    if (!m_transportShip || !m_transportShip->exists() || !(m_transportShip->getHitPoints() > 0))\n    {\n        return;\n    }\n    //unload zealots if close enough or dying\n    int transportHP = m_transportShip->getHitPoints() + m_transportShip->getShields();\n\n    auto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n\n    if (enemyBaseLocation && (m_transportShip->getDistance(enemyBaseLocation->getPosition()) < 300 || transportHP < 100)\n        && m_transportShip->canUnloadAtPosition(m_transportShip->getPosition()))\n    {\n        //unload troops \n        //and return? \n\n        // get the unit's current command\n        BWAPI::UnitCommand currentCommand(m_transportShip->getLastCommand());\n\n        // if we've already told this unit to unload, wait\n        if (currentCommand.getType() == BWAPI::UnitCommandTypes::Unload_All || currentCommand.getType() == BWAPI::UnitCommandTypes::Unload_All_Position)\n        {\n            return;\n        }\n\n        //else unload\n        m_transportShip->unloadAll(m_transportShip->getPosition());\n    }\n\n}\n\nvoid TransportManager::followPerimeter(int clockwise)\n{\n    BWAPI::Position goTo = getFleePosition(clockwise);\n\n    if (Config::Debug::DrawUnitTargetInfo)\n    {\n        BWAPI::Broodwar->drawCircleMap(goTo, 5, BWAPI::Colors::Red, true);\n    }\n\n    Micro::SmartMove(m_transportShip, goTo);\n}\n\nvoid TransportManager::followPerimeter(BWAPI::Position to, BWAPI::Position from)\n{\n    static int following = 0;\n    if (following)\n    {\n        followPerimeter(following);\n        return;\n    }\n\n    //assume we're near FROM! \n    if (m_transportShip->getDistance(from) < 50 && m_waypoints.empty())\n    {\n        //compute waypoints\n        std::pair<int, int> wpIDX = findSafePath(to, from);\n        bool valid = (wpIDX.first > -1 && wpIDX.second > -1);\n        UAB_ASSERT_WARNING(valid, \"waypoints not valid! (transport mgr)\");\n        m_waypoints.push_back(m_mapEdgeVertices[wpIDX.first]);\n        m_waypoints.push_back(m_mapEdgeVertices[wpIDX.second]);\n\n        BWAPI::Broodwar->printf(\"WAYPOINTS: [%d] - [%d]\", wpIDX.first, wpIDX.second);\n\n        Micro::SmartMove(m_transportShip, m_waypoints[0]);\n    }\n    else if (m_waypoints.size() > 1 && m_transportShip->getDistance(m_waypoints[0]) < 100)\n    {\n        BWAPI::Broodwar->printf(\"FOLLOW PERIMETER TO SECOND WAYPOINT!\");\n        //follow perimeter to second waypoint! \n        //clockwise or counterclockwise? \n        int closestPolygonIndex = getClosestVertexIndex(m_transportShip);\n        UAB_ASSERT_WARNING(closestPolygonIndex != -1, \"Couldn't find a closest vertex\");\n\n        if (m_mapEdgeVertices[(closestPolygonIndex + 1) % m_mapEdgeVertices.size()].getApproxDistance(m_waypoints[1]) <\n            m_mapEdgeVertices[(closestPolygonIndex - 1) % m_mapEdgeVertices.size()].getApproxDistance(m_waypoints[1]))\n        {\n            BWAPI::Broodwar->printf(\"FOLLOW clockwise\");\n            following = 1;\n            followPerimeter(following);\n        }\n        else\n        {\n            BWAPI::Broodwar->printf(\"FOLLOW counter clockwise\");\n            following = -1;\n            followPerimeter(following);\n        }\n\n    }\n    else if (m_waypoints.size() > 1 && m_transportShip->getDistance(m_waypoints[1]) < 50)\n    {\n        //if close to second waypoint, go to destination!\n        following = 0;\n        Micro::SmartMove(m_transportShip, to);\n    }\n\n}\n\n\nint TransportManager::getClosestVertexIndex(BWAPI::UnitInterface * unit)\n{\n    int closestIndex = -1;\n    double closestDistance = 10000000;\n\n    for (size_t i(0); i < m_mapEdgeVertices.size(); ++i)\n    {\n        double dist = unit->getDistance(m_mapEdgeVertices[i]);\n        if (dist < closestDistance)\n        {\n            closestDistance = dist;\n            closestIndex = i;\n        }\n    }\n\n    return closestIndex;\n}\n\nint TransportManager::getClosestVertexIndex(BWAPI::Position p)\n{\n    int closestIndex = -1;\n    double closestDistance = 10000000;\n\n    for (size_t i(0); i < m_mapEdgeVertices.size(); ++i)\n    {\n\n        double dist = p.getApproxDistance(m_mapEdgeVertices[i]);\n        if (dist < closestDistance)\n        {\n            closestDistance = dist;\n            closestIndex = i;\n        }\n    }\n\n    return closestIndex;\n}\n\nstd::pair<int, int> TransportManager::findSafePath(BWAPI::Position to, BWAPI::Position from)\n{\n    BWAPI::Broodwar->printf(\"FROM: [%d,%d]\", from.x, from.y);\n    BWAPI::Broodwar->printf(\"TO: [%d,%d]\", to.x, to.y);\n\n    //closest map edge point to destination\n    int endPolygonIndex = getClosestVertexIndex(to);\n    //BWAPI::Broodwar->printf(\"end indx: [%d]\", endPolygonIndex);\n\n    UAB_ASSERT_WARNING(endPolygonIndex != -1, \"Couldn't find a closest vertex\");\n    BWAPI::Position enemyEdge = m_mapEdgeVertices[endPolygonIndex];\n\n    auto * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n    BWAPI::Position enemyPosition = enemyBaseLocation->getPosition();\n\n    //find the projections on the 4 edges\n    UAB_ASSERT_WARNING((m_minCorner.isValid() && m_maxCorner.isValid()), \"Map corners should have been set! (transport mgr)\");\n    std::vector<BWAPI::Position> p;\n    p.push_back(BWAPI::Position(from.x, m_minCorner.y));\n    p.push_back(BWAPI::Position(from.x, m_maxCorner.y));\n    p.push_back(BWAPI::Position(m_minCorner.x, from.y));\n    p.push_back(BWAPI::Position(m_maxCorner.x, from.y));\n\n    int d1 = p[0].getApproxDistance(enemyPosition);\n    int d2 = p[1].getApproxDistance(enemyPosition);\n    int d3 = p[2].getApproxDistance(enemyPosition);\n    int d4 = p[3].getApproxDistance(enemyPosition);\n\n    //have to choose the two points that are not max or min (the sides!)\n    int maxIndex = (d1 > d2 ? d1 : d2) > (d3 > d4 ? d3 : d4) ?\n        (d1 > d2 ? 0 : 1) : (d3 > d4 ? 2 : 3);\n\n    int minIndex = (d1 < d2 ? d1 : d2) < (d3 < d4 ? d3 : d4) ?\n        (d1 < d2 ? 0 : 1) : (d3 < d4 ? 2 : 3);\n\n    if (maxIndex > minIndex)\n    {\n        p.erase(p.begin() + maxIndex);\n        p.erase(p.begin() + minIndex);\n    }\n    else\n    {\n        p.erase(p.begin() + minIndex);\n        p.erase(p.begin() + maxIndex);\n    }\n\n    //get the one that works best from the two.\n    BWAPI::Position waypoint = (enemyEdge.getApproxDistance(p[0]) < enemyEdge.getApproxDistance(p[1])) ? p[0] : p[1];\n\n    int startPolygonIndex = getClosestVertexIndex(waypoint);\n\n    return std::pair<int, int>(startPolygonIndex, endPolygonIndex);\n\n}\n\nBWAPI::Position TransportManager::getFleePosition(int clockwise)\n{\n    UAB_ASSERT_WARNING(!m_mapEdgeVertices.empty(), \"We should have a transport route!\");\n\n    // if this is the first flee, we will not have a previous perimeter index\n    if (m_currentRegionVertexIndex == -1)\n    {\n        // so return the closest position in the polygon\n        int closestPolygonIndex = getClosestVertexIndex(m_transportShip);\n\n        UAB_ASSERT_WARNING(closestPolygonIndex != -1, \"Couldn't find a closest vertex\");\n\n        if (closestPolygonIndex == -1)\n        {\n            return BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());\n        }\n        else\n        {\n            // set the current index so we know how to iterate if we are still fleeing later\n            m_currentRegionVertexIndex = closestPolygonIndex;\n            return m_mapEdgeVertices[closestPolygonIndex];\n        }\n    }\n    // if we are still fleeing from the previous frame, get the next location if we are close enough\n    else\n    {\n        double distanceFromCurrentVertex = m_mapEdgeVertices[m_currentRegionVertexIndex].getDistance(m_transportShip->getPosition());\n\n        // keep going to the next vertex in the perimeter until we get to one we're far enough from to issue another move command\n        while (distanceFromCurrentVertex < 128*2)\n        {\n            m_currentRegionVertexIndex = (m_currentRegionVertexIndex + clockwise*1) % m_mapEdgeVertices.size();\n\n            distanceFromCurrentVertex = m_mapEdgeVertices[m_currentRegionVertexIndex].getDistance(m_transportShip->getPosition());\n        }\n\n        return m_mapEdgeVertices[m_currentRegionVertexIndex];\n    }\n\n}\n\nvoid TransportManager::setTransportShip(BWAPI::UnitInterface * unit)\n{\n    m_transportShip = unit;\n}\n\nvoid TransportManager::setFrom(BWAPI::Position from)\n{\n    if (from.isValid()) { m_from = from; }\n}\nvoid TransportManager::setTo(BWAPI::Position to)\n{\n    if (to.isValid()) { m_to = to; }\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/TransportManager.h",
    "content": "#pragma once\n\n#include <Common.h>\n#include \"MicroManager.h\"\n\nnamespace UAlbertaBot\n{\nclass MicroManager;\n\nclass TransportManager : public MicroManager\n{\n    BWAPI::UnitInterface*           m_transportShip              = nullptr;\n    BWAPI::Position\t\t\t\t\tm_minCorner                  = {-1, -1};\n    BWAPI::Position\t\t\t\t\tm_maxCorner                  = {-1, -1};\n    BWAPI::Position\t\t\t\t\tm_to                         = {-1, -1};\n    BWAPI::Position\t\t\t\t\tm_from                       = {-1, -1};\n    int                             m_currentRegionVertexIndex   = -1;\n    std::vector<BWAPI::Position>\tm_waypoints;\n    std::vector<BWAPI::Position>    m_mapEdgeVertices;\n\n    void calculateMapEdgeVertices();\n    void drawTransportInformation(int x, int y);\n    void moveTransport();\n    void moveTroops();\n    void followPerimeter(int clockwise=1);\n    void followPerimeter(BWAPI::Position to, BWAPI::Position from);\n\n    int getClosestVertexIndex(BWAPI::UnitInterface * unit);\n    int getClosestVertexIndex(BWAPI::Position p);\n    BWAPI::Position getFleePosition(int clockwise=1);\n    std::pair<int, int> findSafePath(BWAPI::Position from, BWAPI::Position to);\n\npublic:\n\n    TransportManager();\n\n    void executeMicro(const BWAPI::Unitset & targets);\n    void update();\n    void setTransportShip(BWAPI::UnitInterface * unit);\n    void setFrom(BWAPI::Position from);\n    void setTo(BWAPI::Position to);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/UABAssert.cpp",
    "content": "#include \"Common.h\"\n#include \"UABAssert.h\"\n#include \"Config.h\"\n#include \"Logger.h\"\n\nusing namespace UAlbertaBot;\n\nnamespace UAlbertaBot\n{\nnamespace Assert\n{\n    std::string lastErrorMessage;\n\n    const std::string currentDateTime() \n    {\n        time_t     now = time(0);\n        struct tm  tstruct;\n        char       buf[80];\n        //tstruct = *localtime(&now);\n\t\tlocaltime_s(&tstruct, &now);\n        strftime(buf, sizeof(buf), \"%Y-%m-%d_%X\", &tstruct);\n\n        return buf;\n    }\n\n    void ReportFailure(const char * condition, const char * file, int line, const char * msg, ...)\n    {\n        char messageBuffer[1024] = \"\";\n        if (msg != nullptr)\n        {\n            va_list args;\n            va_start(args, msg);\n            //vsprintf(messageBuffer, msg, args);\n\t\t\tvsnprintf_s(messageBuffer, 1024, msg, args);\n            va_end(args);\n        }\n\n        std::stringstream ss;\n        ss                                              << std::endl;\n        ss << \"!Assert:   \" << condition                << std::endl;\n        ss << \"File:      \" << file                     << std::endl;\n        ss << \"Message:   \" << messageBuffer            << std::endl;\n        ss << \"Line:      \" << line                     << std::endl;\n        ss << \"Time:      \" << currentDateTime()        << std::endl;\n        \n        lastErrorMessage = messageBuffer;\n\n        std::cerr << ss.str();\n        BWAPI::Broodwar->printf(\"%s\", ss.str().c_str());\n\n        if (Config::Debug::LogAssertToErrorFile)\n        {\n            Logger::LogAppendToFile(Config::Debug::ErrorLogFilename, ss.str());\n        }\n    }\n}\n}\n\n"
  },
  {
    "path": "UAlbertaBot/Source/UABAssert.h",
    "content": "#pragma once\n\n#include <cstdio>\n#include <cstdarg>\n#include \"Logger.h\"\n#include <sstream>\n#include <stdarg.h>\n\n#include <ctime>\n#include <iomanip>\n\n#define UAB_BREAK\n\n#define UAB_ASSERT_ALL\n\n#ifdef UAB_ASSERT_ALL\n    #define UAB_ASSERT(cond, msg, ...) \\\n        do \\\n        { \\\n            if (!(cond)) \\\n            { \\\n                UAlbertaBot::Assert::ReportFailure(#cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \\\n                UAB_BREAK \\\n            } \\\n        } while(0)\n\n    #define UAB_ASSERT_WARNING(cond, msg, ...) \\\n        do \\\n        { \\\n            if (!(cond)) \\\n            { \\\n                UAlbertaBot::Assert::ReportFailure(#cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \\\n            } \\\n        } while(0)\n#else\n    #define UAB_ASSERT(cond, msg, ...) \n#endif\n\nnamespace UAlbertaBot\n{\n    namespace Assert\n    {\n        void ShutDown();\n\n        extern std::string lastErrorMessage;\n\n        const std::string currentDateTime();\n\n        void ReportFailure(const char * condition, const char * file, int line, const char * msg, ...);\n    }\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/UAlbertaBotModule.cpp",
    "content": "/* \n +----------------------------------------------------------------------+\n | UAlbertaBot                                                          |\n +----------------------------------------------------------------------+\n | University of Alberta - AIIDE StarCraft Competition                  |\n +----------------------------------------------------------------------+\n |                                                                      |\n +----------------------------------------------------------------------+\n | Author: David Churchill <dave.churchill@gmail.com>                   |\n +----------------------------------------------------------------------+\n*/\n\n#include \"Common.h\"\n#include \"UAlbertaBotModule.h\"\n#include \"JSONTools.h\"\n#include \"ParseUtils.h\"\n#include \"UnitUtil.h\"\n#include \"Global.h\"\n#include \"StrategyManager.h\"\n#include \"MapTools.h\"\n\nusing namespace UAlbertaBot;\n\nUAlbertaBotModule::UAlbertaBotModule()\n{\n    Global::GameStart();\n}\n\n// This gets called when the bot starts!\nvoid UAlbertaBotModule::onStart()\n{\n    // Parse the bot's configuration file if it has one, change this file path to where your config file is\n    // Any relative path name will be relative to Starcraft installation folder\n    ParseUtils::ParseConfigFile(Config::ConfigFile::ConfigFileLocation);\n\n    // Set our BWAPI options here    \n\tBWAPI::Broodwar->setLocalSpeed(Config::BWAPIOptions::SetLocalSpeed);\n\tBWAPI::Broodwar->setFrameSkip(Config::BWAPIOptions::SetFrameSkip);\n    \n    if (Config::BWAPIOptions::EnableCompleteMapInformation)\n    {\n        BWAPI::Broodwar->enableFlag(BWAPI::Flag::CompleteMapInformation);\n    }\n\n    if (Config::BWAPIOptions::EnableUserInput)\n    {\n        BWAPI::Broodwar->enableFlag(BWAPI::Flag::UserInput);\n    }\n\n    if (Config::BotInfo::PrintInfoOnStart)\n    {\n        BWAPI::Broodwar->printf(\"Hello! I am %s, written by %s\", Config::BotInfo::BotName.c_str(), Config::BotInfo::Authors.c_str());\n    }\n\n    // Call BWTA to read and analyze the current map\n    if (Config::Modules::UsingGameCommander)\n\t{\n        if (Config::Modules::UsingStrategyIO)\n        {\n            Global::Strategy().readResults();\n            Global::Strategy().setLearnedStrategy();\n        }\n\t}\n\n    //Global::Map().saveMapToFile(\"map.txt\");\n}\n\nvoid UAlbertaBotModule::onEnd(bool isWinner) \n{\n\tif (Config::Modules::UsingGameCommander)\n\t{\n\t\tGlobal::Strategy().onEnd(isWinner);\n\t}\n}\n\nvoid UAlbertaBotModule::onFrame()\n{\n    if (BWAPI::Broodwar->getFrameCount() > 100000)\n    {\n        BWAPI::Broodwar->restartGame();\n    }\n\n    const char red = '\\x08';\n    const char green = '\\x07';\n    const char white = '\\x04';\n\n    if (!Config::ConfigFile::ConfigFileFound)\n    {\n        BWAPI::Broodwar->drawBoxScreen(0,0,450,100, BWAPI::Colors::Black, true);\n        BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Huge);\n        BWAPI::Broodwar->drawTextScreen(10, 5, \"%c%s Config File Not Found\", red, Config::BotInfo::BotName.c_str());\n        BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Default);\n        BWAPI::Broodwar->drawTextScreen(10, 30, \"%c%s will not run without its configuration file\", white, Config::BotInfo::BotName.c_str());\n        BWAPI::Broodwar->drawTextScreen(10, 45, \"%cCheck that the file below exists. Incomplete paths are relative to Starcraft directory\", white);\n        BWAPI::Broodwar->drawTextScreen(10, 60, \"%cYou can change this file location in Config::ConfigFile::ConfigFileLocation\", white);\n        BWAPI::Broodwar->drawTextScreen(10, 75, \"%cFile Not Found (or is empty): %c %s\", white, green, Config::ConfigFile::ConfigFileLocation.c_str());\n        return;\n    }\n    else if (!Config::ConfigFile::ConfigFileParsed)\n    {\n        BWAPI::Broodwar->drawBoxScreen(0,0,450,100, BWAPI::Colors::Black, true);\n        BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Huge);\n        BWAPI::Broodwar->drawTextScreen(10, 5, \"%c%s Config File Parse Error\", red, Config::BotInfo::BotName.c_str());\n        BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Default);\n        BWAPI::Broodwar->drawTextScreen(10, 30, \"%c%s will not run without a properly formatted configuration file\", white, Config::BotInfo::BotName.c_str());\n        BWAPI::Broodwar->drawTextScreen(10, 45, \"%cThe configuration file was found, but could not be parsed. Check that it is valid JSON\", white);\n        BWAPI::Broodwar->drawTextScreen(10, 60, \"%cFile Not Parsed: %c %s\", white, green, Config::ConfigFile::ConfigFileLocation.c_str());\n        return;\n    }\n\n\tif (Config::Modules::UsingGameCommander) \n\t{ \n\t\tm_gameCommander.update(); \n\t}\n\n    if (Config::Modules::UsingAutoObserver)\n    {\n        m_autoObserver.onFrame();\n    }\n}\n\nvoid UAlbertaBotModule::onUnitDestroy(BWAPI::Unit unit)\n{\n\tif (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitDestroy(unit); }\n}\n\nvoid UAlbertaBotModule::onUnitMorph(BWAPI::Unit unit)\n{\n\tif (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitMorph(unit); }\n}\n\nvoid UAlbertaBotModule::onSendText(std::string text) \n{ \n\tParseUtils::ParseTextCommand(text);\n}\n\nvoid UAlbertaBotModule::onUnitCreate(BWAPI::Unit unit)\n{ \n\tif (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitCreate(unit); }\n}\n\nvoid UAlbertaBotModule::onUnitComplete(BWAPI::Unit unit)\n{\n\tif (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitComplete(unit); }\n}\n\nvoid UAlbertaBotModule::onUnitShow(BWAPI::Unit unit)\n{ \n\tif (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitShow(unit); }\n}\n\nvoid UAlbertaBotModule::onUnitHide(BWAPI::Unit unit)\n{ \n\tif (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitHide(unit); }\n}\n\nvoid UAlbertaBotModule::onUnitRenegade(BWAPI::Unit unit)\n{ \n\tif (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitRenegade(unit); }\n}"
  },
  {
    "path": "UAlbertaBot/Source/UAlbertaBotModule.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"GameCommander.h\"\n#include \"AutoObserver.h\"\n\nnamespace UAlbertaBot\n{\n\nclass UAlbertaBotModule\n{\n\tGameCommander m_gameCommander;\n    AutoObserver  m_autoObserver;\n\npublic:\n\n\tUAlbertaBotModule();\n\tvoid\tonStart();\n\tvoid\tonFrame();\n\tvoid\tonEnd(bool isWinner);\n\tvoid\tonUnitDestroy(BWAPI::Unit unit);\n\tvoid\tonUnitMorph(BWAPI::Unit unit);\n\tvoid\tonSendText(std::string text);\n\tvoid\tonUnitCreate(BWAPI::Unit unit);\n\tvoid\tonUnitComplete(BWAPI::Unit unit);\n\tvoid\tonUnitShow(BWAPI::Unit unit);\n\tvoid\tonUnitHide(BWAPI::Unit unit);\n\tvoid\tonUnitRenegade(BWAPI::Unit unit);\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/UnitData.cpp",
    "content": "#include \"Common.h\"\n#include \"UnitData.h\"\n\nusing namespace UAlbertaBot;\n\nUnitData::UnitData() \n\t: mineralsLost(0)\n\t, gasLost(0)\n{\n\tint maxTypeID(0);\n\tfor (const BWAPI::UnitType & t : BWAPI::UnitTypes::allUnitTypes())\n\t{\n\t\tmaxTypeID = maxTypeID > t.getID() ? maxTypeID : t.getID();\n\t}\n\n\tnumDeadUnits\t    = std::vector<int>(maxTypeID + 1, 0);\n\tnumUnits\t\t    = std::vector<int>(maxTypeID + 1, 0);\n}\n\nvoid UnitData::updateUnit(BWAPI::Unit unit)\n{\n\tif (!unit) { return; }\n\n    bool firstSeen = false;\n    auto & it = unitMap.find(unit);\n    if (it == unitMap.end())\n    {\n        firstSeen = true;\n        unitMap[unit] = UnitInfo();\n    }\n    \n\tUnitInfo & ui   = unitMap[unit];\n    ui.unit         = unit;\n    ui.player       = unit->getPlayer();\n\tui.lastPosition = unit->getPosition();\n\tui.lastHealth   = unit->getHitPoints();\n    ui.lastShields  = unit->getShields();\n\tui.unitID       = unit->getID();\n\tui.type         = unit->getType();\n    ui.completed    = unit->isCompleted();\n\n    if (firstSeen)\n    {\n        numUnits[unit->getType().getID()]++;\n    }\n}\n\nvoid UnitData::removeUnit(BWAPI::Unit unit)\n{\n\tif (!unit) { return; }\n\n\tmineralsLost += unit->getType().mineralPrice();\n\tgasLost += unit->getType().gasPrice();\n\tnumUnits[unit->getType().getID()]--;\n\tnumDeadUnits[unit->getType().getID()]++;\n\t\t\n\tunitMap.erase(unit);\n}\n\nvoid UnitData::removeBadUnits()\n{\n\tfor (auto iter(unitMap.begin()); iter != unitMap.end();)\n\t{\n\t\tif (badUnitInfo(iter->second))\n\t\t{\n\t\t\tnumUnits[iter->second.type.getID()]--;\n\t\t\titer = unitMap.erase(iter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\titer++;\n\t\t}\n\t}\n}\n\nconst bool UnitData::badUnitInfo(const UnitInfo & ui) const\n{\n    if (!ui.unit)\n    {\n        return false;\n    }\n\n\t// Cull away any refineries/assimilators/extractors that were destroyed and reverted to vespene geysers\n\tif (ui.unit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser)\n\t{ \n\t\treturn true;\n\t}\n\n\t// If the unit is a building and we can currently see its position and it is not there\n\tif (ui.type.isBuilding() && BWAPI::Broodwar->isVisible(ui.lastPosition.x/32, ui.lastPosition.y/32) && !ui.unit->isVisible())\n\t{\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nint UnitData::getGasLost() const \n{ \n    return gasLost; \n}\n\nint UnitData::getMineralsLost() const \n{ \n    return mineralsLost; \n}\n\nint UnitData::getNumUnits(BWAPI::UnitType t) const \n{ \n    return numUnits[t.getID()]; \n}\n\nint UnitData::getNumDeadUnits(BWAPI::UnitType t) const \n{ \n    return numDeadUnits[t.getID()]; \n}\n\nconst std::map<BWAPI::Unit,UnitInfo> & UnitData::getUnits() const \n{ \n    return unitMap; \n}"
  },
  {
    "path": "UAlbertaBot/Source/UnitData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace UAlbertaBot\n{\nstruct UnitInfo\n{\n    // we need to store all of this data because if the unit is not visible, we\n    // can't reference it from the unit pointer\n\n    int             unitID          = 0;\n    int             lastHealth      = 0;\n    int             lastShields     = 0;\n    BWAPI::Player   player          = nullptr;\n    BWAPI::Unit     unit;\n    BWAPI::Position lastPosition    = BWAPI::Positions::None;\n    BWAPI::UnitType type            = BWAPI::UnitTypes::None;\n    bool            completed       = false;\n\n    UnitInfo()\n    {\n\n    }\n\n    const bool operator == (BWAPI::Unit unit) const\n    {\n        return unitID == unit->getID();\n    }\n\n    const bool operator == (const UnitInfo & rhs) const\n    {\n        return (unitID == rhs.unitID);\n    }\n\n    const bool operator < (const UnitInfo & rhs) const\n    {\n        return (unitID < rhs.unitID);\n    }\n};\n\ntypedef std::vector<UnitInfo> UnitInfoVector;\ntypedef std::map<BWAPI::Unit,UnitInfo> UIMap;\n\nclass UnitData\n{\n    UIMap unitMap;\n\n    std::vector<int> numDeadUnits;\n    std::vector<int> numUnits;\n    int mineralsLost = 0;\n    int gasLost      = 0;\n    \n    const bool badUnitInfo(const UnitInfo & ui) const;\n\npublic:\n\n    UnitData();\n\n    void\tupdateUnit(BWAPI::Unit unit);\n    void\tremoveUnit(BWAPI::Unit unit);\n    void\tremoveBadUnits();\n\n    int\t\tgetGasLost()                                const;\n    int\t\tgetMineralsLost()                           const;\n    int\t\tgetNumUnits(BWAPI::UnitType t)              const;\n    int\t\tgetNumDeadUnits(BWAPI::UnitType t)          const;\n    const\tstd::map<BWAPI::Unit,UnitInfo> & getUnits() const;\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/UnitInfoManager.cpp",
    "content": "#include \"UnitInfoManager.h\"\n#include \"Util.h\"\n#include \"CCBot.h\"\n#include \"Unit.h\"\n\n#include <sstream>\n\nUnitInfoManager::UnitInfoManager(CCBot & bot)\n    : m_bot(bot)\n{\n\n}\n\nvoid UnitInfoManager::onStart()\n{\n\n}\n\nvoid UnitInfoManager::onFrame()\n{\n    updateUnitInfo();\n    drawUnitInformation(100, 100);\n    drawSelectedUnitDebugInfo();\n}\n\nvoid UnitInfoManager::updateUnitInfo()\n{\n    m_units[Players::Self].clear();\n    m_units[Players::Enemy].clear();\n    m_units[Players::Neutral].clear();\n\n    for (auto & unit : m_bot.GetUnits())\n    {\n        updateUnit(unit);\n        m_units[unit.getPlayer()].push_back(unit);     \n    }\n\n    // remove bad enemy units\n    m_unitData[Players::Self].removeBadUnits();\n    m_unitData[Players::Enemy].removeBadUnits();\n    m_unitData[Players::Neutral].removeBadUnits();\n}\n\nconst std::map<Unit, UnitInfo> & UnitInfoManager::getUnitInfoMap(CCPlayer player) const\n{\n    return getUnitData(player).getUnitInfoMap();\n}\n\nconst std::vector<Unit> & UnitInfoManager::getUnits(CCPlayer player) const\n{\n    BOT_ASSERT(m_units.find(player) != m_units.end(), \"Couldn't find player units: %d\", player);\n\n    return m_units.at(player);\n}\n\n//static std::string GetAbilityText(sc2::AbilityID ability_id) {\n//    std::string str;\n//    str += sc2::AbilityTypeToName(ability_id);\n//    str += \" (\";\n//    str += std::to_string(uint32_t(ability_id));\n//    str += \")\";\n//    return str;\n//}\n\nvoid UnitInfoManager::drawSelectedUnitDebugInfo()\n{\n//#ifdef SC2API\n//    const sc2::Unit * unit;\n//    for (auto u : m_bot.Observation()->GetUnits()) \n//    {\n//        if (u->is_selected && u->alliance == sc2::Unit::Self) {\n//            unit = u;\n//            break;\n//        }\n//    }\n//\n//    if (!unit) { return; }\n//\n//    auto query = m_bot.Query();\n//    auto abilities = m_bot.Observation()->GetAbilityData();\n//\n//    std::string debug_txt;\n//    debug_txt = UnitTypeToName(unit->unit_type);\n//    if (debug_txt.length() < 1) \n//    {\n//        debug_txt = \"(Unknown name)\";\n//        assert(0);\n//    }\n//    debug_txt += \" (\" + std::to_string(unit->unit_type) + \")\";\n//        \n//    sc2::AvailableAbilities available_abilities = query->GetAbilitiesForUnit(unit);\n//    if (available_abilities.abilities.size() < 1) \n//    {\n//        std::cout << \"No abilities available for this unit\" << std::endl;\n//    }\n//    else \n//    {\n//        for (const sc2::AvailableAbility & available_ability : available_abilities.abilities) \n//        {\n//            if (available_ability.ability_id >= abilities.size()) { continue; }\n//\n//            const sc2::AbilityData & ability = abilities[available_ability.ability_id];\n//\n//            debug_txt += GetAbilityText(ability.ability_id) + \"\\n\";\n//        }\n//    }\n//    m_bot.Map().drawText(unit->pos, debug_txt, CCColor(0, 255, 0));\n//\n//    // Show the direction of the unit.\n//    sc2::Point3D p1; // Use this to show target distance.\n//    {\n//        const float length = 5.0f;\n//        sc2::Point3D p0 = unit->pos;\n//        p0.z += 0.1f; // Raise the line off the ground a bit so it renders more clearly.\n//        p1 = unit->pos;\n//        assert(unit->facing >= 0.0f && unit->facing < 6.29f);\n//        p1.x += length * std::cos(unit->facing);\n//        p1.y += length * std::sin(unit->facing);\n//        m_bot.Map().drawLine(p0, p1, CCColor(255, 255, 0));\n//    }\n//\n//    // Box around the unit.\n//    {\n//        sc2::Point3D p_min = unit->pos;\n//        p_min.x -= 2.0f;\n//        p_min.y -= 2.0f;\n//        p_min.z -= 2.0f;\n//        sc2::Point3D p_max = unit->pos;\n//        p_max.x += 2.0f;\n//        p_max.y += 2.0f;\n//        p_max.z += 2.0f;\n//        m_bot.Map().drawBox(p_min, p_max, CCColor(0, 0, 255));\n//    }\n//\n//    // Sphere around the unit.\n//    {\n//        sc2::Point3D p = unit->pos;\n//        p.z += 0.1f; // Raise the line off the ground a bit so it renders more clearly.\n//        m_bot.Map().drawCircle(p, 1.25f, CCColor(255, 0, 255));\n//    }\n//\n//    // Pathing query to get the target.\n//    bool has_target = false;\n//    sc2::Point3D target;\n//    std::string target_info;\n//    for (const sc2::UnitOrder& unit_order : unit->orders)\n//    {\n//        // TODO: Need to determine if there is a target point, no target point, or the target is a unit/snapshot.\n//        target.x = unit_order.target_pos.x;\n//        target.y = unit_order.target_pos.y;\n//        target.z = p1.z;\n//        has_target = true;\n//\n//        target_info = \"Target:\\n\";\n//        if (unit_order.target_unit_tag != 0x0LL) {\n//            target_info += \"Tag: \" + std::to_string(unit_order.target_unit_tag) + \"\\n\";\n//        }\n//        if (unit_order.progress != 0.0f && unit_order.progress != 1.0f) {\n//            target_info += \"Progress: \" + std::to_string(unit_order.progress) + \"\\n\";\n//        }\n//\n//        // Perform the pathing query.\n//        {\n//            float distance = query->PathingDistance(unit->pos, target);\n//            target_info += \"\\nPathing dist: \" + std::to_string(distance);\n//        }\n//\n//        break;\n//    }\n//\n//    if (has_target)\n//    {\n//        sc2::Point3D p = target;\n//        p.z += 0.1f; // Raise the line off the ground a bit so it renders more clearly.\n//        m_bot.Map().drawCircle(target, 1.25f, CCColor(0, 0, 255));\n//        m_bot.Map().drawText(p1, target_info, CCColor(255, 255, 0));\n//    }\n//#endif\n}\n\n// passing in a unit type of 0 returns a count of all units\nsize_t UnitInfoManager::getUnitTypeCount(CCPlayer player, UnitType type, bool completed) const\n{\n    size_t count = 0;\n\n    for (auto & unit : getUnits(player))\n    {\n        if ((!type.isValid() || type == unit.getType()) && (!completed || unit.isCompleted()))\n        {\n            count++;\n        }\n    }\n\n    return count;\n}\n\nvoid UnitInfoManager::drawUnitInformation(float x,float y) const\n{\n    if (!m_bot.Config().DrawEnemyUnitInfo)\n    {\n        return;\n    }\n\n    std::stringstream ss;\n\n    // TODO: move this to unitData\n\n    //// for each unit in the queue\n    //for (auto & kv : m_)\n    //{\n    //    int numUnits =      m_unitData.at(Players::Self).getNumUnits(t);\n    //    int numDeadUnits =  m_unitData.at(Players::Enemy).getNumDeadUnits(t);\n\n    //    // if there exist units in the vector\n    //    if (numUnits > 0)\n    //    {\n    //        ss << numUnits << \"   \" << numDeadUnits << \"   \" << sc2::UnitTypeToName(t) << \"\\n\";\n    //    }\n    //}\n    //\n    //for (auto & kv : getUnitData(Players::Enemy).getUnitInfoMap())\n    //{\n    //    m_bot.Map().drawCircle(kv.second.lastPosition, 0.5f);\n    //    m_bot.Map().drawText(kv.second.lastPosition, sc2::UnitTypeToName(kv.second.type));\n    //}\n    //\n}\n\nvoid UnitInfoManager::updateUnit(const Unit & unit)\n{\n    m_unitData[unit.getPlayer()].updateUnit(unit);\n}\n\n// is the unit valid?\nbool UnitInfoManager::isValidUnit(const Unit & unit)\n{\n    if (!unit.isValid()) { return false; }\n\n    // if it's a weird unit, don't bother\n    if (unit.getType().isEgg() || unit.getType().isLarva())\n    {\n        return false;\n    }\n\n    // if the position isn't valid throw it out\n    if (!m_bot.Map().isValidPosition(unit.getPosition()))\n    {\n        return false;\n    }\n    \n    // s'all good baby baby\n    return true;\n}\n\nvoid UnitInfoManager::getNearbyForce(std::vector<UnitInfo> & unitInfo, CCPosition p, int player, float radius) const\n{\n    bool hasBunker = false;\n    // for each unit we know about for that player\n    for (const auto & kv : getUnitData(player).getUnitInfoMap())\n    {\n        const UnitInfo & ui(kv.second);\n\n        // if it's a combat unit we care about\n        // and it's finished! \n        if (ui.type.isCombatUnit() && Util::Dist(ui.lastPosition,p) <= radius)\n        {\n            // add it to the vector\n            unitInfo.push_back(ui);\n        }\n    }\n}\n\nconst UnitData & UnitInfoManager::getUnitData(CCPlayer player) const\n{\n    return m_unitData.find(player)->second;\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/UnitInfoManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"UnitData.h\"\n#include \"BaseLocation.h\"\n#include \"Unit.h\"\n\nclass CCBot;\nclass UnitInfoManager \n{\n    CCBot &           m_bot;\n\n    std::map<CCPlayer, UnitData> m_unitData; \n    std::map<CCPlayer, std::vector<Unit>> m_units;\n\n    void                    updateUnit(const Unit & unit);\n    void                    updateUnitInfo();\n    bool                    isValidUnit(const Unit & unit);\n    \n    const UnitData &        getUnitData(CCPlayer player) const;\n\n    void drawSelectedUnitDebugInfo();\n\npublic:\n\n    UnitInfoManager(CCBot & bot);\n\n    void                    onFrame();\n    void                    onStart();\n\n    const std::vector<Unit> & getUnits(CCPlayer player) const;\n\n    size_t                  getUnitTypeCount(CCPlayer player, UnitType type, bool completed = true) const;\n\n    void                    getNearbyForce(std::vector<UnitInfo> & unitInfo, CCPosition p, int player, float radius) const;\n\n    const std::map<Unit, UnitInfo> & getUnitInfoMap(CCPlayer player) const;\n\n    //bool                  enemyHasCloakedUnits() const;\n    void                    drawUnitInformation(float x, float y) const;\n\n};"
  },
  {
    "path": "UAlbertaBot/Source/UnitUtil.cpp",
    "content": "#include \"Common.h\"\n#include \"UnitUtil.h\"\n\nusing namespace UAlbertaBot;\n\nbool UnitUtil::IsCombatUnit(BWAPI::Unit unit)\n{\n    UAB_ASSERT(unit != nullptr, \"Unit was null\");\n    if (!unit)\n    {\n        return false;\n    }\n\n    // no workers or buildings allowed\n    if (unit && unit->getType().isWorker() || unit->getType().isBuilding())\n    {\n        return false;\n    }\n\n    // check for various types of combat units\n    if (unit->getType().canAttack() || \n        unit->getType() == BWAPI::UnitTypes::Terran_Medic ||\n        unit->getType() == BWAPI::UnitTypes::Protoss_High_Templar ||\n        unit->getType() == BWAPI::UnitTypes::Protoss_Observer ||\n        unit->isFlying() && unit->getType().spaceProvided() > 0)\n    {\n        return true;\n    }\n\t\t\n    return false;\n}\n\nbool UnitUtil::IsValidUnit(BWAPI::Unit unit)\n{\n    if (!unit)\n    {\n        return false;\n    }\n\n    if (unit->isCompleted() \n        && unit->getHitPoints() > 0 \n        && unit->exists() \n        && unit->getType() != BWAPI::UnitTypes::Unknown \n        && unit->getPosition().x != BWAPI::Positions::Unknown.x \n        && unit->getPosition().y != BWAPI::Positions::Unknown.y) \n    {\n        return true;\n    }\n    else\n    {\n        return false;\n    }\n}\n\nRect UnitUtil::GetRect(BWAPI::Unit unit)\n{\n    Rect r;\n\n    r.x = unit->getLeft();\n    r.y = unit->getTop();\n    r.height = unit->getBottom() - unit->getTop();\n    r.width = unit->getLeft() - unit->getRight();\n\n    return r;\n}\n\ndouble UnitUtil::GetDistanceBetweenTwoRectangles(Rect & rect1, Rect & rect2)\n{\n    Rect & mostLeft = rect1.x < rect2.x ? rect1 : rect2;\n    Rect & mostRight = rect2.x < rect1.x ? rect1 : rect2;\n    Rect & upper = rect1.y < rect2.y ? rect1 : rect2;\n    Rect & lower = rect2.y < rect1.y ? rect1 : rect2;\n\n    int diffX = std::max(0, mostLeft.x == mostRight.x ? 0 : mostRight.x - (mostLeft.x + mostLeft.width));\n    int diffY = std::max(0, upper.y == lower.y ? 0 : lower.y - (upper.y + upper.height));\n    \n    return std::sqrtf(static_cast<float>(diffX*diffX + diffY*diffY));\n}\n\nbool UnitUtil::CanAttack(BWAPI::Unit attacker, BWAPI::Unit target)\n{\n    return GetWeapon(attacker, target) != BWAPI::WeaponTypes::None;\n}\n\nbool UnitUtil::CanAttackAir(BWAPI::Unit unit)\n{\n    return unit->getType().airWeapon() != BWAPI::WeaponTypes::None;\n}\n\nbool UnitUtil::CanAttackGround(BWAPI::Unit unit)\n{\n    return unit->getType().groundWeapon() != BWAPI::WeaponTypes::None;\n}\n\ndouble UnitUtil::CalculateLTD(BWAPI::Unit attacker, BWAPI::Unit target)\n{\n    BWAPI::WeaponType weapon = GetWeapon(attacker, target);\n\n    if (weapon == BWAPI::WeaponTypes::None)\n    {\n        return 0;\n    }\n\n    return static_cast<double>(weapon.damageAmount()) / weapon.damageCooldown();\n}\n\nBWAPI::WeaponType UnitUtil::GetWeapon(BWAPI::Unit attacker, BWAPI::Unit target)\n{\n    return target->isFlying() ? attacker->getType().airWeapon() : attacker->getType().groundWeapon();\n}\n\nBWAPI::WeaponType UnitUtil::GetWeapon(BWAPI::UnitType attacker, BWAPI::UnitType target)\n{\n    return target.isFlyer() ? attacker.airWeapon() : attacker.groundWeapon();\n}\n\nint UnitUtil::GetAttackRange(BWAPI::Unit attacker, BWAPI::Unit target)\n{\n    BWAPI::WeaponType weapon = GetWeapon(attacker, target);\n\n    if (weapon == BWAPI::WeaponTypes::None)\n    {\n        return 0;\n    }\n\n    int range = weapon.maxRange();\n\n    if ((attacker->getType() == BWAPI::UnitTypes::Protoss_Dragoon) \n        && (attacker->getPlayer() == BWAPI::Broodwar->self())\n        && BWAPI::Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Singularity_Charge))\n\t{\n\t\trange = 6 * 32;\n\t}\n\n    return range;\n}\n\nint UnitUtil::GetAttackRange(BWAPI::UnitType attacker, BWAPI::UnitType target)\n{\n    BWAPI::WeaponType weapon = GetWeapon(attacker, target);\n\n    if (weapon == BWAPI::WeaponTypes::None)\n    {\n        return 0;\n    }\n\n    return weapon.maxRange();\n}\n\nsize_t UnitUtil::GetAllUnitCount(BWAPI::UnitType type)\n{\n    size_t count = 0;\n    for (const auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        // trivial case: unit which exists matches the type\n        if (unit->getType() == type)\n        {\n            count++;\n        }\n\n        // case where a zerg egg contains the unit type\n        if (unit->getType() == BWAPI::UnitTypes::Zerg_Egg && unit->getBuildType() == type)\n        {\n            count += type.isTwoUnitsInOneEgg() ? 2 : 1;\n        }\n\n        // case where a building has started constructing a unit but it doesn't yet have a unit associated with it\n        if (unit->getRemainingTrainTime() > 0)\n        {\n            BWAPI::UnitType trainType = unit->getLastCommand().getUnitType();\n\n            if (trainType == type && unit->getRemainingTrainTime() == trainType.buildTime())\n            {\n                count++;\n            }\n        }\n    }\n\n    return count;\n}\n\n\nBWAPI::Unit UnitUtil::GetClosestUnitTypeToTarget(BWAPI::UnitType type, BWAPI::Position target)\n{\n\tBWAPI::Unit closestUnit = nullptr;\n\tdouble closestDist = 100000;\n\n\tfor (auto & unit : BWAPI::Broodwar->self()->getUnits())\n\t{\n\t\tif (unit->getType() == type)\n\t\t{\n\t\t\tdouble dist = unit->getDistance(target);\n\t\t\tif (!closestUnit || dist < closestDist)\n\t\t\t{\n\t\t\t\tclosestUnit = unit;\n\t\t\t\tclosestDist = dist;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn closestUnit;\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/UnitUtil.h",
    "content": "#pragma once\n\n#include <BWAPI.h>\n\nnamespace UAlbertaBot\n{\n\nstruct Rect\n{\n    int x, y;\n    int height, width;\n};\n\nnamespace UnitUtil\n{      \n    bool IsCombatUnit(BWAPI::Unit unit);\n    bool IsValidUnit(BWAPI::Unit unit);\n    bool CanAttackAir(BWAPI::Unit unit);\n    bool CanAttackGround(BWAPI::Unit unit);\n    bool CanAttack(BWAPI::Unit attacker, BWAPI::Unit target);\n    int GetAttackRange(BWAPI::Unit attacker, BWAPI::Unit target);\n    int GetAttackRange(BWAPI::UnitType attacker, BWAPI::UnitType target);\n    double CalculateLTD(BWAPI::Unit attacker, BWAPI::Unit target);\n\n    size_t GetAllUnitCount(BWAPI::UnitType type);\n        \n    BWAPI::Unit GetClosestUnitTypeToTarget(BWAPI::UnitType type, BWAPI::Position target);\n    BWAPI::WeaponType GetWeapon(BWAPI::Unit attacker, BWAPI::Unit target);\n    BWAPI::WeaponType GetWeapon(BWAPI::UnitType attacker, BWAPI::UnitType target);\n\n    double GetDistanceBetweenTwoRectangles(Rect & rect1, Rect & rect2);\n    Rect GetRect(BWAPI::Unit unit);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/WorkerData.cpp",
    "content": "#include \"WorkerData.h\"\n#include \"Micro.h\"\n\nusing namespace UAlbertaBot;\n\nWorkerData::WorkerData()\n{\n    for (auto & unit : BWAPI::Broodwar->getAllUnits())\n    {\n        if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field))\n        {\n            m_workersOnMineralPatch[unit] = 0;\n        }\n    }\n}\n\nvoid WorkerData::workerDestroyed(BWAPI::Unit unit)\n{\n    if (!unit) { return; }\n\n    clearPreviousJob(unit);\n    m_workers.erase(unit);\n}\n\nvoid WorkerData::addWorker(BWAPI::Unit unit)\n{\n    if (!unit) { return; }\n\n    m_workers.insert(unit);\n    m_workerJobMap[unit] = Default;\n}\n\nvoid WorkerData::addWorker(BWAPI::Unit unit, WorkerJob job, BWAPI::Unit jobUnit)\n{\n    if (!unit || !jobUnit) { return; }\n\n    assert(m_workers.find(unit) == m_workers.end());\n\n    m_workers.insert(unit);\n    setWorkerJob(unit, job, jobUnit);\n}\n\nvoid WorkerData::addWorker(BWAPI::Unit unit, enum WorkerJob job, BWAPI::UnitType jobUnitType)\n{\n    if (!unit) { return; }\n\n    assert(m_workers.find(unit) == m_workers.end());\n    m_workers.insert(unit);\n    setWorkerJob(unit, job, jobUnitType);\n}\n\nvoid WorkerData::addDepot(BWAPI::Unit unit)\n{\n    if (!unit) { return; }\n\n    assert(m_depots.find(unit) == m_depots.end());\n    m_depots.insert(unit);\n    m_depotWorkerCount[unit] = 0;\n}\n\nvoid WorkerData::removeDepot(BWAPI::Unit unit)\n{\n    if (!unit) { return; }\n\n    m_depots.erase(unit);\n    m_depotWorkerCount.erase(unit);\n\n    // re-balance workers in here\n    for (auto & worker : m_workers)\n    {\n        // if a worker was working at this depot\n        if (m_workerDepotMap[worker] == unit)\n        {\n            setWorkerJob(worker, Idle, nullptr);\n        }\n    }\n}\n\nvoid WorkerData::addToMineralPatch(BWAPI::Unit unit, int num)\n{\n    if (m_workersOnMineralPatch.find(unit) == m_workersOnMineralPatch.end())\n    {\n        m_workersOnMineralPatch[unit] = num;\n    }\n    else\n    {\n        m_workersOnMineralPatch[unit] = m_workersOnMineralPatch[unit] + num;\n    }\n}\n\nvoid WorkerData::setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, BWAPI::Unit jobUnit)\n{\n    if (!unit) { return; }\n\n    clearPreviousJob(unit);\n    m_workerJobMap[unit] = job;\n\n    if (job == Minerals)\n    {\n        // increase the number of workers assigned to this nexus\n        m_depotWorkerCount[jobUnit] += 1;\n\n        // set the mineral the worker is working on\n        m_workerDepotMap[unit] = jobUnit;\n\n        BWAPI::Unit mineralToMine = getMineralToMine(unit);\n        m_workerMineralAssignment[unit] = mineralToMine;\n        addToMineralPatch(mineralToMine, 1);\n\n        // right click the mineral to start mining\n        Micro::SmartRightClick(unit, mineralToMine);\n    }\n    else if (job == Gas)\n    {\n        // increase the count of workers assigned to this refinery\n        m_refineryWorkerCount[jobUnit] += 1;\n\n        // set the refinery the worker is working on\n        m_workerRefineryMap[unit] = jobUnit;\n\n        // right click the refinery to start harvesting\n        Micro::SmartRightClick(unit, jobUnit);\n    }\n    else if (job == Repair)\n    {\n        // only SCVs can repair\n        assert(unit->getType() == BWAPI::UnitTypes::Terran_SCV);\n\n        // set the building the worker is to repair\n        m_workerRepairMap[unit] = jobUnit;\n\n        // start repairing \n        if (!unit->isRepairing())\n        {\n            Micro::SmartRepair(unit, jobUnit);\n        }\n    }\n    else if (job == Scout)\n    {\n\n    }\n    else if (job == Build)\n    {\n        BWAPI::Broodwar->printf(\"Setting worker job to build\");\n    }\n}\n\nvoid WorkerData::setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, BWAPI::UnitType jobUnitType)\n{\n    if (!unit) { return; }\n\n    clearPreviousJob(unit);\n    m_workerJobMap[unit] = job;\n\n    if (job == Build)\n    {\n        m_workerBuildingTypeMap[unit] = jobUnitType;\n    }\n}\n\nvoid WorkerData::setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, WorkerMoveData wmd)\n{\n    if (!unit) { return; }\n\n    clearPreviousJob(unit);\n    m_workerJobMap[unit] = job;\n\n    if (job == Move)\n    {\n        m_workerMoveMap[unit] = wmd;\n    }\n\n    if (m_workerJobMap[unit] != Move)\n    {\n        BWAPI::Broodwar->printf(\"Something went horribly wrong\");\n    }\n}\n\n\nvoid WorkerData::clearPreviousJob(BWAPI::Unit unit)\n{\n    if (!unit) { return; }\n\n    WorkerJob previousJob = getWorkerJob(unit);\n\n    if (previousJob == Minerals)\n    {\n        m_depotWorkerCount[m_workerDepotMap[unit]] -= 1;\n\n        m_workerDepotMap.erase(unit);\n\n        // remove a worker from this unit's assigned mineral patch\n        addToMineralPatch(m_workerMineralAssignment[unit], -1);\n\n        // erase the association from the map\n        m_workerMineralAssignment.erase(unit);\n    }\n    else if (previousJob == Gas)\n    {\n        m_refineryWorkerCount[m_workerRefineryMap[unit]] -= 1;\n        m_workerRefineryMap.erase(unit);\n    }\n    else if (previousJob == Build)\n    {\n        m_workerBuildingTypeMap.erase(unit);\n    }\n    else if (previousJob == Repair)\n    {\n        m_workerRepairMap.erase(unit);\n    }\n    else if (previousJob == Move)\n    {\n        m_workerMoveMap.erase(unit);\n    }\n\n    m_workerJobMap.erase(unit);\n}\n\nint WorkerData::getNumWorkers() const\n{\n    return m_workers.size();\n}\n\nint WorkerData::getNumMineralWorkers() const\n{\n    size_t num = 0;\n    for (auto & unit : m_workers)\n    {\n        if (m_workerJobMap.at(unit) == WorkerData::Minerals)\n        {\n            num++;\n        }\n    }\n    return num;\n}\n\nint WorkerData::getNumGasWorkers() const\n{\n    size_t num = 0;\n    for (auto & unit : m_workers)\n    {\n        if (m_workerJobMap.at(unit) == WorkerData::Gas)\n        {\n            num++;\n        }\n    }\n    return num;\n}\n\nint WorkerData::getNumIdleWorkers() const\n{\n    size_t num = 0;\n    for (auto & unit : m_workers)\n    {\n        if (m_workerJobMap.at(unit) == WorkerData::Idle)\n        {\n            num++;\n        }\n    }\n    return num;\n}\n\n\nenum WorkerData::WorkerJob WorkerData::getWorkerJob(BWAPI::Unit unit)\n{\n    if (!unit) { return Default; }\n\n    std::map<BWAPI::Unit, enum WorkerJob>::iterator it = m_workerJobMap.find(unit);\n\n    if (it != m_workerJobMap.end())\n    {\n        return it->second;\n    }\n\n    return Default;\n}\n\nbool WorkerData::depotIsFull(BWAPI::Unit depot)\n{\n    if (!depot) { return false; }\n\n    int assignedWorkers = getNumAssignedWorkers(depot);\n    int mineralsNearDepot = getMineralsNearDepot(depot);\n\n    if (assignedWorkers >= mineralsNearDepot * 3)\n    {\n        return true;\n    }\n    else\n    {\n        return false;\n    }\n}\n\nBWAPI::Unitset WorkerData::getMineralPatchesNearDepot(BWAPI::Unit depot)\n{\n    // if there are minerals near the depot, add them to the set\n    BWAPI::Unitset mineralsNearDepot;\n\n    int radius = 300;\n\n    for (auto & unit : BWAPI::Broodwar->getAllUnits())\n    {\n        if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field) && unit->getDistance(depot) < radius)\n        {\n            mineralsNearDepot.insert(unit);\n        }\n    }\n\n    // if we didn't find any, use the whole map\n    if (mineralsNearDepot.empty())\n    {\n        for (auto & unit : BWAPI::Broodwar->getAllUnits())\n        {\n            if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field))\n            {\n                mineralsNearDepot.insert(unit);\n            }\n        }\n    }\n\n    return mineralsNearDepot;\n}\n\nint WorkerData::getMineralsNearDepot(BWAPI::Unit depot)\n{\n    if (!depot) { return 0; }\n\n    int mineralsNearDepot = 0;\n\n    for (auto & unit : BWAPI::Broodwar->getAllUnits())\n    {\n        if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field) && unit->getDistance(depot) < 200)\n        {\n            mineralsNearDepot++;\n        }\n    }\n\n    return mineralsNearDepot;\n}\n\nBWAPI::Unit WorkerData::getWorkerResource(BWAPI::Unit unit)\n{\n    if (!unit) { return nullptr; }\n\n    // create the iterator\n    std::map<BWAPI::Unit, BWAPI::Unit>::iterator it;\n\n    // if the worker is mining, set the iterator to the mineral map\n    if (getWorkerJob(unit) == Minerals)\n    {\n        it = m_workerMineralMap.find(unit);\n        if (it != m_workerMineralMap.end())\n        {\n            return it->second;\n        }\n    }\n    else if (getWorkerJob(unit) == Gas)\n    {\n        it = m_workerRefineryMap.find(unit);\n        if (it != m_workerRefineryMap.end())\n        {\n            return it->second;\n        }\n    }\n\n    return nullptr;\n}\n\n\nBWAPI::Unit WorkerData::getMineralToMine(BWAPI::Unit worker)\n{\n    if (!worker) { return nullptr; }\n\n\n    // get the depot associated with this unit\n    BWAPI::Unit depot = getWorkerDepot(worker);\n    BWAPI::Unit bestMineral = nullptr;\n    double bestDist = 100000;\n    double bestNumAssigned = 10000;\n\n    if (depot)\n    {\n        BWAPI::Unitset mineralPatches = getMineralPatchesNearDepot(depot);\n\n        for (auto & mineral : mineralPatches)\n        {\n            double dist = mineral->getDistance(depot);\n            double numAssigned = m_workersOnMineralPatch[mineral];\n\n            if (numAssigned < bestNumAssigned)\n            {\n                bestMineral = mineral;\n                bestDist = dist;\n                bestNumAssigned = numAssigned;\n            }\n            else if (numAssigned == bestNumAssigned)\n            {\n                if (dist < bestDist)\n                {\n                    bestMineral = mineral;\n                    bestDist = dist;\n                    bestNumAssigned = numAssigned;\n                }\n            }\n\n        }\n    }\n\n    return bestMineral;\n}\n/*\nBWAPI::Unit WorkerData::getMineralToMine(BWAPI::Unit worker)\n{\n    if (!worker) { return nullptr; }\n\n    // get the depot associated with this unit\n    BWAPI::Unit depot = getWorkerDepot(worker);\n    BWAPI::Unit mineral = nullptr;\n    double closestDist = 10000;\n\n    if (depot)\n    {\n        BOOST_FOREACH (BWAPI::Unit unit, BWAPI::Broodwar->getAllUnits())\n        {\n            if (unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field && unit->getResources() > 0)\n            {\n                double dist = unit->getDistance(depot);\n\n                if (!mineral || dist < closestDist)\n                {\n                    mineral = unit;\n                    closestDist = dist;\n                }\n            }\n        }\n    }\n\n    return mineral;\n}*/\n\nBWAPI::Unit WorkerData::getWorkerRepairUnit(BWAPI::Unit unit)\n{\n    if (!unit) { return nullptr; }\n\n    std::map<BWAPI::Unit, BWAPI::Unit>::iterator it = m_workerRepairMap.find(unit);\n\n    if (it != m_workerRepairMap.end())\n    {\n        return it->second;\n    }\n\n    return nullptr;\n}\n\nBWAPI::Unit WorkerData::getWorkerDepot(BWAPI::Unit unit)\n{\n    if (!unit) { return nullptr; }\n\n    std::map<BWAPI::Unit, BWAPI::Unit>::iterator it = m_workerDepotMap.find(unit);\n\n    if (it != m_workerDepotMap.end())\n    {\n        return it->second;\n    }\n\n    return nullptr;\n}\n\nBWAPI::UnitType\tWorkerData::getWorkerBuildingType(BWAPI::Unit unit)\n{\n    if (!unit) { return BWAPI::UnitTypes::None; }\n\n    std::map<BWAPI::Unit, BWAPI::UnitType>::iterator it = m_workerBuildingTypeMap.find(unit);\n\n    if (it != m_workerBuildingTypeMap.end())\n    {\n        return it->second;\n    }\n\n    return BWAPI::UnitTypes::None;\n}\n\nWorkerMoveData WorkerData::getWorkerMoveData(BWAPI::Unit unit)\n{\n    std::map<BWAPI::Unit, WorkerMoveData>::iterator it = m_workerMoveMap.find(unit);\n\n    assert(it != m_workerMoveMap.end());\n\n    return (it->second);\n}\n\nint WorkerData::getNumAssignedWorkers(BWAPI::Unit unit)\n{\n    if (!unit) { return 0; }\n\n    std::map<BWAPI::Unit, int>::iterator it;\n\n    // if the worker is mining, set the iterator to the mineral map\n    if (unit->getType().isResourceDepot())\n    {\n        it = m_depotWorkerCount.find(unit);\n\n        // if there is an entry, return it\n        if (it != m_depotWorkerCount.end())\n        {\n            return it->second;\n        }\n    }\n    else if (unit->getType().isRefinery())\n    {\n        it = m_refineryWorkerCount.find(unit);\n\n        // if there is an entry, return it\n        if (it != m_refineryWorkerCount.end())\n        {\n            return it->second;\n        }\n        // otherwise, we are only calling this on completed refineries, so set it\n        else\n        {\n            m_refineryWorkerCount[unit] = 0;\n        }\n    }\n\n    // when all else fails, return 0\n    return 0;\n}\n\nchar WorkerData::getJobCode(BWAPI::Unit unit)\n{\n    if (!unit) { return 'X'; }\n\n    WorkerData::WorkerJob j = getWorkerJob(unit);\n\n    if (j == WorkerData::Build) return 'B';\n    if (j == WorkerData::Combat) return 'C';\n    if (j == WorkerData::Default) return 'D';\n    if (j == WorkerData::Gas) return 'G';\n    if (j == WorkerData::Idle) return 'I';\n    if (j == WorkerData::Minerals) return 'M';\n    if (j == WorkerData::Repair) return 'R';\n    if (j == WorkerData::Move) return 'O';\n    if (j == WorkerData::Scout) return 'S';\n    return 'X';\n}\n\nvoid WorkerData::drawDepotDebugInfo()\n{\n    for (auto & depot : m_depots)\n    {\n        int x = depot->getPosition().x - 64;\n        int y = depot->getPosition().y - 32;\n\n        if (Config::Debug::DrawWorkerInfo) BWAPI::Broodwar->drawBoxMap(x-2, y-1, x+75, y+14, BWAPI::Colors::Black, true);\n        if (Config::Debug::DrawWorkerInfo) BWAPI::Broodwar->drawTextMap(x, y, \"\\x04 Workers: %d\", getNumAssignedWorkers(depot));\n\n        BWAPI::Unitset minerals = getMineralPatchesNearDepot(depot);\n\n        for (auto & mineral : minerals)\n        {\n            int x = mineral->getPosition().x;\n            int y = mineral->getPosition().y;\n\n            if (m_workersOnMineralPatch.find(mineral) != m_workersOnMineralPatch.end())\n            {\n                //if (Config::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawBoxMap(x-2, y-1, x+75, y+14, BWAPI::Colors::Black, true);\n                //if (Config::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawTextMap(x, y, \"\\x04 Workers: %d\", workersOnMineralPatch[mineral]);\n            }\n        }\n    }\n}\n\nconst BWAPI::Unitset & WorkerData::getWorkers() const\n{\n    return m_workers;\n}"
  },
  {
    "path": "UAlbertaBot/Source/WorkerData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\nnamespace UAlbertaBot\n{\nclass WorkerMoveData\n{\npublic:\n\n    int mineralsNeeded  = 0;\n    int gasNeeded       = 0;\n    BWAPI::Position position;\n\n    WorkerMoveData(int m, int g, BWAPI::Position p)\n        : mineralsNeeded(m)\n        , gasNeeded(g)\n        , position(p)\n    {\n\n    }\n\n    WorkerMoveData() {}\n};\n\nclass WorkerData\n{\n\npublic:\n\n    enum WorkerJob { Minerals, Gas, Build, Combat, Idle, Repair, Move, Scout, Default };\n\nprivate:\n\n    BWAPI::Unitset m_workers;\n    BWAPI::Unitset m_depots;\n\n    std::map<BWAPI::Unit, enum WorkerJob>   m_workerJobMap;\n    std::map<BWAPI::Unit, BWAPI::Unit>      m_workerMineralMap;\n    std::map<BWAPI::Unit, BWAPI::Unit>      m_workerDepotMap;\n    std::map<BWAPI::Unit, BWAPI::Unit>      m_workerRefineryMap;\n    std::map<BWAPI::Unit, BWAPI::Unit>      m_workerRepairMap;\n    std::map<BWAPI::Unit, WorkerMoveData>   m_workerMoveMap;\n    std::map<BWAPI::Unit, BWAPI::UnitType>  m_workerBuildingTypeMap;\n\n    std::map<BWAPI::Unit, int>              m_depotWorkerCount;\n    std::map<BWAPI::Unit, int>              m_refineryWorkerCount;\n    std::map<BWAPI::Unit, int>              m_workersOnMineralPatch;\n    std::map<BWAPI::Unit, BWAPI::Unit>      m_workerMineralAssignment;\n\n    void clearPreviousJob(BWAPI::Unit unit);\n\npublic:\n\n    WorkerData();\n\n    void workerDestroyed(BWAPI::Unit unit);\n    void addDepot(BWAPI::Unit unit);\n    void removeDepot(BWAPI::Unit unit);\n    void addWorker(BWAPI::Unit unit);\n    void addWorker(BWAPI::Unit unit, WorkerJob job, BWAPI::Unit jobUnit);\n    void addWorker(BWAPI::Unit unit, enum WorkerJob job, BWAPI::UnitType jobUnitType);\n    void addToMineralPatch(BWAPI::Unit unit, int num);\n    void drawDepotDebugInfo();\n    void setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, BWAPI::Unit jobUnit);\n    void setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, BWAPI::UnitType jobUnitType);\n    void setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, WorkerMoveData wmd);\n\n    int  getNumWorkers() const;\n    int  getNumMineralWorkers() const;\n    int  getNumGasWorkers() const;\n    int  getNumIdleWorkers() const;\n    int  getNumAssignedWorkers(BWAPI::Unit unit);\n    int  getMineralsNearDepot(BWAPI::Unit depot);\n    char getJobCode(BWAPI::Unit unit);\n    bool depotIsFull(BWAPI::Unit depot);\n\n    BWAPI::Unit     getMineralToMine(BWAPI::Unit worker);\n    enum WorkerJob  getWorkerJob(BWAPI::Unit unit);\n    BWAPI::Unit     getWorkerResource(BWAPI::Unit unit);\n    BWAPI::Unit     getWorkerDepot(BWAPI::Unit unit);\n    BWAPI::Unit     getWorkerRepairUnit(BWAPI::Unit unit);\n    BWAPI::UnitType getWorkerBuildingType(BWAPI::Unit unit);\n    WorkerMoveData  getWorkerMoveData(BWAPI::Unit unit);\n    BWAPI::Unitset  getMineralPatchesNearDepot(BWAPI::Unit depot);\n\n    const BWAPI::Unitset & getWorkers() const;\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/WorkerManager.cpp",
    "content": "#include \"Common.h\"\n#include \"WorkerManager.h\"\n#include \"Micro.h\"\n#include \"BaseLocationManager.h\"\n#include \"Global.h\"\n#include \"BuildingData.h\"\n\nusing namespace UAlbertaBot;\n\nWorkerManager::WorkerManager()\n{\n\n}\n\nvoid WorkerManager::onFrame()\n{\n    PROFILE_FUNCTION();\n\n    updateWorkerStatus();\n    handleGasWorkers();\n    handleIdleWorkers();\n    handleMoveWorkers();\n    handleCombatWorkers();\n\n    drawResourceDebugInfo();\n    drawWorkerInformation(450, 20);\n\n    m_workerData.drawDepotDebugInfo();\n\n    handleRepairWorkers();\n}\n\nvoid WorkerManager::updateWorkerStatus()\n{\n    PROFILE_FUNCTION();\n\n    // for each of our Workers\n    for (auto & worker : m_workerData.getWorkers())\n    {\n        if (!worker->isCompleted())\n        {\n            continue;\n        }\n\n        // if it's idle\n        if (worker->isIdle() &&\n            (m_workerData.getWorkerJob(worker) != WorkerData::Build) &&\n            (m_workerData.getWorkerJob(worker) != WorkerData::Move) &&\n            (m_workerData.getWorkerJob(worker) != WorkerData::Scout))\n        {\n            m_workerData.setWorkerJob(worker, WorkerData::Idle, nullptr);\n        }\n\n        // if its job is gas\n        if (m_workerData.getWorkerJob(worker) == WorkerData::Gas)\n        {\n            const BWAPI::Unit refinery = m_workerData.getWorkerResource(worker);\n\n            // if the refinery doesn't exist anymore\n            if (!refinery || !refinery->exists() ||\trefinery->getHitPoints() <= 0)\n            {\n                setMineralWorker(worker);\n            }\n        }\n    }\n}\n\nvoid WorkerManager::setRepairWorker(BWAPI::Unit worker, BWAPI::Unit unitToRepair)\n{\n    m_workerData.setWorkerJob(worker, WorkerData::Repair, unitToRepair);\n}\n\nvoid WorkerManager::stopRepairing(BWAPI::Unit worker)\n{\n    m_workerData.setWorkerJob(worker, WorkerData::Idle, nullptr);\n}\n\nvoid WorkerManager::handleGasWorkers()\n{\n    // for each unit we have\n    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        // if that unit is a refinery\n        if (unit->getType().isRefinery() && unit->isCompleted() && !isGasStealRefinery(unit))\n        {\n            // get the number of workers currently assigned to it\n            const int numAssigned = m_workerData.getNumAssignedWorkers(unit);\n\n            // if it's less than we want it to be, fill 'er up\n            for (int i=0; i<(Config::Macro::WorkersPerRefinery-numAssigned); ++i)\n            {\n                BWAPI::Unit gasWorker = getGasWorker(unit);\n                if (gasWorker)\n                {\n                    m_workerData.setWorkerJob(gasWorker, WorkerData::Gas, unit);\n                }\n            }\n        }\n    }\n\n}\n\nbool WorkerManager::isGasStealRefinery(BWAPI::Unit unit)\n{\n    auto * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy());\n    if (!enemyBaseLocation)\n    {\n        return false;\n    }\n\n    if (enemyBaseLocation->getGeysers().empty())\n    {\n        return false;\n    }\n\n    for (auto & u : enemyBaseLocation->getGeysers())\n    {\n        if (unit->getTilePosition() == u->getTilePosition())\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid WorkerManager::handleIdleWorkers()\n{\n    // for each of our workers\n    for (auto & worker : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n        // if it is idle\n        if (m_workerData.getWorkerJob(worker) == WorkerData::Idle)\n        {\n            // send it to the nearest mineral patch\n            setMineralWorker(worker);\n        }\n    }\n}\n\nvoid WorkerManager::handleRepairWorkers()\n{\n    if (BWAPI::Broodwar->self()->getRace() != BWAPI::Races::Terran)\n    {\n        return;\n    }\n\n    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        if (unit->getType().isBuilding() && (unit->getHitPoints() < unit->getType().maxHitPoints()))\n        {\n            const BWAPI::Unit repairWorker = getClosestMineralWorkerTo(unit);\n            setRepairWorker(repairWorker, unit);\n            break;\n        }\n    }\n}\n\n// bad micro for combat workers\nvoid WorkerManager::handleCombatWorkers()\n{\n    for (auto & worker : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n        if (m_workerData.getWorkerJob(worker) == WorkerData::Combat)\n        {\n            BWAPI::Broodwar->drawCircleMap(worker->getPosition().x, worker->getPosition().y, 4, BWAPI::Colors::Yellow, true);\n            const BWAPI::Unit target = getClosestEnemyUnit(worker);\n\n            if (target)\n            {\n                Micro::SmartAttackUnit(worker, target);\n            }\n        }\n    }\n}\n\nBWAPI::Unit WorkerManager::getClosestEnemyUnit(BWAPI::Unit worker)\n{\n    UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n    BWAPI::Unit closestUnit = nullptr;\n    double closestDist = 10000;\n\n    for (auto & unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        const double dist = unit->getDistance(worker);\n\n        if ((dist < 400) && (!closestUnit || (dist < closestDist)))\n        {\n            closestUnit = unit;\n            closestDist = dist;\n        }\n    }\n\n    return closestUnit;\n}\n\nvoid WorkerManager::finishedWithCombatWorkers()\n{\n    for (auto & worker : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n        if (m_workerData.getWorkerJob(worker) == WorkerData::Combat)\n        {\n            setMineralWorker(worker);\n        }\n    }\n}\n\nBWAPI::Unit WorkerManager::getClosestMineralWorkerTo(BWAPI::Unit enemyUnit)\n{\n    UAB_ASSERT(enemyUnit != nullptr, \"enemyUnit was null\");\n\n    BWAPI::Unit closestMineralWorker = nullptr;\n    double closestDist = 100000;\n\n    if (m_previousClosestWorker)\n    {\n        if (m_previousClosestWorker->getHitPoints() > 0)\n        {\n            return m_previousClosestWorker;\n        }\n    }\n\n    // for each of our workers\n    for (auto & worker : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(worker != nullptr, \"Worker was null\");\n        if (!worker)\n        {\n            continue;\n        }\n        // if it is a move worker\n        if (m_workerData.getWorkerJob(worker) == WorkerData::Minerals)\n        {\n            double dist = worker->getDistance(enemyUnit);\n\n            if (!closestMineralWorker || dist < closestDist)\n            {\n                closestMineralWorker = worker;\n                closestDist = dist;\n            }\n        }\n    }\n\n    m_previousClosestWorker = closestMineralWorker;\n    return closestMineralWorker;\n}\n\nBWAPI::Unit WorkerManager::getWorkerScout()\n{\n    // for each of our workers\n    for (auto & worker : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(worker != nullptr, \"Worker was null\");\n        if (!worker)\n        {\n            continue;\n        }\n        // if it is a move worker\n        if (m_workerData.getWorkerJob(worker) == WorkerData::Scout)\n        {\n            return worker;\n        }\n    }\n\n    return nullptr;\n}\n\nvoid WorkerManager::handleMoveWorkers()\n{\n    // for each of our workers\n    for (auto & worker : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n        // if it is a move worker\n        if (m_workerData.getWorkerJob(worker) == WorkerData::Move)\n        {\n            const WorkerMoveData data = m_workerData.getWorkerMoveData(worker);\n\n            Micro::SmartMove(worker, data.position);\n        }\n    }\n}\n\n// set a worker to mine minerals\nvoid WorkerManager::setMineralWorker(BWAPI::Unit unit)\n{\n    UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n    // check if there is a mineral available to send the worker to\n    BWAPI::Unit depot = getClosestDepot(unit);\n\n    // if there is a valid mineral\n    if (depot)\n    {\n        // update workerData with the new job\n        m_workerData.setWorkerJob(unit, WorkerData::Minerals, depot);\n    }\n    else\n    {\n        // BWAPI::Broodwar->printf(\"No valid depot for mineral worker\");\n    }\n}\n\nBWAPI::Unit WorkerManager::getClosestDepot(BWAPI::Unit worker)\n{\n    UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n    BWAPI::Unit closestDepot = nullptr;\n    double closestDistance = 0;\n\n    for (auto & unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n        if (unit->getType().isResourceDepot() && (unit->isCompleted() || unit->getType() == BWAPI::UnitTypes::Zerg_Lair) && !m_workerData.depotIsFull(unit))\n        {\n            const double distance = unit->getDistance(worker);\n            if (!closestDepot || distance < closestDistance)\n            {\n                closestDepot = unit;\n                closestDistance = distance;\n            }\n        }\n    }\n\n    return closestDepot;\n}\n\n\n// other managers that need workers call this when they're done with a unit\nvoid WorkerManager::finishedWithWorker(BWAPI::Unit unit)\n{\n    UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n    //BWAPI::Broodwar->printf(\"BuildingManager finished with worker %d\", unit->getID());\n    if (m_workerData.getWorkerJob(unit) != WorkerData::Scout)\n    {\n        m_workerData.setWorkerJob(unit, WorkerData::Idle, nullptr);\n    }\n}\n\nBWAPI::Unit WorkerManager::getGasWorker(BWAPI::Unit refinery)\n{\n    UAB_ASSERT(refinery != nullptr, \"Refinery was null\");\n\n    BWAPI::Unit closestWorker = nullptr;\n    double closestDistance = 0;\n\n    for (auto & unit : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n        if (m_workerData.getWorkerJob(unit) == WorkerData::Minerals)\n        {\n            const double distance = unit->getDistance(refinery);\n            if (!closestWorker || distance < closestDistance)\n            {\n                closestWorker = unit;\n                closestDistance = distance;\n            }\n        }\n    }\n\n    return closestWorker;\n}\n\nvoid WorkerManager::setBuildingWorker(BWAPI::Unit worker, Building & b)\n{\n    UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n    m_workerData.setWorkerJob(worker, WorkerData::Build, b.type);\n}\n\n// gets a builder for BuildingManager to use\n// if setJobAsBuilder is true (default), it will be flagged as a builder unit\n// set 'setJobAsBuilder' to false if we just want to see which worker will build a building\nBWAPI::Unit WorkerManager::getBuilder(Building & b, bool setJobAsBuilder)\n{\n    // variables to hold the closest worker of each type to the building\n    BWAPI::Unit closestMovingWorker = nullptr;\n    BWAPI::Unit closestMiningWorker = nullptr;\n    double closestMovingWorkerDistance = 0;\n    double closestMiningWorkerDistance = 0;\n\n    // look through each worker that had moved there first\n    for (auto & unit : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n        // gas steal building uses scout worker\n        if (b.isGasSteal && (m_workerData.getWorkerJob(unit) == WorkerData::Scout))\n        {\n            if (setJobAsBuilder)\n            {\n                m_workerData.setWorkerJob(unit, WorkerData::Build, b.type);\n            }\n            return unit;\n        }\n\n        // mining worker check\n        if (unit->isCompleted() && (m_workerData.getWorkerJob(unit) == WorkerData::Minerals))\n        {\n            // if it is a new closest distance, set the pointer\n            const double distance = unit->getDistance(BWAPI::Position(b.finalPosition));\n            if (!closestMiningWorker || distance < closestMiningWorkerDistance)\n            {\n                closestMiningWorker = unit;\n                closestMiningWorkerDistance = distance;\n            }\n        }\n\n        // moving worker check\n        if (unit->isCompleted() && (m_workerData.getWorkerJob(unit) == WorkerData::Move))\n        {\n            // if it is a new closest distance, set the pointer\n            const double distance = unit->getDistance(BWAPI::Position(b.finalPosition));\n            if (!closestMovingWorker || distance < closestMovingWorkerDistance)\n            {\n                closestMovingWorker = unit;\n                closestMovingWorkerDistance = distance;\n            }\n        }\n    }\n\n    // if we found a moving worker, use it, otherwise using a mining worker\n    BWAPI::Unit chosenWorker = closestMovingWorker ? closestMovingWorker : closestMiningWorker;\n\n    // if the worker exists (one may not have been found in rare cases)\n    if (chosenWorker && setJobAsBuilder)\n    {\n        m_workerData.setWorkerJob(chosenWorker, WorkerData::Build, b.type);\n    }\n\n    // return the worker\n    return chosenWorker;\n}\n\n// sets a worker as a scout\nvoid WorkerManager::setScoutWorker(BWAPI::Unit worker)\n{\n    UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n    m_workerData.setWorkerJob(worker, WorkerData::Scout, nullptr);\n}\n\n// gets a worker which will move to a current location\nBWAPI::Unit WorkerManager::getMoveWorker(BWAPI::Position p)\n{\n    // set up the pointer\n    BWAPI::Unit closestWorker = nullptr;\n    double closestDistance = 0;\n\n    // for each worker we currently have\n    for (auto & unit : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n        // only consider it if it's a mineral worker\n        if (unit->isCompleted() && m_workerData.getWorkerJob(unit) == WorkerData::Minerals)\n        {\n            // if it is a new closest distance, set the pointer\n            const double distance = unit->getDistance(p);\n            if (!closestWorker || distance < closestDistance)\n            {\n                closestWorker = unit;\n                closestDistance = distance;\n            }\n        }\n    }\n\n    // return the worker\n    return closestWorker;\n}\n\n// sets a worker to move to a given location\nvoid WorkerManager::setMoveWorker(int mineralsNeeded, int gasNeeded, BWAPI::Position p)\n{\n    // set up the pointer\n    BWAPI::Unit closestWorker = nullptr;\n    double closestDistance = 0;\n\n    // for each worker we currently have\n    for (auto & unit : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n        // only consider it if it's a mineral worker\n        if (unit->isCompleted() && m_workerData.getWorkerJob(unit) == WorkerData::Minerals)\n        {\n            // if it is a new closest distance, set the pointer\n            const double distance = unit->getDistance(p);\n            if (!closestWorker || distance < closestDistance)\n            {\n                closestWorker = unit;\n                closestDistance = distance;\n            }\n        }\n    }\n\n    if (closestWorker)\n    {\n        //BWAPI::Broodwar->printf(\"Setting worker job Move for worker %d\", closestWorker->getID());\n        m_workerData.setWorkerJob(closestWorker, WorkerData::Move, WorkerMoveData(mineralsNeeded, gasNeeded, p));\n    }\n    else\n    {\n        //BWAPI::Broodwar->printf(\"Error, no worker found\");\n    }\n}\n\n// will we have the required resources by the time a worker can travel a certain distance\nbool WorkerManager::willHaveResources(int mineralsRequired, int gasRequired, double distance)\n{\n    // if we don't require anything, we will have it\n    if (mineralsRequired <= 0 && gasRequired <= 0)\n    {\n        return true;\n    }\n\n    // the speed of the worker unit\n    const double speed = BWAPI::Broodwar->self()->getRace().getWorker().topSpeed();\n\n    UAB_ASSERT(speed > 0, \"Speed is negative\");\n\n    // how many frames it will take us to move to the building location\n    // add a second to account for worker getting stuck. better early than late\n    const double framesToMove = (distance / speed) + 50;\n\n    // magic numbers to predict income rates\n    const double mineralRate = getNumMineralWorkers() * 0.045;\n    const double gasRate     = getNumGasWorkers() * 0.07;\n\n    // calculate if we will have enough by the time the worker gets there\n    if (mineralRate * framesToMove >= mineralsRequired &&\n        gasRate * framesToMove >= gasRequired)\n    {\n        return true;\n    }\n    else\n    {\n        return false;\n    }\n}\n\nvoid WorkerManager::setCombatWorker(BWAPI::Unit worker)\n{\n    UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n    m_workerData.setWorkerJob(worker, WorkerData::Combat, nullptr);\n}\n\nvoid WorkerManager::onUnitMorph(BWAPI::Unit unit)\n{\n    UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n    // if something morphs into a worker, add it\n    if (unit->getType().isWorker() && unit->getPlayer() == BWAPI::Broodwar->self() && unit->getHitPoints() >= 0)\n    {\n        m_workerData.addWorker(unit);\n    }\n\n    // if something morphs into a building, it was a worker?\n    if (unit->getType().isBuilding() && unit->getPlayer() == BWAPI::Broodwar->self() && unit->getPlayer()->getRace() == BWAPI::Races::Zerg)\n    {\n        //BWAPI::Broodwar->printf(\"A Drone started building\");\n        m_workerData.workerDestroyed(unit);\n    }\n}\n\nvoid WorkerManager::onUnitShow(BWAPI::Unit unit)\n{\n    UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n    // add the depot if it exists\n    if (unit->getType().isResourceDepot() && unit->getPlayer() == BWAPI::Broodwar->self())\n    {\n        m_workerData.addDepot(unit);\n    }\n\n    // if something morphs into a worker, add it\n    if (unit->getType().isWorker() && unit->getPlayer() == BWAPI::Broodwar->self() && unit->getHitPoints() >= 0)\n    {\n        //BWAPI::Broodwar->printf(\"A worker was shown %d\", unit->getID());\n        m_workerData.addWorker(unit);\n    }\n}\n\n\nvoid WorkerManager::rebalanceWorkers()\n{\n    // for each worker\n    for (auto & worker : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n        if (!m_workerData.getWorkerJob(worker) == WorkerData::Minerals)\n        {\n            continue;\n        }\n\n        BWAPI::Unit depot = m_workerData.getWorkerDepot(worker);\n\n        if (depot && m_workerData.depotIsFull(depot))\n        {\n            m_workerData.setWorkerJob(worker, WorkerData::Idle, nullptr);\n        }\n        else if (!depot)\n        {\n            m_workerData.setWorkerJob(worker, WorkerData::Idle, nullptr);\n        }\n    }\n}\n\nvoid WorkerManager::onUnitDestroy(BWAPI::Unit unit)\n{\n    UAB_ASSERT(unit != nullptr, \"Unit was null\");\n\n    if (unit->getType().isResourceDepot() && unit->getPlayer() == BWAPI::Broodwar->self())\n    {\n        m_workerData.removeDepot(unit);\n    }\n\n    if (unit->getType().isWorker() && unit->getPlayer() == BWAPI::Broodwar->self())\n    {\n        m_workerData.workerDestroyed(unit);\n    }\n\n    if (unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field)\n    {\n        rebalanceWorkers();\n    }\n}\n\nvoid WorkerManager::drawResourceDebugInfo()\n{\n    if (!Config::Debug::DrawResourceInfo)\n    {\n        return;\n    }\n\n    for (auto & worker : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n        const char job = m_workerData.getJobCode(worker);\n\n        const BWAPI::Position pos = worker->getTargetPosition();\n\n        BWAPI::Broodwar->drawTextMap(worker->getPosition().x, worker->getPosition().y - 5, \"\\x07%c\", job);\n\n        BWAPI::Broodwar->drawLineMap(worker->getPosition().x, worker->getPosition().y, pos.x, pos.y, BWAPI::Colors::Cyan);\n\n        const BWAPI::Unit depot = m_workerData.getWorkerDepot(worker);\n        if (depot)\n        {\n            BWAPI::Broodwar->drawLineMap(worker->getPosition().x, worker->getPosition().y, depot->getPosition().x, depot->getPosition().y, BWAPI::Colors::Orange);\n        }\n    }\n}\n\nvoid WorkerManager::drawWorkerInformation(int x, int y)\n{\n    if (!Config::Debug::DrawWorkerInfo)\n    {\n        return;\n    }\n\n    BWAPI::Broodwar->drawTextScreen(x, y, \"\\x04 Workers %d\", m_workerData.getNumMineralWorkers());\n    BWAPI::Broodwar->drawTextScreen(x, y+20, \"\\x04 UnitID\");\n    BWAPI::Broodwar->drawTextScreen(x+50, y+20, \"\\x04 State\");\n\n    int yspace = 0;\n\n    for (auto & unit : m_workerData.getWorkers())\n    {\n        UAB_ASSERT(unit != nullptr, \"Worker was null\");\n\n        BWAPI::Broodwar->drawTextScreen(x, y+40+((yspace)*10), \"\\x03 %d\", unit->getID());\n        BWAPI::Broodwar->drawTextScreen(x+50, y+40+((yspace++)*10), \"\\x03 %c\", m_workerData.getJobCode(unit));\n    }\n}\n\nbool WorkerManager::isFree(BWAPI::Unit worker)\n{\n    UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n    return m_workerData.getWorkerJob(worker) == WorkerData::Minerals || m_workerData.getWorkerJob(worker) == WorkerData::Idle;\n}\n\nbool WorkerManager::isWorkerScout(BWAPI::Unit worker)\n{\n    UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n    return (m_workerData.getWorkerJob(worker) == WorkerData::Scout);\n}\n\nbool WorkerManager::isBuilder(BWAPI::Unit worker)\n{\n    UAB_ASSERT(worker != nullptr, \"Worker was null\");\n\n    return (m_workerData.getWorkerJob(worker) == WorkerData::Build);\n}\n\nint WorkerManager::getNumMineralWorkers()\n{\n    return m_workerData.getNumMineralWorkers();\n}\n\nint WorkerManager::getNumIdleWorkers()\n{\n    return m_workerData.getNumIdleWorkers();\n}\n\nint WorkerManager::getNumGasWorkers()\n{\n    return m_workerData.getNumGasWorkers();\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/WorkerManager.h",
    "content": "#pragma once\n\n#include <Common.h>\n#include \"WorkerData.h\"\n\nnamespace UAlbertaBot\n{\nclass Building;\n\nclass WorkerManager\n{\n    friend class Global;\n\n    WorkerData  m_workerData;\n    BWAPI::Unit m_previousClosestWorker = nullptr;\n\n    void setMineralWorker(BWAPI::Unit unit);\n    bool isGasStealRefinery(BWAPI::Unit unit);\n\n    void handleIdleWorkers();\n    void handleGasWorkers();\n    void handleMoveWorkers();\n    void handleCombatWorkers();\n    void handleRepairWorkers();\n\n    WorkerManager();\n\npublic:\n\n    void onFrame();\n    void onUnitDestroy(BWAPI::Unit unit);\n    void onUnitMorph(BWAPI::Unit unit);\n    void onUnitShow(BWAPI::Unit unit);\n    void finishedWithWorker(BWAPI::Unit unit);\n    void finishedWithCombatWorkers();\n    void drawResourceDebugInfo();\n    void updateWorkerStatus();\n    void drawWorkerInformation(int x, int y);\n\n    int  getNumMineralWorkers();\n    int  getNumGasWorkers();\n    int  getNumIdleWorkers();\n    void setScoutWorker(BWAPI::Unit worker);\n\n    bool isWorkerScout(BWAPI::Unit worker);\n    bool isFree(BWAPI::Unit worker);\n    bool isBuilder(BWAPI::Unit worker);\n\n    BWAPI::Unit getBuilder(Building & b, bool setJobAsBuilder = true);\n    BWAPI::Unit getMoveWorker(BWAPI::Position p);\n    BWAPI::Unit getClosestDepot(BWAPI::Unit worker);\n    BWAPI::Unit getGasWorker(BWAPI::Unit refinery);\n    BWAPI::Unit getClosestEnemyUnit(BWAPI::Unit worker);\n    BWAPI::Unit getClosestMineralWorkerTo(BWAPI::Unit enemyUnit);\n    BWAPI::Unit getWorkerScout();\n\n    void setBuildingWorker(BWAPI::Unit worker, Building & b);\n    void setRepairWorker(BWAPI::Unit worker, BWAPI::Unit unitToRepair);\n    void stopRepairing(BWAPI::Unit worker);\n    void setMoveWorker(int m, int g, BWAPI::Position p);\n    void setCombatWorker(BWAPI::Unit worker);\n\n    bool willHaveResources(int mineralsRequired, int gasRequired, double distance);\n    void rebalanceWorkers();\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/main.cpp",
    "content": "#include <BWAPI.h>\n#include <BWAPI/Client.h>\n#include \"UAlbertaBotModule.h\"\n#include <iostream>\n#include <thread>\n#include <chrono>\n#include \"Global.h\"\n#include \"../../SparCraft/source/SparCraft.h\"\n#include \"../../BOSS/source/BOSS.h\"\n\nusing namespace BWAPI;\nusing namespace UAlbertaBot;\n\nvoid UAlbertaBot_BWAPIReconnect()\n{\n\twhile (!BWAPIClient.connect())\n\t{\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds{ 1000 });\n\t}\n}\n\nvoid UAlbertaBot_PlayGame()\n{\n    PROFILE_FUNCTION();\n\n\tUAlbertaBotModule bot;\n\n\t// The main game loop, which continues while we are connected to BWAPI and in a game\n\twhile (BWAPI::BWAPIClient.isConnected() && BWAPI::Broodwar->isInGame())\n\t{\n\t\t// Handle each of the events that happened on this frame of the game\n\t\tfor (const BWAPI::Event & e : BWAPI::Broodwar->getEvents())\n\t\t{\n\t\t\tswitch (e.getType())\n\t\t\t{\n\t\t\t\tcase BWAPI::EventType::MatchStart:      { bot.onStart();\t\t\t\t\t  break; }\n\t\t\t\tcase BWAPI::EventType::MatchFrame:      { bot.onFrame();                      break; }\n\t\t\t\tcase BWAPI::EventType::MatchEnd:        { bot.onEnd(e.isWinner());            break; }\n\t\t\t\tcase BWAPI::EventType::UnitShow:        { bot.onUnitShow(e.getUnit());        break; }\n\t\t\t\tcase BWAPI::EventType::UnitHide:        { bot.onUnitHide(e.getUnit());        break; }\n\t\t\t\tcase BWAPI::EventType::UnitCreate:      { bot.onUnitCreate(e.getUnit());      break; }\n\t\t\t\tcase BWAPI::EventType::UnitMorph:       { bot.onUnitMorph(e.getUnit());       break; }\n\t\t\t\tcase BWAPI::EventType::UnitDestroy:     { bot.onUnitDestroy(e.getUnit());     break; }\n\t\t\t\tcase BWAPI::EventType::UnitRenegade:    { bot.onUnitRenegade(e.getUnit());    break; }\n\t\t\t\tcase BWAPI::EventType::UnitComplete:    { bot.onUnitComplete(e.getUnit());    break; }\n\t\t\t\tcase BWAPI::EventType::SendText:        { bot.onSendText(e.getText());        break; }\n\t\t\t}\n\t\t}\n        \n\t\tBWAPI::BWAPIClient.update();\n\t\tif (!BWAPI::BWAPIClient.isConnected())\n\t\t{\n\t\t\tstd::cout << \"Disconnected\\n\";\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tstd::cout << \"Game Over\\n\";\n}\n\n\nint main(int argc, char * argv[])\n{\n    PROFILE_FUNCTION();\n\n\tbool exitIfStarcraftShutdown = true;\n    \n    std::cout << \"UAlbertaBot - David Churchill\\n\";\n    std::cout << \"https://github.com/davechurchill/ualbertabot\\n\\n\";\n    std::cout << \"Compiled on \" << __DATE__ << \" @ \" << __TIME__ << \"\\n\\n\";\n\n    // Initialize SparCraft, the combat simulation package\n    SparCraft::init();\n\n    // Initialize BOSS, the Build Order Search System\n    BOSS::init();\n\n\tsize_t gameCount = 0;\n\twhile (true)\n\t{\n\t\t// if we are not currently connected to BWAPI, try to reconnect\n\t\tif (!BWAPI::BWAPIClient.isConnected())\n\t\t{\n\t\t\tUAlbertaBot_BWAPIReconnect();\n\t\t}\n\n\t\t// if we have connected to BWAPI\n\t\twhile (BWAPI::BWAPIClient.isConnected())\n\t\t{\n\t\t\t// wait for the game to start until the game starts\n\t\t\tstd::cout << \"Waiting for game start\\n\";\n\t\t\twhile (BWAPI::BWAPIClient.isConnected() && !BWAPI::Broodwar->isInGame())\n\t\t\t{\n\t\t\t\tBWAPI::BWAPIClient.update();\n\t\t\t}\n\n\t\t\t// Check to see if Starcraft shut down somehow\n\t\t\tif (BWAPI::BroodwarPtr == nullptr)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// If we are successfully in a game, call the module to play the game\n\t\t\tif (BWAPI::Broodwar->isInGame())\n\t\t\t{\n\t\t\t\tstd::cout << \"Playing game \" << gameCount++ << \" on map \" << BWAPI::Broodwar->mapFileName() << \"\\n\";\n\n\t\t\t\tUAlbertaBot_PlayGame();\n\t\t\t}\n\t\t}\n\n\t\tif (exitIfStarcraftShutdown && !BWAPI::BWAPIClient.isConnected())\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\treturn 0;\n}"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/allocators.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ALLOCATORS_H_\n#define RAPIDJSON_ALLOCATORS_H_\n\n#include \"rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// Allocator\n\n/*! \\class rapidjson::Allocator\n    \\brief Concept for allocating, resizing and freeing memory block.\n    \n    Note that Malloc() and Realloc() are non-static but Free() is static.\n    \n    So if an allocator need to support Free(), it needs to put its pointer in \n    the header of memory block.\n\n\\code\nconcept Allocator {\n    static const bool kNeedFree;    //!< Whether this allocator needs to call Free().\n\n    // Allocate a memory block.\n    // \\param size of the memory block in bytes.\n    // \\returns pointer to the memory block.\n    void* Malloc(size_t size);\n\n    // Resize a memory block.\n    // \\param originalPtr The pointer to current memory block. Null pointer is permitted.\n    // \\param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)\n    // \\param newSize the new size in bytes.\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);\n\n    // Free a memory block.\n    // \\param pointer to the memory block. Null pointer is permitted.\n    static void Free(void *ptr);\n};\n\\endcode\n*/\n\n///////////////////////////////////////////////////////////////////////////////\n// CrtAllocator\n\n//! C-runtime library allocator.\n/*! This class is just wrapper for standard C library memory routines.\n    \\note implements Allocator concept\n*/\nclass CrtAllocator {\npublic:\n    static const bool kNeedFree = true;\n    void* Malloc(size_t size) { \n        if (size) //  behavior of malloc(0) is implementation defined.\n            return std::malloc(size);\n        else\n            return NULL; // standardize to returning NULL.\n    }\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {\n        (void)originalSize;\n        if (newSize == 0) {\n            std::free(originalPtr);\n            return NULL;\n        }\n        return std::realloc(originalPtr, newSize);\n    }\n    static void Free(void *ptr) { std::free(ptr); }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// MemoryPoolAllocator\n\n//! Default memory allocator used by the parser and DOM.\n/*! This allocator allocate memory blocks from pre-allocated memory chunks. \n\n    It does not free memory blocks. And Realloc() only allocate new memory.\n\n    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.\n\n    User may also supply a buffer as the first chunk.\n\n    If the user-buffer is full then additional chunks are allocated by BaseAllocator.\n\n    The user-buffer is not deallocated by this allocator.\n\n    \\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.\n    \\note implements Allocator concept\n*/\ntemplate <typename BaseAllocator = CrtAllocator>\nclass MemoryPoolAllocator {\npublic:\n    static const bool kNeedFree = false;    //!< Tell users that no need to call Free() with this allocator. (concept Allocator)\n\n    //! Constructor with chunkSize.\n    /*! \\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.\n        \\param baseAllocator The allocator for allocating memory chunks.\n    */\n    MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : \n        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)\n    {\n    }\n\n    //! Constructor with user-supplied buffer.\n    /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.\n\n        The user buffer will not be deallocated when this allocator is destructed.\n\n        \\param buffer User supplied buffer.\n        \\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).\n        \\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.\n        \\param baseAllocator The allocator for allocating memory chunks.\n    */\n    MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :\n        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)\n    {\n        RAPIDJSON_ASSERT(buffer != 0);\n        RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));\n        chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);\n        chunkHead_->capacity = size - sizeof(ChunkHeader);\n        chunkHead_->size = 0;\n        chunkHead_->next = 0;\n    }\n\n    //! Destructor.\n    /*! This deallocates all memory chunks, excluding the user-supplied buffer.\n    */\n    ~MemoryPoolAllocator() {\n        Clear();\n        RAPIDJSON_DELETE(ownBaseAllocator_);\n    }\n\n    //! Deallocates all memory chunks, excluding the user-supplied buffer.\n    void Clear() {\n        while (chunkHead_ && chunkHead_ != userBuffer_) {\n            ChunkHeader* next = chunkHead_->next;\n            baseAllocator_->Free(chunkHead_);\n            chunkHead_ = next;\n        }\n        if (chunkHead_ && chunkHead_ == userBuffer_)\n            chunkHead_->size = 0; // Clear user buffer\n    }\n\n    //! Computes the total capacity of allocated memory chunks.\n    /*! \\return total capacity in bytes.\n    */\n    size_t Capacity() const {\n        size_t capacity = 0;\n        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)\n            capacity += c->capacity;\n        return capacity;\n    }\n\n    //! Computes the memory blocks allocated.\n    /*! \\return total used bytes.\n    */\n    size_t Size() const {\n        size_t size = 0;\n        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)\n            size += c->size;\n        return size;\n    }\n\n    //! Allocates a memory block. (concept Allocator)\n    void* Malloc(size_t size) {\n        if (!size)\n            return NULL;\n\n        size = RAPIDJSON_ALIGN(size);\n        if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)\n            AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);\n\n        void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;\n        chunkHead_->size += size;\n        return buffer;\n    }\n\n    //! Resizes a memory block (concept Allocator)\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {\n        if (originalPtr == 0)\n            return Malloc(newSize);\n\n        if (newSize == 0)\n            return NULL;\n\n        // Do not shrink if new size is smaller than original\n        if (originalSize >= newSize)\n            return originalPtr;\n\n        // Simply expand it if it is the last allocation and there is sufficient space\n        if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {\n            size_t increment = static_cast<size_t>(newSize - originalSize);\n            increment = RAPIDJSON_ALIGN(increment);\n            if (chunkHead_->size + increment <= chunkHead_->capacity) {\n                chunkHead_->size += increment;\n                return originalPtr;\n            }\n        }\n\n        // Realloc process: allocate and copy memory, do not free original buffer.\n        void* newBuffer = Malloc(newSize);\n        RAPIDJSON_ASSERT(newBuffer != 0);   // Do not handle out-of-memory explicitly.\n        if (originalSize)\n            std::memcpy(newBuffer, originalPtr, originalSize);\n        return newBuffer;\n    }\n\n    //! Frees a memory block (concept Allocator)\n    static void Free(void *ptr) { (void)ptr; } // Do nothing\n\nprivate:\n    //! Copy constructor is not permitted.\n    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;\n    //! Copy assignment operator is not permitted.\n    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;\n\n    //! Creates a new chunk.\n    /*! \\param capacity Capacity of the chunk in bytes.\n    */\n    void AddChunk(size_t capacity) {\n        if (!baseAllocator_)\n            ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());\n        ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));\n        chunk->capacity = capacity;\n        chunk->size = 0;\n        chunk->next = chunkHead_;\n        chunkHead_ =  chunk;\n    }\n\n    static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.\n\n    //! Chunk header for perpending to each chunk.\n    /*! Chunks are stored as a singly linked list.\n    */\n    struct ChunkHeader {\n        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).\n        size_t size;        //!< Current size of allocated memory in bytes.\n        ChunkHeader *next;  //!< Next chunk in the linked list.\n    };\n\n    ChunkHeader *chunkHead_;    //!< Head of the chunk linked-list. Only the head chunk serves allocation.\n    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.\n    void *userBuffer_;          //!< User supplied buffer.\n    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.\n    BaseAllocator* ownBaseAllocator_;   //!< base allocator created by this object.\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ENCODINGS_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/document.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_DOCUMENT_H_\n#define RAPIDJSON_DOCUMENT_H_\n\n/*! \\file document.h */\n\n#include \"reader.h\"\n#include \"internal/meta.h\"\n#include \"internal/strfunc.h\"\n#include <new>      // placement new\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4127) // conditional expression is constant\n#elif defined(__GNUC__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_HAS_STDSTRING\n\n#ifndef RAPIDJSON_HAS_STDSTRING\n#ifdef RAPIDJSON_DOXYGEN_RUNNING\n#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation\n#else\n#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default\n#endif\n/*! \\def RAPIDJSON_HAS_STDSTRING\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Enable RapidJSON support for \\c std::string\n\n    By defining this preprocessor symbol to \\c 1, several convenience functions for using\n    \\ref rapidjson::GenericValue with \\c std::string are enabled, especially\n    for construction and comparison.\n\n    \\hideinitializer\n*/\n#endif // !defined(RAPIDJSON_HAS_STDSTRING)\n\n#if RAPIDJSON_HAS_STDSTRING\n#include <string>\n#endif // RAPIDJSON_HAS_STDSTRING\n\n#ifndef RAPIDJSON_NOMEMBERITERATORCLASS\n#include <iterator> // std::iterator, std::random_access_iterator_tag\n#endif\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n#include <utility> // std::move\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n// Forward declaration.\ntemplate <typename Encoding, typename Allocator>\nclass GenericValue;\n\n//! Name-value pair in a JSON object value.\n/*!\n    This class was internal to GenericValue. It used to be a inner struct.\n    But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.\n    https://code.google.com/p/rapidjson/issues/detail?id=64\n*/\ntemplate <typename Encoding, typename Allocator> \nstruct GenericMember { \n    GenericValue<Encoding, Allocator> name;     //!< name of member (must be a string)\n    GenericValue<Encoding, Allocator> value;    //!< value of member.\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericMemberIterator\n\n#ifndef RAPIDJSON_NOMEMBERITERATORCLASS\n\n//! (Constant) member iterator for a JSON object value\n/*!\n    \\tparam Const Is this a constant iterator?\n    \\tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)\n    \\tparam Allocator   Allocator type for allocating memory of object, array and string.\n\n    This class implements a Random Access Iterator for GenericMember elements\n    of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].\n\n    \\note This iterator implementation is mainly intended to avoid implicit\n        conversions from iterator values to \\c NULL,\n        e.g. from GenericValue::FindMember.\n\n    \\note Define \\c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a\n        pointer-based implementation, if your platform doesn't provide\n        the C++ <iterator> header.\n\n    \\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator\n */\ntemplate <bool Const, typename Encoding, typename Allocator>\nclass GenericMemberIterator\n    : public std::iterator<std::random_access_iterator_tag\n        , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {\n\n    friend class GenericValue<Encoding,Allocator>;\n    template <bool, typename, typename> friend class GenericMemberIterator;\n\n    typedef GenericMember<Encoding,Allocator> PlainType;\n    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;\n    typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;\n\npublic:\n    //! Iterator type itself\n    typedef GenericMemberIterator Iterator;\n    //! Constant iterator type\n    typedef GenericMemberIterator<true,Encoding,Allocator>  ConstIterator;\n    //! Non-constant iterator type\n    typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;\n\n    //! Pointer to (const) GenericMember\n    typedef typename BaseType::pointer         Pointer;\n    //! Reference to (const) GenericMember\n    typedef typename BaseType::reference       Reference;\n    //! Signed integer type (e.g. \\c ptrdiff_t)\n    typedef typename BaseType::difference_type DifferenceType;\n\n    //! Default constructor (singular value)\n    /*! Creates an iterator pointing to no element.\n        \\note All operations, except for comparisons, are undefined on such values.\n     */\n    GenericMemberIterator() : ptr_() {}\n\n    //! Iterator conversions to more const\n    /*!\n        \\param it (Non-const) iterator to copy from\n\n        Allows the creation of an iterator from another GenericMemberIterator\n        that is \"less const\".  Especially, creating a non-constant iterator\n        from a constant iterator are disabled:\n        \\li const -> non-const (not ok)\n        \\li const -> const (ok)\n        \\li non-const -> const (ok)\n        \\li non-const -> non-const (ok)\n\n        \\note If the \\c Const template parameter is already \\c false, this\n            constructor effectively defines a regular copy-constructor.\n            Otherwise, the copy constructor is implicitly defined.\n    */\n    GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}\n\n    //! @name stepping\n    //@{\n    Iterator& operator++(){ ++ptr_; return *this; }\n    Iterator& operator--(){ --ptr_; return *this; }\n    Iterator  operator++(int){ Iterator old(*this); ++ptr_; return old; }\n    Iterator  operator--(int){ Iterator old(*this); --ptr_; return old; }\n    //@}\n\n    //! @name increment/decrement\n    //@{\n    Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }\n    Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }\n\n    Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }\n    Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }\n    //@}\n\n    //! @name relations\n    //@{\n    bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }\n    bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }\n    bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }\n    bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }\n    bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }\n    bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }\n    //@}\n\n    //! @name dereference\n    //@{\n    Reference operator*() const { return *ptr_; }\n    Pointer   operator->() const { return ptr_; }\n    Reference operator[](DifferenceType n) const { return ptr_[n]; }\n    //@}\n\n    //! Distance\n    DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }\n\nprivate:\n    //! Internal constructor from plain pointer\n    explicit GenericMemberIterator(Pointer p) : ptr_(p) {}\n\n    Pointer ptr_; //!< raw pointer\n};\n\n#else // RAPIDJSON_NOMEMBERITERATORCLASS\n\n// class-based member iterator implementation disabled, use plain pointers\n\ntemplate <bool Const, typename Encoding, typename Allocator>\nstruct GenericMemberIterator;\n\n//! non-const GenericMemberIterator\ntemplate <typename Encoding, typename Allocator>\nstruct GenericMemberIterator<false,Encoding,Allocator> {\n    //! use plain pointer as iterator type\n    typedef GenericMember<Encoding,Allocator>* Iterator;\n};\n//! const GenericMemberIterator\ntemplate <typename Encoding, typename Allocator>\nstruct GenericMemberIterator<true,Encoding,Allocator> {\n    //! use plain const pointer as iterator type\n    typedef const GenericMember<Encoding,Allocator>* Iterator;\n};\n\n#endif // RAPIDJSON_NOMEMBERITERATORCLASS\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericStringRef\n\n//! Reference to a constant string (not taking a copy)\n/*!\n    \\tparam CharType character type of the string\n\n    This helper class is used to automatically infer constant string\n    references for string literals, especially from \\c const \\b (!)\n    character arrays.\n\n    The main use is for creating JSON string values without copying the\n    source string via an \\ref Allocator.  This requires that the referenced\n    string pointers have a sufficient lifetime, which exceeds the lifetime\n    of the associated GenericValue.\n\n    \\b Example\n    \\code\n    Value v(\"foo\");   // ok, no need to copy & calculate length\n    const char foo[] = \"foo\";\n    v.SetString(foo); // ok\n\n    const char* bar = foo;\n    // Value x(bar); // not ok, can't rely on bar's lifetime\n    Value x(StringRef(bar)); // lifetime explicitly guaranteed by user\n    Value y(StringRef(bar, 3));  // ok, explicitly pass length\n    \\endcode\n\n    \\see StringRef, GenericValue::SetString\n*/\ntemplate<typename CharType>\nstruct GenericStringRef {\n    typedef CharType Ch; //!< character type of the string\n\n    //! Create string reference from \\c const character array\n    /*!\n        This constructor implicitly creates a constant string reference from\n        a \\c const character array.  It has better performance than\n        \\ref StringRef(const CharType*) by inferring the string \\ref length\n        from the array length, and also supports strings containing null\n        characters.\n\n        \\tparam N length of the string, automatically inferred\n\n        \\param str Constant character array, lifetime assumed to be longer\n            than the use of the string in e.g. a GenericValue\n\n        \\post \\ref s == str\n\n        \\note Constant complexity.\n        \\note There is a hidden, private overload to disallow references to\n            non-const character arrays to be created via this constructor.\n            By this, e.g. function-scope arrays used to be filled via\n            \\c snprintf are excluded from consideration.\n            In such cases, the referenced string should be \\b copied to the\n            GenericValue instead.\n     */\n    template<SizeType N>\n    GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT\n        : s(str), length(N-1) {}\n\n    //! Explicitly create string reference from \\c const character pointer\n    /*!\n        This constructor can be used to \\b explicitly  create a reference to\n        a constant string pointer.\n\n        \\see StringRef(const CharType*)\n\n        \\param str Constant character pointer, lifetime assumed to be longer\n            than the use of the string in e.g. a GenericValue\n\n        \\post \\ref s == str\n\n        \\note There is a hidden, private overload to disallow references to\n            non-const character arrays to be created via this constructor.\n            By this, e.g. function-scope arrays used to be filled via\n            \\c snprintf are excluded from consideration.\n            In such cases, the referenced string should be \\b copied to the\n            GenericValue instead.\n     */\n    explicit GenericStringRef(const CharType* str)\n        : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }\n\n    //! Create constant string reference from pointer and length\n    /*! \\param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n        \\param len length of the string, excluding the trailing NULL terminator\n\n        \\post \\ref s == str && \\ref length == len\n        \\note Constant complexity.\n     */\n    GenericStringRef(const CharType* str, SizeType len)\n        : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }\n\n    //! implicit conversion to plain CharType pointer\n    operator const Ch *() const { return s; }\n\n    const Ch* const s; //!< plain CharType pointer\n    const SizeType length; //!< length of the string (excluding the trailing NULL terminator)\n\nprivate:\n    //! Disallow copy-assignment\n    GenericStringRef operator=(const GenericStringRef&);\n    //! Disallow construction from non-const array\n    template<SizeType N>\n    GenericStringRef(CharType (&str)[N]) /* = delete */;\n};\n\n//! Mark a character pointer as constant string\n/*! Mark a plain character pointer as a \"string literal\".  This function\n    can be used to avoid copying a character string to be referenced as a\n    value in a JSON GenericValue object, if the string's lifetime is known\n    to be valid long enough.\n    \\tparam CharType Character type of the string\n    \\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n    \\return GenericStringRef string reference object\n    \\relatesalso GenericStringRef\n\n    \\see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember\n*/\ntemplate<typename CharType>\ninline GenericStringRef<CharType> StringRef(const CharType* str) {\n    return GenericStringRef<CharType>(str, internal::StrLen(str));\n}\n\n//! Mark a character pointer as constant string\n/*! Mark a plain character pointer as a \"string literal\".  This function\n    can be used to avoid copying a character string to be referenced as a\n    value in a JSON GenericValue object, if the string's lifetime is known\n    to be valid long enough.\n\n    This version has better performance with supplied length, and also\n    supports string containing null characters.\n\n    \\tparam CharType character type of the string\n    \\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n    \\param length The length of source string.\n    \\return GenericStringRef string reference object\n    \\relatesalso GenericStringRef\n*/\ntemplate<typename CharType>\ninline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {\n    return GenericStringRef<CharType>(str, SizeType(length));\n}\n\n#if RAPIDJSON_HAS_STDSTRING\n//! Mark a string object as constant string\n/*! Mark a string object (e.g. \\c std::string) as a \"string literal\".\n    This function can be used to avoid copying a string to be referenced as a\n    value in a JSON GenericValue object, if the string's lifetime is known\n    to be valid long enough.\n\n    \\tparam CharType character type of the string\n    \\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n    \\return GenericStringRef string reference object\n    \\relatesalso GenericStringRef\n    \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n*/\ntemplate<typename CharType>\ninline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {\n    return GenericStringRef<CharType>(str.data(), SizeType(str.size()));\n}\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericValue type traits\nnamespace internal {\n\ntemplate <typename T, typename Encoding = void, typename Allocator = void>\nstruct IsGenericValueImpl : FalseType {};\n\n// select candidates according to nested encoding and allocator types\ntemplate <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>\n    : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};\n\n// helper to match arbitrary GenericValue instantiations, including derived classes\ntemplate <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};\n\n} // namespace internal\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericValue\n\n//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.\n/*!\n    A JSON value can be one of 7 types. This class is a variant type supporting\n    these types.\n\n    Use the Value if UTF8 and default allocator\n\n    \\tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)\n    \\tparam Allocator   Allocator type for allocating memory of object, array and string.\n*/\ntemplate <typename Encoding, typename Allocator = MemoryPoolAllocator<> > \nclass GenericValue {\npublic:\n    //! Name-value pair in an object.\n    typedef GenericMember<Encoding, Allocator> Member;\n    typedef Encoding EncodingType;                  //!< Encoding type from template parameter.\n    typedef Allocator AllocatorType;                //!< Allocator type from template parameter.\n    typedef typename Encoding::Ch Ch;               //!< Character type derived from Encoding.\n    typedef GenericStringRef<Ch> StringRefType;     //!< Reference to a constant string\n    typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator;  //!< Member iterator for iterating in object.\n    typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator;  //!< Constant member iterator for iterating in object.\n    typedef GenericValue* ValueIterator;            //!< Value iterator for iterating in array.\n    typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.\n    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of itself.\n\n    //!@name Constructors and destructor.\n    //@{\n\n    //! Default constructor creates a null value.\n    GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {}\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move constructor in C++11\n    GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) {\n        rhs.flags_ = kNullFlag; // give up contents\n    }\n#endif\n\nprivate:\n    //! Copy constructor is not permitted.\n    GenericValue(const GenericValue& rhs);\n\npublic:\n\n    //! Constructor with JSON value type.\n    /*! This creates a Value of specified type with default content.\n        \\param type Type of the value.\n        \\note Default content for number is zero.\n    */\n    explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {\n        static const unsigned defaultFlags[7] = {\n            kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,\n            kNumberAnyFlag\n        };\n        RAPIDJSON_ASSERT(type <= kNumberType);\n        flags_ = defaultFlags[type];\n\n        // Use ShortString to store empty string.\n        if (type == kStringType)\n            data_.ss.SetLength(0);\n    }\n\n    //! Explicit copy constructor (with allocator)\n    /*! Creates a copy of a Value by using the given Allocator\n        \\tparam SourceAllocator allocator of \\c rhs\n        \\param rhs Value to copy from (read-only)\n        \\param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().\n        \\see CopyFrom()\n    */\n    template< typename SourceAllocator >\n    GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);\n\n    //! Constructor for boolean value.\n    /*! \\param b Boolean value\n        \\note This constructor is limited to \\em real boolean values and rejects\n            implicitly converted types like arbitrary pointers.  Use an explicit cast\n            to \\c bool, if you want to construct a boolean JSON value in such cases.\n     */\n#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen\n    template <typename T>\n    explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>))) RAPIDJSON_NOEXCEPT\n#else\n    explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT\n#endif\n        : data_(), flags_(b ? kTrueFlag : kFalseFlag) {\n            // safe-guard against failing SFINAE\n            RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));\n    }\n\n    //! Constructor for int value.\n    explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) {\n        data_.n.i64 = i;\n        if (i >= 0)\n            flags_ |= kUintFlag | kUint64Flag;\n    }\n\n    //! Constructor for unsigned value.\n    explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) {\n        data_.n.u64 = u; \n        if (!(u & 0x80000000))\n            flags_ |= kIntFlag | kInt64Flag;\n    }\n\n    //! Constructor for int64_t value.\n    explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) {\n        data_.n.i64 = i64;\n        if (i64 >= 0) {\n            flags_ |= kNumberUint64Flag;\n            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))\n                flags_ |= kUintFlag;\n            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))\n                flags_ |= kIntFlag;\n        }\n        else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))\n            flags_ |= kIntFlag;\n    }\n\n    //! Constructor for uint64_t value.\n    explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {\n        data_.n.u64 = u64;\n        if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))\n            flags_ |= kInt64Flag;\n        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))\n            flags_ |= kUintFlag;\n        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))\n            flags_ |= kIntFlag;\n    }\n\n    //! Constructor for double value.\n    explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }\n\n    //! Constructor for constant string (i.e. do not make a copy of string)\n    GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); }\n\n    //! Constructor for constant string (i.e. do not make a copy of string)\n    explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); }\n\n    //! Constructor for copy-string (i.e. do make a copy of string)\n    GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); }\n\n    //! Constructor for copy-string (i.e. do make a copy of string)\n    GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Constructor for copy-string from a string object (i.e. do make a copy of string)\n    /*! \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n     */\n    GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }\n#endif\n\n    //! Destructor.\n    /*! Need to destruct elements of array, members of object, or copy-string.\n    */\n    ~GenericValue() {\n        if (Allocator::kNeedFree) { // Shortcut by Allocator's trait\n            switch(flags_) {\n            case kArrayFlag:\n                for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)\n                    v->~GenericValue();\n                Allocator::Free(data_.a.elements);\n                break;\n\n            case kObjectFlag:\n                for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)\n                    m->~Member();\n                Allocator::Free(data_.o.members);\n                break;\n\n            case kCopyStringFlag:\n                Allocator::Free(const_cast<Ch*>(data_.s.str));\n                break;\n\n            default:\n                break;  // Do nothing for other types.\n            }\n        }\n    }\n\n    //@}\n\n    //!@name Assignment operators\n    //@{\n\n    //! Assignment with move semantics.\n    /*! \\param rhs Source of the assignment. It will become a null value after assignment.\n    */\n    GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {\n        RAPIDJSON_ASSERT(this != &rhs);\n        this->~GenericValue();\n        RawAssign(rhs);\n        return *this;\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move assignment in C++11\n    GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {\n        return *this = rhs.Move();\n    }\n#endif\n\n    //! Assignment of constant string reference (no copy)\n    /*! \\param str Constant string reference to be assigned\n        \\note This overload is needed to avoid clashes with the generic primitive type assignment overload below.\n        \\see GenericStringRef, operator=(T)\n    */\n    GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {\n        GenericValue s(str);\n        return *this = s;\n    }\n\n    //! Assignment with primitive types.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param value The value to be assigned.\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref SetString(const Ch*, Allocator&) (for copying) or\n            \\ref StringRef() (to explicitly mark the pointer as constant) instead.\n            All other pointer types would implicitly convert to \\c bool,\n            use \\ref SetBool() instead.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))\n    operator=(T value) {\n        GenericValue v(value);\n        return *this = v;\n    }\n\n    //! Deep-copy assignment from Value\n    /*! Assigns a \\b copy of the Value to the current Value object\n        \\tparam SourceAllocator Allocator type of \\c rhs\n        \\param rhs Value to copy from (read-only)\n        \\param allocator Allocator to use for copying\n     */\n    template <typename SourceAllocator>\n    GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {\n        RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);\n        this->~GenericValue();\n        new (this) GenericValue(rhs, allocator);\n        return *this;\n    }\n\n    //! Exchange the contents of this value with those of other.\n    /*!\n        \\param other Another value.\n        \\note Constant complexity.\n    */\n    GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {\n        GenericValue temp;\n        temp.RawAssign(*this);\n        RawAssign(other);\n        other.RawAssign(temp);\n        return *this;\n    }\n\n    //! Prepare Value for move semantics\n    /*! \\return *this */\n    GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }\n    //@}\n\n    //!@name Equal-to and not-equal-to operators\n    //@{\n    //! Equal-to operator\n    /*!\n        \\note If an object contains duplicated named member, comparing equality with any object is always \\c false.\n        \\note Linear time complexity (number of all values in the subtree and total lengths of all strings).\n    */\n    template <typename SourceAllocator>\n    bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {\n        typedef GenericValue<Encoding, SourceAllocator> RhsType;\n        if (GetType() != rhs.GetType())\n            return false;\n\n        switch (GetType()) {\n        case kObjectType: // Warning: O(n^2) inner-loop\n            if (data_.o.size != rhs.data_.o.size)\n                return false;           \n            for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {\n                typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);\n                if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)\n                    return false;\n            }\n            return true;\n            \n        case kArrayType:\n            if (data_.a.size != rhs.data_.a.size)\n                return false;\n            for (SizeType i = 0; i < data_.a.size; i++)\n                if ((*this)[i] != rhs[i])\n                    return false;\n            return true;\n\n        case kStringType:\n            return StringEqual(rhs);\n\n        case kNumberType:\n            if (IsDouble() || rhs.IsDouble()) {\n                double a = GetDouble();     // May convert from integer to double.\n                double b = rhs.GetDouble(); // Ditto\n                return a >= b && a <= b;    // Prevent -Wfloat-equal\n            }\n            else\n                return data_.n.u64 == rhs.data_.n.u64;\n\n        default: // kTrueType, kFalseType, kNullType\n            return true;\n        }\n    }\n\n    //! Equal-to operator with const C-string pointer\n    bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Equal-to operator with string object\n    /*! \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n     */\n    bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }\n#endif\n\n    //! Equal-to operator with primitive types\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c double, \\c true, \\c false\n    */\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }\n\n    //! Not-equal-to operator\n    /*! \\return !(*this == rhs)\n     */\n    template <typename SourceAllocator>\n    bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }\n\n    //! Not-equal-to operator with const C-string pointer\n    bool operator!=(const Ch* rhs) const { return !(*this == rhs); }\n\n    //! Not-equal-to operator with arbitrary types\n    /*! \\return !(*this == rhs)\n     */\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }\n\n    //! Equal-to operator with arbitrary types (symmetric version)\n    /*! \\return (rhs == lhs)\n     */\n    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }\n\n    //! Not-Equal-to operator with arbitrary types (symmetric version)\n    /*! \\return !(rhs == lhs)\n     */\n    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }\n    //@}\n\n    //!@name Type\n    //@{\n\n    Type GetType()  const { return static_cast<Type>(flags_ & kTypeMask); }\n    bool IsNull()   const { return flags_ == kNullFlag; }\n    bool IsFalse()  const { return flags_ == kFalseFlag; }\n    bool IsTrue()   const { return flags_ == kTrueFlag; }\n    bool IsBool()   const { return (flags_ & kBoolFlag) != 0; }\n    bool IsObject() const { return flags_ == kObjectFlag; }\n    bool IsArray()  const { return flags_ == kArrayFlag; }\n    bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }\n    bool IsInt()    const { return (flags_ & kIntFlag) != 0; }\n    bool IsUint()   const { return (flags_ & kUintFlag) != 0; }\n    bool IsInt64()  const { return (flags_ & kInt64Flag) != 0; }\n    bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }\n    bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }\n    bool IsString() const { return (flags_ & kStringFlag) != 0; }\n\n    //@}\n\n    //!@name Null\n    //@{\n\n    GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }\n\n    //@}\n\n    //!@name Bool\n    //@{\n\n    bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }\n    //!< Set boolean value\n    /*! \\post IsBool() == true */\n    GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }\n\n    //@}\n\n    //!@name Object\n    //@{\n\n    //! Set this value as an empty object.\n    /*! \\post IsObject() == true */\n    GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }\n\n    //! Get the number of members in the object.\n    SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }\n\n    //! Check whether the object is empty.\n    bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }\n\n    //! Get a value from an object associated with the name.\n    /*! \\pre IsObject() == true\n        \\tparam T Either \\c Ch or \\c const \\c Ch (template used for disambiguation with \\ref operator[](SizeType))\n        \\note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.\n        Since 0.2, if the name is not correct, it will assert.\n        If user is unsure whether a member exists, user should use HasMember() first.\n        A better approach is to use FindMember().\n        \\note Linear time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {\n        GenericValue n(StringRef(name));\n        return (*this)[n];\n    }\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }\n\n    //! Get a value from an object associated with the name.\n    /*! \\pre IsObject() == true\n        \\tparam SourceAllocator Allocator of the \\c name value\n\n        \\note Compared to \\ref operator[](T*), this version is faster because it does not need a StrLen().\n        And it can also handle strings with embedded null characters.\n\n        \\note Linear time complexity.\n    */\n    template <typename SourceAllocator>\n    GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {\n        MemberIterator member = FindMember(name);\n        if (member != MemberEnd())\n            return member->value;\n        else {\n            RAPIDJSON_ASSERT(false);    // see above note\n            static GenericValue NullValue;\n            return NullValue;\n        }\n    }\n    template <typename SourceAllocator>\n    const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Get a value from an object associated with name (string object).\n    GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }\n    const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }\n#endif\n\n    //! Const member iterator\n    /*! \\pre IsObject() == true */\n    ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }\n    //! Const \\em past-the-end member iterator\n    /*! \\pre IsObject() == true */\n    ConstMemberIterator MemberEnd() const   { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); }\n    //! Member iterator\n    /*! \\pre IsObject() == true */\n    MemberIterator MemberBegin()            { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); }\n    //! \\em Past-the-end member iterator\n    /*! \\pre IsObject() == true */\n    MemberIterator MemberEnd()              { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); }\n\n    //! Check whether a member exists in the object.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Whether a member with that name exists.\n        \\note It is better to use FindMember() directly if you need the obtain the value as well.\n        \\note Linear time complexity.\n    */\n    bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Check whether a member exists in the object with string object.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Whether a member with that name exists.\n        \\note It is better to use FindMember() directly if you need the obtain the value as well.\n        \\note Linear time complexity.\n    */\n    bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }\n#endif\n\n    //! Check whether a member exists in the object with GenericValue name.\n    /*!\n        This version is faster because it does not need a StrLen(). It can also handle string with null character.\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Whether a member with that name exists.\n        \\note It is better to use FindMember() directly if you need the obtain the value as well.\n        \\note Linear time complexity.\n    */\n    template <typename SourceAllocator>\n    bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }\n\n    //! Find member by name.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Iterator to member, if it exists.\n            Otherwise returns \\ref MemberEnd().\n\n        \\note Earlier versions of Rapidjson returned a \\c NULL pointer, in case\n            the requested member doesn't exist. For consistency with e.g.\n            \\c std::map, this has been changed to MemberEnd() now.\n        \\note Linear time complexity.\n    */\n    MemberIterator FindMember(const Ch* name) {\n        GenericValue n(StringRef(name));\n        return FindMember(n);\n    }\n\n    ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }\n\n    //! Find member by name.\n    /*!\n        This version is faster because it does not need a StrLen(). It can also handle string with null character.\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Iterator to member, if it exists.\n            Otherwise returns \\ref MemberEnd().\n\n        \\note Earlier versions of Rapidjson returned a \\c NULL pointer, in case\n            the requested member doesn't exist. For consistency with e.g.\n            \\c std::map, this has been changed to MemberEnd() now.\n        \\note Linear time complexity.\n    */\n    template <typename SourceAllocator>\n    MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(name.IsString());\n        MemberIterator member = MemberBegin();\n        for ( ; member != MemberEnd(); ++member)\n            if (name.StringEqual(member->name))\n                break;\n        return member;\n    }\n    template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Find member by string object name.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Iterator to member, if it exists.\n            Otherwise returns \\ref MemberEnd().\n    */\n    MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(StringRef(name)); }\n    ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(StringRef(name)); }\n#endif\n\n    //! Add a member (name-value pair) to the object.\n    /*! \\param name A string value as name of member.\n        \\param value Value of any type.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note The ownership of \\c name and \\c value will be transferred to this object on success.\n        \\pre  IsObject() && name.IsString()\n        \\post name.IsNull() && value.IsNull()\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(name.IsString());\n\n        Object& o = data_.o;\n        if (o.size >= o.capacity) {\n            if (o.capacity == 0) {\n                o.capacity = kDefaultObjectCapacity;\n                o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));\n            }\n            else {\n                SizeType oldCapacity = o.capacity;\n                o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5\n                o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)));\n            }\n        }\n        o.members[o.size].name.RawAssign(name);\n        o.members[o.size].value.RawAssign(value);\n        o.size++;\n        return *this;\n    }\n\n    //! Add a constant string value as member (name-value pair) to the object.\n    /*! \\param name A string value as name of member.\n        \\param value constant string reference as value of member.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n        \\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {\n        GenericValue v(value);\n        return AddMember(name, v, allocator);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Add a string object as member (name-value pair) to the object.\n    /*! \\param name A string value as name of member.\n        \\param value constant string reference as value of member.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n        \\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {\n        GenericValue v(value, allocator);\n        return AddMember(name, v, allocator);\n    }\n#endif\n\n    //! Add any primitive value as member (name-value pair) to the object.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param name A string value as name of member.\n        \\param value Value of primitive type \\c T as value of member\n        \\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref AddMember(StringRefType, GenericValue&, Allocator&) or \\ref\n            AddMember(StringRefType, StringRefType, Allocator&).\n            All other pointer types would implicitly convert to \\c bool,\n            use an explicit cast instead, if needed.\n        \\note Amortized Constant time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))\n    AddMember(GenericValue& name, T value, Allocator& allocator) {\n        GenericValue v(value);\n        return AddMember(name, v, allocator);\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {\n        return AddMember(name, value, allocator);\n    }\n    GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {\n        return AddMember(name, value, allocator);\n    }\n    GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {\n        return AddMember(name, value, allocator);\n    }\n    GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {\n        GenericValue n(name);\n        return AddMember(n, value, allocator);\n    }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n\n\n    //! Add a member (name-value pair) to the object.\n    /*! \\param name A constant string reference as name of member.\n        \\param value Value of any type.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note The ownership of \\c value will be transferred to this object on success.\n        \\pre  IsObject()\n        \\post value.IsNull()\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {\n        GenericValue n(name);\n        return AddMember(n, value, allocator);\n    }\n\n    //! Add a constant string value as member (name-value pair) to the object.\n    /*! \\param name A constant string reference as name of member.\n        \\param value constant string reference as value of member.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n        \\note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {\n        GenericValue v(value);\n        return AddMember(name, v, allocator);\n    }\n\n    //! Add any primitive value as member (name-value pair) to the object.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param name A constant string reference as name of member.\n        \\param value Value of primitive type \\c T as value of member\n        \\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref AddMember(StringRefType, GenericValue&, Allocator&) or \\ref\n            AddMember(StringRefType, StringRefType, Allocator&).\n            All other pointer types would implicitly convert to \\c bool,\n            use an explicit cast instead, if needed.\n        \\note Amortized Constant time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))\n    AddMember(StringRefType name, T value, Allocator& allocator) {\n        GenericValue n(name);\n        return AddMember(n, value, allocator);\n    }\n\n    //! Remove all members in the object.\n    /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.\n        \\note Linear time complexity.\n    */\n    void RemoveAllMembers() {\n        RAPIDJSON_ASSERT(IsObject()); \n        for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)\n            m->~Member();\n        data_.o.size = 0;\n    }\n\n    //! Remove a member in object by its name.\n    /*! \\param name Name of member to be removed.\n        \\return Whether the member existed.\n        \\note This function may reorder the object members. Use \\ref\n            EraseMember(ConstMemberIterator) if you need to preserve the\n            relative order of the remaining members.\n        \\note Linear time complexity.\n    */\n    bool RemoveMember(const Ch* name) {\n        GenericValue n(StringRef(name));\n        return RemoveMember(n);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }\n#endif\n\n    template <typename SourceAllocator>\n    bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {\n        MemberIterator m = FindMember(name);\n        if (m != MemberEnd()) {\n            RemoveMember(m);\n            return true;\n        }\n        else\n            return false;\n    }\n\n    //! Remove a member in object by iterator.\n    /*! \\param m member iterator (obtained by FindMember() or MemberBegin()).\n        \\return the new iterator after removal.\n        \\note This function may reorder the object members. Use \\ref\n            EraseMember(ConstMemberIterator) if you need to preserve the\n            relative order of the remaining members.\n        \\note Constant time complexity.\n    */\n    MemberIterator RemoveMember(MemberIterator m) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(data_.o.size > 0);\n        RAPIDJSON_ASSERT(data_.o.members != 0);\n        RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());\n\n        MemberIterator last(data_.o.members + (data_.o.size - 1));\n        if (data_.o.size > 1 && m != last) {\n            // Move the last one to this place\n            *m = *last;\n        }\n        else {\n            // Only one left, just destroy\n            m->~Member();\n        }\n        --data_.o.size;\n        return m;\n    }\n\n    //! Remove a member from an object by iterator.\n    /*! \\param pos iterator to the member to remove\n        \\pre IsObject() == true && \\ref MemberBegin() <= \\c pos < \\ref MemberEnd()\n        \\return Iterator following the removed element.\n            If the iterator \\c pos refers to the last element, the \\ref MemberEnd() iterator is returned.\n        \\note This function preserves the relative order of the remaining object\n            members. If you do not need this, use the more efficient \\ref RemoveMember(MemberIterator).\n        \\note Linear time complexity.\n    */\n    MemberIterator EraseMember(ConstMemberIterator pos) {\n        return EraseMember(pos, pos +1);\n    }\n\n    //! Remove members in the range [first, last) from an object.\n    /*! \\param first iterator to the first member to remove\n        \\param last  iterator following the last member to remove\n        \\pre IsObject() == true && \\ref MemberBegin() <= \\c first <= \\c last <= \\ref MemberEnd()\n        \\return Iterator following the last removed element.\n        \\note This function preserves the relative order of the remaining object\n            members.\n        \\note Linear time complexity.\n    */\n    MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(data_.o.size > 0);\n        RAPIDJSON_ASSERT(data_.o.members != 0);\n        RAPIDJSON_ASSERT(first >= MemberBegin());\n        RAPIDJSON_ASSERT(first <= last);\n        RAPIDJSON_ASSERT(last <= MemberEnd());\n\n        MemberIterator pos = MemberBegin() + (first - MemberBegin());\n        for (MemberIterator itr = pos; itr != last; ++itr)\n            itr->~Member();\n        std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member));\n        data_.o.size -= (last - first);\n        return pos;\n    }\n\n    //! Erase a member in object by its name.\n    /*! \\param name Name of member to be removed.\n        \\return Whether the member existed.\n        \\note Linear time complexity.\n    */\n    bool EraseMember(const Ch* name) {\n        GenericValue n(StringRef(name));\n        return EraseMember(n);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }\n#endif\n\n    template <typename SourceAllocator>\n    bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {\n        MemberIterator m = FindMember(name);\n        if (m != MemberEnd()) {\n            EraseMember(m);\n            return true;\n        }\n        else\n            return false;\n    }\n\n    //@}\n\n    //!@name Array\n    //@{\n\n    //! Set this value as an empty array.\n    /*! \\post IsArray == true */\n    GenericValue& SetArray() {  this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }\n\n    //! Get the number of elements in array.\n    SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }\n\n    //! Get the capacity of array.\n    SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }\n\n    //! Check whether the array is empty.\n    bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }\n\n    //! Remove all elements in the array.\n    /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.\n        \\note Linear time complexity.\n    */\n    void Clear() {\n        RAPIDJSON_ASSERT(IsArray()); \n        for (SizeType i = 0; i < data_.a.size; ++i)\n            data_.a.elements[i].~GenericValue();\n        data_.a.size = 0;\n    }\n\n    //! Get an element from array by index.\n    /*! \\pre IsArray() == true\n        \\param index Zero-based index of element.\n        \\see operator[](T*)\n    */\n    GenericValue& operator[](SizeType index) {\n        RAPIDJSON_ASSERT(IsArray());\n        RAPIDJSON_ASSERT(index < data_.a.size);\n        return data_.a.elements[index];\n    }\n    const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }\n\n    //! Element iterator\n    /*! \\pre IsArray() == true */\n    ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }\n    //! \\em Past-the-end element iterator\n    /*! \\pre IsArray() == true */\n    ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }\n    //! Constant element iterator\n    /*! \\pre IsArray() == true */\n    ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }\n    //! Constant \\em past-the-end element iterator\n    /*! \\pre IsArray() == true */\n    ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }\n\n    //! Request the array to have enough capacity to store elements.\n    /*! \\param newCapacity  The capacity that the array at least need to have.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note Linear time complexity.\n    */\n    GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {\n        RAPIDJSON_ASSERT(IsArray());\n        if (newCapacity > data_.a.capacity) {\n            data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));\n            data_.a.capacity = newCapacity;\n        }\n        return *this;\n    }\n\n    //! Append a GenericValue at the end of the array.\n    /*! \\param value        Value to be appended.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\pre IsArray() == true\n        \\post value.IsNull() == true\n        \\return The value itself for fluent API.\n        \\note The ownership of \\c value will be transferred to this array on success.\n        \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n        \\note Amortized constant time complexity.\n    */\n    GenericValue& PushBack(GenericValue& value, Allocator& allocator) {\n        RAPIDJSON_ASSERT(IsArray());\n        if (data_.a.size >= data_.a.capacity)\n            Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);\n        data_.a.elements[data_.a.size++].RawAssign(value);\n        return *this;\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {\n        return PushBack(value, allocator);\n    }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n\n    //! Append a constant string reference at the end of the array.\n    /*! \\param value        Constant string reference to be appended.\n        \\param allocator    Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().\n        \\pre IsArray() == true\n        \\return The value itself for fluent API.\n        \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n        \\note Amortized constant time complexity.\n        \\see GenericStringRef\n    */\n    GenericValue& PushBack(StringRefType value, Allocator& allocator) {\n        return (*this).template PushBack<StringRefType>(value, allocator);\n    }\n\n    //! Append a primitive value at the end of the array.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param value Value of primitive type T to be appended.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\pre IsArray() == true\n        \\return The value itself for fluent API.\n        \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref PushBack(GenericValue&, Allocator&) or \\ref\n            PushBack(StringRefType, Allocator&).\n            All other pointer types would implicitly convert to \\c bool,\n            use an explicit cast instead, if needed.\n        \\note Amortized constant time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))\n    PushBack(T value, Allocator& allocator) {\n        GenericValue v(value);\n        return PushBack(v, allocator);\n    }\n\n    //! Remove the last element in the array.\n    /*!\n        \\note Constant time complexity.\n    */\n    GenericValue& PopBack() {\n        RAPIDJSON_ASSERT(IsArray());\n        RAPIDJSON_ASSERT(!Empty());\n        data_.a.elements[--data_.a.size].~GenericValue();\n        return *this;\n    }\n\n    //! Remove an element of array by iterator.\n    /*!\n        \\param pos iterator to the element to remove\n        \\pre IsArray() == true && \\ref Begin() <= \\c pos < \\ref End()\n        \\return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.\n        \\note Linear time complexity.\n    */\n    ValueIterator Erase(ConstValueIterator pos) {\n        return Erase(pos, pos + 1);\n    }\n\n    //! Remove elements in the range [first, last) of the array.\n    /*!\n        \\param first iterator to the first element to remove\n        \\param last  iterator following the last element to remove\n        \\pre IsArray() == true && \\ref Begin() <= \\c first <= \\c last <= \\ref End()\n        \\return Iterator following the last removed element.\n        \\note Linear time complexity.\n    */\n    ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {\n        RAPIDJSON_ASSERT(IsArray());\n        RAPIDJSON_ASSERT(data_.a.size > 0);\n        RAPIDJSON_ASSERT(data_.a.elements != 0);\n        RAPIDJSON_ASSERT(first >= Begin());\n        RAPIDJSON_ASSERT(first <= last);\n        RAPIDJSON_ASSERT(last <= End());\n        ValueIterator pos = Begin() + (first - Begin());\n        for (ValueIterator itr = pos; itr != last; ++itr)\n            itr->~GenericValue();       \n        std::memmove(pos, last, (End() - last) * sizeof(GenericValue));\n        data_.a.size -= (last - first);\n        return pos;\n    }\n\n    //@}\n\n    //!@name Number\n    //@{\n\n    int GetInt() const          { RAPIDJSON_ASSERT(flags_ & kIntFlag);   return data_.n.i.i;   }\n    unsigned GetUint() const    { RAPIDJSON_ASSERT(flags_ & kUintFlag);  return data_.n.u.u;   }\n    int64_t GetInt64() const    { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }\n    uint64_t GetUint64() const  { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }\n\n    double GetDouble() const {\n        RAPIDJSON_ASSERT(IsNumber());\n        if ((flags_ & kDoubleFlag) != 0)                return data_.n.d;   // exact type, no conversion.\n        if ((flags_ & kIntFlag) != 0)                   return data_.n.i.i; // int -> double\n        if ((flags_ & kUintFlag) != 0)                  return data_.n.u.u; // unsigned -> double\n        if ((flags_ & kInt64Flag) != 0)                 return (double)data_.n.i64; // int64_t -> double (may lose precision)\n        RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0);  return (double)data_.n.u64; // uint64_t -> double (may lose precision)\n    }\n\n    GenericValue& SetInt(int i)             { this->~GenericValue(); new (this) GenericValue(i);    return *this; }\n    GenericValue& SetUint(unsigned u)       { this->~GenericValue(); new (this) GenericValue(u);    return *this; }\n    GenericValue& SetInt64(int64_t i64)     { this->~GenericValue(); new (this) GenericValue(i64);  return *this; }\n    GenericValue& SetUint64(uint64_t u64)   { this->~GenericValue(); new (this) GenericValue(u64);  return *this; }\n    GenericValue& SetDouble(double d)       { this->~GenericValue(); new (this) GenericValue(d);    return *this; }\n\n    //@}\n\n    //!@name String\n    //@{\n\n    const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); }\n\n    //! Get the length of string.\n    /*! Since rapidjson permits \"\\\\u0000\" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().\n    */\n    SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }\n\n    //! Set this value as a string without copying source string.\n    /*! This version has better performance with supplied length, and also support string containing null character.\n        \\param s source string pointer. \n        \\param length The length of source string, excluding the trailing null terminator.\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() == s && GetStringLength() == length\n        \\see SetString(StringRefType)\n    */\n    GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }\n\n    //! Set this value as a string without copying source string.\n    /*! \\param s source string reference\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() == s && GetStringLength() == s.length\n    */\n    GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }\n\n    //! Set this value as a string by copying from source string.\n    /*! This version has better performance with supplied length, and also support string containing null character.\n        \\param s source string. \n        \\param length The length of source string, excluding the trailing null terminator.\n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length\n    */\n    GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }\n\n    //! Set this value as a string by copying from source string.\n    /*! \\param s source string. \n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length\n    */\n    GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Set this value as a string by copying from source string.\n    /*! \\param s source string.\n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()\n        \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n    */\n    GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }\n#endif\n\n    //@}\n\n    //! Generate events of this value to a Handler.\n    /*! This function adopts the GoF visitor pattern.\n        Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.\n        It can also be used to deep clone this value via GenericDocument, which is also a Handler.\n        \\tparam Handler type of handler.\n        \\param handler An object implementing concept Handler.\n    */\n    template <typename Handler>\n    bool Accept(Handler& handler) const {\n        switch(GetType()) {\n        case kNullType:     return handler.Null();\n        case kFalseType:    return handler.Bool(false);\n        case kTrueType:     return handler.Bool(true);\n\n        case kObjectType:\n            if (!handler.StartObject())\n                return false;\n            for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {\n                RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.\n                if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0))\n                    return false;\n                if (!m->value.Accept(handler))\n                    return false;\n            }\n            return handler.EndObject(data_.o.size);\n\n        case kArrayType:\n            if (!handler.StartArray())\n                return false;\n            for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)\n                if (!v->Accept(handler))\n                    return false;\n            return handler.EndArray(data_.a.size);\n    \n        case kStringType:\n            return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);\n    \n        default:\n            RAPIDJSON_ASSERT(GetType() == kNumberType);\n            if (IsInt())            return handler.Int(data_.n.i.i);\n            else if (IsUint())      return handler.Uint(data_.n.u.u);\n            else if (IsInt64())     return handler.Int64(data_.n.i64);\n            else if (IsUint64())    return handler.Uint64(data_.n.u64);\n            else                    return handler.Double(data_.n.d);\n        }\n    }\n\nprivate:\n    template <typename, typename> friend class GenericValue;\n    template <typename, typename, typename> friend class GenericDocument;\n\n    enum {\n        kBoolFlag = 0x100,\n        kNumberFlag = 0x200,\n        kIntFlag = 0x400,\n        kUintFlag = 0x800,\n        kInt64Flag = 0x1000,\n        kUint64Flag = 0x2000,\n        kDoubleFlag = 0x4000,\n        kStringFlag = 0x100000,\n        kCopyFlag = 0x200000,\n        kInlineStrFlag = 0x400000,\n\n        // Initial flags of different types.\n        kNullFlag = kNullType,\n        kTrueFlag = kTrueType | kBoolFlag,\n        kFalseFlag = kFalseType | kBoolFlag,\n        kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,\n        kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,\n        kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,\n        kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,\n        kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,\n        kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,\n        kConstStringFlag = kStringType | kStringFlag,\n        kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,\n        kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,\n        kObjectFlag = kObjectType,\n        kArrayFlag = kArrayType,\n\n        kTypeMask = 0xFF    // bitwise-and with mask of 0xFF can be optimized by compiler\n    };\n\n    static const SizeType kDefaultArrayCapacity = 16;\n    static const SizeType kDefaultObjectCapacity = 16;\n\n    struct String {\n        const Ch* str;\n        SizeType length;\n        unsigned hashcode;  //!< reserved\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars\n    // (excluding the terminating zero) and store a value to determine the length of the contained\n    // string in the last character str[LenPos] by storing \"MaxSize - length\" there. If the string\n    // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as\n    // the string terminator as well. For getting the string length back from that value just use\n    // \"MaxSize - str[LenPos]\".\n    // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode\n    // inline (for `UTF8`-encoded strings).\n    struct ShortString {\n        enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };\n        Ch str[MaxChars];\n\n        inline static bool Usable(SizeType len) { return            (MaxSize >= len); }\n        inline void     SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize -  len); }\n        inline SizeType GetLength() const       { return  (SizeType)(MaxSize -  str[LenPos]); }\n    };  // at most as many bytes as \"String\" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    // By using proper binary layout, retrieval of different integer types do not need conversions.\n    union Number {\n#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN\n        struct I {\n            int i;\n            char padding[4];\n        }i;\n        struct U {\n            unsigned u;\n            char padding2[4];\n        }u;\n#else\n        struct I {\n            char padding[4];\n            int i;\n        }i;\n        struct U {\n            char padding2[4];\n            unsigned u;\n        }u;\n#endif\n        int64_t i64;\n        uint64_t u64;\n        double d;\n    };  // 8 bytes\n\n    struct Object {\n        Member* members;\n        SizeType size;\n        SizeType capacity;\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    struct Array {\n        GenericValue* elements;\n        SizeType size;\n        SizeType capacity;\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    union Data {\n        String s;\n        ShortString ss;\n        Number n;\n        Object o;\n        Array a;\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    // Initialize this value as array with initial data, without calling destructor.\n    void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {\n        flags_ = kArrayFlag;\n        if (count) {\n            data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));\n            std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));\n        }\n        else\n            data_.a.elements = NULL;\n        data_.a.size = data_.a.capacity = count;\n    }\n\n    //! Initialize this value as object with initial data, without calling destructor.\n    void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {\n        flags_ = kObjectFlag;\n        if (count) {\n            data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));\n            std::memcpy(data_.o.members, members, count * sizeof(Member));\n        }\n        else\n            data_.o.members = NULL;\n        data_.o.size = data_.o.capacity = count;\n    }\n\n    //! Initialize this value as constant string, without calling destructor.\n    void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {\n        flags_ = kConstStringFlag;\n        data_.s.str = s;\n        data_.s.length = s.length;\n    }\n\n    //! Initialize this value as copy string with initial data, without calling destructor.\n    void SetStringRaw(StringRefType s, Allocator& allocator) {\n        Ch* str = NULL;\n        if(ShortString::Usable(s.length)) {\n            flags_ = kShortStringFlag;\n            data_.ss.SetLength(s.length);\n            str = data_.ss.str;\n        } else {\n            flags_ = kCopyStringFlag;\n            data_.s.length = s.length;\n            str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch));\n            data_.s.str = str;\n        }\n        std::memcpy(str, s, s.length * sizeof(Ch));\n        str[s.length] = '\\0';\n    }\n\n    //! Assignment without calling destructor\n    void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {\n        data_ = rhs.data_;\n        flags_ = rhs.flags_;\n        rhs.flags_ = kNullFlag;\n    }\n\n    template <typename SourceAllocator>\n    bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {\n        RAPIDJSON_ASSERT(IsString());\n        RAPIDJSON_ASSERT(rhs.IsString());\n\n        const SizeType len1 = GetStringLength();\n        const SizeType len2 = rhs.GetStringLength();\n        if(len1 != len2) { return false; }\n\n        const Ch* const str1 = GetString();\n        const Ch* const str2 = rhs.GetString();\n        if(str1 == str2) { return true; } // fast path for constant string\n\n        return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);\n    }\n\n    Data data_;\n    unsigned flags_;\n};\n\n//! GenericValue with UTF8 encoding\ntypedef GenericValue<UTF8<> > Value;\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericDocument \n\n//! A document for parsing JSON text as DOM.\n/*!\n    \\note implements Handler concept\n    \\tparam Encoding Encoding for both parsing and string storage.\n    \\tparam Allocator Allocator for allocating memory for the DOM\n    \\tparam StackAllocator Allocator for allocating memory for stack during parsing.\n    \\warning Although GenericDocument inherits from GenericValue, the API does \\b not provide any virtual functions, especially no virtual destructor.  To avoid memory leaks, do not \\c delete a GenericDocument object via a pointer to a GenericValue.\n*/\ntemplate <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>\nclass GenericDocument : public GenericValue<Encoding, Allocator> {\npublic:\n    typedef typename Encoding::Ch Ch;                       //!< Character type derived from Encoding.\n    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of the document.\n    typedef Allocator AllocatorType;                        //!< Allocator type from template parameter.\n\n    //! Constructor\n    /*! Creates an empty document of specified type.\n        \\param type             Mandatory type of object to create.\n        \\param allocator        Optional allocator for allocating memory.\n        \\param stackCapacity    Optional initial capacity of stack in bytes.\n        \\param stackAllocator   Optional allocator for allocating memory for stack.\n    */\n    explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :\n        GenericValue<Encoding, Allocator>(type),  allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()\n    {\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n    }\n\n    //! Constructor\n    /*! Creates an empty document which type is Null. \n        \\param allocator        Optional allocator for allocating memory.\n        \\param stackCapacity    Optional initial capacity of stack in bytes.\n        \\param stackAllocator   Optional allocator for allocating memory for stack.\n    */\n    GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : \n        allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()\n    {\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move constructor in C++11\n    GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT\n        : ValueType(std::move(rhs)),\n          allocator_(rhs.allocator_),\n          ownAllocator_(rhs.ownAllocator_),\n          stack_(std::move(rhs.stack_)),\n          parseResult_(rhs.parseResult_)\n    {\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.parseResult_ = ParseResult();\n    }\n#endif\n\n    ~GenericDocument() {\n        Destroy();\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move assignment in C++11\n    GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT\n    {\n        // The cast to ValueType is necessary here, because otherwise it would\n        // attempt to call GenericValue's templated assignment operator.\n        ValueType::operator=(std::forward<ValueType>(rhs));\n\n        // Calling the destructor here would prematurely call stack_'s destructor\n        Destroy();\n\n        allocator_ = rhs.allocator_;\n        ownAllocator_ = rhs.ownAllocator_;\n        stack_ = std::move(rhs.stack_);\n        parseResult_ = rhs.parseResult_;\n\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.parseResult_ = ParseResult();\n\n        return *this;\n    }\n#endif\n\n    //!@name Parse from stream\n    //!@{\n\n    //! Parse JSON text from an input stream (with Encoding conversion)\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\tparam SourceEncoding Encoding of input stream\n        \\tparam InputStream Type of input stream, implementing Stream concept\n        \\param is Input stream to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <unsigned parseFlags, typename SourceEncoding, typename InputStream>\n    GenericDocument& ParseStream(InputStream& is) {\n        ValueType::SetNull(); // Remove existing root if exist\n        GenericReader<SourceEncoding, Encoding, StackAllocator> reader(&stack_.GetAllocator());\n        ClearStackOnExit scope(*this);\n        parseResult_ = reader.template Parse<parseFlags>(is, *this);\n        if (parseResult_) {\n            RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object\n            this->RawAssign(*stack_.template Pop<ValueType>(1));    // Add this-> to prevent issue 13.\n        }\n        return *this;\n    }\n\n    //! Parse JSON text from an input stream\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\tparam InputStream Type of input stream, implementing Stream concept\n        \\param is Input stream to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <unsigned parseFlags, typename InputStream>\n    GenericDocument& ParseStream(InputStream& is) {\n        return ParseStream<parseFlags, Encoding, InputStream>(is);\n    }\n\n    //! Parse JSON text from an input stream (with \\ref kParseDefaultFlags)\n    /*! \\tparam InputStream Type of input stream, implementing Stream concept\n        \\param is Input stream to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <typename InputStream>\n    GenericDocument& ParseStream(InputStream& is) {\n        return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);\n    }\n    //!@}\n\n    //!@name Parse in-place from mutable string\n    //!@{\n\n    //! Parse JSON text from a mutable string\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\param str Mutable zero-terminated string to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <unsigned parseFlags>\n    GenericDocument& ParseInsitu(Ch* str) {\n        GenericInsituStringStream<Encoding> s(str);\n        return ParseStream<parseFlags | kParseInsituFlag>(s);\n    }\n\n    //! Parse JSON text from a mutable string (with \\ref kParseDefaultFlags)\n    /*! \\param str Mutable zero-terminated string to be parsed.\n        \\return The document itself for fluent API.\n    */\n    GenericDocument& ParseInsitu(Ch* str) {\n        return ParseInsitu<kParseDefaultFlags>(str);\n    }\n    //!@}\n\n    //!@name Parse from read-only string\n    //!@{\n\n    //! Parse JSON text from a read-only string (with Encoding conversion)\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag (must not contain \\ref kParseInsituFlag).\n        \\tparam SourceEncoding Transcoding from input Encoding\n        \\param str Read-only zero-terminated string to be parsed.\n    */\n    template <unsigned parseFlags, typename SourceEncoding>\n    GenericDocument& Parse(const Ch* str) {\n        RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));\n        GenericStringStream<SourceEncoding> s(str);\n        return ParseStream<parseFlags, SourceEncoding>(s);\n    }\n\n    //! Parse JSON text from a read-only string\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag (must not contain \\ref kParseInsituFlag).\n        \\param str Read-only zero-terminated string to be parsed.\n    */\n    template <unsigned parseFlags>\n    GenericDocument& Parse(const Ch* str) {\n        return Parse<parseFlags, Encoding>(str);\n    }\n\n    //! Parse JSON text from a read-only string (with \\ref kParseDefaultFlags)\n    /*! \\param str Read-only zero-terminated string to be parsed.\n    */\n    GenericDocument& Parse(const Ch* str) {\n        return Parse<kParseDefaultFlags>(str);\n    }\n    //!@}\n\n    //!@name Handling parse errors\n    //!@{\n\n    //! Whether a parse error has occured in the last parsing.\n    bool HasParseError() const { return parseResult_.IsError(); }\n\n    //! Get the \\ref ParseErrorCode of last parsing.\n    ParseErrorCode GetParseError() const { return parseResult_.Code(); }\n\n    //! Get the position of last parsing error in input, 0 otherwise.\n    size_t GetErrorOffset() const { return parseResult_.Offset(); }\n\n    //!@}\n\n    //! Get the allocator of this document.\n    Allocator& GetAllocator() { return *allocator_; }\n\n    //! Get the capacity of stack in bytes.\n    size_t GetStackCapacity() const { return stack_.GetCapacity(); }\n\nprivate:\n    // clear stack on any exit from ParseStream, e.g. due to exception\n    struct ClearStackOnExit {\n        explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}\n        ~ClearStackOnExit() { d_.ClearStack(); }\n    private:\n        ClearStackOnExit(const ClearStackOnExit&);\n        ClearStackOnExit& operator=(const ClearStackOnExit&);\n        GenericDocument& d_;\n    };\n\n    // callers of the following private Handler functions\n    template <typename,typename,typename> friend class GenericReader; // for parsing\n    template <typename, typename> friend class GenericValue; // for deep copying\n\n    // Implementation of Handler\n    bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }\n    bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }\n    bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }\n\n    bool String(const Ch* str, SizeType length, bool copy) { \n        if (copy) \n            new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());\n        else\n            new (stack_.template Push<ValueType>()) ValueType(str, length);\n        return true;\n    }\n\n    bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }\n    \n    bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }\n\n    bool EndObject(SizeType memberCount) {\n        typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);\n        stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());\n        return true;\n    }\n\n    bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }\n    \n    bool EndArray(SizeType elementCount) {\n        ValueType* elements = stack_.template Pop<ValueType>(elementCount);\n        stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());\n        return true;\n    }\n\nprivate:\n    //! Prohibit copying\n    GenericDocument(const GenericDocument&);\n    //! Prohibit assignment\n    GenericDocument& operator=(const GenericDocument&);\n\n    void ClearStack() {\n        if (Allocator::kNeedFree)\n            while (stack_.GetSize() > 0)    // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)\n                (stack_.template Pop<ValueType>(1))->~ValueType();\n        else\n            stack_.Clear();\n        stack_.ShrinkToFit();\n    }\n\n    void Destroy() {\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    static const size_t kDefaultStackCapacity = 1024;\n    Allocator* allocator_;\n    Allocator* ownAllocator_;\n    internal::Stack<StackAllocator> stack_;\n    ParseResult parseResult_;\n};\n\n//! GenericDocument with UTF8 encoding\ntypedef GenericDocument<UTF8<> > Document;\n\n// defined here due to the dependency on GenericDocument\ntemplate <typename Encoding, typename Allocator>\ntemplate <typename SourceAllocator>\ninline\nGenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)\n{\n    switch (rhs.GetType()) {\n    case kObjectType:\n    case kArrayType: { // perform deep copy via SAX Handler\n            GenericDocument<Encoding,Allocator> d(&allocator);\n            rhs.Accept(d);\n            RawAssign(*d.stack_.template Pop<GenericValue>(1));\n        }\n        break;\n    case kStringType:\n        if (rhs.flags_ == kConstStringFlag) {\n            flags_ = rhs.flags_;\n            data_  = *reinterpret_cast<const Data*>(&rhs.data_);\n        } else {\n            SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);\n        }\n        break;\n    default: // kNumberType, kTrueType, kFalseType, kNullType\n        flags_ = rhs.flags_;\n        data_  = *reinterpret_cast<const Data*>(&rhs.data_);\n    }\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(_MSC_VER) || defined(__GNUC__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_DOCUMENT_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/encodedstream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ENCODEDSTREAM_H_\n#define RAPIDJSON_ENCODEDSTREAM_H_\n\n#include \"rapidjson.h\"\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Input byte stream wrapper with a statically bound encoding.\n/*!\n    \\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.\n    \\tparam InputByteStream Type of input byte stream. For example, FileReadStream.\n*/\ntemplate <typename Encoding, typename InputByteStream>\nclass EncodedInputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    EncodedInputStream(InputByteStream& is) : is_(is) { \n        current_ = Encoding::TakeBOM(is_);\n    }\n\n    Ch Peek() const { return current_; }\n    Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }\n    size_t Tell() const { return is_.Tell(); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    EncodedInputStream(const EncodedInputStream&);\n    EncodedInputStream& operator=(const EncodedInputStream&);\n\n    InputByteStream& is_;\n    Ch current_;\n};\n\n//! Output byte stream wrapper with statically bound encoding.\n/*!\n    \\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.\n    \\tparam InputByteStream Type of input byte stream. For example, FileWriteStream.\n*/\ntemplate <typename Encoding, typename OutputByteStream>\nclass EncodedOutputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { \n        if (putBOM)\n            Encoding::PutBOM(os_);\n    }\n\n    void Put(Ch c) { Encoding::Put(os_, c);  }\n    void Flush() { os_.Flush(); }\n\n    // Not implemented\n    Ch Peek() const { RAPIDJSON_ASSERT(false); }\n    Ch Take() { RAPIDJSON_ASSERT(false);  }\n    size_t Tell() const { RAPIDJSON_ASSERT(false);  return 0; }\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    EncodedOutputStream(const EncodedOutputStream&);\n    EncodedOutputStream& operator=(const EncodedOutputStream&);\n\n    OutputByteStream& os_;\n};\n\n#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x\n\n//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.\n/*!\n    \\tparam CharType Type of character for reading.\n    \\tparam InputByteStream type of input byte stream to be wrapped.\n*/\ntemplate <typename CharType, typename InputByteStream>\nclass AutoUTFInputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\npublic:\n    typedef CharType Ch;\n\n    //! Constructor.\n    /*!\n        \\param is input stream to be wrapped.\n        \\param type UTF encoding type if it is not detected from the stream.\n    */\n    AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {\n        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);        \n        DetectType();\n        static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };\n        takeFunc_ = f[type_];\n        current_ = takeFunc_(*is_);\n    }\n\n    UTFType GetType() const { return type_; }\n    bool HasBOM() const { return hasBOM_; }\n\n    Ch Peek() const { return current_; }\n    Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }\n    size_t Tell() const { return is_->Tell(); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    AutoUTFInputStream(const AutoUTFInputStream&);\n    AutoUTFInputStream& operator=(const AutoUTFInputStream&);\n\n    // Detect encoding type with BOM or RFC 4627\n    void DetectType() {\n        // BOM (Byte Order Mark):\n        // 00 00 FE FF  UTF-32BE\n        // FF FE 00 00  UTF-32LE\n        // FE FF        UTF-16BE\n        // FF FE        UTF-16LE\n        // EF BB BF     UTF-8\n\n        const unsigned char* c = (const unsigned char *)is_->Peek4();\n        if (!c)\n            return;\n\n        unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);\n        hasBOM_ = false;\n        if (bom == 0xFFFE0000)                  { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }\n        else if (bom == 0x0000FEFF)             { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }\n        else if ((bom & 0xFFFF) == 0xFFFE)      { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take();                           }\n        else if ((bom & 0xFFFF) == 0xFEFF)      { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take();                           }\n        else if ((bom & 0xFFFFFF) == 0xBFBBEF)  { type_ = kUTF8;    hasBOM_ = true; is_->Take(); is_->Take(); is_->Take();              }\n\n        // RFC 4627: Section 3\n        // \"Since the first two characters of a JSON text will always be ASCII\n        // characters [RFC0020], it is possible to determine whether an octet\n        // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking\n        // at the pattern of nulls in the first four octets.\"\n        // 00 00 00 xx  UTF-32BE\n        // 00 xx 00 xx  UTF-16BE\n        // xx 00 00 00  UTF-32LE\n        // xx 00 xx 00  UTF-16LE\n        // xx xx xx xx  UTF-8\n\n        if (!hasBOM_) {\n            unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);\n            switch (pattern) {\n            case 0x08: type_ = kUTF32BE; break;\n            case 0x0A: type_ = kUTF16BE; break;\n            case 0x01: type_ = kUTF32LE; break;\n            case 0x05: type_ = kUTF16LE; break;\n            case 0x0F: type_ = kUTF8;    break;\n            default: break; // Use type defined by user.\n            }\n        }\n\n        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.\n        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);\n        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);\n    }\n\n    typedef Ch (*TakeFunc)(InputByteStream& is);\n    InputByteStream* is_;\n    UTFType type_;\n    Ch current_;\n    TakeFunc takeFunc_;\n    bool hasBOM_;\n};\n\n//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.\n/*!\n    \\tparam CharType Type of character for writing.\n    \\tparam InputByteStream type of output byte stream to be wrapped.\n*/\ntemplate <typename CharType, typename OutputByteStream>\nclass AutoUTFOutputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\npublic:\n    typedef CharType Ch;\n\n    //! Constructor.\n    /*!\n        \\param os output stream to be wrapped.\n        \\param type UTF encoding type.\n        \\param putBOM Whether to write BOM at the beginning of the stream.\n    */\n    AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {\n        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);\n\n        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.\n        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);\n        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);\n\n        static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };\n        putFunc_ = f[type_];\n\n        if (putBOM)\n            PutBOM();\n    }\n\n    UTFType GetType() const { return type_; }\n\n    void Put(Ch c) { putFunc_(*os_, c); }\n    void Flush() { os_->Flush(); } \n\n    // Not implemented\n    Ch Peek() const { RAPIDJSON_ASSERT(false); }\n    Ch Take() { RAPIDJSON_ASSERT(false); }\n    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    AutoUTFOutputStream(const AutoUTFOutputStream&);\n    AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);\n\n    void PutBOM() { \n        typedef void (*PutBOMFunc)(OutputByteStream&);\n        static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };\n        f[type_](*os_);\n    }\n\n    typedef void (*PutFunc)(OutputByteStream&, Ch);\n\n    OutputByteStream* os_;\n    UTFType type_;\n    PutFunc putFunc_;\n};\n\n#undef RAPIDJSON_ENCODINGS_FUNC\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/encodings.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ENCODINGS_H_\n#define RAPIDJSON_ENCODINGS_H_\n\n#include \"rapidjson.h\"\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data\nRAPIDJSON_DIAG_OFF(4702)  // unreachable code\n#elif defined(__GNUC__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\nRAPIDJSON_DIAG_OFF(overflow)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// Encoding\n\n/*! \\class rapidjson::Encoding\n    \\brief Concept for encoding of Unicode characters.\n\n\\code\nconcept Encoding {\n    typename Ch;    //! Type of character. A \"character\" is actually a code unit in unicode's definition.\n\n    enum { supportUnicode = 1 }; // or 0 if not supporting unicode\n\n    //! \\brief Encode a Unicode codepoint to an output stream.\n    //! \\param os Output stream.\n    //! \\param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint);\n\n    //! \\brief Decode a Unicode codepoint from an input stream.\n    //! \\param is Input stream.\n    //! \\param codepoint Output of the unicode codepoint.\n    //! \\return true if a valid codepoint can be decoded from the stream.\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint);\n\n    //! \\brief Validate one Unicode codepoint from an encoded stream.\n    //! \\param is Input stream to obtain codepoint.\n    //! \\param os Output for copying one codepoint.\n    //! \\return true if it is valid.\n    //! \\note This function just validating and copying the codepoint without actually decode it.\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os);\n\n    // The following functions are deal with byte streams.\n\n    //! Take a character from input byte stream, skip BOM if exist.\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is);\n\n    //! Take a character from input byte stream.\n    template <typename InputByteStream>\n    static Ch Take(InputByteStream& is);\n\n    //! Put BOM to output byte stream.\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os);\n\n    //! Put a character to output byte stream.\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, Ch c);\n};\n\\endcode\n*/\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF8\n\n//! UTF-8 encoding.\n/*! http://en.wikipedia.org/wiki/UTF-8\n    http://tools.ietf.org/html/rfc3629\n    \\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.\n    \\note implements Encoding concept\n*/\ntemplate<typename CharType = char>\nstruct UTF8 {\n    typedef CharType Ch;\n\n    enum { supportUnicode = 1 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        if (codepoint <= 0x7F) \n            os.Put(static_cast<Ch>(codepoint & 0xFF));\n        else if (codepoint <= 0x7FF) {\n            os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));\n        }\n        else if (codepoint <= 0xFFFF) {\n            os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)\n#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)\n#define TAIL() COPY(); TRANS(0x70)\n        Ch c = is.Take();\n        if (!(c & 0x80)) {\n            *codepoint = (unsigned char)c;\n            return true;\n        }\n\n        unsigned char type = GetRange((unsigned char)c);\n        *codepoint = (0xFF >> type) & (unsigned char)c;\n        bool result = true;\n        switch (type) {\n        case 2: TAIL(); return result;\n        case 3: TAIL(); TAIL(); return result;\n        case 4: COPY(); TRANS(0x50); TAIL(); return result;\n        case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;\n        case 6: TAIL(); TAIL(); TAIL(); return result;\n        case 10: COPY(); TRANS(0x20); TAIL(); return result;\n        case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;\n        default: return false;\n        }\n#undef COPY\n#undef TRANS\n#undef TAIL\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n#define COPY() os.Put(c = is.Take())\n#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)\n#define TAIL() COPY(); TRANS(0x70)\n        Ch c;\n        COPY();\n        if (!(c & 0x80))\n            return true;\n\n        bool result = true;\n        switch (GetRange((unsigned char)c)) {\n        case 2: TAIL(); return result;\n        case 3: TAIL(); TAIL(); return result;\n        case 4: COPY(); TRANS(0x50); TAIL(); return result;\n        case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;\n        case 6: TAIL(); TAIL(); TAIL(); return result;\n        case 10: COPY(); TRANS(0x20); TAIL(); return result;\n        case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;\n        default: return false;\n        }\n#undef COPY\n#undef TRANS\n#undef TAIL\n    }\n\n    static unsigned char GetRange(unsigned char c) {\n        // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n        // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.\n        static const unsigned char type[] = {\n            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n            0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,\n            0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,\n            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,\n            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,\n            8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,\n            10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,\n        };\n        return type[c];\n    }\n\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        Ch c = Take(is);\n        if ((unsigned char)c != 0xEFu) return c;\n        c = is.Take();\n        if ((unsigned char)c != 0xBBu) return c;\n        c = is.Take();\n        if ((unsigned char)c != 0xBFu) return c;\n        c = is.Take();\n        return c;\n    }\n\n    template <typename InputByteStream>\n    static Ch Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        return is.Take();\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, Ch c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(c));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF16\n\n//! UTF-16 encoding.\n/*! http://en.wikipedia.org/wiki/UTF-16\n    http://tools.ietf.org/html/rfc2781\n    \\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.\n    \\note implements Encoding concept\n\n    \\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.\n    For streaming, use UTF16LE and UTF16BE, which handle endianness.\n*/\ntemplate<typename CharType = wchar_t>\nstruct UTF16 {\n    typedef CharType Ch;\n    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);\n\n    enum { supportUnicode = 1 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);\n        if (codepoint <= 0xFFFF) {\n            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair \n            os.Put(static_cast<typename OutputStream::Ch>(codepoint));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            unsigned v = codepoint - 0x10000;\n            os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));\n            os.Put((v & 0x3FF) | 0xDC00);\n        }\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);\n        Ch c = is.Take();\n        if (c < 0xD800 || c > 0xDFFF) {\n            *codepoint = c;\n            return true;\n        }\n        else if (c <= 0xDBFF) {\n            *codepoint = (c & 0x3FF) << 10;\n            c = is.Take();\n            *codepoint |= (c & 0x3FF);\n            *codepoint += 0x10000;\n            return c >= 0xDC00 && c <= 0xDFFF;\n        }\n        return false;\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);\n        Ch c;\n        os.Put(c = is.Take());\n        if (c < 0xD800 || c > 0xDFFF)\n            return true;\n        else if (c <= 0xDBFF) {\n            os.Put(c = is.Take());\n            return c >= 0xDC00 && c <= 0xDFFF;\n        }\n        return false;\n    }\n};\n\n//! UTF-16 little endian encoding.\ntemplate<typename CharType = wchar_t>\nstruct UTF16LE : UTF16<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return (unsigned short)c == 0xFEFFu ? Take(is) : c;\n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = (unsigned char)is.Take();\n        c |= (unsigned char)is.Take() << 8;\n        return c;\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(0xFFu); os.Put(0xFEu);\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(c & 0xFFu);\n        os.Put((c >> 8) & 0xFFu);\n    }\n};\n\n//! UTF-16 big endian encoding.\ntemplate<typename CharType = wchar_t>\nstruct UTF16BE : UTF16<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return (unsigned short)c == 0xFEFFu ? Take(is) : c;\n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = (unsigned char)is.Take() << 8;\n        c |= (unsigned char)is.Take();\n        return c;\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(0xFEu); os.Put(0xFFu);\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put((c >> 8) & 0xFFu);\n        os.Put(c & 0xFFu);\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF32\n\n//! UTF-32 encoding. \n/*! http://en.wikipedia.org/wiki/UTF-32\n    \\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.\n    \\note implements Encoding concept\n\n    \\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.\n    For streaming, use UTF32LE and UTF32BE, which handle endianness.\n*/\ntemplate<typename CharType = unsigned>\nstruct UTF32 {\n    typedef CharType Ch;\n    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);\n\n    enum { supportUnicode = 1 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);\n        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n        os.Put(codepoint);\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);\n        Ch c = is.Take();\n        *codepoint = c;\n        return c <= 0x10FFFF;\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);\n        Ch c;\n        os.Put(c = is.Take());\n        return c <= 0x10FFFF;\n    }\n};\n\n//! UTF-32 little endian enocoding.\ntemplate<typename CharType = unsigned>\nstruct UTF32LE : UTF32<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return (unsigned)c == 0x0000FEFFu ? Take(is) : c;\n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = (unsigned char)is.Take();\n        c |= (unsigned char)is.Take() << 8;\n        c |= (unsigned char)is.Take() << 16;\n        c |= (unsigned char)is.Take() << 24;\n        return c;\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(c & 0xFFu);\n        os.Put((c >> 8) & 0xFFu);\n        os.Put((c >> 16) & 0xFFu);\n        os.Put((c >> 24) & 0xFFu);\n    }\n};\n\n//! UTF-32 big endian encoding.\ntemplate<typename CharType = unsigned>\nstruct UTF32BE : UTF32<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return (unsigned)c == 0x0000FEFFu ? Take(is) : c; \n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = (unsigned char)is.Take() << 24;\n        c |= (unsigned char)is.Take() << 16;\n        c |= (unsigned char)is.Take() << 8;\n        c |= (unsigned char)is.Take();\n        return c;\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put((c >> 24) & 0xFFu);\n        os.Put((c >> 16) & 0xFFu);\n        os.Put((c >> 8) & 0xFFu);\n        os.Put(c & 0xFFu);\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// ASCII\n\n//! ASCII encoding.\n/*! http://en.wikipedia.org/wiki/ASCII\n    \\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.\n    \\note implements Encoding concept\n*/\ntemplate<typename CharType = char>\nstruct ASCII {\n    typedef CharType Ch;\n\n    enum { supportUnicode = 0 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_ASSERT(codepoint <= 0x7F);\n        os.Put(static_cast<Ch>(codepoint & 0xFF));\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n        unsigned char c = static_cast<unsigned char>(is.Take());\n        *codepoint = c;\n        return c <= 0X7F;\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n        unsigned char c = is.Take();\n        os.Put(c);\n        return c <= 0x7F;\n    }\n\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        Ch c = Take(is);\n        return c;\n    }\n\n    template <typename InputByteStream>\n    static Ch Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        return is.Take();\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        (void)os;\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, Ch c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(c));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// AutoUTF\n\n//! Runtime-specified UTF encoding type of a stream.\nenum UTFType {\n    kUTF8 = 0,      //!< UTF-8.\n    kUTF16LE = 1,   //!< UTF-16 little endian.\n    kUTF16BE = 2,   //!< UTF-16 big endian.\n    kUTF32LE = 3,   //!< UTF-32 little endian.\n    kUTF32BE = 4    //!< UTF-32 big endian.\n};\n\n//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.\n/*! \\note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().\n*/\ntemplate<typename CharType>\nstruct AutoUTF {\n    typedef CharType Ch;\n\n    enum { supportUnicode = 1 };\n\n#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x\n\n    template<typename OutputStream>\n    RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {\n        typedef void (*EncodeFunc)(OutputStream&, unsigned);\n        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };\n        (*f[os.GetType()])(os, codepoint);\n    }\n\n    template <typename InputStream>\n    RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {\n        typedef bool (*DecodeFunc)(InputStream&, unsigned*);\n        static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };\n        return (*f[is.GetType()])(is, codepoint);\n    }\n\n    template <typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {\n        typedef bool (*ValidateFunc)(InputStream&, OutputStream&);\n        static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };\n        return (*f[is.GetType()])(is, os);\n    }\n\n#undef RAPIDJSON_ENCODINGS_FUNC\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Transcoder\n\n//! Encoding conversion.\ntemplate<typename SourceEncoding, typename TargetEncoding>\nstruct Transcoder {\n    //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.\n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {\n        unsigned codepoint;\n        if (!SourceEncoding::Decode(is, &codepoint))\n            return false;\n        TargetEncoding::Encode(os, codepoint);\n        return true;\n    }\n\n    //! Validate one Unicode codepoint from an encoded stream.\n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {\n        return Transcode(is, os);   // Since source/target encoding is different, must transcode.\n    }\n};\n\n//! Specialization of Transcoder with same source and target encoding.\ntemplate<typename Encoding>\nstruct Transcoder<Encoding, Encoding> {\n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {\n        os.Put(is.Take());  // Just copy one code unit. This semantic is different from primary template class.\n        return true;\n    }\n    \n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {\n        return Encoding::Validate(is, os);  // source/target encoding are the same\n    }\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__GNUC__) || defined(_MSV_VER)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_ENCODINGS_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/error/en.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ERROR_EN_H__\n#define RAPIDJSON_ERROR_EN_H__\n\n#include \"error.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Maps error code of parsing into error message.\n/*!\n    \\ingroup RAPIDJSON_ERRORS\n    \\param parseErrorCode Error code obtained in parsing.\n    \\return the error message.\n    \\note User can make a copy of this function for localization.\n        Using switch-case is safer for future modification of error codes.\n*/\ninline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {\n    switch (parseErrorCode) {\n        case kParseErrorNone:                           return RAPIDJSON_ERROR_STRING(\"No error.\");\n\n        case kParseErrorDocumentEmpty:                  return RAPIDJSON_ERROR_STRING(\"The document is empty.\");\n        case kParseErrorDocumentRootNotSingular:        return RAPIDJSON_ERROR_STRING(\"The document root must not follow by other values.\");\n    \n        case kParseErrorValueInvalid:                   return RAPIDJSON_ERROR_STRING(\"Invalid value.\");\n    \n        case kParseErrorObjectMissName:                 return RAPIDJSON_ERROR_STRING(\"Missing a name for object member.\");\n        case kParseErrorObjectMissColon:                return RAPIDJSON_ERROR_STRING(\"Missing a colon after a name of object member.\");\n        case kParseErrorObjectMissCommaOrCurlyBracket:  return RAPIDJSON_ERROR_STRING(\"Missing a comma or '}' after an object member.\");\n    \n        case kParseErrorArrayMissCommaOrSquareBracket:  return RAPIDJSON_ERROR_STRING(\"Missing a comma or ']' after an array element.\");\n\n        case kParseErrorStringUnicodeEscapeInvalidHex:  return RAPIDJSON_ERROR_STRING(\"Incorrect hex digit after \\\\u escape in string.\");\n        case kParseErrorStringUnicodeSurrogateInvalid:  return RAPIDJSON_ERROR_STRING(\"The surrogate pair in string is invalid.\");\n        case kParseErrorStringEscapeInvalid:            return RAPIDJSON_ERROR_STRING(\"Invalid escape character in string.\");\n        case kParseErrorStringMissQuotationMark:        return RAPIDJSON_ERROR_STRING(\"Missing a closing quotation mark in string.\");\n        case kParseErrorStringInvalidEncoding:          return RAPIDJSON_ERROR_STRING(\"Invalid encoding in string.\");\n\n        case kParseErrorNumberTooBig:                   return RAPIDJSON_ERROR_STRING(\"Number too big to be stored in double.\");\n        case kParseErrorNumberMissFraction:             return RAPIDJSON_ERROR_STRING(\"Miss fraction part in number.\");\n        case kParseErrorNumberMissExponent:             return RAPIDJSON_ERROR_STRING(\"Miss exponent in number.\");\n\n        case kParseErrorTermination:                    return RAPIDJSON_ERROR_STRING(\"Terminate parsing due to Handler error.\");\n        case kParseErrorUnspecificSyntaxError:          return RAPIDJSON_ERROR_STRING(\"Unspecific syntax error.\");\n\n        default:\n            return RAPIDJSON_ERROR_STRING(\"Unknown error.\");\n    }\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ERROR_EN_H__\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/error/error.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ERROR_ERROR_H__\n#define RAPIDJSON_ERROR_ERROR_H__\n\n#include \"../rapidjson.h\"\n\n/*! \\file error.h */\n\n/*! \\defgroup RAPIDJSON_ERRORS RapidJSON error handling */\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ERROR_CHARTYPE\n\n//! Character type of error messages.\n/*! \\ingroup RAPIDJSON_ERRORS\n    The default character type is \\c char.\n    On Windows, user can define this macro as \\c TCHAR for supporting both\n    unicode/non-unicode settings.\n*/\n#ifndef RAPIDJSON_ERROR_CHARTYPE\n#define RAPIDJSON_ERROR_CHARTYPE char\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ERROR_STRING\n\n//! Macro for converting string literial to \\ref RAPIDJSON_ERROR_CHARTYPE[].\n/*! \\ingroup RAPIDJSON_ERRORS\n    By default this conversion macro does nothing.\n    On Windows, user can define this macro as \\c _T(x) for supporting both\n    unicode/non-unicode settings.\n*/\n#ifndef RAPIDJSON_ERROR_STRING\n#define RAPIDJSON_ERROR_STRING(x) x\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// ParseErrorCode\n\n//! Error code of parsing.\n/*! \\ingroup RAPIDJSON_ERRORS\n    \\see GenericReader::Parse, GenericReader::GetParseErrorCode\n*/\nenum ParseErrorCode {\n    kParseErrorNone = 0,                        //!< No error.\n\n    kParseErrorDocumentEmpty,                   //!< The document is empty.\n    kParseErrorDocumentRootNotSingular,         //!< The document root must not follow by other values.\n\n    kParseErrorValueInvalid,                    //!< Invalid value.\n\n    kParseErrorObjectMissName,                  //!< Missing a name for object member.\n    kParseErrorObjectMissColon,                 //!< Missing a colon after a name of object member.\n    kParseErrorObjectMissCommaOrCurlyBracket,   //!< Missing a comma or '}' after an object member.\n\n    kParseErrorArrayMissCommaOrSquareBracket,   //!< Missing a comma or ']' after an array element.\n\n    kParseErrorStringUnicodeEscapeInvalidHex,   //!< Incorrect hex digit after \\\\u escape in string.\n    kParseErrorStringUnicodeSurrogateInvalid,   //!< The surrogate pair in string is invalid.\n    kParseErrorStringEscapeInvalid,             //!< Invalid escape character in string.\n    kParseErrorStringMissQuotationMark,         //!< Missing a closing quotation mark in string.\n    kParseErrorStringInvalidEncoding,           //!< Invalid encoding in string.\n\n    kParseErrorNumberTooBig,                    //!< Number too big to be stored in double.\n    kParseErrorNumberMissFraction,              //!< Miss fraction part in number.\n    kParseErrorNumberMissExponent,              //!< Miss exponent in number.\n\n    kParseErrorTermination,                     //!< Parsing was terminated.\n    kParseErrorUnspecificSyntaxError            //!< Unspecific syntax error.\n};\n\n//! Result of parsing (wraps ParseErrorCode)\n/*!\n    \\ingroup RAPIDJSON_ERRORS\n    \\code\n        Document doc;\n        ParseResult ok = doc.Parse(\"[42]\");\n        if (!ok) {\n            fprintf(stderr, \"JSON parse error: %s (%u)\",\n                    GetParseError_En(ok.Code()), ok.Offset());\n            exit(EXIT_FAILURE);\n        }\n    \\endcode\n    \\see GenericReader::Parse, GenericDocument::Parse\n*/\nstruct ParseResult {\n\n    //! Default constructor, no error.\n    ParseResult() : code_(kParseErrorNone), offset_(0) {}\n    //! Constructor to set an error.\n    ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}\n\n    //! Get the error code.\n    ParseErrorCode Code() const { return code_; }\n    //! Get the error offset, if \\ref IsError(), 0 otherwise.\n    size_t Offset() const { return offset_; }\n\n    //! Conversion to \\c bool, returns \\c true, iff !\\ref IsError().\n    operator bool() const { return !IsError(); }\n    //! Whether the result is an error.\n    bool IsError() const { return code_ != kParseErrorNone; }\n\n    bool operator==(const ParseResult& that) const { return code_ == that.code_; }\n    bool operator==(ParseErrorCode code) const { return code_ == code; }\n    friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }\n\n    //! Reset error code.\n    void Clear() { Set(kParseErrorNone); }\n    //! Update error code and offset.\n    void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }\n\nprivate:\n    ParseErrorCode code_;\n    size_t offset_;\n};\n\n//! Function pointer type of GetParseError().\n/*! \\ingroup RAPIDJSON_ERRORS\n\n    This is the prototype for \\c GetParseError_X(), where \\c X is a locale.\n    User can dynamically change locale in runtime, e.g.:\n\\code\n    GetParseErrorFunc GetParseError = GetParseError_En; // or whatever\n    const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());\n\\endcode\n*/\ntypedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ERROR_ERROR_H__\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/filereadstream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_FILEREADSTREAM_H_\n#define RAPIDJSON_FILEREADSTREAM_H_\n\n#include \"rapidjson.h\"\n#include <cstdio>\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! File byte stream for input using fread().\n/*!\n    \\note implements Stream concept\n*/\nclass FileReadStream {\npublic:\n    typedef char Ch;    //!< Character type (byte).\n\n    //! Constructor.\n    /*!\n        \\param fp File pointer opened for read.\n        \\param buffer user-supplied buffer.\n        \\param bufferSize size of buffer in bytes. Must >=4 bytes.\n    */\n    FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { \n        RAPIDJSON_ASSERT(fp_ != 0);\n        RAPIDJSON_ASSERT(bufferSize >= 4);\n        Read();\n    }\n\n    Ch Peek() const { return *current_; }\n    Ch Take() { Ch c = *current_; Read(); return c; }\n    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    // For encoding detection only.\n    const Ch* Peek4() const {\n        return (current_ + 4 <= bufferLast_) ? current_ : 0;\n    }\n\nprivate:\n    void Read() {\n        if (current_ < bufferLast_)\n            ++current_;\n        else if (!eof_) {\n            count_ += readCount_;\n            readCount_ = fread(buffer_, 1, bufferSize_, fp_);\n            bufferLast_ = buffer_ + readCount_ - 1;\n            current_ = buffer_;\n\n            if (readCount_ < bufferSize_) {\n                buffer_[readCount_] = '\\0';\n                ++bufferLast_;\n                eof_ = true;\n            }\n        }\n    }\n\n    std::FILE* fp_;\n    Ch *buffer_;\n    size_t bufferSize_;\n    Ch *bufferLast_;\n    Ch *current_;\n    size_t readCount_;\n    size_t count_;  //!< Number of characters read\n    bool eof_;\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/filewritestream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_FILEWRITESTREAM_H_\n#define RAPIDJSON_FILEWRITESTREAM_H_\n\n#include \"rapidjson.h\"\n#include <cstdio>\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Wrapper of C file stream for input using fread().\n/*!\n    \\note implements Stream concept\n*/\nclass FileWriteStream {\npublic:\n    typedef char Ch;    //!< Character type. Only support char.\n\n    FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { \n        RAPIDJSON_ASSERT(fp_ != 0);\n    }\n\n    void Put(char c) { \n        if (current_ >= bufferEnd_)\n            Flush();\n\n        *current_++ = c;\n    }\n\n    void PutN(char c, size_t n) {\n        size_t avail = static_cast<size_t>(bufferEnd_ - current_);\n        while (n > avail) {\n            std::memset(current_, c, avail);\n            current_ += avail;\n            Flush();\n            n -= avail;\n            avail = static_cast<size_t>(bufferEnd_ - current_);\n        }\n\n        if (n > 0) {\n            std::memset(current_, c, n);\n            current_ += n;\n        }\n    }\n\n    void Flush() {\n        if (current_ != buffer_) {\n            fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);\n            current_ = buffer_;\n        }\n    }\n\n    // Not implemented\n    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }\n    char Take() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }\n    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    FileWriteStream(const FileWriteStream&);\n    FileWriteStream& operator=(const FileWriteStream&);\n\n    std::FILE* fp_;\n    char *buffer_;\n    char *bufferEnd_;\n    char *current_;\n};\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(FileWriteStream& stream, char c, size_t n) {\n    stream.PutN(c, n);\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/biginteger.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_BIGINTEGER_H_\n#define RAPIDJSON_BIGINTEGER_H_\n\n#include \"../rapidjson.h\"\n\n#if defined(_MSC_VER) && defined(_M_AMD64)\n#include <intrin.h> // for _umul128\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\nclass BigInteger {\npublic:\n    typedef uint64_t Type;\n\n    BigInteger(const BigInteger& rhs) : count_(rhs.count_) {\n        std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));\n    }\n\n    explicit BigInteger(uint64_t u) : count_(1) {\n        digits_[0] = u;\n    }\n\n    BigInteger(const char* decimals, size_t length) : count_(1) {\n        RAPIDJSON_ASSERT(length > 0);\n        digits_[0] = 0;\n        size_t i = 0;\n        const size_t kMaxDigitPerIteration = 19;  // 2^64 = 18446744073709551616 > 10^19\n        while (length >= kMaxDigitPerIteration) {\n            AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);\n            length -= kMaxDigitPerIteration;\n            i += kMaxDigitPerIteration;\n        }\n\n        if (length > 0)\n            AppendDecimal64(decimals + i, decimals + i + length);\n    }\n\n    BigInteger& operator=(uint64_t u) {\n        digits_[0] = u;            \n        count_ = 1;\n        return *this;\n    }\n\n    BigInteger& operator+=(uint64_t u) {\n        Type backup = digits_[0];\n        digits_[0] += u;\n        for (size_t i = 0; i < count_ - 1; i++) {\n            if (digits_[i] >= backup)\n                return *this; // no carry\n            backup = digits_[i + 1];\n            digits_[i + 1] += 1;\n        }\n\n        // Last carry\n        if (digits_[count_ - 1] < backup)\n            PushBack(1);\n\n        return *this;\n    }\n\n    BigInteger& operator*=(uint64_t u) {\n        if (u == 0) return *this = 0;\n        if (u == 1) return *this;\n        if (*this == 1) return *this = u;\n\n        uint64_t k = 0;\n        for (size_t i = 0; i < count_; i++) {\n            uint64_t hi;\n            digits_[i] = MulAdd64(digits_[i], u, k, &hi);\n            k = hi;\n        }\n        \n        if (k > 0)\n            PushBack(k);\n\n        return *this;\n    }\n\n    BigInteger& operator*=(uint32_t u) {\n        if (u == 0) return *this = 0;\n        if (u == 1) return *this;\n        if (*this == 1) return *this = u;\n\n        uint64_t k = 0;\n        for (size_t i = 0; i < count_; i++) {\n            const uint64_t c = digits_[i] >> 32;\n            const uint64_t d = digits_[i] & 0xFFFFFFFF;\n            const uint64_t uc = u * c;\n            const uint64_t ud = u * d;\n            const uint64_t p0 = ud + k;\n            const uint64_t p1 = uc + (p0 >> 32);\n            digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);\n            k = p1 >> 32;\n        }\n        \n        if (k > 0)\n            PushBack(k);\n\n        return *this;\n    }\n\n    BigInteger& operator<<=(size_t shift) {\n        if (IsZero() || shift == 0) return *this;\n\n        size_t offset = shift / kTypeBit;\n        size_t interShift = shift % kTypeBit;\n        RAPIDJSON_ASSERT(count_ + offset <= kCapacity);\n\n        if (interShift == 0) {\n            std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));\n            count_ += offset;\n        }\n        else {\n            digits_[count_] = 0;\n            for (size_t i = count_; i > 0; i--)\n                digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));\n            digits_[offset] = digits_[0] << interShift;\n            count_ += offset;\n            if (digits_[count_])\n                count_++;\n        }\n\n        std::memset(digits_, 0, offset * sizeof(Type));\n\n        return *this;\n    }\n\n    bool operator==(const BigInteger& rhs) const {\n        return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;\n    }\n\n    bool operator==(const Type rhs) const {\n        return count_ == 1 && digits_[0] == rhs;\n    }\n\n    BigInteger& MultiplyPow5(unsigned exp) {\n        static const uint32_t kPow5[12] = {\n            5,\n            5 * 5,\n            5 * 5 * 5,\n            5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5\n        };\n        if (exp == 0) return *this;\n        for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27\n        for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13\n        if (exp > 0)                 *this *= kPow5[exp - 1];\n        return *this;\n    }\n\n    // Compute absolute difference of this and rhs.\n    // Assume this != rhs\n    bool Difference(const BigInteger& rhs, BigInteger* out) const {\n        int cmp = Compare(rhs);\n        RAPIDJSON_ASSERT(cmp != 0);\n        const BigInteger *a, *b;  // Makes a > b\n        bool ret;\n        if (cmp < 0) { a = &rhs; b = this; ret = true; }\n        else         { a = this; b = &rhs; ret = false; }\n\n        Type borrow = 0;\n        for (size_t i = 0; i < a->count_; i++) {\n            Type d = a->digits_[i] - borrow;\n            if (i < b->count_)\n                d -= b->digits_[i];\n            borrow = (d > a->digits_[i]) ? 1 : 0;\n            out->digits_[i] = d;\n            if (d != 0)\n                out->count_ = i + 1;\n        }\n\n        return ret;\n    }\n\n    int Compare(const BigInteger& rhs) const {\n        if (count_ != rhs.count_)\n            return count_ < rhs.count_ ? -1 : 1;\n\n        for (size_t i = count_; i-- > 0;)\n            if (digits_[i] != rhs.digits_[i])\n                return digits_[i] < rhs.digits_[i] ? -1 : 1;\n\n        return 0;\n    }\n\n    size_t GetCount() const { return count_; }\n    Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }\n    bool IsZero() const { return count_ == 1 && digits_[0] == 0; }\n\nprivate:\n    void AppendDecimal64(const char* begin, const char* end) {\n        uint64_t u = ParseUint64(begin, end);\n        if (IsZero())\n            *this = u;\n        else {\n            unsigned exp = static_cast<unsigned>(end - begin);\n            (MultiplyPow5(exp) <<= exp) += u;   // *this = *this * 10^exp + u\n        }\n    }\n\n    void PushBack(Type digit) {\n        RAPIDJSON_ASSERT(count_ < kCapacity);\n        digits_[count_++] = digit;\n    }\n\n    static uint64_t ParseUint64(const char* begin, const char* end) {\n        uint64_t r = 0;\n        for (const char* p = begin; p != end; ++p) {\n            RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');\n            r = r * 10 + (*p - '0');\n        }\n        return r;\n    }\n\n    // Assume a * b + k < 2^128\n    static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {\n#if defined(_MSC_VER) && defined(_M_AMD64)\n        uint64_t low = _umul128(a, b, outHigh) + k;\n        if (low < k)\n            (*outHigh)++;\n        return low;\n#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)\n        __extension__ typedef unsigned __int128 uint128;\n        uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);\n        p += k;\n        *outHigh = static_cast<uint64_t>(p >> 64);\n        return static_cast<uint64_t>(p);\n#else\n        const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;\n        uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;\n        x1 += (x0 >> 32); // can't give carry\n        x1 += x2;\n        if (x1 < x2)\n            x3 += (static_cast<uint64_t>(1) << 32);\n        uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);\n        uint64_t hi = x3 + (x1 >> 32);\n\n        lo += k;\n        if (lo < k)\n            hi++;\n        *outHigh = hi;\n        return lo;\n#endif\n    }\n\n    static const size_t kBitCount = 3328;  // 64bit * 54 > 10^1000\n    static const size_t kCapacity = kBitCount / sizeof(Type);\n    static const size_t kTypeBit = sizeof(Type) * 8;\n\n    Type digits_[kCapacity];\n    size_t count_;\n};\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_BIGINTEGER_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/diyfp.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n// This is a C++ header-only implementation of Grisu2 algorithm from the publication:\n// Loitsch, Florian. \"Printing floating-point numbers quickly and accurately with\n// integers.\" ACM Sigplan Notices 45.6 (2010): 233-243.\n\n#ifndef RAPIDJSON_DIYFP_H_\n#define RAPIDJSON_DIYFP_H_\n\n#include \"../rapidjson.h\"\n\n#if defined(_MSC_VER) && defined(_M_AMD64)\n#include <intrin.h>\n#pragma intrinsic(_BitScanReverse64)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\nstruct DiyFp {\n    DiyFp() {}\n\n    DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}\n\n    explicit DiyFp(double d) {\n        union {\n            double d;\n            uint64_t u64;\n        } u = { d };\n\n        int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);\n        uint64_t significand = (u.u64 & kDpSignificandMask);\n        if (biased_e != 0) {\n            f = significand + kDpHiddenBit;\n            e = biased_e - kDpExponentBias;\n        } \n        else {\n            f = significand;\n            e = kDpMinExponent + 1;\n        }\n    }\n\n    DiyFp operator-(const DiyFp& rhs) const {\n        return DiyFp(f - rhs.f, e);\n    }\n\n    DiyFp operator*(const DiyFp& rhs) const {\n#if defined(_MSC_VER) && defined(_M_AMD64)\n        uint64_t h;\n        uint64_t l = _umul128(f, rhs.f, &h);\n        if (l & (uint64_t(1) << 63)) // rounding\n            h++;\n        return DiyFp(h, e + rhs.e + 64);\n#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)\n        __extension__ typedef unsigned __int128 uint128;\n        uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);\n        uint64_t h = static_cast<uint64_t>(p >> 64);\n        uint64_t l = static_cast<uint64_t>(p);\n        if (l & (uint64_t(1) << 63)) // rounding\n            h++;\n        return DiyFp(h, e + rhs.e + 64);\n#else\n        const uint64_t M32 = 0xFFFFFFFF;\n        const uint64_t a = f >> 32;\n        const uint64_t b = f & M32;\n        const uint64_t c = rhs.f >> 32;\n        const uint64_t d = rhs.f & M32;\n        const uint64_t ac = a * c;\n        const uint64_t bc = b * c;\n        const uint64_t ad = a * d;\n        const uint64_t bd = b * d;\n        uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);\n        tmp += 1U << 31;  /// mult_round\n        return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);\n#endif\n    }\n\n    DiyFp Normalize() const {\n#if defined(_MSC_VER) && defined(_M_AMD64)\n        unsigned long index;\n        _BitScanReverse64(&index, f);\n        return DiyFp(f << (63 - index), e - (63 - index));\n#elif defined(__GNUC__) && __GNUC__ >= 4\n        int s = __builtin_clzll(f);\n        return DiyFp(f << s, e - s);\n#else\n        DiyFp res = *this;\n        while (!(res.f & (static_cast<uint64_t>(1) << 63))) {\n            res.f <<= 1;\n            res.e--;\n        }\n        return res;\n#endif\n    }\n\n    DiyFp NormalizeBoundary() const {\n        DiyFp res = *this;\n        while (!(res.f & (kDpHiddenBit << 1))) {\n            res.f <<= 1;\n            res.e--;\n        }\n        res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);\n        res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);\n        return res;\n    }\n\n    void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {\n        DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();\n        DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);\n        mi.f <<= mi.e - pl.e;\n        mi.e = pl.e;\n        *plus = pl;\n        *minus = mi;\n    }\n\n    double ToDouble() const {\n        union {\n            double d;\n            uint64_t u64;\n        }u;\n        const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : \n            static_cast<uint64_t>(e + kDpExponentBias);\n        u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);\n        return u.d;\n    }\n\n    static const int kDiySignificandSize = 64;\n    static const int kDpSignificandSize = 52;\n    static const int kDpExponentBias = 0x3FF + kDpSignificandSize;\n    static const int kDpMaxExponent = 0x7FF - kDpExponentBias;\n    static const int kDpMinExponent = -kDpExponentBias;\n    static const int kDpDenormalExponent = -kDpExponentBias + 1;\n    static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);\n    static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);\n    static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);\n\n    uint64_t f;\n    int e;\n};\n\ninline DiyFp GetCachedPowerByIndex(size_t index) {\n    // 10^-348, 10^-340, ..., 10^340\n    static const uint64_t kCachedPowers_F[] = {\n        RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),\n        RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),\n        RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),\n        RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),\n        RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),\n        RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),\n        RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),\n        RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),\n        RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),\n        RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),\n        RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),\n        RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),\n        RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),\n        RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),\n        RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),\n        RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),\n        RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),\n        RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),\n        RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),\n        RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),\n        RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),\n        RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),\n        RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),\n        RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),\n        RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),\n        RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),\n        RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),\n        RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),\n        RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),\n        RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),\n        RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),\n        RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),\n        RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),\n        RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),\n        RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),\n        RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),\n        RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),\n        RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),\n        RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),\n        RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),\n        RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),\n        RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),\n        RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),\n        RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)\n    };\n    static const int16_t kCachedPowers_E[] = {\n        -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007,  -980,\n        -954,  -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,\n        -688,  -661,  -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,\n        -422,  -396,  -369,  -343,  -316,  -289,  -263,  -236,  -210,  -183,\n        -157,  -130,  -103,   -77,   -50,   -24,     3,    30,    56,    83,\n        109,   136,   162,   189,   216,   242,   269,   295,   322,   348,\n        375,   402,   428,   455,   481,   508,   534,   561,   588,   614,\n        641,   667,   694,   720,   747,   774,   800,   827,   853,   880,\n        907,   933,   960,   986,  1013,  1039,  1066\n    };\n    return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);\n}\n    \ninline DiyFp GetCachedPower(int e, int* K) {\n\n    //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;\n    double dk = (-61 - e) * 0.30102999566398114 + 347;  // dk must be positive, so can do ceiling in positive\n    int k = static_cast<int>(dk);\n    if (dk - k > 0.0)\n        k++;\n\n    unsigned index = static_cast<unsigned>((k >> 3) + 1);\n    *K = -(-348 + static_cast<int>(index << 3));    // decimal exponent no need lookup table\n\n    return GetCachedPowerByIndex(index);\n}\n\ninline DiyFp GetCachedPower10(int exp, int *outExp) {\n     unsigned index = (exp + 348) / 8;\n     *outExp = -348 + index * 8;\n     return GetCachedPowerByIndex(index);\n }\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_DIYFP_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/dtoa.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n// This is a C++ header-only implementation of Grisu2 algorithm from the publication:\n// Loitsch, Florian. \"Printing floating-point numbers quickly and accurately with\n// integers.\" ACM Sigplan Notices 45.6 (2010): 233-243.\n\n#ifndef RAPIDJSON_DTOA_\n#define RAPIDJSON_DTOA_\n\n#include \"itoa.h\" // GetDigitsLut()\n#include \"diyfp.h\"\n#include \"ieee754.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\ninline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {\n    while (rest < wp_w && delta - rest >= ten_kappa &&\n           (rest + ten_kappa < wp_w ||  /// closer\n            wp_w - rest > rest + ten_kappa - wp_w)) {\n        buffer[len - 1]--;\n        rest += ten_kappa;\n    }\n}\n\ninline unsigned CountDecimalDigit32(uint32_t n) {\n    // Simple pure C++ implementation was faster than __builtin_clz version in this situation.\n    if (n < 10) return 1;\n    if (n < 100) return 2;\n    if (n < 1000) return 3;\n    if (n < 10000) return 4;\n    if (n < 100000) return 5;\n    if (n < 1000000) return 6;\n    if (n < 10000000) return 7;\n    if (n < 100000000) return 8;\n    // Will not reach 10 digits in DigitGen()\n    //if (n < 1000000000) return 9;\n    //return 10;\n    return 9;\n}\n\ninline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {\n    static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };\n    const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);\n    const DiyFp wp_w = Mp - W;\n    uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);\n    uint64_t p2 = Mp.f & (one.f - 1);\n    int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]\n    *len = 0;\n\n    while (kappa > 0) {\n        uint32_t d = 0;\n        switch (kappa) {\n            case  9: d = p1 /  100000000; p1 %=  100000000; break;\n            case  8: d = p1 /   10000000; p1 %=   10000000; break;\n            case  7: d = p1 /    1000000; p1 %=    1000000; break;\n            case  6: d = p1 /     100000; p1 %=     100000; break;\n            case  5: d = p1 /      10000; p1 %=      10000; break;\n            case  4: d = p1 /       1000; p1 %=       1000; break;\n            case  3: d = p1 /        100; p1 %=        100; break;\n            case  2: d = p1 /         10; p1 %=         10; break;\n            case  1: d = p1;              p1 =           0; break;\n            default:;\n        }\n        if (d || *len)\n            buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));\n        kappa--;\n        uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;\n        if (tmp <= delta) {\n            *K += kappa;\n            GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);\n            return;\n        }\n    }\n\n    // kappa = 0\n    for (;;) {\n        p2 *= 10;\n        delta *= 10;\n        char d = static_cast<char>(p2 >> -one.e);\n        if (d || *len)\n            buffer[(*len)++] = static_cast<char>('0' + d);\n        p2 &= one.f - 1;\n        kappa--;\n        if (p2 < delta) {\n            *K += kappa;\n            GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);\n            return;\n        }\n    }\n}\n\ninline void Grisu2(double value, char* buffer, int* length, int* K) {\n    const DiyFp v(value);\n    DiyFp w_m, w_p;\n    v.NormalizedBoundaries(&w_m, &w_p);\n\n    const DiyFp c_mk = GetCachedPower(w_p.e, K);\n    const DiyFp W = v.Normalize() * c_mk;\n    DiyFp Wp = w_p * c_mk;\n    DiyFp Wm = w_m * c_mk;\n    Wm.f++;\n    Wp.f--;\n    DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);\n}\n\ninline char* WriteExponent(int K, char* buffer) {\n    if (K < 0) {\n        *buffer++ = '-';\n        K = -K;\n    }\n\n    if (K >= 100) {\n        *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));\n        K %= 100;\n        const char* d = GetDigitsLut() + K * 2;\n        *buffer++ = d[0];\n        *buffer++ = d[1];\n    }\n    else if (K >= 10) {\n        const char* d = GetDigitsLut() + K * 2;\n        *buffer++ = d[0];\n        *buffer++ = d[1];\n    }\n    else\n        *buffer++ = static_cast<char>('0' + static_cast<char>(K));\n\n    return buffer;\n}\n\ninline char* Prettify(char* buffer, int length, int k) {\n    const int kk = length + k;  // 10^(kk-1) <= v < 10^kk\n\n    if (length <= kk && kk <= 21) {\n        // 1234e7 -> 12340000000\n        for (int i = length; i < kk; i++)\n            buffer[i] = '0';\n        buffer[kk] = '.';\n        buffer[kk + 1] = '0';\n        return &buffer[kk + 2];\n    }\n    else if (0 < kk && kk <= 21) {\n        // 1234e-2 -> 12.34\n        std::memmove(&buffer[kk + 1], &buffer[kk], length - kk);\n        buffer[kk] = '.';\n        return &buffer[length + 1];\n    }\n    else if (-6 < kk && kk <= 0) {\n        // 1234e-6 -> 0.001234\n        const int offset = 2 - kk;\n        std::memmove(&buffer[offset], &buffer[0], length);\n        buffer[0] = '0';\n        buffer[1] = '.';\n        for (int i = 2; i < offset; i++)\n            buffer[i] = '0';\n        return &buffer[length + offset];\n    }\n    else if (length == 1) {\n        // 1e30\n        buffer[1] = 'e';\n        return WriteExponent(kk - 1, &buffer[2]);\n    }\n    else {\n        // 1234e30 -> 1.234e33\n        std::memmove(&buffer[2], &buffer[1], length - 1);\n        buffer[1] = '.';\n        buffer[length + 1] = 'e';\n        return WriteExponent(kk - 1, &buffer[0 + length + 2]);\n    }\n}\n\ninline char* dtoa(double value, char* buffer) {\n    Double d(value);\n    if (d.IsZero()) {\n        if (d.Sign())\n            *buffer++ = '-';     // -0.0, Issue #289\n        buffer[0] = '0';\n        buffer[1] = '.';\n        buffer[2] = '0';\n        return &buffer[3];\n    }\n    else {\n        if (value < 0) {\n            *buffer++ = '-';\n            value = -value;\n        }\n        int length, K;\n        Grisu2(value, buffer, &length, &K);\n        return Prettify(buffer, length, K);\n    }\n}\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_DTOA_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/ieee754.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_IEEE754_\n#define RAPIDJSON_IEEE754_\n\n#include \"../rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\nclass Double {\npublic:\n    Double() {}\n    Double(double d) : d_(d) {}\n    Double(uint64_t u) : u_(u) {}\n\n    double Value() const { return d_; }\n    uint64_t Uint64Value() const { return u_; }\n\n    double NextPositiveDouble() const {\n        RAPIDJSON_ASSERT(!Sign());\n        return Double(u_ + 1).Value();\n    }\n\n    bool Sign() const { return (u_ & kSignMask) != 0; }\n    uint64_t Significand() const { return u_ & kSignificandMask; }\n    int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }\n\n    bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }\n    bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }\n    bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }\n    bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }\n\n    uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }\n    int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }\n    uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }\n\n    static unsigned EffectiveSignificandSize(int order) {\n        if (order >= -1021)\n            return 53;\n        else if (order <= -1074)\n            return 0;\n        else\n            return order + 1074;\n    }\n\nprivate:\n    static const int kSignificandSize = 52;\n    static const int kExponentBias = 0x3FF;\n    static const int kDenormalExponent = 1 - kExponentBias;\n    static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);\n    static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);\n    static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);\n    static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);\n\n    union {\n        double d_;\n        uint64_t u_;\n    };\n};\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_IEEE754_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/itoa.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ITOA_\n#define RAPIDJSON_ITOA_\n\n#include \"../rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\ninline const char* GetDigitsLut() {\n    static const char cDigitsLut[200] = {\n        '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',\n        '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',\n        '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',\n        '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',\n        '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',\n        '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',\n        '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',\n        '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',\n        '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',\n        '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'\n    };\n    return cDigitsLut;\n}\n\ninline char* u32toa(uint32_t value, char* buffer) {\n    const char* cDigitsLut = GetDigitsLut();\n\n    if (value < 10000) {\n        const uint32_t d1 = (value / 100) << 1;\n        const uint32_t d2 = (value % 100) << 1;\n        \n        if (value >= 1000)\n            *buffer++ = cDigitsLut[d1];\n        if (value >= 100)\n            *buffer++ = cDigitsLut[d1 + 1];\n        if (value >= 10)\n            *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n    }\n    else if (value < 100000000) {\n        // value = bbbbcccc\n        const uint32_t b = value / 10000;\n        const uint32_t c = value % 10000;\n        \n        const uint32_t d1 = (b / 100) << 1;\n        const uint32_t d2 = (b % 100) << 1;\n        \n        const uint32_t d3 = (c / 100) << 1;\n        const uint32_t d4 = (c % 100) << 1;\n        \n        if (value >= 10000000)\n            *buffer++ = cDigitsLut[d1];\n        if (value >= 1000000)\n            *buffer++ = cDigitsLut[d1 + 1];\n        if (value >= 100000)\n            *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n        \n        *buffer++ = cDigitsLut[d3];\n        *buffer++ = cDigitsLut[d3 + 1];\n        *buffer++ = cDigitsLut[d4];\n        *buffer++ = cDigitsLut[d4 + 1];\n    }\n    else {\n        // value = aabbbbcccc in decimal\n        \n        const uint32_t a = value / 100000000; // 1 to 42\n        value %= 100000000;\n        \n        if (a >= 10) {\n            const unsigned i = a << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n        }\n        else\n            *buffer++ = static_cast<char>('0' + static_cast<char>(a));\n\n        const uint32_t b = value / 10000; // 0 to 9999\n        const uint32_t c = value % 10000; // 0 to 9999\n        \n        const uint32_t d1 = (b / 100) << 1;\n        const uint32_t d2 = (b % 100) << 1;\n        \n        const uint32_t d3 = (c / 100) << 1;\n        const uint32_t d4 = (c % 100) << 1;\n        \n        *buffer++ = cDigitsLut[d1];\n        *buffer++ = cDigitsLut[d1 + 1];\n        *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n        *buffer++ = cDigitsLut[d3];\n        *buffer++ = cDigitsLut[d3 + 1];\n        *buffer++ = cDigitsLut[d4];\n        *buffer++ = cDigitsLut[d4 + 1];\n    }\n    return buffer;\n}\n\ninline char* i32toa(int32_t value, char* buffer) {\n    uint32_t u = static_cast<uint32_t>(value);\n    if (value < 0) {\n        *buffer++ = '-';\n        u = ~u + 1;\n    }\n\n    return u32toa(u, buffer);\n}\n\ninline char* u64toa(uint64_t value, char* buffer) {\n    const char* cDigitsLut = GetDigitsLut();\n    const uint64_t  kTen8 = 100000000;\n    const uint64_t  kTen9 = kTen8 * 10;\n    const uint64_t kTen10 = kTen8 * 100;\n    const uint64_t kTen11 = kTen8 * 1000;\n    const uint64_t kTen12 = kTen8 * 10000;\n    const uint64_t kTen13 = kTen8 * 100000;\n    const uint64_t kTen14 = kTen8 * 1000000;\n    const uint64_t kTen15 = kTen8 * 10000000;\n    const uint64_t kTen16 = kTen8 * kTen8;\n    \n    if (value < kTen8) {\n        uint32_t v = static_cast<uint32_t>(value);\n        if (v < 10000) {\n            const uint32_t d1 = (v / 100) << 1;\n            const uint32_t d2 = (v % 100) << 1;\n            \n            if (v >= 1000)\n                *buffer++ = cDigitsLut[d1];\n            if (v >= 100)\n                *buffer++ = cDigitsLut[d1 + 1];\n            if (v >= 10)\n                *buffer++ = cDigitsLut[d2];\n            *buffer++ = cDigitsLut[d2 + 1];\n        }\n        else {\n            // value = bbbbcccc\n            const uint32_t b = v / 10000;\n            const uint32_t c = v % 10000;\n            \n            const uint32_t d1 = (b / 100) << 1;\n            const uint32_t d2 = (b % 100) << 1;\n            \n            const uint32_t d3 = (c / 100) << 1;\n            const uint32_t d4 = (c % 100) << 1;\n            \n            if (value >= 10000000)\n                *buffer++ = cDigitsLut[d1];\n            if (value >= 1000000)\n                *buffer++ = cDigitsLut[d1 + 1];\n            if (value >= 100000)\n                *buffer++ = cDigitsLut[d2];\n            *buffer++ = cDigitsLut[d2 + 1];\n            \n            *buffer++ = cDigitsLut[d3];\n            *buffer++ = cDigitsLut[d3 + 1];\n            *buffer++ = cDigitsLut[d4];\n            *buffer++ = cDigitsLut[d4 + 1];\n        }\n    }\n    else if (value < kTen16) {\n        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);\n        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);\n        \n        const uint32_t b0 = v0 / 10000;\n        const uint32_t c0 = v0 % 10000;\n        \n        const uint32_t d1 = (b0 / 100) << 1;\n        const uint32_t d2 = (b0 % 100) << 1;\n        \n        const uint32_t d3 = (c0 / 100) << 1;\n        const uint32_t d4 = (c0 % 100) << 1;\n\n        const uint32_t b1 = v1 / 10000;\n        const uint32_t c1 = v1 % 10000;\n        \n        const uint32_t d5 = (b1 / 100) << 1;\n        const uint32_t d6 = (b1 % 100) << 1;\n        \n        const uint32_t d7 = (c1 / 100) << 1;\n        const uint32_t d8 = (c1 % 100) << 1;\n\n        if (value >= kTen15)\n            *buffer++ = cDigitsLut[d1];\n        if (value >= kTen14)\n            *buffer++ = cDigitsLut[d1 + 1];\n        if (value >= kTen13)\n            *buffer++ = cDigitsLut[d2];\n        if (value >= kTen12)\n            *buffer++ = cDigitsLut[d2 + 1];\n        if (value >= kTen11)\n            *buffer++ = cDigitsLut[d3];\n        if (value >= kTen10)\n            *buffer++ = cDigitsLut[d3 + 1];\n        if (value >= kTen9)\n            *buffer++ = cDigitsLut[d4];\n        if (value >= kTen8)\n            *buffer++ = cDigitsLut[d4 + 1];\n        \n        *buffer++ = cDigitsLut[d5];\n        *buffer++ = cDigitsLut[d5 + 1];\n        *buffer++ = cDigitsLut[d6];\n        *buffer++ = cDigitsLut[d6 + 1];\n        *buffer++ = cDigitsLut[d7];\n        *buffer++ = cDigitsLut[d7 + 1];\n        *buffer++ = cDigitsLut[d8];\n        *buffer++ = cDigitsLut[d8 + 1];\n    }\n    else {\n        const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844\n        value %= kTen16;\n        \n        if (a < 10)\n            *buffer++ = static_cast<char>('0' + static_cast<char>(a));\n        else if (a < 100) {\n            const uint32_t i = a << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n        }\n        else if (a < 1000) {\n            *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));\n            \n            const uint32_t i = (a % 100) << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n        }\n        else {\n            const uint32_t i = (a / 100) << 1;\n            const uint32_t j = (a % 100) << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n            *buffer++ = cDigitsLut[j];\n            *buffer++ = cDigitsLut[j + 1];\n        }\n        \n        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);\n        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);\n        \n        const uint32_t b0 = v0 / 10000;\n        const uint32_t c0 = v0 % 10000;\n        \n        const uint32_t d1 = (b0 / 100) << 1;\n        const uint32_t d2 = (b0 % 100) << 1;\n        \n        const uint32_t d3 = (c0 / 100) << 1;\n        const uint32_t d4 = (c0 % 100) << 1;\n        \n        const uint32_t b1 = v1 / 10000;\n        const uint32_t c1 = v1 % 10000;\n        \n        const uint32_t d5 = (b1 / 100) << 1;\n        const uint32_t d6 = (b1 % 100) << 1;\n        \n        const uint32_t d7 = (c1 / 100) << 1;\n        const uint32_t d8 = (c1 % 100) << 1;\n        \n        *buffer++ = cDigitsLut[d1];\n        *buffer++ = cDigitsLut[d1 + 1];\n        *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n        *buffer++ = cDigitsLut[d3];\n        *buffer++ = cDigitsLut[d3 + 1];\n        *buffer++ = cDigitsLut[d4];\n        *buffer++ = cDigitsLut[d4 + 1];\n        *buffer++ = cDigitsLut[d5];\n        *buffer++ = cDigitsLut[d5 + 1];\n        *buffer++ = cDigitsLut[d6];\n        *buffer++ = cDigitsLut[d6 + 1];\n        *buffer++ = cDigitsLut[d7];\n        *buffer++ = cDigitsLut[d7 + 1];\n        *buffer++ = cDigitsLut[d8];\n        *buffer++ = cDigitsLut[d8 + 1];\n    }\n    \n    return buffer;\n}\n\ninline char* i64toa(int64_t value, char* buffer) {\n    uint64_t u = static_cast<uint64_t>(value);\n    if (value < 0) {\n        *buffer++ = '-';\n        u = ~u + 1;\n    }\n\n    return u64toa(u, buffer);\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ITOA_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/meta.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_META_H_\n#define RAPIDJSON_INTERNAL_META_H_\n\n#include \"../rapidjson.h\"\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n#if defined(_MSC_VER)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(6334)\n#endif\n\n#if RAPIDJSON_HAS_CXX11_TYPETRAITS\n#include <type_traits>\n#endif\n\n//@cond RAPIDJSON_INTERNAL\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching\ntemplate <typename T> struct Void { typedef void Type; };\n\n///////////////////////////////////////////////////////////////////////////////\n// BoolType, TrueType, FalseType\n//\ntemplate <bool Cond> struct BoolType {\n    static const bool Value = Cond;\n    typedef BoolType Type;\n};\ntypedef BoolType<true> TrueType;\ntypedef BoolType<false> FalseType;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr\n//\n\ntemplate <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };\ntemplate <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };\ntemplate <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};\ntemplate <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};\n\ntemplate <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};\ntemplate <> struct AndExprCond<true, true> : TrueType {};\ntemplate <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};\ntemplate <> struct OrExprCond<false, false> : FalseType {};\n\ntemplate <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};\ntemplate <typename C> struct NotExpr  : SelectIf<C,FalseType,TrueType>::Type {};\ntemplate <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};\ntemplate <typename C1, typename C2> struct OrExpr  : OrExprCond<C1::Value, C2::Value>::Type {};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// AddConst, MaybeAddConst, RemoveConst\ntemplate <typename T> struct AddConst { typedef const T Type; };\ntemplate <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};\ntemplate <typename T> struct RemoveConst { typedef T Type; };\ntemplate <typename T> struct RemoveConst<const T> { typedef T Type; };\n\n\n///////////////////////////////////////////////////////////////////////////////\n// IsSame, IsConst, IsMoreConst, IsPointer\n//\ntemplate <typename T, typename U> struct IsSame : FalseType {};\ntemplate <typename T> struct IsSame<T, T> : TrueType {};\n\ntemplate <typename T> struct IsConst : FalseType {};\ntemplate <typename T> struct IsConst<const T> : TrueType {};\n\ntemplate <typename CT, typename T>\nstruct IsMoreConst\n    : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,\n              BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};\n\ntemplate <typename T> struct IsPointer : FalseType {};\ntemplate <typename T> struct IsPointer<T*> : TrueType {};\n\n///////////////////////////////////////////////////////////////////////////////\n// IsBaseOf\n//\n#if RAPIDJSON_HAS_CXX11_TYPETRAITS\n\ntemplate <typename B, typename D> struct IsBaseOf\n    : BoolType< ::std::is_base_of<B,D>::value> {};\n\n#else // simplified version adopted from Boost\n\ntemplate<typename B, typename D> struct IsBaseOfImpl {\n    RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);\n    RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);\n\n    typedef char (&Yes)[1];\n    typedef char (&No) [2];\n\n    template <typename T>\n    static Yes Check(const D*, T);\n    static No  Check(const B*, int);\n\n    struct Host {\n        operator const B*() const;\n        operator const D*();\n    };\n\n    enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };\n};\n\ntemplate <typename B, typename D> struct IsBaseOf\n    : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};\n\n#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS\n\n\n//////////////////////////////////////////////////////////////////////////\n// EnableIf / DisableIf\n//\ntemplate <bool Condition, typename T = void> struct EnableIfCond  { typedef T Type; };\ntemplate <typename T> struct EnableIfCond<false, T> { /* empty */ };\n\ntemplate <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };\ntemplate <typename T> struct DisableIfCond<true, T> { /* empty */ };\n\ntemplate <typename Condition, typename T = void>\nstruct EnableIf : EnableIfCond<Condition::Value, T> {};\n\ntemplate <typename Condition, typename T = void>\nstruct DisableIf : DisableIfCond<Condition::Value, T> {};\n\n// SFINAE helpers\nstruct SfinaeTag {};\ntemplate <typename T> struct RemoveSfinaeTag;\ntemplate <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };\n\n#define RAPIDJSON_REMOVEFPTR_(type) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \\\n        < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type\n\n#define RAPIDJSON_ENABLEIF(cond) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL\n\n#define RAPIDJSON_DISABLEIF(cond) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL\n\n#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond), \\\n         RAPIDJSON_REMOVEFPTR_(returntype)>::Type\n\n#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond), \\\n         RAPIDJSON_REMOVEFPTR_(returntype)>::Type\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n//@endcond\n\n#if defined(__GNUC__) || defined(_MSC_VER)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_INTERNAL_META_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/pow10.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_POW10_\n#define RAPIDJSON_POW10_\n\n#include \"../rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n//! Computes integer powers of 10 in double (10.0^n).\n/*! This function uses lookup table for fast and accurate results.\n    \\param n non-negative exponent. Must <= 308.\n    \\return 10.0^n\n*/\ninline double Pow10(int n) {\n    static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes\n        1e+0,  \n        1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, \n        1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,\n        1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,\n        1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,\n        1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,\n        1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,\n        1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,\n        1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,\n        1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,\n        1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,\n        1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,\n        1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,\n        1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,\n        1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,\n        1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,\n        1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308\n    };\n    RAPIDJSON_ASSERT(n >= 0 && n <= 308);\n    return e[n];\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_POW10_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/stack.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_STACK_H_\n#define RAPIDJSON_INTERNAL_STACK_H_\n\n#include \"../rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n///////////////////////////////////////////////////////////////////////////////\n// Stack\n\n//! A type-unsafe stack for storing different types of data.\n/*! \\tparam Allocator Allocator for allocating stack memory.\n*/\ntemplate <typename Allocator>\nclass Stack {\npublic:\n    // Optimization note: Do not allocate memory for stack_ in constructor.\n    // Do it lazily when first Push() -> Expand() -> Resize().\n    Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {\n        RAPIDJSON_ASSERT(stackCapacity > 0);\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    Stack(Stack&& rhs)\n        : allocator_(rhs.allocator_),\n          ownAllocator_(rhs.ownAllocator_),\n          stack_(rhs.stack_),\n          stackTop_(rhs.stackTop_),\n          stackEnd_(rhs.stackEnd_),\n          initialCapacity_(rhs.initialCapacity_)\n    {\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.stack_ = 0;\n        rhs.stackTop_ = 0;\n        rhs.stackEnd_ = 0;\n        rhs.initialCapacity_ = 0;\n    }\n#endif\n\n    ~Stack() {\n        Destroy();\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    Stack& operator=(Stack&& rhs) {\n        if (&rhs != this)\n        {\n            Destroy();\n\n            allocator_ = rhs.allocator_;\n            ownAllocator_ = rhs.ownAllocator_;\n            stack_ = rhs.stack_;\n            stackTop_ = rhs.stackTop_;\n            stackEnd_ = rhs.stackEnd_;\n            initialCapacity_ = rhs.initialCapacity_;\n\n            rhs.allocator_ = 0;\n            rhs.ownAllocator_ = 0;\n            rhs.stack_ = 0;\n            rhs.stackTop_ = 0;\n            rhs.stackEnd_ = 0;\n            rhs.initialCapacity_ = 0;\n        }\n        return *this;\n    }\n#endif\n\n    void Clear() { stackTop_ = stack_; }\n\n    void ShrinkToFit() { \n        if (Empty()) {\n            // If the stack is empty, completely deallocate the memory.\n            Allocator::Free(stack_);\n            stack_ = 0;\n            stackTop_ = 0;\n            stackEnd_ = 0;\n        }\n        else\n            Resize(GetSize());\n    }\n\n    // Optimization note: try to minimize the size of this function for force inline.\n    // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.\n    template<typename T>\n    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {\n         // Expand the stack if needed\n        if (stackTop_ + sizeof(T) * count >= stackEnd_)\n            Expand<T>(count);\n\n        T* ret = reinterpret_cast<T*>(stackTop_);\n        stackTop_ += sizeof(T) * count;\n        return ret;\n    }\n\n    template<typename T>\n    T* Pop(size_t count) {\n        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));\n        stackTop_ -= count * sizeof(T);\n        return reinterpret_cast<T*>(stackTop_);\n    }\n\n    template<typename T>\n    T* Top() { \n        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));\n        return reinterpret_cast<T*>(stackTop_ - sizeof(T));\n    }\n\n    template<typename T>\n    T* Bottom() { return (T*)stack_; }\n\n    Allocator& GetAllocator() { return *allocator_; }\n    bool Empty() const { return stackTop_ == stack_; }\n    size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }\n    size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }\n\nprivate:\n    template<typename T>\n    void Expand(size_t count) {\n        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.\n        size_t newCapacity;\n        if (stack_ == 0) {\n            if (!allocator_)\n                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n            newCapacity = initialCapacity_;\n        } else {\n            newCapacity = GetCapacity();\n            newCapacity += (newCapacity + 1) / 2;\n        }\n        size_t newSize = GetSize() + sizeof(T) * count;\n        if (newCapacity < newSize)\n            newCapacity = newSize;\n\n        Resize(newCapacity);\n    }\n\n    void Resize(size_t newCapacity) {\n        const size_t size = GetSize();  // Backup the current size\n        stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);\n        stackTop_ = stack_ + size;\n        stackEnd_ = stack_ + newCapacity;\n    }\n\n    void Destroy() {\n        Allocator::Free(stack_);\n        RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack\n    }\n\n    // Prohibit copy constructor & assignment operator.\n    Stack(const Stack&);\n    Stack& operator=(const Stack&);\n\n    Allocator* allocator_;\n    Allocator* ownAllocator_;\n    char *stack_;\n    char *stackTop_;\n    char *stackEnd_;\n    size_t initialCapacity_;\n};\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_STACK_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/strfunc.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_\n#define RAPIDJSON_INTERNAL_STRFUNC_H_\n\n#include \"../rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n//! Custom strlen() which works on different character types.\n/*! \\tparam Ch Character type (e.g. char, wchar_t, short)\n    \\param s Null-terminated input string.\n    \\return Number of characters in the string. \n    \\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.\n*/\ntemplate <typename Ch>\ninline SizeType StrLen(const Ch* s) {\n    const Ch* p = s;\n    while (*p) ++p;\n    return SizeType(p - s);\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_INTERNAL_STRFUNC_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/internal/strtod.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_STRTOD_\n#define RAPIDJSON_STRTOD_\n\n#include \"../rapidjson.h\"\n#include \"ieee754.h\"\n#include \"biginteger.h\"\n#include \"diyfp.h\"\n#include \"pow10.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\ninline double FastPath(double significand, int exp) {\n    if (exp < -308)\n        return 0.0;\n    else if (exp >= 0)\n        return significand * internal::Pow10(exp);\n    else\n        return significand / internal::Pow10(-exp);\n}\n\ninline double StrtodNormalPrecision(double d, int p) {\n    if (p < -308) {\n        // Prevent expSum < -308, making Pow10(p) = 0\n        d = FastPath(d, -308);\n        d = FastPath(d, p + 308);\n    }\n    else\n        d = FastPath(d, p);\n    return d;\n}\n\ntemplate <typename T>\ninline T Min3(T a, T b, T c) {\n    T m = a;\n    if (m > b) m = b;\n    if (m > c) m = c;\n    return m;\n}\n\ninline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {\n    const Double db(b);\n    const uint64_t bInt = db.IntegerSignificand();\n    const int bExp = db.IntegerExponent();\n    const int hExp = bExp - 1;\n\n    int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;\n\n    // Adjust for decimal exponent\n    if (dExp >= 0) {\n        dS_Exp2 += dExp;\n        dS_Exp5 += dExp;\n    }\n    else {\n        bS_Exp2 -= dExp;\n        bS_Exp5 -= dExp;\n        hS_Exp2 -= dExp;\n        hS_Exp5 -= dExp;\n    }\n\n    // Adjust for binary exponent\n    if (bExp >= 0)\n        bS_Exp2 += bExp;\n    else {\n        dS_Exp2 -= bExp;\n        hS_Exp2 -= bExp;\n    }\n\n    // Adjust for half ulp exponent\n    if (hExp >= 0)\n        hS_Exp2 += hExp;\n    else {\n        dS_Exp2 -= hExp;\n        bS_Exp2 -= hExp;\n    }\n\n    // Remove common power of two factor from all three scaled values\n    int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);\n    dS_Exp2 -= common_Exp2;\n    bS_Exp2 -= common_Exp2;\n    hS_Exp2 -= common_Exp2;\n\n    BigInteger dS = d;\n    dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2;\n\n    BigInteger bS(bInt);\n    bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2;\n\n    BigInteger hS(1);\n    hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2;\n\n    BigInteger delta(0);\n    dS.Difference(bS, &delta);\n\n    return delta.Compare(hS);\n}\n\ninline bool StrtodFast(double d, int p, double* result) {\n    // Use fast path for string-to-double conversion if possible\n    // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/\n    if (p > 22  && p < 22 + 16) {\n        // Fast Path Cases In Disguise\n        d *= internal::Pow10(p - 22);\n        p = 22;\n    }\n\n    if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1\n        *result = FastPath(d, p);\n        return true;\n    }\n    else\n        return false;\n}\n\n// Compute an approximation and see if it is within 1/2 ULP\ninline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {\n    uint64_t significand = 0;\n    size_t i = 0;   // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999    \n    for (; i < length; i++) {\n        if (significand  >  RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||\n            (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))\n            break;\n        significand = significand * 10 + (decimals[i] - '0');\n    }\n    \n    if (i < length && decimals[i] >= '5') // Rounding\n        significand++;\n\n    size_t remaining = length - i;\n    const unsigned kUlpShift = 3;\n    const unsigned kUlp = 1 << kUlpShift;\n    int error = (remaining == 0) ? 0 : kUlp / 2;\n\n    DiyFp v(significand, 0);\n    v = v.Normalize();\n    error <<= -v.e;\n\n    const int dExp = (int)decimalPosition - (int)i + exp;\n\n    int actualExp;\n    DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);\n    if (actualExp != dExp) {\n        static const DiyFp kPow10[] = {\n            DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60),  // 10^1\n            DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57),  // 10^2\n            DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54),  // 10^3\n            DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50),  // 10^4\n            DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47),  // 10^5\n            DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44),  // 10^6\n            DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40)   // 10^7\n        };\n        int adjustment = dExp - actualExp - 1;\n        RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);\n        v = v * kPow10[adjustment];\n        if (length + adjustment > 19) // has more digits than decimal digits in 64-bit\n            error += kUlp / 2;\n    }\n\n    v = v * cachedPower;\n\n    error += kUlp + (error == 0 ? 0 : 1);\n\n    const int oldExp = v.e;\n    v = v.Normalize();\n    error <<= oldExp - v.e;\n\n    const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);\n    unsigned precisionSize = 64 - effectiveSignificandSize;\n    if (precisionSize + kUlpShift >= 64) {\n        unsigned scaleExp = (precisionSize + kUlpShift) - 63;\n        v.f >>= scaleExp;\n        v.e += scaleExp; \n        error = (error >> scaleExp) + 1 + kUlp;\n        precisionSize -= scaleExp;\n    }\n\n    DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);\n    const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;\n    const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;\n    if (precisionBits >= halfWay + error) {\n        rounded.f++;\n        if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)\n            rounded.f >>= 1;\n            rounded.e++;\n        }\n    }\n\n    *result = rounded.ToDouble();\n\n    return halfWay - error >= precisionBits || precisionBits >= halfWay + error;\n}\n\ninline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {\n    const BigInteger dInt(decimals, length);\n    const int dExp = (int)decimalPosition - (int)length + exp;\n    Double a(approx);\n    int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);\n    if (cmp < 0)\n        return a.Value();  // within half ULP\n    else if (cmp == 0) {\n        // Round towards even\n        if (a.Significand() & 1)\n            return a.NextPositiveDouble();\n        else\n            return a.Value();\n    }\n    else // adjustment\n        return a.NextPositiveDouble();\n}\n\ninline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {\n    RAPIDJSON_ASSERT(d >= 0.0);\n    RAPIDJSON_ASSERT(length >= 1);\n\n    double result;\n    if (StrtodFast(d, p, &result))\n        return result;\n\n    // Trim leading zeros\n    while (*decimals == '0' && length > 1) {\n        length--;\n        decimals++;\n        decimalPosition--;\n    }\n\n    // Trim trailing zeros\n    while (decimals[length - 1] == '0' && length > 1) {\n        length--;\n        decimalPosition--;\n        exp++;\n    }\n\n    // Trim right-most digits\n    const int kMaxDecimalDigit = 780;\n    if ((int)length > kMaxDecimalDigit) {\n        int delta = (int(length) - kMaxDecimalDigit);\n        exp += delta;\n        decimalPosition -= delta;\n        length = kMaxDecimalDigit;\n    }\n\n    // If too small, underflow to zero\n    if (int(length) + exp < -324)\n        return 0.0;\n\n    if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))\n        return result;\n\n    // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison\n    return StrtodBigInteger(result, decimals, length, decimalPosition, exp);\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_STRTOD_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/memorybuffer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_MEMORYBUFFER_H_\n#define RAPIDJSON_MEMORYBUFFER_H_\n\n#include \"rapidjson.h\"\n#include \"internal/stack.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Represents an in-memory output byte stream.\n/*!\n    This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.\n\n    It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.\n\n    Differences between MemoryBuffer and StringBuffer:\n    1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. \n    2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.\n\n    \\tparam Allocator type for allocating memory buffer.\n    \\note implements Stream concept\n*/\ntemplate <typename Allocator = CrtAllocator>\nstruct GenericMemoryBuffer {\n    typedef char Ch; // byte\n\n    GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}\n\n    void Put(Ch c) { *stack_.template Push<Ch>() = c; }\n    void Flush() {}\n\n    void Clear() { stack_.Clear(); }\n    void ShrinkToFit() { stack_.ShrinkToFit(); }\n    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }\n    void Pop(size_t count) { stack_.template Pop<Ch>(count); }\n\n    const Ch* GetBuffer() const {\n        return stack_.template Bottom<Ch>();\n    }\n\n    size_t GetSize() const { return stack_.GetSize(); }\n\n    static const size_t kDefaultCapacity = 256;\n    mutable internal::Stack<Allocator> stack_;\n};\n\ntypedef GenericMemoryBuffer<> MemoryBuffer;\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {\n    std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_MEMORYBUFFER_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/memorystream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_MEMORYSTREAM_H_\n#define RAPIDJSON_MEMORYSTREAM_H_\n\n#include \"rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Represents an in-memory input byte stream.\n/*!\n    This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.\n\n    It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.\n\n    Differences between MemoryStream and StringStream:\n    1. StringStream has encoding but MemoryStream is a byte stream.\n    2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.\n    3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().\n    \\note implements Stream concept\n*/\nstruct MemoryStream {\n    typedef char Ch; // byte\n\n    MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}\n\n    Ch Peek() const { return (src_ == end_) ? '\\0' : *src_; }\n    Ch Take() { return (src_ == end_) ? '\\0' : *src_++; }\n    size_t Tell() const { return static_cast<size_t>(src_ - begin_); }\n\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    // For encoding detection only.\n    const Ch* Peek4() const {\n        return Tell() + 4 <= size_ ? src_ : 0;\n    }\n\n    const Ch* src_;     //!< Current read position.\n    const Ch* begin_;   //!< Original head of the string.\n    const Ch* end_;     //!< End of stream.\n    size_t size_;       //!< Size of the stream.\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_MEMORYBUFFER_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/msinttypes/inttypes.h",
    "content": "// ISO C9x  compliant inttypes.h for Microsoft Visual Studio\n// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 \n// \n//  Copyright (c) 2006-2013 Alexander Chemeris\n// \n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n// \n//   1. Redistributions of source code must retain the above copyright notice,\n//      this list of conditions and the following disclaimer.\n// \n//   2. Redistributions in binary form must reproduce the above copyright\n//      notice, this list of conditions and the following disclaimer in the\n//      documentation and/or other materials provided with the distribution.\n// \n//   3. Neither the name of the product nor the names of its contributors may\n//      be used to endorse or promote products derived from this software\n//      without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \n// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n// \n///////////////////////////////////////////////////////////////////////////////\n\n// The above software in this distribution may have been modified by \n// THL A29 Limited (\"Tencent Modifications\"). \n// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.\n\n#ifndef _MSC_VER // [\n#error \"Use this header only with Microsoft Visual C++ compilers!\"\n#endif // _MSC_VER ]\n\n#ifndef _MSC_INTTYPES_H_ // [\n#define _MSC_INTTYPES_H_\n\n#if _MSC_VER > 1000\n#pragma once\n#endif\n\n#include \"stdint.h\"\n\n// miloyip: VC supports inttypes.h since VC2013\n#if _MSC_VER >= 1800\n#include <inttypes.h>\n#else\n\n// 7.8 Format conversion of integer types\n\ntypedef struct {\n   intmax_t quot;\n   intmax_t rem;\n} imaxdiv_t;\n\n// 7.8.1 Macros for format specifiers\n\n#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198\n\n// The fprintf macros for signed integers are:\n#define PRId8       \"d\"\n#define PRIi8       \"i\"\n#define PRIdLEAST8  \"d\"\n#define PRIiLEAST8  \"i\"\n#define PRIdFAST8   \"d\"\n#define PRIiFAST8   \"i\"\n\n#define PRId16       \"hd\"\n#define PRIi16       \"hi\"\n#define PRIdLEAST16  \"hd\"\n#define PRIiLEAST16  \"hi\"\n#define PRIdFAST16   \"hd\"\n#define PRIiFAST16   \"hi\"\n\n#define PRId32       \"I32d\"\n#define PRIi32       \"I32i\"\n#define PRIdLEAST32  \"I32d\"\n#define PRIiLEAST32  \"I32i\"\n#define PRIdFAST32   \"I32d\"\n#define PRIiFAST32   \"I32i\"\n\n#define PRId64       \"I64d\"\n#define PRIi64       \"I64i\"\n#define PRIdLEAST64  \"I64d\"\n#define PRIiLEAST64  \"I64i\"\n#define PRIdFAST64   \"I64d\"\n#define PRIiFAST64   \"I64i\"\n\n#define PRIdMAX     \"I64d\"\n#define PRIiMAX     \"I64i\"\n\n#define PRIdPTR     \"Id\"\n#define PRIiPTR     \"Ii\"\n\n// The fprintf macros for unsigned integers are:\n#define PRIo8       \"o\"\n#define PRIu8       \"u\"\n#define PRIx8       \"x\"\n#define PRIX8       \"X\"\n#define PRIoLEAST8  \"o\"\n#define PRIuLEAST8  \"u\"\n#define PRIxLEAST8  \"x\"\n#define PRIXLEAST8  \"X\"\n#define PRIoFAST8   \"o\"\n#define PRIuFAST8   \"u\"\n#define PRIxFAST8   \"x\"\n#define PRIXFAST8   \"X\"\n\n#define PRIo16       \"ho\"\n#define PRIu16       \"hu\"\n#define PRIx16       \"hx\"\n#define PRIX16       \"hX\"\n#define PRIoLEAST16  \"ho\"\n#define PRIuLEAST16  \"hu\"\n#define PRIxLEAST16  \"hx\"\n#define PRIXLEAST16  \"hX\"\n#define PRIoFAST16   \"ho\"\n#define PRIuFAST16   \"hu\"\n#define PRIxFAST16   \"hx\"\n#define PRIXFAST16   \"hX\"\n\n#define PRIo32       \"I32o\"\n#define PRIu32       \"I32u\"\n#define PRIx32       \"I32x\"\n#define PRIX32       \"I32X\"\n#define PRIoLEAST32  \"I32o\"\n#define PRIuLEAST32  \"I32u\"\n#define PRIxLEAST32  \"I32x\"\n#define PRIXLEAST32  \"I32X\"\n#define PRIoFAST32   \"I32o\"\n#define PRIuFAST32   \"I32u\"\n#define PRIxFAST32   \"I32x\"\n#define PRIXFAST32   \"I32X\"\n\n#define PRIo64       \"I64o\"\n#define PRIu64       \"I64u\"\n#define PRIx64       \"I64x\"\n#define PRIX64       \"I64X\"\n#define PRIoLEAST64  \"I64o\"\n#define PRIuLEAST64  \"I64u\"\n#define PRIxLEAST64  \"I64x\"\n#define PRIXLEAST64  \"I64X\"\n#define PRIoFAST64   \"I64o\"\n#define PRIuFAST64   \"I64u\"\n#define PRIxFAST64   \"I64x\"\n#define PRIXFAST64   \"I64X\"\n\n#define PRIoMAX     \"I64o\"\n#define PRIuMAX     \"I64u\"\n#define PRIxMAX     \"I64x\"\n#define PRIXMAX     \"I64X\"\n\n#define PRIoPTR     \"Io\"\n#define PRIuPTR     \"Iu\"\n#define PRIxPTR     \"Ix\"\n#define PRIXPTR     \"IX\"\n\n// The fscanf macros for signed integers are:\n#define SCNd8       \"d\"\n#define SCNi8       \"i\"\n#define SCNdLEAST8  \"d\"\n#define SCNiLEAST8  \"i\"\n#define SCNdFAST8   \"d\"\n#define SCNiFAST8   \"i\"\n\n#define SCNd16       \"hd\"\n#define SCNi16       \"hi\"\n#define SCNdLEAST16  \"hd\"\n#define SCNiLEAST16  \"hi\"\n#define SCNdFAST16   \"hd\"\n#define SCNiFAST16   \"hi\"\n\n#define SCNd32       \"ld\"\n#define SCNi32       \"li\"\n#define SCNdLEAST32  \"ld\"\n#define SCNiLEAST32  \"li\"\n#define SCNdFAST32   \"ld\"\n#define SCNiFAST32   \"li\"\n\n#define SCNd64       \"I64d\"\n#define SCNi64       \"I64i\"\n#define SCNdLEAST64  \"I64d\"\n#define SCNiLEAST64  \"I64i\"\n#define SCNdFAST64   \"I64d\"\n#define SCNiFAST64   \"I64i\"\n\n#define SCNdMAX     \"I64d\"\n#define SCNiMAX     \"I64i\"\n\n#ifdef _WIN64 // [\n#  define SCNdPTR     \"I64d\"\n#  define SCNiPTR     \"I64i\"\n#else  // _WIN64 ][\n#  define SCNdPTR     \"ld\"\n#  define SCNiPTR     \"li\"\n#endif  // _WIN64 ]\n\n// The fscanf macros for unsigned integers are:\n#define SCNo8       \"o\"\n#define SCNu8       \"u\"\n#define SCNx8       \"x\"\n#define SCNX8       \"X\"\n#define SCNoLEAST8  \"o\"\n#define SCNuLEAST8  \"u\"\n#define SCNxLEAST8  \"x\"\n#define SCNXLEAST8  \"X\"\n#define SCNoFAST8   \"o\"\n#define SCNuFAST8   \"u\"\n#define SCNxFAST8   \"x\"\n#define SCNXFAST8   \"X\"\n\n#define SCNo16       \"ho\"\n#define SCNu16       \"hu\"\n#define SCNx16       \"hx\"\n#define SCNX16       \"hX\"\n#define SCNoLEAST16  \"ho\"\n#define SCNuLEAST16  \"hu\"\n#define SCNxLEAST16  \"hx\"\n#define SCNXLEAST16  \"hX\"\n#define SCNoFAST16   \"ho\"\n#define SCNuFAST16   \"hu\"\n#define SCNxFAST16   \"hx\"\n#define SCNXFAST16   \"hX\"\n\n#define SCNo32       \"lo\"\n#define SCNu32       \"lu\"\n#define SCNx32       \"lx\"\n#define SCNX32       \"lX\"\n#define SCNoLEAST32  \"lo\"\n#define SCNuLEAST32  \"lu\"\n#define SCNxLEAST32  \"lx\"\n#define SCNXLEAST32  \"lX\"\n#define SCNoFAST32   \"lo\"\n#define SCNuFAST32   \"lu\"\n#define SCNxFAST32   \"lx\"\n#define SCNXFAST32   \"lX\"\n\n#define SCNo64       \"I64o\"\n#define SCNu64       \"I64u\"\n#define SCNx64       \"I64x\"\n#define SCNX64       \"I64X\"\n#define SCNoLEAST64  \"I64o\"\n#define SCNuLEAST64  \"I64u\"\n#define SCNxLEAST64  \"I64x\"\n#define SCNXLEAST64  \"I64X\"\n#define SCNoFAST64   \"I64o\"\n#define SCNuFAST64   \"I64u\"\n#define SCNxFAST64   \"I64x\"\n#define SCNXFAST64   \"I64X\"\n\n#define SCNoMAX     \"I64o\"\n#define SCNuMAX     \"I64u\"\n#define SCNxMAX     \"I64x\"\n#define SCNXMAX     \"I64X\"\n\n#ifdef _WIN64 // [\n#  define SCNoPTR     \"I64o\"\n#  define SCNuPTR     \"I64u\"\n#  define SCNxPTR     \"I64x\"\n#  define SCNXPTR     \"I64X\"\n#else  // _WIN64 ][\n#  define SCNoPTR     \"lo\"\n#  define SCNuPTR     \"lu\"\n#  define SCNxPTR     \"lx\"\n#  define SCNXPTR     \"lX\"\n#endif  // _WIN64 ]\n\n#endif // __STDC_FORMAT_MACROS ]\n\n// 7.8.2 Functions for greatest-width integer types\n\n// 7.8.2.1 The imaxabs function\n#define imaxabs _abs64\n\n// 7.8.2.2 The imaxdiv function\n\n// This is modified version of div() function from Microsoft's div.c found\n// in %MSVC.NET%\\crt\\src\\div.c\n#ifdef STATIC_IMAXDIV // [\nstatic\n#else // STATIC_IMAXDIV ][\n_inline\n#endif // STATIC_IMAXDIV ]\nimaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)\n{\n   imaxdiv_t result;\n\n   result.quot = numer / denom;\n   result.rem = numer % denom;\n\n   if (numer < 0 && result.rem > 0) {\n      // did division wrong; must fix up\n      ++result.quot;\n      result.rem -= denom;\n   }\n\n   return result;\n}\n\n// 7.8.2.3 The strtoimax and strtoumax functions\n#define strtoimax _strtoi64\n#define strtoumax _strtoui64\n\n// 7.8.2.4 The wcstoimax and wcstoumax functions\n#define wcstoimax _wcstoi64\n#define wcstoumax _wcstoui64\n\n#endif // _MSC_VER >= 1800\n\n#endif // _MSC_INTTYPES_H_ ]\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/msinttypes/stdint.h",
    "content": "// ISO C9x  compliant stdint.h for Microsoft Visual Studio\n// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 \n// \n//  Copyright (c) 2006-2013 Alexander Chemeris\n// \n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n// \n//   1. Redistributions of source code must retain the above copyright notice,\n//      this list of conditions and the following disclaimer.\n// \n//   2. Redistributions in binary form must reproduce the above copyright\n//      notice, this list of conditions and the following disclaimer in the\n//      documentation and/or other materials provided with the distribution.\n// \n//   3. Neither the name of the product nor the names of its contributors may\n//      be used to endorse or promote products derived from this software\n//      without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \n// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n// \n///////////////////////////////////////////////////////////////////////////////\n\n// The above software in this distribution may have been modified by \n// THL A29 Limited (\"Tencent Modifications\"). \n// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.\n\n#ifndef _MSC_VER // [\n#error \"Use this header only with Microsoft Visual C++ compilers!\"\n#endif // _MSC_VER ]\n\n#ifndef _MSC_STDINT_H_ // [\n#define _MSC_STDINT_H_\n\n#if _MSC_VER > 1000\n#pragma once\n#endif\n\n// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.\n#if _MSC_VER >= 1600 // [\n#include <stdint.h>\n\n#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260\n\n#undef INT8_C\n#undef INT16_C\n#undef INT32_C\n#undef INT64_C\n#undef UINT8_C\n#undef UINT16_C\n#undef UINT32_C\n#undef UINT64_C\n\n// 7.18.4.1 Macros for minimum-width integer constants\n\n#define INT8_C(val)  val##i8\n#define INT16_C(val) val##i16\n#define INT32_C(val) val##i32\n#define INT64_C(val) val##i64\n\n#define UINT8_C(val)  val##ui8\n#define UINT16_C(val) val##ui16\n#define UINT32_C(val) val##ui32\n#define UINT64_C(val) val##ui64\n\n// 7.18.4.2 Macros for greatest-width integer constants\n// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.\n// Check out Issue 9 for the details.\n#ifndef INTMAX_C //   [\n#  define INTMAX_C   INT64_C\n#endif // INTMAX_C    ]\n#ifndef UINTMAX_C //  [\n#  define UINTMAX_C  UINT64_C\n#endif // UINTMAX_C   ]\n\n#endif // __STDC_CONSTANT_MACROS ]\n\n#else // ] _MSC_VER >= 1700 [\n\n#include <limits.h>\n\n// For Visual Studio 6 in C++ mode and for many Visual Studio versions when\n// compiling for ARM we should wrap <wchar.h> include with 'extern \"C++\" {}'\n// or compiler give many errors like this:\n//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#  include <wchar.h>\n#ifdef __cplusplus\n}\n#endif\n\n// Define _W64 macros to mark types changing their size, like intptr_t.\n#ifndef _W64\n#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300\n#     define _W64 __w64\n#  else\n#     define _W64\n#  endif\n#endif\n\n\n// 7.18.1 Integer types\n\n// 7.18.1.1 Exact-width integer types\n\n// Visual Studio 6 and Embedded Visual C++ 4 doesn't\n// realize that, e.g. char has the same size as __int8\n// so we give up on __intX for them.\n#if (_MSC_VER < 1300)\n   typedef signed char       int8_t;\n   typedef signed short      int16_t;\n   typedef signed int        int32_t;\n   typedef unsigned char     uint8_t;\n   typedef unsigned short    uint16_t;\n   typedef unsigned int      uint32_t;\n#else\n   typedef signed __int8     int8_t;\n   typedef signed __int16    int16_t;\n   typedef signed __int32    int32_t;\n   typedef unsigned __int8   uint8_t;\n   typedef unsigned __int16  uint16_t;\n   typedef unsigned __int32  uint32_t;\n#endif\ntypedef signed __int64       int64_t;\ntypedef unsigned __int64     uint64_t;\n\n\n// 7.18.1.2 Minimum-width integer types\ntypedef int8_t    int_least8_t;\ntypedef int16_t   int_least16_t;\ntypedef int32_t   int_least32_t;\ntypedef int64_t   int_least64_t;\ntypedef uint8_t   uint_least8_t;\ntypedef uint16_t  uint_least16_t;\ntypedef uint32_t  uint_least32_t;\ntypedef uint64_t  uint_least64_t;\n\n// 7.18.1.3 Fastest minimum-width integer types\ntypedef int8_t    int_fast8_t;\ntypedef int16_t   int_fast16_t;\ntypedef int32_t   int_fast32_t;\ntypedef int64_t   int_fast64_t;\ntypedef uint8_t   uint_fast8_t;\ntypedef uint16_t  uint_fast16_t;\ntypedef uint32_t  uint_fast32_t;\ntypedef uint64_t  uint_fast64_t;\n\n// 7.18.1.4 Integer types capable of holding object pointers\n#ifdef _WIN64 // [\n   typedef signed __int64    intptr_t;\n   typedef unsigned __int64  uintptr_t;\n#else // _WIN64 ][\n   typedef _W64 signed int   intptr_t;\n   typedef _W64 unsigned int uintptr_t;\n#endif // _WIN64 ]\n\n// 7.18.1.5 Greatest-width integer types\ntypedef int64_t   intmax_t;\ntypedef uint64_t  uintmax_t;\n\n\n// 7.18.2 Limits of specified-width integer types\n\n#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259\n\n// 7.18.2.1 Limits of exact-width integer types\n#define INT8_MIN     ((int8_t)_I8_MIN)\n#define INT8_MAX     _I8_MAX\n#define INT16_MIN    ((int16_t)_I16_MIN)\n#define INT16_MAX    _I16_MAX\n#define INT32_MIN    ((int32_t)_I32_MIN)\n#define INT32_MAX    _I32_MAX\n#define INT64_MIN    ((int64_t)_I64_MIN)\n#define INT64_MAX    _I64_MAX\n#define UINT8_MAX    _UI8_MAX\n#define UINT16_MAX   _UI16_MAX\n#define UINT32_MAX   _UI32_MAX\n#define UINT64_MAX   _UI64_MAX\n\n// 7.18.2.2 Limits of minimum-width integer types\n#define INT_LEAST8_MIN    INT8_MIN\n#define INT_LEAST8_MAX    INT8_MAX\n#define INT_LEAST16_MIN   INT16_MIN\n#define INT_LEAST16_MAX   INT16_MAX\n#define INT_LEAST32_MIN   INT32_MIN\n#define INT_LEAST32_MAX   INT32_MAX\n#define INT_LEAST64_MIN   INT64_MIN\n#define INT_LEAST64_MAX   INT64_MAX\n#define UINT_LEAST8_MAX   UINT8_MAX\n#define UINT_LEAST16_MAX  UINT16_MAX\n#define UINT_LEAST32_MAX  UINT32_MAX\n#define UINT_LEAST64_MAX  UINT64_MAX\n\n// 7.18.2.3 Limits of fastest minimum-width integer types\n#define INT_FAST8_MIN    INT8_MIN\n#define INT_FAST8_MAX    INT8_MAX\n#define INT_FAST16_MIN   INT16_MIN\n#define INT_FAST16_MAX   INT16_MAX\n#define INT_FAST32_MIN   INT32_MIN\n#define INT_FAST32_MAX   INT32_MAX\n#define INT_FAST64_MIN   INT64_MIN\n#define INT_FAST64_MAX   INT64_MAX\n#define UINT_FAST8_MAX   UINT8_MAX\n#define UINT_FAST16_MAX  UINT16_MAX\n#define UINT_FAST32_MAX  UINT32_MAX\n#define UINT_FAST64_MAX  UINT64_MAX\n\n// 7.18.2.4 Limits of integer types capable of holding object pointers\n#ifdef _WIN64 // [\n#  define INTPTR_MIN   INT64_MIN\n#  define INTPTR_MAX   INT64_MAX\n#  define UINTPTR_MAX  UINT64_MAX\n#else // _WIN64 ][\n#  define INTPTR_MIN   INT32_MIN\n#  define INTPTR_MAX   INT32_MAX\n#  define UINTPTR_MAX  UINT32_MAX\n#endif // _WIN64 ]\n\n// 7.18.2.5 Limits of greatest-width integer types\n#define INTMAX_MIN   INT64_MIN\n#define INTMAX_MAX   INT64_MAX\n#define UINTMAX_MAX  UINT64_MAX\n\n// 7.18.3 Limits of other integer types\n\n#ifdef _WIN64 // [\n#  define PTRDIFF_MIN  _I64_MIN\n#  define PTRDIFF_MAX  _I64_MAX\n#else  // _WIN64 ][\n#  define PTRDIFF_MIN  _I32_MIN\n#  define PTRDIFF_MAX  _I32_MAX\n#endif  // _WIN64 ]\n\n#define SIG_ATOMIC_MIN  INT_MIN\n#define SIG_ATOMIC_MAX  INT_MAX\n\n#ifndef SIZE_MAX // [\n#  ifdef _WIN64 // [\n#     define SIZE_MAX  _UI64_MAX\n#  else // _WIN64 ][\n#     define SIZE_MAX  _UI32_MAX\n#  endif // _WIN64 ]\n#endif // SIZE_MAX ]\n\n// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>\n#ifndef WCHAR_MIN // [\n#  define WCHAR_MIN  0\n#endif  // WCHAR_MIN ]\n#ifndef WCHAR_MAX // [\n#  define WCHAR_MAX  _UI16_MAX\n#endif  // WCHAR_MAX ]\n\n#define WINT_MIN  0\n#define WINT_MAX  _UI16_MAX\n\n#endif // __STDC_LIMIT_MACROS ]\n\n\n// 7.18.4 Limits of other integer types\n\n#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260\n\n// 7.18.4.1 Macros for minimum-width integer constants\n\n#define INT8_C(val)  val##i8\n#define INT16_C(val) val##i16\n#define INT32_C(val) val##i32\n#define INT64_C(val) val##i64\n\n#define UINT8_C(val)  val##ui8\n#define UINT16_C(val) val##ui16\n#define UINT32_C(val) val##ui32\n#define UINT64_C(val) val##ui64\n\n// 7.18.4.2 Macros for greatest-width integer constants\n// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.\n// Check out Issue 9 for the details.\n#ifndef INTMAX_C //   [\n#  define INTMAX_C   INT64_C\n#endif // INTMAX_C    ]\n#ifndef UINTMAX_C //  [\n#  define UINTMAX_C  UINT64_C\n#endif // UINTMAX_C   ]\n\n#endif // __STDC_CONSTANT_MACROS ]\n\n#endif // _MSC_VER >= 1600 ]\n\n#endif // _MSC_STDINT_H_ ]\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/pointer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_POINTER_H_\n#define RAPIDJSON_POINTER_H_\n\n#include \"document.h\"\n#include \"internal/itoa.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\nstatic const SizeType kPointerInvalidIndex = ~SizeType(0);  //!< Represents an invalid index in GenericPointer::Token\n\n//! Error code of parsing.\n/*! \\ingroup RAPIDJSON_ERRORS\n    \\see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode\n*/\nenum PointerParseErrorCode {\n    kPointerParseErrorNone = 0,                     //!< The parse is successful\n\n    kPointerParseErrorTokenMustBeginWithSolidus,    //!< A token must begin with a '/'\n    kPointerParseErrorInvalidEscape,                //!< Invalid escape\n    kPointerParseErrorInvalidPercentEncoding,       //!< Invalid percent encoding in URI fragment\n    kPointerParseErrorCharacterMustPercentEncode    //!< A character must percent encoded in URI fragment\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericPointer\n\n//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.\n/*!\n    This class implements RFC 6901 \"JavaScript Object Notation (JSON) Pointer\" \n    (https://tools.ietf.org/html/rfc6901).\n\n    A JSON pointer is for identifying a specific value in a JSON document\n    (GenericDocument). It can simplify coding of DOM tree manipulation, because it\n    can access multiple-level depth of DOM tree with single API call.\n\n    After it parses a string representation (e.g. \"/foo/0\" or URI fragment \n    representation (e.g. \"#/foo/0\") into its internal representation (tokens),\n    it can be used to resolve a specific value in multiple documents, or sub-tree \n    of documents.\n\n    Contrary to GenericValue, Pointer can be copy constructed and copy assigned.\n    Apart from assignment, a Pointer cannot be modified after construction.\n\n    Although Pointer is very convenient, please aware that constructing Pointer\n    involves parsing and dynamic memory allocation. A special constructor with user-\n    supplied tokens eliminates these.\n\n    GenericPointer depends on GenericDocument and GenericValue.\n    \n    \\tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >\n    \\tparam Allocator The allocator type for allocating memory for internal representation.\n    \n    \\note GenericPointer uses same encoding of ValueType.\n    However, Allocator of GenericPointer is independent of Allocator of Value.\n*/\ntemplate <typename ValueType, typename Allocator = CrtAllocator>\nclass GenericPointer {\npublic:\n    typedef typename ValueType::EncodingType EncodingType;  //!< Encoding type from Value\n    typedef typename EncodingType::Ch Ch;                   //!< Character type from Value\n\n    //! A token is the basic units of internal representation.\n    /*!\n        A JSON pointer string representation \"/foo/123\" is parsed to two tokens: \n        \"foo\" and 123. 123 will be represented in both numeric form and string form.\n        They are resolved according to the actual value type (object or array).\n\n        For token that are not numbers, or the numeric value is out of bound\n        (greater than limits of SizeType), they are only treated as string form\n        (i.e. the token's index will be equal to kPointerInvalidIndex).\n\n        This struct is public so that user can create a Pointer without parsing and \n        allocation, using a special constructor.\n    */\n    struct Token {\n        const Ch* name;             //!< Name of the token. It has null character at the end but it can contain null character.\n        SizeType length;            //!< Length of the name.\n        SizeType index;             //!< A valid array index, if it is not equal to kPointerInvalidIndex.\n    };\n\n    //!@name Constructors and destructor.\n    //@{\n\n    //! Default constructor.\n    GenericPointer() : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}\n\n    //! Constructor that parses a string or URI fragment representation.\n    /*!\n        \\param source A null-terminated, string or URI fragment representation of JSON pointer.\n        \\param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.\n    */\n    explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        Parse(source, internal::StrLen(source));\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Constructor that parses a string or URI fragment representation.\n    /*!\n        \\param source A string or URI fragment representation of JSON pointer.\n        \\param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.\n        \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n    */\n    explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        Parse(source.c_str(), source.size());\n    }\n#endif\n\n    //! Constructor that parses a string or URI fragment representation, with length of the source string.\n    /*!\n        \\param source A string or URI fragment representation of JSON pointer.\n        \\param length Length of source.\n        \\param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.\n        \\note Slightly faster than the overload without length.\n    */\n    GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        Parse(source, length);\n    }\n\n    //! Constructor with user-supplied tokens.\n    /*!\n        This constructor let user supplies const array of tokens.\n        This prevents the parsing process and eliminates allocation.\n        This is preferred for memory constrained environments.\n\n        \\param tokens An constant array of tokens representing the JSON pointer.\n        \\param tokenCount Number of tokens.\n\n        \\b Example\n        \\code\n        #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }\n        #define INDEX(i) { #i, sizeof(#i) - 1, i }\n\n        static const Pointer::Token kTokens[] = { NAME(\"foo\"), INDEX(123) };\n        static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));\n        // Equivalent to static const Pointer p(\"/foo/123\");\n\n        #undef NAME\n        #undef INDEX\n        \\endcode\n    */\n    GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}\n\n    //! Copy constructor.\n    GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        *this = rhs;\n    }\n\n    //! Destructor.\n    ~GenericPointer() {\n        if (nameBuffer_)    // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.\n            Allocator::Free(tokens_);\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    //! Assignment operator.\n    GenericPointer& operator=(const GenericPointer& rhs) {\n        if (this != &rhs) {\n            // Do not delete ownAllcator\n            if (nameBuffer_)\n                Allocator::Free(tokens_);\n\n            tokenCount_ = rhs.tokenCount_;\n            parseErrorOffset_ = rhs.parseErrorOffset_;\n            parseErrorCode_ = rhs.parseErrorCode_;\n\n            if (rhs.nameBuffer_)\n                CopyFromRaw(rhs); // Normally parsed tokens.\n            else {\n                tokens_ = rhs.tokens_; // User supplied const tokens.\n                nameBuffer_ = 0;\n            }\n        }\n        return *this;\n    }\n\n    //@}\n\n    //!@name Append token\n    //@{\n\n    //! Append a token and return a new Pointer\n    /*!\n        \\param token Token to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const Token& token, Allocator* allocator = 0) const {\n        GenericPointer r;\n        r.allocator_ = allocator;\n        Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);\n        std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));\n        r.tokens_[tokenCount_].name = p;\n        r.tokens_[tokenCount_].length = token.length;\n        r.tokens_[tokenCount_].index = token.index;\n        return r;\n    }\n\n    //! Append a name token with length, and return a new Pointer\n    /*!\n        \\param name Name to be appended.\n        \\param length Length of name.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {\n        Token token = { name, length, kPointerInvalidIndex };\n        return Append(token, allocator);\n    }\n\n    //! Append a name token without length, and return a new Pointer\n    /*!\n        \\param name Name (const Ch*) to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))\n    Append(T* name, Allocator* allocator = 0) const {\n        return Append(name, StrLen(name), allocator);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Append a name token, and return a new Pointer\n    /*!\n        \\param name Name to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {\n        return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);\n    }\n#endif\n\n    //! Append a index token, and return a new Pointer\n    /*!\n        \\param index Index to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(SizeType index, Allocator* allocator = 0) const {\n        char buffer[21];\n        SizeType length = (sizeof(SizeType) == 4 ? internal::u32toa(index, buffer): internal::u64toa(index, buffer)) - buffer;\n        buffer[length] = '\\0';\n\n        if (sizeof(Ch) == 1) {\n            Token token = { (Ch*)buffer, length, index };\n            return Append(token, allocator);\n        }\n        else {\n            Ch name[21];\n            for (size_t i = 0; i <= length; i++)\n                name[i] = buffer[i];\n            Token token = { name, length, index };\n            return Append(token, allocator);\n        }\n    }\n\n    //! Append a token by value, and return a new Pointer\n    /*!\n        \\param value Value (either Uint or String) to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {\n        if (token.IsString())\n            return Append(token.GetString(), token.GetStringLength(), allocator);\n        else {\n            RAPIDJSON_ASSERT(token.IsUint64());\n            RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));\n            return Append(static_cast<SizeType>(token.GetUint64()), allocator);\n        }\n    }\n\n    //!@name Handling Parse Error\n    //@{\n\n    //! Check whether this is a valid pointer.\n    bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }\n\n    //! Get the parsing error offset in code unit.\n    size_t GetParseErrorOffset() const { return parseErrorOffset_; }\n\n    //! Get the parsing error code.\n    PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }\n\n    //@}\n\n    //!@name Tokens\n    //@{\n\n    //! Get the token array (const version only).\n    const Token* GetTokens() const { return tokens_; }\n\n    //! Get the number of tokens.\n    size_t GetTokenCount() const { return tokenCount_; }\n\n    //@}\n\n    //!@name Equality/inequality operators\n    //@{\n\n    //! Equality operator.\n    /*!\n        \\note When any pointers are invalid, always returns false.\n    */\n    bool operator==(const GenericPointer& rhs) const {\n        if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)\n            return false;\n\n        for (size_t i = 0; i < tokenCount_; i++) {\n            if (tokens_[i].index != rhs.tokens_[i].index ||\n                tokens_[i].length != rhs.tokens_[i].length || \n                (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    //! Inequality operator.\n    /*!\n        \\note When any pointers are invalid, always returns true.\n    */\n    bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }\n\n    //@}\n\n    //!@name Stringify\n    //@{\n\n    //! Stringify the pointer into string representation.\n    /*!\n        \\tparam OutputStream Type of output stream.\n        \\param os The output stream.\n    */\n    template<typename OutputStream>\n    bool Stringify(OutputStream& os) const {\n        return Stringify<false, OutputStream>(os);\n    }\n\n    //! Stringify the pointer into URI fragment representation.\n    /*!\n        \\tparam OutputStream Type of output stream.\n        \\param os The output stream.\n    */\n    template<typename OutputStream>\n    bool StringifyUriFragment(OutputStream& os) const {\n        return Stringify<true, OutputStream>(os);\n    }\n\n    //@}\n\n    //!@name Create value\n    //@{\n\n    //! Create a value in a subtree.\n    /*!\n        If the value is not exist, it creates all parent values and a JSON Null value.\n        So it always succeed and return the newly created or existing value.\n\n        Remind that it may change types of parents according to tokens, so it \n        potentially removes previously stored values. For example, if a document \n        was an array, and \"/foo\" is used to create a value, then the document \n        will be changed to an object, and all existing array elements are lost.\n\n        \\param root Root value of a DOM subtree to be resolved. It can be any value other than document root.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\param alreadyExist If non-null, it stores whether the resolved value is already exist.\n        \\return The resolved newly created (a JSON Null value), or already exists value.\n    */\n    ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {\n        RAPIDJSON_ASSERT(IsValid());\n        ValueType* v = &root;\n        bool exist = true;\n        for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {\n            if (v->IsArray() && t->name[0] == '-' && t->length == 1) {\n                v->PushBack(Value().Move(), allocator);\n                v = &((*v)[v->Size() - 1]);\n                exist = false;\n            }\n            else {\n                if (t->index == kPointerInvalidIndex) { // must be object name\n                    if (!v->IsObject())\n                        v->SetObject(); // Change to Object\n                }\n                else { // object name or array index\n                    if (!v->IsArray() && !v->IsObject())\n                        v->SetArray(); // Change to Array\n                }\n\n                if (v->IsArray()) {\n                    if (t->index >= v->Size()) {\n                        v->Reserve(t->index + 1, allocator);\n                        while (t->index >= v->Size())\n                            v->PushBack(Value().Move(), allocator);\n                        exist = false;\n                    }\n                    v = &((*v)[t->index]);\n                }\n                else {\n                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));\n                    if (m == v->MemberEnd()) {\n                        v->AddMember(Value(t->name, t->length, allocator).Move(), Value().Move(), allocator);\n                        v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end\n                        exist = false;\n                    }\n                    else\n                        v = &m->value;\n                }\n            }\n        }\n\n        if (alreadyExist)\n            *alreadyExist = exist;\n\n        return *v;\n    }\n\n    //! Creates a value in a document.\n    /*!\n        \\param document A document to be resolved.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\param alreadyExist If non-null, it stores whether the resolved value is already exist.\n        \\return The resolved newly created, or already exists value.\n    */\n    template <typename stackAllocator>\n    ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {\n        return Create(document, document.GetAllocator(), alreadyExist);\n    }\n\n    //@}\n\n    //!@name Query value\n    //@{\n\n    //! Query a value in a subtree.\n    /*!\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\return Pointer to the value if it can be resolved. Otherwise null.\n    */\n    ValueType* Get(ValueType& root) const {\n        RAPIDJSON_ASSERT(IsValid());\n        ValueType* v = &root;\n        for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {\n            switch (v->GetType()) {\n            case kObjectType:\n                {\n                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));\n                    if (m == v->MemberEnd())\n                        return 0;\n                    v = &m->value;\n                }\n                break;\n            case kArrayType:\n                if (t->index == kPointerInvalidIndex || t->index >= v->Size())\n                    return 0;\n                v = &((*v)[t->index]);\n                break;\n            default:\n                return 0;\n            }\n        }\n        return v;\n    }\n\n    //! Query a const value in a const subtree.\n    /*!\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\return Pointer to the value if it can be resolved. Otherwise null.\n    */\n    const ValueType* Get(const ValueType& root) const { return Get(const_cast<ValueType&>(root)); }\n\n    //@}\n\n    //!@name Query a value with default\n    //@{\n\n    //! Query a value in a subtree with default value.\n    /*!\n        Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.\n        So that this function always succeed.\n\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param defaultValue Default value to be cloned if the value was not exists.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\see Create()\n    */\n    ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {\n        bool alreadyExist;\n        Value& v = Create(root, allocator, &alreadyExist);\n        return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);\n    }\n\n    //! Query a value in a subtree with default null-terminated string.\n    ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {\n        bool alreadyExist;\n        Value& v = Create(root, allocator, &alreadyExist);\n        return alreadyExist ? v : v.SetString(defaultValue, allocator);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Query a value in a subtree with default std::basic_string.\n    ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {\n        bool alreadyExist;\n        Value& v = Create(root, allocator, &alreadyExist);\n        return alreadyExist ? v : v.SetString(defaultValue, allocator);\n    }\n#endif\n\n    //! Query a value in a subtree with default primitive value.\n    /*!\n        \\tparam T \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n    GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {\n        return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);\n    }\n\n    //! Query a value in a document with default value.\n    template <typename stackAllocator>\n    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n\n    //! Query a value in a document with default null-terminated string.\n    template <typename stackAllocator>\n    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n    \n#if RAPIDJSON_HAS_STDSTRING\n    //! Query a value in a document with default std::basic_string.\n    template <typename stackAllocator>\n    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n#endif\n\n    //! Query a value in a document with default primitive value.\n    /*!\n        \\tparam T \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T, typename stackAllocator>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n    GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n\n    //@}\n\n    //!@name Set a value\n    //@{\n\n    //! Set a value in a subtree, with move semantics.\n    /*!\n        It creates all parents if they are not exist or types are different to the tokens.\n        So this function always succeeds but potentially remove existing values.\n\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param value Value to be set.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\see Create()\n    */\n    ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = value;\n    }\n\n    //! Set a value in a subtree, with copy semantics.\n    ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator).CopyFrom(value, allocator);\n    }\n\n    //! Set a null-terminated string in a subtree.\n    ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = ValueType(value, allocator).Move();\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Set a std::basic_string in a subtree.\n    ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = ValueType(value, allocator).Move();\n    }\n#endif\n\n    //! Set a primitive value in a subtree.\n    /*!\n        \\tparam T \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n    Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = ValueType(value).Move();\n    }\n\n    //! Set a value in a document, with move semantics.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {\n        return Create(document) = value;\n    }\n\n    //! Set a value in a document, with copy semantics.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {\n        return Create(document).CopyFrom(value, document.GetAllocator());\n    }\n\n    //! Set a null-terminated string in a document.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {\n        return Create(document) = ValueType(value, document.GetAllocator()).Move();\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Sets a std::basic_string in a document.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {\n        return Create(document) = ValueType(value, document.GetAllocator()).Move();\n    }\n#endif\n\n    //! Set a primitive value in a document.\n    /*!\n    \\tparam T \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T, typename stackAllocator>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n        Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {\n            return Create(document) = value;\n    }\n\n    //@}\n\n    //!@name Swap a value\n    //@{\n\n    //! Swap a value with a value in a subtree.\n    /*!\n        It creates all parents if they are not exist or types are different to the tokens.\n        So this function always succeeds but potentially remove existing values.\n\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param value Value to be swapped.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\see Create()\n    */\n    ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator).Swap(value);\n    }\n\n    //! Swap a value with a value in a document.\n    template <typename stackAllocator>\n    ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {\n        return Create(document).Swap(value);\n    }\n\n    //@}\n\n    //! Erase a value in a subtree.\n    /*!\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\return Whether the resolved value is found and erased.\n\n        \\note Erasing with an empty pointer \\c Pointer(\"\"), i.e. the root, always fail and return false.\n    */\n    bool Erase(ValueType& root) const {\n        RAPIDJSON_ASSERT(IsValid());\n        if (tokenCount_ == 0) // Cannot erase the root\n            return false;\n\n        ValueType* v = &root;\n        const Token* last = tokens_ + (tokenCount_ - 1);\n        for (const Token *t = tokens_; t != last; ++t) {\n            switch (v->GetType()) {\n            case kObjectType:\n                {\n                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));\n                    if (m == v->MemberEnd())\n                        return false;\n                    v = &m->value;\n                }\n                break;\n            case kArrayType:\n                if (t->index == kPointerInvalidIndex || t->index >= v->Size())\n                    return false;\n                v = &((*v)[t->index]);\n                break;\n            default:\n                return false;\n            }\n        }\n\n        switch (v->GetType()) {\n        case kObjectType:\n            return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));\n        case kArrayType:\n            if (last->index == kPointerInvalidIndex || last->index >= v->Size())\n                return false;\n            v->Erase(v->Begin() + last->index);\n            return true;\n        default:\n            return false;\n        }\n    }\n\nprivate:\n    //! Clone the content from rhs to this.\n    /*!\n        \\param rhs Source pointer.\n        \\param extraToken Extra tokens to be allocated.\n        \\param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.\n        \\return Start of non-occupied name buffer, for storing extra names.\n    */\n    Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {\n        if (!allocator_) // allocator is independently owned.\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n\n        size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens\n        for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)\n            nameBufferSize += t->length;\n\n        tokenCount_ = rhs.tokenCount_ + extraToken;\n        tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));\n        nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);\n        std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));\n        std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));\n\n        // Adjust pointers to name buffer\n        std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;\n        for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)\n            t->name += diff;\n\n        return nameBuffer_ + nameBufferSize;\n    }\n\n    //! Check whether a character should be percent-encoded.\n    /*!\n        According to RFC 3986 2.3 Unreserved Characters.\n        \\param c The character (code unit) to be tested.\n    */\n    bool NeedPercentEncode(Ch c) const {\n        return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');\n    }\n\n    //! Parse a JSON String or its URI fragment representation into tokens.\n    /*!\n        \\param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.\n        \\param length Length of the source string.\n        \\note Source cannot be JSON String Representation of JSON Pointer, e.g. In \"/\\u0000\", \\u0000 will not be unescaped.\n    */\n    void Parse(const Ch* source, size_t length) {\n        RAPIDJSON_ASSERT(source != NULL);\n        RAPIDJSON_ASSERT(nameBuffer_ == 0);\n        RAPIDJSON_ASSERT(tokens_ == 0);\n\n        // Create own allocator if user did not supply.\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n\n        // Count number of '/' as tokenCount\n        tokenCount_ = 0;\n        for (const Ch* s = source; s != source + length; s++) \n            if (*s == '/')\n                tokenCount_++;\n\n        Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));\n        Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);\n        size_t i = 0;\n\n        // Detect if it is a URI fragment\n        bool uriFragment = false;\n        if (source[i] == '#') {\n            uriFragment = true;\n            i++;\n        }\n\n        if (i != length && source[i] != '/') {\n            parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;\n            goto error;\n        }\n\n        while (i < length) {\n            RAPIDJSON_ASSERT(source[i] == '/');\n            i++; // consumes '/'\n\n            token->name = name;\n            bool isNumber = true;\n\n            while (i < length && source[i] != '/') {\n                Ch c = source[i];\n                if (uriFragment) {\n                    // Decoding percent-encoding for URI fragment\n                    if (c == '%') {\n                        PercentDecodeStream is(&source[i], source + length);\n                        GenericInsituStringStream<EncodingType> os(name);\n                        Ch* begin = os.PutBegin();\n                        if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {\n                            parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;\n                            goto error;\n                        }\n                        size_t len = os.PutEnd(begin);\n                        i += is.Tell() - 1;\n                        if (len == 1)\n                            c = *name;\n                        else {\n                            name += len;\n                            isNumber = false;\n                            i++;\n                            continue;\n                        }\n                    }\n                    else if (NeedPercentEncode(c)) {\n                        parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;\n                        goto error;\n                    }\n                }\n\n                i++;\n                \n                // Escaping \"~0\" -> '~', \"~1\" -> '/'\n                if (c == '~') {\n                    if (i < length) {\n                        c = source[i];\n                        if (c == '0')       c = '~';\n                        else if (c == '1')  c = '/';\n                        else {\n                            parseErrorCode_ = kPointerParseErrorInvalidEscape;\n                            goto error;\n                        }\n                        i++;\n                    }\n                    else {\n                        parseErrorCode_ = kPointerParseErrorInvalidEscape;\n                        goto error;\n                    }\n                }\n\n                // First check for index: all of characters are digit\n                if (c < '0' || c > '9')\n                    isNumber = false;\n\n                *name++ = c;\n            }\n            token->length = name - token->name;\n            if (token->length == 0)\n                isNumber = false;\n            *name++ = '\\0'; // Null terminator\n\n            // Second check for index: more than one digit cannot have leading zero\n            if (isNumber && token->length > 1 && token->name[0] == '0')\n                isNumber = false;\n\n            // String to SizeType conversion\n            SizeType n = 0;\n            if (isNumber) {\n                for (size_t j = 0; j < token->length; j++) {\n                    SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');\n                    if (m < n) {   // overflow detection\n                        isNumber = false;\n                        break;\n                    }\n                    n = m;\n                }\n            }\n\n            token->index = isNumber ? n : kPointerInvalidIndex;\n            token++;\n        }\n\n        RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer\n        parseErrorCode_ = kPointerParseErrorNone;\n        return;\n\n    error:\n        Allocator::Free(tokens_);\n        nameBuffer_ = 0;\n        tokens_ = 0;\n        tokenCount_ = 0;\n        parseErrorOffset_ = i;\n        return;\n    }\n\n    //! Stringify to string or URI fragment representation.\n    /*!\n        \\tparam uriFragment True for stringifying to URI fragment representation. False for string representation.\n        \\tparam OutputStream type of output stream.\n        \\param os The output stream.\n    */\n    template<bool uriFragment, typename OutputStream>\n    bool Stringify(OutputStream& os) const {\n        RAPIDJSON_ASSERT(IsValid());\n\n        if (uriFragment)\n            os.Put('#');\n\n        for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {\n            os.Put('/');\n            for (size_t j = 0; j < t->length; j++) {\n                Ch c = t->name[j];\n                if (c == '~') {\n                    os.Put('~');\n                    os.Put('0');\n                }\n                else if (c == '/') {\n                    os.Put('~');\n                    os.Put('1');\n                }\n                else if (uriFragment && NeedPercentEncode(c)) { \n                    // Transcode to UTF8 sequence\n                    GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);\n                    PercentEncodeStream<OutputStream> target(os);\n                    if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))\n                        return false;\n                    j += source.Tell() - 1;\n                }\n                else\n                    os.Put(c);\n            }\n        }\n        return true;\n    }\n\n    //! A helper stream for decoding a percent-encoded sequence into code unit.\n    /*!\n        This stream decodes %XY triplet into code unit (0-255).\n        If it encounters invalid characters, it sets output code unit as 0 and \n        mark invalid, and to be checked by IsValid().\n    */\n    class PercentDecodeStream {\n    public:\n        //! Constructor\n        /*!\n            \\param source Start of the stream\n            \\param end Past-the-end of the stream.\n        */\n        PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}\n\n        Ch Take() {\n            if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet\n                valid_ = false;\n                return 0;\n            }\n            src_++;\n            Ch c = 0;\n            for (int j = 0; j < 2; j++) {\n                c <<= 4;\n                Ch h = *src_;\n                if      (h >= '0' && h <= '9') c += h - '0';\n                else if (h >= 'A' && h <= 'F') c += h - 'A' + 10;\n                else if (h >= 'a' && h <= 'f') c += h - 'a' + 10;\n                else {\n                    valid_ = false;\n                    return 0;\n                }\n                src_++;\n            }\n            return c;\n        }\n\n        size_t Tell() const { return src_ - head_; }\n        bool IsValid() const { return valid_; }\n\n    private:\n        const Ch* src_;     //!< Current read position.\n        const Ch* head_;    //!< Original head of the string.\n        const Ch* end_;     //!< Past-the-end position.\n        bool valid_;        //!< Whether the parsing is valid.\n    };\n\n    //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.\n    template <typename OutputStream>\n    class PercentEncodeStream {\n    public:\n        PercentEncodeStream(OutputStream& os) : os_(os) {}\n        void Put(char c) { // UTF-8 must be byte\n            unsigned char u = static_cast<unsigned char>(c);\n            static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n            os_.Put('%');\n            os_.Put(hexDigits[u >> 4]);\n            os_.Put(hexDigits[u & 15]);\n        }\n    private:\n        OutputStream& os_;\n    };\n\n    Allocator* allocator_;                  //!< The current allocator. It is either user-supplied or equal to ownAllocator_.\n    Allocator* ownAllocator_;               //!< Allocator owned by this Pointer.\n    Ch* nameBuffer_;                        //!< A buffer containing all names in tokens.\n    Token* tokens_;                         //!< A list of tokens.\n    size_t tokenCount_;                     //!< Number of tokens in tokens_.\n    size_t parseErrorOffset_;               //!< Offset in code unit when parsing fail.\n    PointerParseErrorCode parseErrorCode_;  //!< Parsing error code.\n};\n\n//! GenericPointer for Value (UTF-8, default allocator).\ntypedef GenericPointer<Value> Pointer;\n\n//!@name Helper functions for GenericPointer\n//@{\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {\n    return pointer.Create(root, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);\n}\n\n// No allocator parameter\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {\n    return pointer.Create(document);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {\n    return pointer.Get(root);\n}\n\ntemplate <typename T>\nconst typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer) {\n    return pointer.Get(root);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N]) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Get(root);\n}\n\ntemplate <typename T, typename CharType, size_t N>\nconst typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N]) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Get(root);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n\ntemplate <typename T>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n#endif\n\ntemplate <typename T, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nGetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n#endif\n\ntemplate <typename T, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nGetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n\n// No allocator parameter\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n#endif\n\ntemplate <typename DocumentType, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nGetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n#endif\n\ntemplate <typename DocumentType, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nGetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n#endif\n\ntemplate <typename T, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nSetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n#endif\n\ntemplate <typename T, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nSetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\n// No allocator parameter\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {\n    return pointer.Set(document, value);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {\n    return pointer.Set(document, value);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {\n    return pointer.Set(document, value);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {\n    return pointer.Set(document, value);\n}\n#endif\n\ntemplate <typename DocumentType, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nSetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {\n    return pointer.Set(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n#endif\n\ntemplate <typename DocumentType, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nSetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {\n    return pointer.Swap(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {\n    return pointer.Swap(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\nbool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {\n    return pointer.Erase(root);\n}\n\ntemplate <typename T, typename CharType, size_t N>\nbool EraseValueByPointer(T& root, const CharType(&source)[N]) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);\n}\n\n//@}\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_POINTER_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/prettywriter.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_PRETTYWRITER_H_\n#define RAPIDJSON_PRETTYWRITER_H_\n\n#include \"writer.h\"\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Writer with indentation and spacing.\n/*!\n    \\tparam OutputStream Type of ouptut os.\n    \\tparam SourceEncoding Encoding of source string.\n    \\tparam TargetEncoding Encoding of output stream.\n    \\tparam StackAllocator Type of allocator for allocating memory of stack.\n*/\ntemplate<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>\nclass PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> {\npublic:\n    typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;\n    typedef typename Base::Ch Ch;\n\n    //! Constructor\n    /*! \\param os Output stream.\n        \\param allocator User supplied allocator. If it is null, it will create a private one.\n        \\param levelDepth Initial capacity of stack.\n    */\n    PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : \n        Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}\n\n    //! Set custom indentation.\n    /*! \\param indentChar       Character for indentation. Must be whitespace character (' ', '\\\\t', '\\\\n', '\\\\r').\n        \\param indentCharCount  Number of indent characters for each indentation level.\n        \\note The default indentation is 4 spaces.\n    */\n    PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {\n        RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\\t' || indentChar == '\\n' || indentChar == '\\r');\n        indentChar_ = indentChar;\n        indentCharCount_ = indentCharCount;\n        return *this;\n    }\n\n    /*! @name Implementation of Handler\n        \\see Handler\n    */\n    //@{\n\n    bool Null()                 { PrettyPrefix(kNullType);   return Base::WriteNull(); }\n    bool Bool(bool b)           { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }\n    bool Int(int i)             { PrettyPrefix(kNumberType); return Base::WriteInt(i); }\n    bool Uint(unsigned u)       { PrettyPrefix(kNumberType); return Base::WriteUint(u); }\n    bool Int64(int64_t i64)     { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }\n    bool Uint64(uint64_t u64)   { PrettyPrefix(kNumberType); return Base::WriteUint64(u64);  }\n    bool Double(double d)       { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }\n\n    bool String(const Ch* str, SizeType length, bool copy = false) {\n        (void)copy;\n        PrettyPrefix(kStringType);\n        return Base::WriteString(str, length);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool String(const std::basic_string<Ch>& str) {\n        return String(str.data(), SizeType(str.size()));\n    }\n#endif\n\n    bool StartObject() {\n        PrettyPrefix(kObjectType);\n        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);\n        return Base::WriteStartObject();\n    }\n\n    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }\n\t\n    bool EndObject(SizeType memberCount = 0) {\n        (void)memberCount;\n        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));\n        RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);\n        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;\n\n        if (!empty) {\n            Base::os_->Put('\\n');\n            WriteIndent();\n        }\n        bool ret = Base::WriteEndObject();\n        (void)ret;\n        RAPIDJSON_ASSERT(ret == true);\n        if (Base::level_stack_.Empty()) // end of json text\n            Base::os_->Flush();\n        return true;\n    }\n\n    bool StartArray() {\n        PrettyPrefix(kArrayType);\n        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);\n        return Base::WriteStartArray();\n    }\n\n    bool EndArray(SizeType memberCount = 0) {\n        (void)memberCount;\n        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));\n        RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);\n        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;\n\n        if (!empty) {\n            Base::os_->Put('\\n');\n            WriteIndent();\n        }\n        bool ret = Base::WriteEndArray();\n        (void)ret;\n        RAPIDJSON_ASSERT(ret == true);\n        if (Base::level_stack_.Empty()) // end of json text\n            Base::os_->Flush();\n        return true;\n    }\n\n    //@}\n\n    /*! @name Convenience extensions */\n    //@{\n\n    //! Simpler but slower overload.\n    bool String(const Ch* str) { return String(str, internal::StrLen(str)); }\n    bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }\n\n    //@}\nprotected:\n    void PrettyPrefix(Type type) {\n        (void)type;\n        if (Base::level_stack_.GetSize() != 0) { // this value is not at root\n            typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();\n\n            if (level->inArray) {\n                if (level->valueCount > 0) {\n                    Base::os_->Put(','); // add comma if it is not the first element in array\n                    Base::os_->Put('\\n');\n                }\n                else\n                    Base::os_->Put('\\n');\n                WriteIndent();\n            }\n            else {  // in object\n                if (level->valueCount > 0) {\n                    if (level->valueCount % 2 == 0) {\n                        Base::os_->Put(',');\n                        Base::os_->Put('\\n');\n                    }\n                    else {\n                        Base::os_->Put(':');\n                        Base::os_->Put(' ');\n                    }\n                }\n                else\n                    Base::os_->Put('\\n');\n\n                if (level->valueCount % 2 == 0)\n                    WriteIndent();\n            }\n            if (!level->inArray && level->valueCount % 2 == 0)\n                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name\n            level->valueCount++;\n        }\n        else {\n            RAPIDJSON_ASSERT(!Base::hasRoot_);  // Should only has one and only one root.\n            Base::hasRoot_ = true;\n        }\n    }\n\n    void WriteIndent()  {\n        size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;\n        PutN(*Base::os_, indentChar_, count);\n    }\n\n    Ch indentChar_;\n    unsigned indentCharCount_;\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    PrettyWriter(const PrettyWriter&);\n    PrettyWriter& operator=(const PrettyWriter&);\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/rapidjson.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_RAPIDJSON_H_\n#define RAPIDJSON_RAPIDJSON_H_\n\n/*!\\file rapidjson.h\n    \\brief common definitions and configuration\n    \n    \\see RAPIDJSON_CONFIG\n */\n\n/*! \\defgroup RAPIDJSON_CONFIG RapidJSON configuration\n    \\brief Configuration macros for library features\n\n    Some RapidJSON features are configurable to adapt the library to a wide\n    variety of platforms, environments and usage scenarios.  Most of the\n    features can be configured in terms of overriden or predefined\n    preprocessor macros at compile-time.\n\n    Some additional customization is available in the \\ref RAPIDJSON_ERRORS APIs.\n\n    \\note These macros should be given on the compiler command-line\n          (where applicable)  to avoid inconsistent values when compiling\n          different translation units of a single application.\n */\n\n#include <cstdlib>  // malloc(), realloc(), free(), size_t\n#include <cstring>  // memset(), memcpy(), memmove(), memcmp()\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_VERSION_STRING\n//\n// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.\n//\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n// token stringification\n#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)\n#define RAPIDJSON_DO_STRINGIFY(x) #x\n//!@endcond\n\n/*! \\def RAPIDJSON_MAJOR_VERSION\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Major version of RapidJSON in integer.\n*/\n/*! \\def RAPIDJSON_MINOR_VERSION\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Minor version of RapidJSON in integer.\n*/\n/*! \\def RAPIDJSON_PATCH_VERSION\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Patch version of RapidJSON in integer.\n*/\n/*! \\def RAPIDJSON_VERSION_STRING\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Version of RapidJSON in \"<major>.<minor>.<patch>\" string format.\n*/\n#define RAPIDJSON_MAJOR_VERSION 1\n#define RAPIDJSON_MINOR_VERSION 0\n#define RAPIDJSON_PATCH_VERSION 2\n#define RAPIDJSON_VERSION_STRING \\\n    RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NAMESPACE_(BEGIN|END)\n/*! \\def RAPIDJSON_NAMESPACE\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief   provide custom rapidjson namespace\n\n    In order to avoid symbol clashes and/or \"One Definition Rule\" errors\n    between multiple inclusions of (different versions of) RapidJSON in\n    a single binary, users can customize the name of the main RapidJSON\n    namespace.\n\n    In case of a single nesting level, defining \\c RAPIDJSON_NAMESPACE\n    to a custom name (e.g. \\c MyRapidJSON) is sufficient.  If multiple\n    levels are needed, both \\ref RAPIDJSON_NAMESPACE_BEGIN and \\ref\n    RAPIDJSON_NAMESPACE_END need to be defined as well:\n\n    \\code\n    // in some .cpp file\n    #define RAPIDJSON_NAMESPACE my::rapidjson\n    #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {\n    #define RAPIDJSON_NAMESPACE_END   } }\n    #include \"rapidjson/...\"\n    \\endcode\n\n    \\see rapidjson\n */\n/*! \\def RAPIDJSON_NAMESPACE_BEGIN\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief   provide custom rapidjson namespace (opening expression)\n    \\see RAPIDJSON_NAMESPACE\n*/\n/*! \\def RAPIDJSON_NAMESPACE_END\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief   provide custom rapidjson namespace (closing expression)\n    \\see RAPIDJSON_NAMESPACE\n*/\n#ifndef RAPIDJSON_NAMESPACE\n#define RAPIDJSON_NAMESPACE rapidjson\n#endif\n#ifndef RAPIDJSON_NAMESPACE_BEGIN\n#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {\n#endif\n#ifndef RAPIDJSON_NAMESPACE_END\n#define RAPIDJSON_NAMESPACE_END }\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NO_INT64DEFINE\n\n/*! \\def RAPIDJSON_NO_INT64DEFINE\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Use external 64-bit integer types.\n\n    RapidJSON requires the 64-bit integer types \\c int64_t and  \\c uint64_t types\n    to be available at global scope.\n\n    If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to\n    prevent RapidJSON from defining its own types.\n*/\n#ifndef RAPIDJSON_NO_INT64DEFINE\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#ifdef _MSC_VER\n#include \"msinttypes/stdint.h\"\n#include \"msinttypes/inttypes.h\"\n#else\n// Other compilers should have this.\n#include <stdint.h>\n#include <inttypes.h>\n#endif\n//!@endcond\n#ifdef RAPIDJSON_DOXYGEN_RUNNING\n#define RAPIDJSON_NO_INT64DEFINE\n#endif\n#endif // RAPIDJSON_NO_INT64TYPEDEF\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_FORCEINLINE\n\n#ifndef RAPIDJSON_FORCEINLINE\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#if defined(_MSC_VER) && !defined(NDEBUG)\n#define RAPIDJSON_FORCEINLINE __forceinline\n#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG)\n#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))\n#else\n#define RAPIDJSON_FORCEINLINE\n#endif\n//!@endcond\n#endif // RAPIDJSON_FORCEINLINE\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ENDIAN\n#define RAPIDJSON_LITTLEENDIAN  0   //!< Little endian machine\n#define RAPIDJSON_BIGENDIAN     1   //!< Big endian machine\n\n//! Endianness of the machine.\n/*!\n    \\def RAPIDJSON_ENDIAN\n    \\ingroup RAPIDJSON_CONFIG\n\n    GCC 4.6 provided macro for detecting endianness of the target machine. But other\n    compilers may not have this. User can define RAPIDJSON_ENDIAN to either\n    \\ref RAPIDJSON_LITTLEENDIAN or \\ref RAPIDJSON_BIGENDIAN.\n\n    Default detection implemented with reference to\n    \\li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html\n    \\li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp\n*/\n#ifndef RAPIDJSON_ENDIAN\n// Detect with GCC 4.6's macro\n#  ifdef __BYTE_ORDER__\n#    if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#    elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#    else\n#      error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.\n#    endif // __BYTE_ORDER__\n// Detect with GLIBC's endian.h\n#  elif defined(__GLIBC__)\n#    include <endian.h>\n#    if (__BYTE_ORDER == __LITTLE_ENDIAN)\n#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#    elif (__BYTE_ORDER == __BIG_ENDIAN)\n#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#    else\n#      error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.\n#   endif // __GLIBC__\n// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro\n#  elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#  elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n// Detect with architecture macros\n#  elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#  elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#  elif defined(RAPIDJSON_DOXYGEN_RUNNING)\n#    define RAPIDJSON_ENDIAN\n#  else\n#    error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.   \n#  endif\n#endif // RAPIDJSON_ENDIAN\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_64BIT\n\n//! Whether using 64-bit architecture\n#ifndef RAPIDJSON_64BIT\n#if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__)\n#define RAPIDJSON_64BIT 1\n#else\n#define RAPIDJSON_64BIT 0\n#endif\n#endif // RAPIDJSON_64BIT\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ALIGN\n\n//! Data alignment of the machine.\n/*! \\ingroup RAPIDJSON_CONFIG\n    \\param x pointer to align\n\n    Some machines require strict data alignment. Currently the default uses 4 bytes\n    alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.,\n*/\n#ifndef RAPIDJSON_ALIGN\n#if RAPIDJSON_64BIT == 1\n#define RAPIDJSON_ALIGN(x) ((x + 7u) & ~7u)\n#else\n#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)\n#endif\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_UINT64_C2\n\n//! Construct a 64-bit literal by a pair of 32-bit integer.\n/*!\n    64-bit literal with or without ULL suffix is prone to compiler warnings.\n    UINT64_C() is C macro which cause compilation problems.\n    Use this macro to define 64-bit constants by a pair of 32-bit integer.\n*/\n#ifndef RAPIDJSON_UINT64_C2\n#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD\n\n/*! \\def RAPIDJSON_SIMD\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Enable SSE2/SSE4.2 optimization.\n\n    RapidJSON supports optimized implementations for some parsing operations\n    based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible\n    processors.\n\n    To enable these optimizations, two different symbols can be defined;\n    \\code\n    // Enable SSE2 optimization.\n    #define RAPIDJSON_SSE2\n\n    // Enable SSE4.2 optimization.\n    #define RAPIDJSON_SSE42\n    \\endcode\n\n    \\c RAPIDJSON_SSE42 takes precedence, if both are defined.\n\n    If any of these symbols is defined, RapidJSON defines the macro\n    \\c RAPIDJSON_SIMD to indicate the availability of the optimized code.\n*/\n#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \\\n    || defined(RAPIDJSON_DOXYGEN_RUNNING)\n#define RAPIDJSON_SIMD\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NO_SIZETYPEDEFINE\n\n#ifndef RAPIDJSON_NO_SIZETYPEDEFINE\n/*! \\def RAPIDJSON_NO_SIZETYPEDEFINE\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief User-provided \\c SizeType definition.\n\n    In order to avoid using 32-bit size types for indexing strings and arrays,\n    define this preprocessor symbol and provide the type rapidjson::SizeType\n    before including RapidJSON:\n    \\code\n    #define RAPIDJSON_NO_SIZETYPEDEFINE\n    namespace rapidjson { typedef ::std::size_t SizeType; }\n    #include \"rapidjson/...\"\n    \\endcode\n\n    \\see rapidjson::SizeType\n*/\n#ifdef RAPIDJSON_DOXYGEN_RUNNING\n#define RAPIDJSON_NO_SIZETYPEDEFINE\n#endif\nRAPIDJSON_NAMESPACE_BEGIN\n//! Size type (for string lengths, array sizes, etc.)\n/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,\n    instead of using \\c size_t. Users may override the SizeType by defining\n    \\ref RAPIDJSON_NO_SIZETYPEDEFINE.\n*/\ntypedef unsigned SizeType;\nRAPIDJSON_NAMESPACE_END\n#endif\n\n// always import std::size_t to rapidjson namespace\nRAPIDJSON_NAMESPACE_BEGIN\nusing std::size_t;\nRAPIDJSON_NAMESPACE_END\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ASSERT\n\n//! Assertion.\n/*! \\ingroup RAPIDJSON_CONFIG\n    By default, rapidjson uses C \\c assert() for internal assertions.\n    User can override it by defining RAPIDJSON_ASSERT(x) macro.\n\n    \\note Parsing errors are handled and can be customized by the\n          \\ref RAPIDJSON_ERRORS APIs.\n*/\n#ifndef RAPIDJSON_ASSERT\n#include <cassert>\n#define RAPIDJSON_ASSERT(x) assert(x)\n#endif // RAPIDJSON_ASSERT\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_STATIC_ASSERT\n\n// Adopt from boost\n#ifndef RAPIDJSON_STATIC_ASSERT\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\nRAPIDJSON_NAMESPACE_BEGIN\ntemplate <bool x> struct STATIC_ASSERTION_FAILURE;\ntemplate <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };\ntemplate<int x> struct StaticAssertTest {};\nRAPIDJSON_NAMESPACE_END\n\n#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)\n#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)\n#define RAPIDJSON_DO_JOIN2(X, Y) X##Y\n\n#if defined(__GNUC__)\n#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))\n#else\n#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE \n#endif\n//!@endcond\n\n/*! \\def RAPIDJSON_STATIC_ASSERT\n    \\brief (Internal) macro to check for conditions at compile-time\n    \\param x compile-time condition\n    \\hideinitializer\n */\n#define RAPIDJSON_STATIC_ASSERT(x) \\\n    typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \\\n      sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \\\n    RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// Helpers\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n\n#define RAPIDJSON_MULTILINEMACRO_BEGIN do {  \n#define RAPIDJSON_MULTILINEMACRO_END \\\n} while((void)0, 0)\n\n// adopted from Boost\n#define RAPIDJSON_VERSION_CODE(x,y,z) \\\n  (((x)*100000) + ((y)*100) + (z))\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF\n\n#if defined(__GNUC__)\n#define RAPIDJSON_GNUC \\\n    RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)\n#endif\n\n#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))\n\n#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))\n#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)\n#define RAPIDJSON_DIAG_OFF(x) \\\n    RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))\n\n// push/pop support in Clang and GCC>=4.6\n#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))\n#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)\n#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)\n#else // GCC >= 4.2, < 4.6\n#define RAPIDJSON_DIAG_PUSH /* ignored */\n#define RAPIDJSON_DIAG_POP /* ignored */\n#endif\n\n#elif defined(_MSC_VER)\n\n// pragma (MSVC specific)\n#define RAPIDJSON_PRAGMA(x) __pragma(x)\n#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))\n\n#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)\n#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)\n#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)\n\n#else\n\n#define RAPIDJSON_DIAG_OFF(x) /* ignored */\n#define RAPIDJSON_DIAG_PUSH   /* ignored */\n#define RAPIDJSON_DIAG_POP    /* ignored */\n\n#endif // RAPIDJSON_DIAG_*\n\n///////////////////////////////////////////////////////////////////////////////\n// C++11 features\n\n#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS\n#if defined(__clang__)\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \\\n    (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)\n#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \\\n      (defined(_MSC_VER) && _MSC_VER >= 1600)\n\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1\n#else\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0\n#endif\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n\n#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT\n#if defined(__clang__)\n#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)\n#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))\n//    (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported\n#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1\n#else\n#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0\n#endif\n#endif\n#if RAPIDJSON_HAS_CXX11_NOEXCEPT\n#define RAPIDJSON_NOEXCEPT noexcept\n#else\n#define RAPIDJSON_NOEXCEPT /* noexcept */\n#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT\n\n// no automatic detection, yet\n#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS\n#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0\n#endif\n\n//!@endcond\n\n///////////////////////////////////////////////////////////////////////////////\n// new/delete\n\n#ifndef RAPIDJSON_NEW\n///! customization point for global \\c new\n#define RAPIDJSON_NEW(x) new x\n#endif\n#ifndef RAPIDJSON_DELETE\n///! customization point for global \\c delete\n#define RAPIDJSON_DELETE(x) delete x\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// Allocators and Encodings\n\n#include \"allocators.h\"\n#include \"encodings.h\"\n\n/*! \\namespace rapidjson\n    \\brief main RapidJSON namespace\n    \\see RAPIDJSON_NAMESPACE\n*/\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n//  Stream\n\n/*! \\class rapidjson::Stream\n    \\brief Concept for reading and writing characters.\n\n    For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().\n\n    For write-only stream, only need to implement Put() and Flush().\n\n\\code\nconcept Stream {\n    typename Ch;    //!< Character type of the stream.\n\n    //! Read the current character from stream without moving the read cursor.\n    Ch Peek() const;\n\n    //! Read the current character from stream and moving the read cursor to next character.\n    Ch Take();\n\n    //! Get the current read cursor.\n    //! \\return Number of characters read from start.\n    size_t Tell();\n\n    //! Begin writing operation at the current read pointer.\n    //! \\return The begin writer pointer.\n    Ch* PutBegin();\n\n    //! Write a character.\n    void Put(Ch c);\n\n    //! Flush the buffer.\n    void Flush();\n\n    //! End the writing operation.\n    //! \\param begin The begin write pointer returned by PutBegin().\n    //! \\return Number of characters written.\n    size_t PutEnd(Ch* begin);\n}\n\\endcode\n*/\n\n//! Provides additional information for stream.\n/*!\n    By using traits pattern, this type provides a default configuration for stream.\n    For custom stream, this type can be specialized for other configuration.\n    See TEST(Reader, CustomStringStream) in readertest.cpp for example.\n*/\ntemplate<typename Stream>\nstruct StreamTraits {\n    //! Whether to make local copy of stream for optimization during parsing.\n    /*!\n        By default, for safety, streams do not use local copy optimization.\n        Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.\n    */\n    enum { copyOptimization = 0 };\n};\n\n//! Put N copies of a character to a stream.\ntemplate<typename Stream, typename Ch>\ninline void PutN(Stream& stream, Ch c, size_t n) {\n    for (size_t i = 0; i < n; i++)\n        stream.Put(c);\n}\n\n///////////////////////////////////////////////////////////////////////////////\n// StringStream\n\n//! Read-only string stream.\n/*! \\note implements Stream concept\n*/\ntemplate <typename Encoding>\nstruct GenericStringStream {\n    typedef typename Encoding::Ch Ch;\n\n    GenericStringStream(const Ch *src) : src_(src), head_(src) {}\n\n    Ch Peek() const { return *src_; }\n    Ch Take() { return *src_++; }\n    size_t Tell() const { return static_cast<size_t>(src_ - head_); }\n\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    const Ch* src_;     //!< Current read position.\n    const Ch* head_;    //!< Original head of the string.\n};\n\ntemplate <typename Encoding>\nstruct StreamTraits<GenericStringStream<Encoding> > {\n    enum { copyOptimization = 1 };\n};\n\n//! String stream with UTF8 encoding.\ntypedef GenericStringStream<UTF8<> > StringStream;\n\n///////////////////////////////////////////////////////////////////////////////\n// InsituStringStream\n\n//! A read-write string stream.\n/*! This string stream is particularly designed for in-situ parsing.\n    \\note implements Stream concept\n*/\ntemplate <typename Encoding>\nstruct GenericInsituStringStream {\n    typedef typename Encoding::Ch Ch;\n\n    GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}\n\n    // Read\n    Ch Peek() { return *src_; }\n    Ch Take() { return *src_++; }\n    size_t Tell() { return static_cast<size_t>(src_ - head_); }\n\n    // Write\n    void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }\n\n    Ch* PutBegin() { return dst_ = src_; }\n    size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }\n    void Flush() {}\n\n    Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }\n    void Pop(size_t count) { dst_ -= count; }\n\n    Ch* src_;\n    Ch* dst_;\n    Ch* head_;\n};\n\ntemplate <typename Encoding>\nstruct StreamTraits<GenericInsituStringStream<Encoding> > {\n    enum { copyOptimization = 1 };\n};\n\n//! Insitu string stream with UTF8 encoding.\ntypedef GenericInsituStringStream<UTF8<> > InsituStringStream;\n\n///////////////////////////////////////////////////////////////////////////////\n// Type\n\n//! Type of JSON value\nenum Type {\n    kNullType = 0,      //!< null\n    kFalseType = 1,     //!< false\n    kTrueType = 2,      //!< true\n    kObjectType = 3,    //!< object\n    kArrayType = 4,     //!< array \n    kStringType = 5,    //!< string\n    kNumberType = 6     //!< number\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/reader.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_READER_H_\n#define RAPIDJSON_READER_H_\n\n/*! \\file reader.h */\n\n#include \"rapidjson.h\"\n#include \"encodings.h\"\n#include \"internal/meta.h\"\n#include \"internal/stack.h\"\n#include \"internal/strtod.h\"\n\n#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)\n#include <intrin.h>\n#pragma intrinsic(_BitScanForward)\n#endif\n#ifdef RAPIDJSON_SSE42\n#include <nmmintrin.h>\n#elif defined(RAPIDJSON_SSE2)\n#include <emmintrin.h>\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4127)  // conditional expression is constant\nRAPIDJSON_DIAG_OFF(4702)  // unreachable code\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#define RAPIDJSON_NOTHING /* deliberately empty */\n#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN\n#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \\\n    RAPIDJSON_MULTILINEMACRO_BEGIN \\\n    if (HasParseError()) { return value; } \\\n    RAPIDJSON_MULTILINEMACRO_END\n#endif\n#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \\\n    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)\n//!@endcond\n\n/*! \\def RAPIDJSON_PARSE_ERROR_NORETURN\n    \\ingroup RAPIDJSON_ERRORS\n    \\brief Macro to indicate a parse error.\n    \\param parseErrorCode \\ref rapidjson::ParseErrorCode of the error\n    \\param offset  position of the error in JSON input (\\c size_t)\n\n    This macros can be used as a customization point for the internal\n    error handling mechanism of RapidJSON.\n\n    A common usage model is to throw an exception instead of requiring the\n    caller to explicitly check the \\ref rapidjson::GenericReader::Parse's\n    return value:\n\n    \\code\n    #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \\\n       throw ParseException(parseErrorCode, #parseErrorCode, offset)\n\n    #include <stdexcept>               // std::runtime_error\n    #include \"rapidjson/error/error.h\" // rapidjson::ParseResult\n\n    struct ParseException : std::runtime_error, rapidjson::ParseResult {\n      ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset)\n        : std::runtime_error(msg), ParseResult(code, offset) {}\n    };\n\n    #include \"rapidjson/reader.h\"\n    \\endcode\n\n    \\see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse\n */\n#ifndef RAPIDJSON_PARSE_ERROR_NORETURN\n#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \\\n    RAPIDJSON_MULTILINEMACRO_BEGIN \\\n    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \\\n    SetParseError(parseErrorCode, offset); \\\n    RAPIDJSON_MULTILINEMACRO_END\n#endif\n\n/*! \\def RAPIDJSON_PARSE_ERROR\n    \\ingroup RAPIDJSON_ERRORS\n    \\brief (Internal) macro to indicate and handle a parse error.\n    \\param parseErrorCode \\ref rapidjson::ParseErrorCode of the error\n    \\param offset  position of the error in JSON input (\\c size_t)\n\n    Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.\n\n    \\see RAPIDJSON_PARSE_ERROR_NORETURN\n    \\hideinitializer\n */\n#ifndef RAPIDJSON_PARSE_ERROR\n#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \\\n    RAPIDJSON_MULTILINEMACRO_BEGIN \\\n    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \\\n    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \\\n    RAPIDJSON_MULTILINEMACRO_END\n#endif\n\n#include \"error/error.h\" // ParseErrorCode, ParseResult\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// ParseFlag\n\n/*! \\def RAPIDJSON_PARSE_DEFAULT_FLAGS \n    \\ingroup RAPIDJSON_CONFIG\n    \\brief User-defined kParseDefaultFlags definition.\n\n    User can define this as any \\c ParseFlag combinations.\n*/\n#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS\n#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags\n#endif\n\n//! Combination of parseFlags\n/*! \\see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream\n */\nenum ParseFlag {\n    kParseNoFlags = 0,              //!< No flags are set.\n    kParseInsituFlag = 1,           //!< In-situ(destructive) parsing.\n    kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.\n    kParseIterativeFlag = 4,        //!< Iterative(constant complexity in terms of function call stack size) parsing.\n    kParseStopWhenDoneFlag = 8,     //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.\n    kParseFullPrecisionFlag = 16,   //!< Parse number in full precision (but slower).\n    kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS  //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Handler\n\n/*! \\class rapidjson::Handler\n    \\brief Concept for receiving events from GenericReader upon parsing.\n    The functions return true if no error occurs. If they return false, \n    the event publisher should terminate the process.\n\\code\nconcept Handler {\n    typename Ch;\n\n    bool Null();\n    bool Bool(bool b);\n    bool Int(int i);\n    bool Uint(unsigned i);\n    bool Int64(int64_t i);\n    bool Uint64(uint64_t i);\n    bool Double(double d);\n    bool String(const Ch* str, SizeType length, bool copy);\n    bool StartObject();\n    bool Key(const Ch* str, SizeType length, bool copy);\n    bool EndObject(SizeType memberCount);\n    bool StartArray();\n    bool EndArray(SizeType elementCount);\n};\n\\endcode\n*/\n///////////////////////////////////////////////////////////////////////////////\n// BaseReaderHandler\n\n//! Default implementation of Handler.\n/*! This can be used as base class of any reader handler.\n    \\note implements Handler concept\n*/\ntemplate<typename Encoding = UTF8<>, typename Derived = void>\nstruct BaseReaderHandler {\n    typedef typename Encoding::Ch Ch;\n\n    typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;\n\n    bool Default() { return true; }\n    bool Null() { return static_cast<Override&>(*this).Default(); }\n    bool Bool(bool) { return static_cast<Override&>(*this).Default(); }\n    bool Int(int) { return static_cast<Override&>(*this).Default(); }\n    bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }\n    bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }\n    bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }\n    bool Double(double) { return static_cast<Override&>(*this).Default(); }\n    bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }\n    bool StartObject() { return static_cast<Override&>(*this).Default(); }\n    bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }\n    bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }\n    bool StartArray() { return static_cast<Override&>(*this).Default(); }\n    bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// StreamLocalCopy\n\nnamespace internal {\n\ntemplate<typename Stream, int = StreamTraits<Stream>::copyOptimization>\nclass StreamLocalCopy;\n\n//! Do copy optimization.\ntemplate<typename Stream>\nclass StreamLocalCopy<Stream, 1> {\npublic:\n    StreamLocalCopy(Stream& original) : s(original), original_(original) {}\n    ~StreamLocalCopy() { original_ = s; }\n\n    Stream s;\n\nprivate:\n    StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;\n\n    Stream& original_;\n};\n\n//! Keep reference.\ntemplate<typename Stream>\nclass StreamLocalCopy<Stream, 0> {\npublic:\n    StreamLocalCopy(Stream& original) : s(original) {}\n\n    Stream& s;\n\nprivate:\n    StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;\n};\n\n} // namespace internal\n\n///////////////////////////////////////////////////////////////////////////////\n// SkipWhitespace\n\n//! Skip the JSON white spaces in a stream.\n/*! \\param is A input stream for skipping white spaces.\n    \\note This function has SSE2/SSE4.2 specialization.\n*/\ntemplate<typename InputStream>\nvoid SkipWhitespace(InputStream& is) {\n    internal::StreamLocalCopy<InputStream> copy(is);\n    InputStream& s(copy.s);\n\n    while (s.Peek() == ' ' || s.Peek() == '\\n' || s.Peek() == '\\r' || s.Peek() == '\\t')\n        s.Take();\n}\n\n#ifdef RAPIDJSON_SSE42\n//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.\ninline const char *SkipWhitespace_SIMD(const char* p) {\n    // Fast return for single non-whitespace\n    if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n        ++p;\n    else\n        return p;\n\n    // 16-byte align to the next boundary\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);\n    while (p != nextAligned)\n        if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n            ++p;\n        else\n            return p;\n\n    // The rest of string using SIMD\n    static const char whitespace[16] = \" \\n\\r\\t\";\n    const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);\n\n    for (;; p += 16) {\n        const __m128i s = _mm_load_si128((const __m128i *)p);\n        const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));\n        if (r != 0) {   // some of characters is non-whitespace\n#ifdef _MSC_VER         // Find the index of first non-whitespace\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            return p + offset;\n#else\n            return p + __builtin_ffs(r) - 1;\n#endif\n        }\n    }\n}\n\n#elif defined(RAPIDJSON_SSE2)\n\n//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.\ninline const char *SkipWhitespace_SIMD(const char* p) {\n    // Fast return for single non-whitespace\n    if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n        ++p;\n    else\n        return p;\n\n    // 16-byte align to the next boundary\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);\n    while (p != nextAligned)\n        if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n            ++p;\n        else\n            return p;\n\n    // The rest of string\n    static const char whitespaces[4][17] = {\n        \"                \",\n        \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\n        \"\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r\",\n        \"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\"};\n\n        const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);\n        const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);\n        const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);\n        const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);\n\n    for (;; p += 16) {\n        const __m128i s = _mm_load_si128((const __m128i *)p);\n        __m128i x = _mm_cmpeq_epi8(s, w0);\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));\n        unsigned short r = (unsigned short)~_mm_movemask_epi8(x);\n        if (r != 0) {   // some of characters may be non-whitespace\n#ifdef _MSC_VER         // Find the index of first non-whitespace\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            return p + offset;\n#else\n            return p + __builtin_ffs(r) - 1;\n#endif\n        }\n    }\n}\n\n#endif // RAPIDJSON_SSE2\n\n#ifdef RAPIDJSON_SIMD\n//! Template function specialization for InsituStringStream\ntemplate<> inline void SkipWhitespace(InsituStringStream& is) { \n    is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));\n}\n\n//! Template function specialization for StringStream\ntemplate<> inline void SkipWhitespace(StringStream& is) {\n    is.src_ = SkipWhitespace_SIMD(is.src_);\n}\n#endif // RAPIDJSON_SIMD\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericReader\n\n//! SAX-style JSON parser. Use \\ref Reader for UTF8 encoding and default allocator.\n/*! GenericReader parses JSON text from a stream, and send events synchronously to an \n    object implementing Handler concept.\n\n    It needs to allocate a stack for storing a single decoded string during \n    non-destructive parsing.\n\n    For in-situ parsing, the decoded string is directly written to the source \n    text string, no temporary buffer is required.\n\n    A GenericReader object can be reused for parsing multiple JSON text.\n    \n    \\tparam SourceEncoding Encoding of the input stream.\n    \\tparam TargetEncoding Encoding of the parse output.\n    \\tparam StackAllocator Allocator type for stack.\n*/\ntemplate <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>\nclass GenericReader {\npublic:\n    typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type\n\n    //! Constructor.\n    /*! \\param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)\n        \\param stackCapacity stack capacity in bytes for storing a single decoded string.  (Only use for non-destructive parsing)\n    */\n    GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}\n\n    //! Parse JSON text.\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\tparam InputStream Type of input stream, implementing Stream concept.\n        \\tparam Handler Type of handler, implementing Handler concept.\n        \\param is Input stream to be parsed.\n        \\param handler The handler to receive events.\n        \\return Whether the parsing is successful.\n    */\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    ParseResult Parse(InputStream& is, Handler& handler) {\n        if (parseFlags & kParseIterativeFlag)\n            return IterativeParse<parseFlags>(is, handler);\n\n        parseResult_.Clear();\n\n        ClearStackOnExit scope(*this);\n\n        SkipWhitespace(is);\n\n        if (is.Peek() == '\\0') {\n            RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n        }\n        else {\n            ParseValue<parseFlags>(is, handler);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n\n            if (!(parseFlags & kParseStopWhenDoneFlag)) {\n                SkipWhitespace(is);\n\n                if (is.Peek() != '\\0') {\n                    RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());\n                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n                }\n            }\n        }\n\n        return parseResult_;\n    }\n\n    //! Parse JSON text (with \\ref kParseDefaultFlags)\n    /*! \\tparam InputStream Type of input stream, implementing Stream concept\n        \\tparam Handler Type of handler, implementing Handler concept.\n        \\param is Input stream to be parsed.\n        \\param handler The handler to receive events.\n        \\return Whether the parsing is successful.\n    */\n    template <typename InputStream, typename Handler>\n    ParseResult Parse(InputStream& is, Handler& handler) {\n        return Parse<kParseDefaultFlags>(is, handler);\n    }\n\n    //! Whether a parse error has occured in the last parsing.\n    bool HasParseError() const { return parseResult_.IsError(); }\n    \n    //! Get the \\ref ParseErrorCode of last parsing.\n    ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }\n\n    //! Get the position of last parsing error in input, 0 otherwise.\n    size_t GetErrorOffset() const { return parseResult_.Offset(); }\n\nprotected:\n    void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    GenericReader(const GenericReader&);\n    GenericReader& operator=(const GenericReader&);\n\n    void ClearStack() { stack_.Clear(); }\n\n    // clear stack on any exit from ParseStream, e.g. due to exception\n    struct ClearStackOnExit {\n        explicit ClearStackOnExit(GenericReader& r) : r_(r) {}\n        ~ClearStackOnExit() { r_.ClearStack(); }\n    private:\n        GenericReader& r_;\n        ClearStackOnExit(const ClearStackOnExit&);\n        ClearStackOnExit& operator=(const ClearStackOnExit&);\n    };\n\n    // Parse object: { string : value, ... }\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseObject(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == '{');\n        is.Take();  // Skip '{'\n        \n        if (!handler.StartObject())\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n\n        SkipWhitespace(is);\n\n        if (is.Peek() == '}') {\n            is.Take();\n            if (!handler.EndObject(0))  // empty object\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n            return;\n        }\n\n        for (SizeType memberCount = 0;;) {\n            if (is.Peek() != '\"')\n                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());\n\n            ParseString<parseFlags>(is, handler, true);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            SkipWhitespace(is);\n\n            if (is.Take() != ':')\n                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());\n\n            SkipWhitespace(is);\n\n            ParseValue<parseFlags>(is, handler);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            SkipWhitespace(is);\n\n            ++memberCount;\n\n            switch (is.Take()) {\n                case ',': SkipWhitespace(is); break;\n                case '}': \n                    if (!handler.EndObject(memberCount))\n                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                    return;\n                default:  RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());\n            }\n        }\n    }\n\n    // Parse array: [ value, ... ]\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseArray(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == '[');\n        is.Take();  // Skip '['\n        \n        if (!handler.StartArray())\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        \n        SkipWhitespace(is);\n\n        if (is.Peek() == ']') {\n            is.Take();\n            if (!handler.EndArray(0)) // empty array\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n            return;\n        }\n\n        for (SizeType elementCount = 0;;) {\n            ParseValue<parseFlags>(is, handler);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            ++elementCount;\n            SkipWhitespace(is);\n\n            switch (is.Take()) {\n                case ',': SkipWhitespace(is); break;\n                case ']': \n                    if (!handler.EndArray(elementCount))\n                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                    return;\n                default:  RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());\n            }\n        }\n    }\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseNull(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == 'n');\n        is.Take();\n\n        if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') {\n            if (!handler.Null())\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);\n    }\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseTrue(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == 't');\n        is.Take();\n\n        if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') {\n            if (!handler.Bool(true))\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);\n    }\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseFalse(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == 'f');\n        is.Take();\n\n        if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') {\n            if (!handler.Bool(false))\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);\n    }\n\n    // Helper function to parse four hexidecimal digits in \\uXXXX in ParseString().\n    template<typename InputStream>\n    unsigned ParseHex4(InputStream& is) {\n        unsigned codepoint = 0;\n        for (int i = 0; i < 4; i++) {\n            Ch c = is.Take();\n            codepoint <<= 4;\n            codepoint += static_cast<unsigned>(c);\n            if (c >= '0' && c <= '9')\n                codepoint -= '0';\n            else if (c >= 'A' && c <= 'F')\n                codepoint -= 'A' - 10;\n            else if (c >= 'a' && c <= 'f')\n                codepoint -= 'a' - 10;\n            else {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1);\n                RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);\n            }\n        }\n        return codepoint;\n    }\n\n    template <typename CharType>\n    class StackStream {\n    public:\n        typedef CharType Ch;\n\n        StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}\n        RAPIDJSON_FORCEINLINE void Put(Ch c) {\n            *stack_.template Push<Ch>() = c;\n            ++length_;\n        }\n        size_t Length() const { return length_; }\n        Ch* Pop() {\n            return stack_.template Pop<Ch>(length_);\n        }\n\n    private:\n        StackStream(const StackStream&);\n        StackStream& operator=(const StackStream&);\n\n        internal::Stack<StackAllocator>& stack_;\n        SizeType length_;\n    };\n\n    // Parse string and generate String event. Different code paths for kParseInsituFlag.\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseString(InputStream& is, Handler& handler, bool isKey = false) {\n        internal::StreamLocalCopy<InputStream> copy(is);\n        InputStream& s(copy.s);\n\n        bool success = false;\n        if (parseFlags & kParseInsituFlag) {\n            typename InputStream::Ch *head = s.PutBegin();\n            ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n            size_t length = s.PutEnd(head) - 1;\n            RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);\n            const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head;\n            success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));\n        }\n        else {\n            StackStream<typename TargetEncoding::Ch> stackStream(stack_);\n            ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n            SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;\n            const typename TargetEncoding::Ch* const str = stackStream.Pop();\n            success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));\n        }\n        if (!success)\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());\n    }\n\n    // Parse string to an output is\n    // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.\n    template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n        static const char escape[256] = {\n            Z16, Z16, 0, 0,'\\\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', \n            Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\\\', 0, 0, 0, \n            0, 0,'\\b', 0, 0, 0,'\\f', 0, 0, 0, 0, 0, 0, 0,'\\n', 0, \n            0, 0,'\\r', 0,'\\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \n            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16\n        };\n#undef Z16\n//!@endcond\n\n        RAPIDJSON_ASSERT(is.Peek() == '\\\"');\n        is.Take();  // Skip '\\\"'\n\n        for (;;) {\n            Ch c = is.Peek();\n            if (c == '\\\\') {    // Escape\n                is.Take();\n                Ch e = is.Take();\n                if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) {\n                    os.Put(escape[(unsigned char)e]);\n                }\n                else if (e == 'u') {    // Unicode\n                    unsigned codepoint = ParseHex4(is);\n                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n                    if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {\n                        // Handle UTF-16 surrogate pair\n                        if (is.Take() != '\\\\' || is.Take() != 'u')\n                            RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);\n                        unsigned codepoint2 = ParseHex4(is);\n                        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n                        if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)\n                            RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);\n                        codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;\n                    }\n                    TEncoding::Encode(os, codepoint);\n                }\n                else\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);\n            }\n            else if (c == '\"') {    // Closing double quote\n                is.Take();\n                os.Put('\\0');   // null-terminate the string\n                return;\n            }\n            else if (c == '\\0')\n                RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);\n            else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF\n                RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);\n            else {\n                if (parseFlags & kParseValidateEncodingFlag ? \n                    !Transcoder<SEncoding, TEncoding>::Validate(is, os) : \n                    !Transcoder<SEncoding, TEncoding>::Transcode(is, os))\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());\n            }\n        }\n    }\n\n    template<typename InputStream, bool backup>\n    class NumberStream;\n\n    template<typename InputStream>\n    class NumberStream<InputStream, false> {\n    public:\n        NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader;  }\n        ~NumberStream() {}\n\n        RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }\n        RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }\n        RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }\n        size_t Tell() { return is.Tell(); }\n        size_t Length() { return 0; }\n        const char* Pop() { return 0; }\n\n    protected:\n        NumberStream& operator=(const NumberStream&);\n\n        InputStream& is;\n    };\n\n    template<typename InputStream>\n    class NumberStream<InputStream, true> : public NumberStream<InputStream, false> {\n        typedef NumberStream<InputStream, false> Base;\n    public:\n        NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}\n        ~NumberStream() {}\n\n        RAPIDJSON_FORCEINLINE Ch TakePush() {\n            stackStream.Put((char)Base::is.Peek());\n            return Base::is.Take();\n        }\n\n        size_t Length() { return stackStream.Length(); }\n\n        const char* Pop() {\n            stackStream.Put('\\0');\n            return stackStream.Pop();\n        }\n\n    private:\n        StackStream<char> stackStream;\n    };\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseNumber(InputStream& is, Handler& handler) {\n        internal::StreamLocalCopy<InputStream> copy(is);\n        NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);\n\n        // Parse minus\n        bool minus = false;\n        if (s.Peek() == '-') {\n            minus = true;\n            s.Take();\n        }\n\n        // Parse int: zero / ( digit1-9 *DIGIT )\n        unsigned i = 0;\n        uint64_t i64 = 0;\n        bool use64bit = false;\n        int significandDigit = 0;\n        if (s.Peek() == '0') {\n            i = 0;\n            s.TakePush();\n        }\n        else if (s.Peek() >= '1' && s.Peek() <= '9') {\n            i = static_cast<unsigned>(s.TakePush() - '0');\n\n            if (minus)\n                while (s.Peek() >= '0' && s.Peek() <= '9') {\n                    if (i >= 214748364) { // 2^31 = 2147483648\n                        if (i != 214748364 || s.Peek() > '8') {\n                            i64 = i;\n                            use64bit = true;\n                            break;\n                        }\n                    }\n                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n            else\n                while (s.Peek() >= '0' && s.Peek() <= '9') {\n                    if (i >= 429496729) { // 2^32 - 1 = 4294967295\n                        if (i != 429496729 || s.Peek() > '5') {\n                            i64 = i;\n                            use64bit = true;\n                            break;\n                        }\n                    }\n                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());\n\n        // Parse 64bit int\n        bool useDouble = false;\n        double d = 0.0;\n        if (use64bit) {\n            if (minus) \n                while (s.Peek() >= '0' && s.Peek() <= '9') {                    \n                     if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808\n                        if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') {\n                            d = i64;\n                            useDouble = true;\n                            break;\n                        }\n                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n            else\n                while (s.Peek() >= '0' && s.Peek() <= '9') {                    \n                    if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615\n                        if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') {\n                            d = i64;\n                            useDouble = true;\n                            break;\n                        }\n                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n        }\n\n        // Force double for big integer\n        if (useDouble) {\n            while (s.Peek() >= '0' && s.Peek() <= '9') {\n                if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0\n                    RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());\n                d = d * 10 + (s.TakePush() - '0');\n            }\n        }\n\n        // Parse frac = decimal-point 1*DIGIT\n        int expFrac = 0;\n        size_t decimalPosition;\n        if (s.Peek() == '.') {\n            s.Take();\n            decimalPosition = s.Length();\n\n            if (!(s.Peek() >= '0' && s.Peek() <= '9'))\n                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());\n\n            if (!useDouble) {\n#if RAPIDJSON_64BIT\n                // Use i64 to store significand in 64-bit architecture\n                if (!use64bit)\n                    i64 = i;\n        \n                while (s.Peek() >= '0' && s.Peek() <= '9') {\n                    if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path\n                        break;\n                    else {\n                        i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                        --expFrac;\n                        if (i64 != 0)\n                            significandDigit++;\n                    }\n                }\n\n                d = (double)i64;\n#else\n                // Use double to store significand in 32-bit architecture\n                d = use64bit ? (double)i64 : (double)i;\n#endif\n                useDouble = true;\n            }\n\n            while (s.Peek() >= '0' && s.Peek() <= '9') {\n                if (significandDigit < 17) {\n                    d = d * 10.0 + (s.TakePush() - '0');\n                    --expFrac;\n                    if (d > 0.0)\n                        significandDigit++;\n                }\n                else\n                    s.TakePush();\n            }\n        }\n        else\n            decimalPosition = s.Length(); // decimal position at the end of integer.\n\n        // Parse exp = e [ minus / plus ] 1*DIGIT\n        int exp = 0;\n        if (s.Peek() == 'e' || s.Peek() == 'E') {\n            if (!useDouble) {\n                d = use64bit ? i64 : i;\n                useDouble = true;\n            }\n            s.Take();\n\n            bool expMinus = false;\n            if (s.Peek() == '+')\n                s.Take();\n            else if (s.Peek() == '-') {\n                s.Take();\n                expMinus = true;\n            }\n\n            if (s.Peek() >= '0' && s.Peek() <= '9') {\n                exp = s.Take() - '0';\n                if (expMinus) {\n                    while (s.Peek() >= '0' && s.Peek() <= '9') {\n                        exp = exp * 10 + (s.Take() - '0');\n                        if (exp >= 214748364) {                         // Issue #313: prevent overflow exponent\n                            while (s.Peek() >= '0' && s.Peek() <= '9')  // Consume the rest of exponent\n                                s.Take();\n                        }\n                    }\n                }\n                else {  // positive exp\n                    int maxExp = 308 - expFrac;\n                    while (s.Peek() >= '0' && s.Peek() <= '9') {\n                        exp = exp * 10 + (s.Take() - '0');\n                        if (exp > maxExp)\n                            RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());\n                    }\n                }\n            }\n            else\n                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());\n\n            if (expMinus)\n                exp = -exp;\n        }\n\n        // Finish parsing, call event according to the type of number.\n        bool cont = true;\n        size_t length = s.Length();\n        const char* decimal = s.Pop();  // Pop stack no matter if it will be used or not.\n\n        if (useDouble) {\n            int p = exp + expFrac;\n            if (parseFlags & kParseFullPrecisionFlag)\n                d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);\n            else\n                d = internal::StrtodNormalPrecision(d, p);\n\n            cont = handler.Double(minus ? -d : d);\n        }\n        else {\n            if (use64bit) {\n                if (minus)\n                    cont = handler.Int64(static_cast<int64_t>(~i64 + 1));\n                else\n                    cont = handler.Uint64(i64);\n            }\n            else {\n                if (minus)\n                    cont = handler.Int(static_cast<int32_t>(~i + 1));\n                else\n                    cont = handler.Uint(i);\n            }\n        }\n        if (!cont)\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());\n    }\n\n    // Parse any JSON value\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseValue(InputStream& is, Handler& handler) {\n        switch (is.Peek()) {\n            case 'n': ParseNull  <parseFlags>(is, handler); break;\n            case 't': ParseTrue  <parseFlags>(is, handler); break;\n            case 'f': ParseFalse <parseFlags>(is, handler); break;\n            case '\"': ParseString<parseFlags>(is, handler); break;\n            case '{': ParseObject<parseFlags>(is, handler); break;\n            case '[': ParseArray <parseFlags>(is, handler); break;\n            default : ParseNumber<parseFlags>(is, handler);\n        }\n    }\n\n    // Iterative Parsing\n\n    // States\n    enum IterativeParsingState {\n        IterativeParsingStartState = 0,\n        IterativeParsingFinishState,\n        IterativeParsingErrorState,\n\n        // Object states\n        IterativeParsingObjectInitialState,\n        IterativeParsingMemberKeyState,\n        IterativeParsingKeyValueDelimiterState,\n        IterativeParsingMemberValueState,\n        IterativeParsingMemberDelimiterState,\n        IterativeParsingObjectFinishState,\n\n        // Array states\n        IterativeParsingArrayInitialState,\n        IterativeParsingElementState,\n        IterativeParsingElementDelimiterState,\n        IterativeParsingArrayFinishState,\n\n        // Single value state\n        IterativeParsingValueState,\n\n        cIterativeParsingStateCount\n    };\n\n    // Tokens\n    enum Token {\n        LeftBracketToken = 0,\n        RightBracketToken,\n\n        LeftCurlyBracketToken,\n        RightCurlyBracketToken,\n\n        CommaToken,\n        ColonToken,\n\n        StringToken,\n        FalseToken,\n        TrueToken,\n        NullToken,\n        NumberToken,\n\n        kTokenCount\n    };\n\n    RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#define N NumberToken\n#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N\n        // Maps from ASCII to Token\n        static const unsigned char tokenMap[256] = {\n            N16, // 00~0F\n            N16, // 10~1F\n            N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F\n            N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F\n            N16, // 40~4F\n            N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F\n            N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F\n            N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F\n            N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF\n        };\n#undef N\n#undef N16\n//!@endcond\n        \n        if (sizeof(Ch) == 1 || unsigned(c) < 256)\n            return (Token)tokenMap[(unsigned char)c];\n        else\n            return NumberToken;\n    }\n\n    RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {\n        // current state x one lookahead token -> new state\n        static const char G[cIterativeParsingStateCount][kTokenCount] = {\n            // Start\n            {\n                IterativeParsingArrayInitialState,  // Left bracket\n                IterativeParsingErrorState,         // Right bracket\n                IterativeParsingObjectInitialState, // Left curly bracket\n                IterativeParsingErrorState,         // Right curly bracket\n                IterativeParsingErrorState,         // Comma\n                IterativeParsingErrorState,         // Colon\n                IterativeParsingValueState,         // String\n                IterativeParsingValueState,         // False\n                IterativeParsingValueState,         // True\n                IterativeParsingValueState,         // Null\n                IterativeParsingValueState          // Number\n            },\n            // Finish(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // Error(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // ObjectInitial\n            {\n                IterativeParsingErrorState,         // Left bracket\n                IterativeParsingErrorState,         // Right bracket\n                IterativeParsingErrorState,         // Left curly bracket\n                IterativeParsingObjectFinishState,  // Right curly bracket\n                IterativeParsingErrorState,         // Comma\n                IterativeParsingErrorState,         // Colon\n                IterativeParsingMemberKeyState,     // String\n                IterativeParsingErrorState,         // False\n                IterativeParsingErrorState,         // True\n                IterativeParsingErrorState,         // Null\n                IterativeParsingErrorState          // Number\n            },\n            // MemberKey\n            {\n                IterativeParsingErrorState,             // Left bracket\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingErrorState,             // Left curly bracket\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingKeyValueDelimiterState, // Colon\n                IterativeParsingErrorState,             // String\n                IterativeParsingErrorState,             // False\n                IterativeParsingErrorState,             // True\n                IterativeParsingErrorState,             // Null\n                IterativeParsingErrorState              // Number\n            },\n            // KeyValueDelimiter\n            {\n                IterativeParsingArrayInitialState,      // Left bracket(push MemberValue state)\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingObjectInitialState,     // Left curly bracket(push MemberValue state)\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingMemberValueState,       // String\n                IterativeParsingMemberValueState,       // False\n                IterativeParsingMemberValueState,       // True\n                IterativeParsingMemberValueState,       // Null\n                IterativeParsingMemberValueState        // Number\n            },\n            // MemberValue\n            {\n                IterativeParsingErrorState,             // Left bracket\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingErrorState,             // Left curly bracket\n                IterativeParsingObjectFinishState,      // Right curly bracket\n                IterativeParsingMemberDelimiterState,   // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingErrorState,             // String\n                IterativeParsingErrorState,             // False\n                IterativeParsingErrorState,             // True\n                IterativeParsingErrorState,             // Null\n                IterativeParsingErrorState              // Number\n            },\n            // MemberDelimiter\n            {\n                IterativeParsingErrorState,         // Left bracket\n                IterativeParsingErrorState,         // Right bracket\n                IterativeParsingErrorState,         // Left curly bracket\n                IterativeParsingErrorState,         // Right curly bracket\n                IterativeParsingErrorState,         // Comma\n                IterativeParsingErrorState,         // Colon\n                IterativeParsingMemberKeyState,     // String\n                IterativeParsingErrorState,         // False\n                IterativeParsingErrorState,         // True\n                IterativeParsingErrorState,         // Null\n                IterativeParsingErrorState          // Number\n            },\n            // ObjectFinish(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // ArrayInitial\n            {\n                IterativeParsingArrayInitialState,      // Left bracket(push Element state)\n                IterativeParsingArrayFinishState,       // Right bracket\n                IterativeParsingObjectInitialState,     // Left curly bracket(push Element state)\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingElementState,           // String\n                IterativeParsingElementState,           // False\n                IterativeParsingElementState,           // True\n                IterativeParsingElementState,           // Null\n                IterativeParsingElementState            // Number\n            },\n            // Element\n            {\n                IterativeParsingErrorState,             // Left bracket\n                IterativeParsingArrayFinishState,       // Right bracket\n                IterativeParsingErrorState,             // Left curly bracket\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingElementDelimiterState,  // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingErrorState,             // String\n                IterativeParsingErrorState,             // False\n                IterativeParsingErrorState,             // True\n                IterativeParsingErrorState,             // Null\n                IterativeParsingErrorState              // Number\n            },\n            // ElementDelimiter\n            {\n                IterativeParsingArrayInitialState,      // Left bracket(push Element state)\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingObjectInitialState,     // Left curly bracket(push Element state)\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingElementState,           // String\n                IterativeParsingElementState,           // False\n                IterativeParsingElementState,           // True\n                IterativeParsingElementState,           // Null\n                IterativeParsingElementState            // Number\n            },\n            // ArrayFinish(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // Single Value (sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            }\n        }; // End of G\n\n        return (IterativeParsingState)G[state][token];\n    }\n\n    // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().\n    // May return a new state on state pop.\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {\n        (void)token;\n\n        switch (dst) {\n        case IterativeParsingErrorState:\n            return dst;\n\n        case IterativeParsingObjectInitialState:\n        case IterativeParsingArrayInitialState:\n        {\n            // Push the state(Element or MemeberValue) if we are nested in another array or value of member.\n            // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.\n            IterativeParsingState n = src;\n            if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)\n                n = IterativeParsingElementState;\n            else if (src == IterativeParsingKeyValueDelimiterState)\n                n = IterativeParsingMemberValueState;\n            // Push current state.\n            *stack_.template Push<SizeType>(1) = n;\n            // Initialize and push the member/element count.\n            *stack_.template Push<SizeType>(1) = 0;\n            // Call handler\n            bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray();\n            // On handler short circuits the parsing.\n            if (!hr) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            else {\n                is.Take();\n                return dst;\n            }\n        }\n\n        case IterativeParsingMemberKeyState:\n            ParseString<parseFlags>(is, handler, true);\n            if (HasParseError())\n                return IterativeParsingErrorState;\n            else\n                return dst;\n\n        case IterativeParsingKeyValueDelimiterState:\n            RAPIDJSON_ASSERT(token == ColonToken);\n            is.Take();\n            return dst;\n\n        case IterativeParsingMemberValueState:\n            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.\n            ParseValue<parseFlags>(is, handler);\n            if (HasParseError()) {\n                return IterativeParsingErrorState;\n            }\n            return dst;\n\n        case IterativeParsingElementState:\n            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.\n            ParseValue<parseFlags>(is, handler);\n            if (HasParseError()) {\n                return IterativeParsingErrorState;\n            }\n            return dst;\n\n        case IterativeParsingMemberDelimiterState:\n        case IterativeParsingElementDelimiterState:\n            is.Take();\n            // Update member/element count.\n            *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;\n            return dst;\n\n        case IterativeParsingObjectFinishState:\n        {\n            // Get member count.\n            SizeType c = *stack_.template Pop<SizeType>(1);\n            // If the object is not empty, count the last member.\n            if (src == IterativeParsingMemberValueState)\n                ++c;\n            // Restore the state.\n            IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));\n            // Transit to Finish state if this is the topmost scope.\n            if (n == IterativeParsingStartState)\n                n = IterativeParsingFinishState;\n            // Call handler\n            bool hr = handler.EndObject(c);\n            // On handler short circuits the parsing.\n            if (!hr) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            else {\n                is.Take();\n                return n;\n            }\n        }\n\n        case IterativeParsingArrayFinishState:\n        {\n            // Get element count.\n            SizeType c = *stack_.template Pop<SizeType>(1);\n            // If the array is not empty, count the last element.\n            if (src == IterativeParsingElementState)\n                ++c;\n            // Restore the state.\n            IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));\n            // Transit to Finish state if this is the topmost scope.\n            if (n == IterativeParsingStartState)\n                n = IterativeParsingFinishState;\n            // Call handler\n            bool hr = handler.EndArray(c);\n            // On handler short circuits the parsing.\n            if (!hr) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            else {\n                is.Take();\n                return n;\n            }\n        }\n\n        default:\n            // This branch is for IterativeParsingValueState actually.\n            // Use `default:` rather than\n            // `case IterativeParsingValueState:` is for code coverage.\n\n            // The IterativeParsingStartState is not enumerated in this switch-case.\n            // It is impossible for that case. And it can be caught by following assertion.\n\n            // The IterativeParsingFinishState is not enumerated in this switch-case either.\n            // It is a \"derivative\" state which cannot triggered from Predict() directly.\n            // Therefore it cannot happen here. And it can be caught by following assertion.\n            RAPIDJSON_ASSERT(dst == IterativeParsingValueState);\n\n            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.\n            ParseValue<parseFlags>(is, handler);\n            if (HasParseError()) {\n                return IterativeParsingErrorState;\n            }\n            return IterativeParsingFinishState;\n        }\n    }\n\n    template <typename InputStream>\n    void HandleError(IterativeParsingState src, InputStream& is) {\n        if (HasParseError()) {\n            // Error flag has been set.\n            return;\n        }\n        \n        switch (src) {\n        case IterativeParsingStartState:            RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;\n        case IterativeParsingFinishState:           RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;\n        case IterativeParsingObjectInitialState:\n        case IterativeParsingMemberDelimiterState:  RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;\n        case IterativeParsingMemberKeyState:        RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;\n        case IterativeParsingMemberValueState:      RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;\n        case IterativeParsingElementState:          RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;\n        default:                                    RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());\n        }       \n    }\n\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    ParseResult IterativeParse(InputStream& is, Handler& handler) {\n        parseResult_.Clear();\n        ClearStackOnExit scope(*this);\n        IterativeParsingState state = IterativeParsingStartState;\n\n        SkipWhitespace(is);\n        while (is.Peek() != '\\0') {\n            Token t = Tokenize(is.Peek());\n            IterativeParsingState n = Predict(state, t);\n            IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);\n\n            if (d == IterativeParsingErrorState) {\n                HandleError(state, is);\n                break;\n            }\n\n            state = d;\n\n            // Do not further consume streams if a root JSON has been parsed.\n            if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)\n                break;\n\n            SkipWhitespace(is);\n        }\n\n        // Handle the end of file.\n        if (state != IterativeParsingFinishState)\n            HandleError(state, is);\n\n        return parseResult_;\n    }\n\n    static const size_t kDefaultStackCapacity = 256;    //!< Default stack capacity in bytes for storing a single decoded string.\n    internal::Stack<StackAllocator> stack_;  //!< A stack for storing decoded string temporarily during non-destructive parsing.\n    ParseResult parseResult_;\n}; // class GenericReader\n\n//! Reader with UTF8 encoding and default allocator.\ntypedef GenericReader<UTF8<>, UTF8<> > Reader;\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_READER_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/stringbuffer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_STRINGBUFFER_H_\n#define RAPIDJSON_STRINGBUFFER_H_\n\n#include \"rapidjson.h\"\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n#include <utility> // std::move\n#endif\n\n#include \"internal/stack.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Represents an in-memory output stream.\n/*!\n    \\tparam Encoding Encoding of the stream.\n    \\tparam Allocator type for allocating memory buffer.\n    \\note implements Stream concept\n*/\ntemplate <typename Encoding, typename Allocator = CrtAllocator>\nclass GenericStringBuffer {\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}\n    GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {\n        if (&rhs != this)\n            stack_ = std::move(rhs.stack_);\n        return *this;\n    }\n#endif\n\n    void Put(Ch c) { *stack_.template Push<Ch>() = c; }\n    void Flush() {}\n\n    void Clear() { stack_.Clear(); }\n    void ShrinkToFit() {\n        // Push and pop a null terminator. This is safe.\n        *stack_.template Push<Ch>() = '\\0';\n        stack_.ShrinkToFit();\n        stack_.template Pop<Ch>(1);\n    }\n    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }\n    void Pop(size_t count) { stack_.template Pop<Ch>(count); }\n\n    const Ch* GetString() const {\n        // Push and pop a null terminator. This is safe.\n        *stack_.template Push<Ch>() = '\\0';\n        stack_.template Pop<Ch>(1);\n\n        return stack_.template Bottom<Ch>();\n    }\n\n    size_t GetSize() const { return stack_.GetSize(); }\n\n    static const size_t kDefaultCapacity = 256;\n    mutable internal::Stack<Allocator> stack_;\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    GenericStringBuffer(const GenericStringBuffer&);\n    GenericStringBuffer& operator=(const GenericStringBuffer&);\n};\n\n//! String buffer with UTF8 encoding\ntypedef GenericStringBuffer<UTF8<> > StringBuffer;\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {\n    std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_STRINGBUFFER_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/rapidjson/writer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_WRITER_H_\n#define RAPIDJSON_WRITER_H_\n\n#include \"rapidjson.h\"\n#include \"internal/stack.h\"\n#include \"internal/strfunc.h\"\n#include \"internal/dtoa.h\"\n#include \"internal/itoa.h\"\n#include \"stringbuffer.h\"\n#include <new>      // placement new\n\n#if RAPIDJSON_HAS_STDSTRING\n#include <string>\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4127) // conditional expression is constant\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! JSON writer\n/*! Writer implements the concept Handler.\n    It generates JSON text by events to an output os.\n\n    User may programmatically calls the functions of a writer to generate JSON text.\n\n    On the other side, a writer can also be passed to objects that generates events, \n\n    for example Reader::Parse() and Document::Accept().\n\n    \\tparam OutputStream Type of output stream.\n    \\tparam SourceEncoding Encoding of source string.\n    \\tparam TargetEncoding Encoding of output stream.\n    \\tparam StackAllocator Type of allocator for allocating memory of stack.\n    \\note implements Handler concept\n*/\ntemplate<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>\nclass Writer {\npublic:\n    typedef typename SourceEncoding::Ch Ch;\n\n    //! Constructor\n    /*! \\param os Output stream.\n        \\param stackAllocator User supplied allocator. If it is null, it will create a private one.\n        \\param levelDepth Initial capacity of stack.\n    */\n    explicit\n    Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : \n        os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {}\n\n    explicit\n    Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :\n        os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}\n\n    //! Reset the writer with a new stream.\n    /*!\n        This function reset the writer with a new stream and default settings,\n        in order to make a Writer object reusable for output multiple JSONs.\n\n        \\param os New output stream.\n        \\code\n        Writer<OutputStream> writer(os1);\n        writer.StartObject();\n        // ...\n        writer.EndObject();\n\n        writer.Reset(os2);\n        writer.StartObject();\n        // ...\n        writer.EndObject();\n        \\endcode\n    */\n    void Reset(OutputStream& os) {\n        os_ = &os;\n        hasRoot_ = false;\n        level_stack_.Clear();\n    }\n\n    //! Checks whether the output is a complete JSON.\n    /*!\n        A complete JSON has a complete root object or array.\n    */\n    bool IsComplete() const {\n        return hasRoot_ && level_stack_.Empty();\n    }\n\n    /*!@name Implementation of Handler\n        \\see Handler\n    */\n    //@{\n\n    bool Null()                 { Prefix(kNullType);   return WriteNull(); }\n    bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }\n    bool Int(int i)             { Prefix(kNumberType); return WriteInt(i); }\n    bool Uint(unsigned u)       { Prefix(kNumberType); return WriteUint(u); }\n    bool Int64(int64_t i64)     { Prefix(kNumberType); return WriteInt64(i64); }\n    bool Uint64(uint64_t u64)   { Prefix(kNumberType); return WriteUint64(u64); }\n\n    //! Writes the given \\c double value to the stream\n    /*!\n        \\param d The value to be written.\n        \\return Whether it is succeed.\n    */\n    bool Double(double d)       { Prefix(kNumberType); return WriteDouble(d); }\n\n    bool String(const Ch* str, SizeType length, bool copy = false) {\n        (void)copy;\n        Prefix(kStringType);\n        return WriteString(str, length);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool String(const std::basic_string<Ch>& str) {\n        return String(str.data(), SizeType(str.size()));\n    }\n#endif\n\n    bool StartObject() {\n        Prefix(kObjectType);\n        new (level_stack_.template Push<Level>()) Level(false);\n        return WriteStartObject();\n    }\n\n    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }\n\t\n    bool EndObject(SizeType memberCount = 0) {\n        (void)memberCount;\n        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));\n        RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);\n        level_stack_.template Pop<Level>(1);\n        bool ret = WriteEndObject();\n        if (level_stack_.Empty())   // end of json text\n            os_->Flush();\n        return ret;\n    }\n\n    bool StartArray() {\n        Prefix(kArrayType);\n        new (level_stack_.template Push<Level>()) Level(true);\n        return WriteStartArray();\n    }\n\n    bool EndArray(SizeType elementCount = 0) {\n        (void)elementCount;\n        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));\n        RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);\n        level_stack_.template Pop<Level>(1);\n        bool ret = WriteEndArray();\n        if (level_stack_.Empty())   // end of json text\n            os_->Flush();\n        return ret;\n    }\n    //@}\n\n    /*! @name Convenience extensions */\n    //@{\n\n    //! Simpler but slower overload.\n    bool String(const Ch* str) { return String(str, internal::StrLen(str)); }\n    bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }\n\n    //@}\n\nprotected:\n    //! Information for each nested level\n    struct Level {\n        Level(bool inArray_) : valueCount(0), inArray(inArray_) {}\n        size_t valueCount;  //!< number of values in this level\n        bool inArray;       //!< true if in array, otherwise in object\n    };\n\n    static const size_t kDefaultLevelDepth = 32;\n\n    bool WriteNull()  {\n        os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;\n    }\n\n    bool WriteBool(bool b)  {\n        if (b) {\n            os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');\n        }\n        else {\n            os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');\n        }\n        return true;\n    }\n\n    bool WriteInt(int i) {\n        char buffer[11];\n        const char* end = internal::i32toa(i, buffer);\n        for (const char* p = buffer; p != end; ++p)\n            os_->Put(*p);\n        return true;\n    }\n\n    bool WriteUint(unsigned u) {\n        char buffer[10];\n        const char* end = internal::u32toa(u, buffer);\n        for (const char* p = buffer; p != end; ++p)\n            os_->Put(*p);\n        return true;\n    }\n\n    bool WriteInt64(int64_t i64) {\n        char buffer[21];\n        const char* end = internal::i64toa(i64, buffer);\n        for (const char* p = buffer; p != end; ++p)\n            os_->Put(*p);\n        return true;\n    }\n\n    bool WriteUint64(uint64_t u64) {\n        char buffer[20];\n        char* end = internal::u64toa(u64, buffer);\n        for (char* p = buffer; p != end; ++p)\n            os_->Put(*p);\n        return true;\n    }\n\n    bool WriteDouble(double d) {\n        char buffer[25];\n        char* end = internal::dtoa(d, buffer);\n        for (char* p = buffer; p != end; ++p)\n            os_->Put(*p);\n        return true;\n    }\n\n    bool WriteString(const Ch* str, SizeType length)  {\n        static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n        static const char escape[256] = {\n#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n            //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F\n            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00\n            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10\n              0,   0, '\"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20\n            Z16, Z16,                                                                       // 30~4F\n              0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\\\',   0,   0,   0, // 50\n            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF\n#undef Z16\n        };\n\n        os_->Put('\\\"');\n        GenericStringStream<SourceEncoding> is(str);\n        while (is.Tell() < length) {\n            const Ch c = is.Peek();\n            if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) {\n                // Unicode escaping\n                unsigned codepoint;\n                if (!SourceEncoding::Decode(is, &codepoint))\n                    return false;\n                os_->Put('\\\\');\n                os_->Put('u');\n                if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {\n                    os_->Put(hexDigits[(codepoint >> 12) & 15]);\n                    os_->Put(hexDigits[(codepoint >>  8) & 15]);\n                    os_->Put(hexDigits[(codepoint >>  4) & 15]);\n                    os_->Put(hexDigits[(codepoint      ) & 15]);\n                }\n                else {\n                    RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);\n                    // Surrogate pair\n                    unsigned s = codepoint - 0x010000;\n                    unsigned lead = (s >> 10) + 0xD800;\n                    unsigned trail = (s & 0x3FF) + 0xDC00;\n                    os_->Put(hexDigits[(lead >> 12) & 15]);\n                    os_->Put(hexDigits[(lead >>  8) & 15]);\n                    os_->Put(hexDigits[(lead >>  4) & 15]);\n                    os_->Put(hexDigits[(lead      ) & 15]);\n                    os_->Put('\\\\');\n                    os_->Put('u');\n                    os_->Put(hexDigits[(trail >> 12) & 15]);\n                    os_->Put(hexDigits[(trail >>  8) & 15]);\n                    os_->Put(hexDigits[(trail >>  4) & 15]);\n                    os_->Put(hexDigits[(trail      ) & 15]);                    \n                }\n            }\n            else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c])  {\n                is.Take();\n                os_->Put('\\\\');\n                os_->Put(escape[(unsigned char)c]);\n                if (escape[(unsigned char)c] == 'u') {\n                    os_->Put('0');\n                    os_->Put('0');\n                    os_->Put(hexDigits[(unsigned char)c >> 4]);\n                    os_->Put(hexDigits[(unsigned char)c & 0xF]);\n                }\n            }\n            else\n                if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))\n                    return false;\n        }\n        os_->Put('\\\"');\n        return true;\n    }\n\n    bool WriteStartObject() { os_->Put('{'); return true; }\n    bool WriteEndObject()   { os_->Put('}'); return true; }\n    bool WriteStartArray()  { os_->Put('['); return true; }\n    bool WriteEndArray()    { os_->Put(']'); return true; }\n\n    void Prefix(Type type) {\n        (void)type;\n        if (level_stack_.GetSize() != 0) { // this value is not at root\n            Level* level = level_stack_.template Top<Level>();\n            if (level->valueCount > 0) {\n                if (level->inArray) \n                    os_->Put(','); // add comma if it is not the first element in array\n                else  // in object\n                    os_->Put((level->valueCount % 2 == 0) ? ',' : ':');\n            }\n            if (!level->inArray && level->valueCount % 2 == 0)\n                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name\n            level->valueCount++;\n        }\n        else {\n            RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root.\n            hasRoot_ = true;\n        }\n    }\n\n    OutputStream* os_;\n    internal::Stack<StackAllocator> level_stack_;\n    bool hasRoot_;\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    Writer(const Writer&);\n    Writer& operator=(const Writer&);\n};\n\n// Full specialization for StringStream to prevent memory copying\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteInt(int i) {\n    char *buffer = os_->Push(11);\n    const char* end = internal::i32toa(i, buffer);\n    os_->Pop(11 - (end - buffer));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteUint(unsigned u) {\n    char *buffer = os_->Push(10);\n    const char* end = internal::u32toa(u, buffer);\n    os_->Pop(10 - (end - buffer));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {\n    char *buffer = os_->Push(21);\n    const char* end = internal::i64toa(i64, buffer);\n    os_->Pop(21 - (end - buffer));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {\n    char *buffer = os_->Push(20);\n    const char* end = internal::u64toa(u, buffer);\n    os_->Pop(20 - (end - buffer));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteDouble(double d) {\n    char *buffer = os_->Push(25);\n    char* end = internal::dtoa(d, buffer);\n    os_->Pop(25 - (end - buffer));\n    return true;\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "UAlbertaBot/Source/research/CombatData.cpp",
    "content": "#include \"CombatData.h\"\n\nCombatUnitData::CombatUnitData()\n\t: _unit(NULL)\n\t, _phase(CombatUnitData::NONE)\n\t, _enteredReady(0)\n\t, _enteredAttacking(0)\n\t, _enteredReloading(0)\n\t, _waitCommandGiven(0)\n{\n\n}\n\nCombatUnitData::CombatUnitData(BWAPI::Unit * unit)\n\t: _unit(unit)\n\t, _phase(CombatUnitData::NONE)\n\t, _enteredReady(0)\n\t, _enteredAttacking(0)\n\t, _enteredReloading(0)\n\t, _waitCommandGiven(0)\n{\n}\n\nconst bool CombatUnitData::isWaiting() const\n{\n\treturn (getPhase() == RELOADING) && (_waitCommandGiven > _enteredReloading);\n}\n\nconst int CombatUnitData::getPhase() const\n{\n\treturn _phase;\n}\n\nvoid CombatUnitData::waitCommand() \n{\n\t_waitCommandGiven = BWAPI::Broodwar->getFrameCount();\n}\n\nvoid CombatUnitData::update()\n{\n\tint currentFrame = BWAPI::Broodwar->getFrameCount();\n\n\tif (_phase == NONE)\n\t{\n\t\tif (_unit->getGroundWeaponCooldown() == 0)\n\t\t{\n\t\t\t_phase = READY;\n\t\t\t_enteredReady = currentFrame;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_phase = RELOADING;\n\t\t\t_enteredReloading = currentFrame;\n\t\t}\n\t}\n\telse if (_phase == READY)\n\t{\n\t\tif (_unit->isAttackFrame() || _unit->isStartingAttack())\n\t\t{\n\t\t\t_phase = ATTACKING;\n\t\t\t_enteredAttacking = currentFrame;\n\t\t}\n\t}\n\telse if (_phase == ATTACKING)\n\t{\n\t\tif (_unit->getGroundWeaponCooldown() == 0)\n\t\t{\n\t\t\t_phase = READY;\n\t\t\t_enteredReady = currentFrame;\n\t\t}\n\t\telse if (!_unit->isAttackFrame() || ((currentFrame - _enteredAttacking) > Search::StarcraftData::getAttackFrames(_unit->getType()).first))\n\t\t{\n\t\t\t_phase = RELOADING;\n\t\t\t_enteredReloading = currentFrame;\n\t\t}\n\t}\n\telse if (_phase == RELOADING)\n\t{\n\t\tif (_unit->getGroundWeaponCooldown() == 0)\n\t\t{\n\t\t\t_phase = READY;\n\t\t\t_enteredReady = currentFrame;\n\t\t}\n\t}\n}\n\nCombatData::CombatData() {}\n\nCombatUnitData & CombatData::getUnitData(BWAPI::Unit * unit)\n{\n\treturn map[unit];\n}\n\nvoid CombatData::updateUnit(BWAPI::Unit * unit)\n{\n\t// if it's not in our map, add a default entry\n\tif (!exists(unit))\n\t{\n\t\taddUnit(unit);\n\t}\n\n\tgetUnitData(unit).update();\n}\n\nvoid CombatData::addUnit(BWAPI::Unit * unit)\n{\n\tmap[unit] = CombatUnitData(unit);\n}\n\nvoid CombatData::removeUnit(BWAPI::Unit * unit)\n{\n\tmap.erase(unit);\n}\n\nbool CombatData::exists(BWAPI::Unit * unit) const\n{\n\treturn map.find(unit) != map.end();\n}\n\nbool CombatData::commandWillInterruptAttack(BWAPI::Unit * unit)\n{\n\tconst CombatUnitData & unitData(getUnitData(unit));\n\n\tif (unitData.getPhase() == CombatUnitData::ATTACKING)\n\t{\n\t\treturn true;\n\t}\n\n\tBWAPI::Broodwar->drawTextScreen(20, 20, \"ATTACK PASS!\");\n\n\treturn false;\n}\n\nbool CombatData::canIssueAttackCommand(BWAPI::Unit * attacker, BWAPI::Unit * target)\n{\n\tBWAPI::UnitCommand currentCommand(attacker->getLastCommand());\n\tBWAPI::UnitCommandType commandType = currentCommand.getType();\n\n\t// if we have already given a command this frame, don't issue another one\n\t//if (commandType != BWAPI::UnitCommandTypes::None && BWAPI::Broodwar->getFrameCount() - attacker->getLastCommandFrame() <= 7)\n\t//{\n\t//\tdrawDebugPlate(attacker, \"A FRAME\");\n\t//\treturn false;\n\t//}\n\n\t// if the last command given was an attack command\n\tif (currentCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit)\n\t{\n\t\t// if the target is the same as the current one, we don't need to switch\n\t\tif (currentCommand.getTarget() == target)\n\t\t{\n\t\t\tdrawDebugPlate(attacker, \"SAME\");\n\t\t\treturn false;\n\t\t}\n\t}\n\t\t\n\treturn true;\n\t//return !commandWillInterruptAttack(attacker);\n}\n\nbool CombatData::canIssueMoveCommand(BWAPI::Unit * unit, BWAPI::Position & position)\n{\n\tBWAPI::UnitCommand currentCommand(unit->getLastCommand());\n\tBWAPI::UnitCommandType commandType = currentCommand.getType();\n\n\tint threshold = 5;\n\n\t// if we have already given a command this frame, don't issue another one\n\t//if (commandType != BWAPI::UnitCommandTypes::None && BWAPI::Broodwar->getFrameCount() - unit->getLastCommandFrame() <= 7)\n\t//{\n\t//\tdrawDebugPlate(unit, \"M FRAME\");\n\t//\treturn false;\n\t//}\n\n\tif (getUnitData(unit).isWaiting())\n\t{\n\t\tdrawDebugPlate(unit, \"WAIT\");\n\t\treturn false;\n\t}\n\n\t// if the last command given was an attack command\n\tif (currentCommand.type == BWAPI::UnitCommandTypes::Move)\n\t{\n\t\tif (!unit->isMoving())\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn unit->getDistance(position) < 28;\n\t\t}\n\t}\n\n\treturn !commandWillInterruptAttack(unit);\n}\n\nbool CombatData::canIssueStopCommand(BWAPI::Unit * unit)\n{\n\t// if the last move was attacking a unit do nothing\n\tif (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Unit)\n\t{\n\t\treturn false;\n\t}\n\n\treturn !commandWillInterruptAttack(unit);\n}\n\nconst std::pair<int, int> CombatData::getUnitCooldown(BWAPI::Unit * unit, MicroSearch::Unit & u) const\n{\n\tint attackCooldown(0);\n\tint moveCooldown(0);\n\n\tBWAPI::UnitCommand lastCommand = unit->getLastCommand();\n\tint lastCommandFrame = unit->getLastCommandFrame();\n\tint currentFrame = BWAPI::Broodwar->getFrameCount();\n\tint framesSinceCommand = currentFrame - lastCommandFrame;\n\n\t\n\tif ((unit->getType() == BWAPI::UnitTypes::Protoss_Dragoon) && (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Unit))\n\t{\n\t\t// dragoons are one of only 2 unit types whose attack can be canceled by the in-game targeter being called too early so\n\t\t// this hack makes up for that by taking it's stop-delay into account\n\t\tattackCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, unit->getGroundWeaponCooldown()-Search::StarcraftData::getAttackFrames(unit->getType()).first);\n\t}\n\telse\n\t{\n\t\tattackCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, unit->getGroundWeaponCooldown()-2);\n\t}\n\n\t// if the last attack was an attack command\n\tif (lastCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit)\n\t{\n\t\tmoveCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, u.attackInitFrameTime() - framesSinceCommand);\n\n\t\t//BWAPI::Broodwar->drawTextScreen(100,100, \"%d, %d\", attackCooldown-currentFrame, moveCooldown-currentFrame);\n\t}\n\t// if the last command was a move command\n\telse if (lastCommand.getType() == BWAPI::UnitCommandTypes::Move)\n\t{\n\t\tmoveCooldown = currentFrame;\n\t}\n\n\tif (moveCooldown - BWAPI::Broodwar->getFrameCount() < 4 || unit->isMoving())\n\t{\n\t\tmoveCooldown = currentFrame;\n\t}\n\n\tmoveCooldown = std::min(moveCooldown, attackCooldown);\n\n\treturn std::pair<int, int>(attackCooldown, moveCooldown);\n}\n\nvoid CombatData::drawDebugPlate(BWAPI::Unit * unit, char * string)\n{\n\tBWAPI::Broodwar->drawBoxMap(unit->getPosition().x()-15, unit->getPosition().y()-10, unit->getPosition().x() + 10, unit->getPosition().y(), BWAPI::Colors::Black, true);\n\tBWAPI::Broodwar->drawTextMap(unit->getPosition().x()-15, unit->getPosition().y()-10, string);\n}\n\nvoid CombatData::waitCommand(BWAPI::Unit * unit)\n{\n\tgetUnitData(unit).waitCommand();\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/research/CombatData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BWAPI.h\"\n#include \"GameCommander.h\"\n#include \"..\\..\\AdversarialSearch\\source\\Timer.h\"\n#include \"..\\..\\AdversarialSearch\\source\\GameState.h\"\n#include \"..\\..\\AdversarialSearch\\source\\Player.h\"\n#include \"..\\..\\AdversarialSearch\\source\\TranspositionTable.h\"\n\n#include <boost/shared_ptr.hpp>\n\n\nclass CombatUnitData\n{\t\n\tBWAPI::Unit * _unit;\n\n\tint\t\t_phase,\n\t\t\t_enteredReady,\n\t\t\t_enteredAttacking,\n\t\t\t_enteredReloading,\n\t\t\t_waitCommandGiven;\n\npublic:\n\n\tenum\t{ NONE, READY, ATTACKING, RELOADING };\n\n\tCombatUnitData();\n\tCombatUnitData(BWAPI::Unit * unit);\n\n\tvoid update();\n\tvoid waitCommand();\n\tvoid attackCommand();\n\tconst bool isWaiting() const;\n\tconst int getPhase() const;\n};\n\nclass CombatData\n{\n\tstd::map<BWAPI::Unit *, CombatUnitData> map;\n\n\tCombatUnitData & getUnitData(BWAPI::Unit * unit);\n\npublic:\n\n\tCombatData();\n\n\tvoid updateUnit(BWAPI::Unit * unit);\n\tvoid addUnit(BWAPI::Unit * unit);\n\tvoid removeUnit(BWAPI::Unit * unit);\n\tvoid drawDebugPlate(BWAPI::Unit * unit, char * string);\n\n\tbool exists(BWAPI::Unit * unit) const;\n\tbool commandWillInterruptAttack(BWAPI::Unit * unit);\n\tbool canIssueAttackCommand(BWAPI::Unit * attacker, BWAPI::Unit * target);\n\tbool canIssueMoveCommand(BWAPI::Unit * unit, BWAPI::Position & position);\n\tbool canIssueStopCommand(BWAPI::Unit * unit);\n\tint attackAnimStartTime(BWAPI::Unit * unit);\n\n\tvoid waitCommand(BWAPI::Unit * unit);\n\tvoid attackCommand(BWAPI::Unit * unit);\n\n\tconst std::pair<int, int> getUnitCooldown(BWAPI::Unit * unit, MicroSearch::Unit & u) const;\n};\n"
  },
  {
    "path": "UAlbertaBot/Source/research/GameHistory.hpp",
    "content": "#pragma once\n\n#include \"BWAPI.h\"\n#include <fstream>\n#include <iostream>\n#include <vector>\n\nclass UnitFrameData\n{\n    BWAPI::UnitType m_type;\n    BWAPI::Position m_pos;\n    BWAPI::Order    m_order;\n    BWAPI::Position m_orderPos;\n\n    int     m_id     = 0;\n    int     m_player = 0;\n    int     m_hp     = 0;\n    int     m_shields= 0;\n    int     m_energy = 0;\n    double  m_angle  = 0;\n\npublic:\n\n    UnitFrameData(BWAPI::Unit unit)\n        : m_type     (unit->getType())\n        , m_pos      (unit->getPosition())\n        , m_order    (unit->getOrder())\n        , m_orderPos (unit->getOrderTargetPosition())\n        , m_id       (unit->getID())\n        , m_player   (unit->getPlayer()->getID())\n        , m_hp       (unit->getHitPoints())\n        , m_shields  (unit->getShields())\n        , m_energy   (unit->getEnergy())\n        , m_angle    (unit->getAngle())\n    {\n\n    }\n\n    void writeToFile(std::ofstream & fout) const\n    {\n        fout << m_player << \" \";         // 1 byte\n        fout << m_type.getID() << \" \";   // 1 byte\n        fout << m_id << \" \";             // 2 byte\n        fout << m_hp << \" \";             // 2 byte\n        fout << m_shields << \" \";        // 2 byte\n        fout << m_pos.x << \" \";          // 2 byte\n        fout << m_pos.y << \" \";          // 2 byte\n    }\n};\n\nclass GameFrame\n{\n    int                         m_frame = 0;\n    std::vector<UnitFrameData>  m_units;\n\npublic:\n\n    GameFrame()\n        : m_frame(BWAPI::Broodwar->getFrameCount())\n    {\n        for (const BWAPI::Unit & unit : BWAPI::Broodwar->getAllUnits())\n        {\n            if (unit->getPlayer()->getID() != -1)\n            {\n                m_units.push_back(UnitFrameData(unit));\n            }\n        }\n    }\n\n    int getFrame() const\n    {\n        return m_frame;\n    }\n\n    void writeToFile(std::ofstream & fout) const\n    {\n        fout << \"f \" << m_frame << \"\\n\";\n        for (const auto & unit : m_units)\n        {\n            unit.writeToFile(fout);\n            fout << \"\\n\";\n        }\n    }\n};\n\nclass GameMap\n{\n    int                 m_width  = 0;\n    int                 m_height = 0;\n    std::vector<int>    m_walkable;\n\npublic:\n\n    GameMap()\n        : m_width(BWAPI::Broodwar->mapWidth() * 4)\n        , m_height(BWAPI::Broodwar->mapHeight() * 4)\n        , m_walkable(BWAPI::Broodwar->mapHeight() * BWAPI::Broodwar->mapWidth() * 16, 0)\n    {\n        for (int h(0); h < m_height; ++h)\n        {\n            for (int w(0); w < m_width; ++w)\n            {\n                m_walkable[h*w + w] = BWAPI::Broodwar->isWalkable(h, w);\n            }\n        }\n    }\n\n    void writeToFile(std::ofstream & fout) const\n    {\n\n    }\n};\n\nclass GameHistory\n{\n    GameMap                 m_map;\n    std::vector<GameFrame>  m_frames;\n    int                     m_frameSkip = 0;\n\npublic:\n\n    GameHistory()\n    {\n    }\n\n    void setFrameSkip(int frames)\n    {\n        m_frameSkip = frames;\n    }\n\n    void onFrame()\n    {\n        if (m_frames.empty() || (BWAPI::Broodwar->getFrameCount() - m_frames.back().getFrame() >= m_frameSkip))\n        {\n            m_frames.push_back(GameFrame());\n        }\n    }\n\n    void writeToFile(const std::string & filename) const\n    {\n        std::ofstream fout(filename);\n\n        for (const auto & frame : m_frames)\n        {\n            frame.writeToFile(fout);\n        }\n\n        fout.close();\n    }\n};\n"
  },
  {
    "path": "UAlbertaBot/Source/research/HardCodedInfo.cpp",
    "content": "/*#include \"Common.h\"\n#include \"BWAPI.h\"\n#include \"HardCodedInfo.h\"\n\n// gotta keep c++ static happy\nHardCodedInfo * HardCodedInfo::Instance() = NULL;\n\n// constructor\nHardCodedInfo::HardCodedInfo() \n{\n\tsetChokeDefendLocations();\n}\n\n// get an instance of this\nHardCodedInfo * HardCodedInfo::Instance() \n{\n\t// if the instance doesn't exist, create it\n\tif (!HardCodedInfo::Instance()) \n\t{\n\t\tHardCodedInfo::Instance() = new HardCodedInfo();\n\t}\n\n\treturn HardCodedInfo::Instance();\n}\n\nvoid HardCodedInfo::setChokeDefendLocations()\n{\n\t// (2)Benzene.scx ---- af618ea3ed8a8926ca7b17619eebcb9126f0d8b1\n\tmainChokes[\"af618ea3ed8a8926ca7b17619eebcb9126f0d8b1\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"af618ea3ed8a8926ca7b17619eebcb9126f0d8b1\"].push_back(BWAPI::Position(3334, 953));\n\tmainChokes[\"af618ea3ed8a8926ca7b17619eebcb9126f0d8b1\"].push_back(BWAPI::Position(741, 2614));\n\n\tnaturalChokes[\"af618ea3ed8a8926ca7b17619eebcb9126f0d8b1\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"af618ea3ed8a8926ca7b17619eebcb9126f0d8b1\"].push_back(BWAPI::Position(3683, 1530));\n\tnaturalChokes[\"af618ea3ed8a8926ca7b17619eebcb9126f0d8b1\"].push_back(BWAPI::Position(368, 1994));\n\n\t// (2)Destination.scx ---- 4e24f217d2fe4dbfa6799bc57f74d8dc939d425b\n\tmainChokes[\"4e24f217d2fe4dbfa6799bc57f74d8dc939d425b\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"4e24f217d2fe4dbfa6799bc57f74d8dc939d425b\"].push_back(BWAPI::Position(1417, 3752));\n\tmainChokes[\"4e24f217d2fe4dbfa6799bc57f74d8dc939d425b\"].push_back(BWAPI::Position(1610, 311));\n\n\tnaturalChokes[\"4e24f217d2fe4dbfa6799bc57f74d8dc939d425b\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"4e24f217d2fe4dbfa6799bc57f74d8dc939d425b\"].push_back(BWAPI::Position(1049, 3274));\n\tnaturalChokes[\"4e24f217d2fe4dbfa6799bc57f74d8dc939d425b\"].push_back(BWAPI::Position(2015, 805));\n\n\t//mainChokes[\"4e24f217d2fe4dbfa6799bc57f74d8dc939d425b\"].push_back(BWAPI::Position(, ));\n\t// (2)Heartbreak Ridge.scx ---- 6f8da3c3cc8d08d9cf882700efa049280aedca8c\n\tmainChokes[\"6f8da3c3cc8d08d9cf882700efa049280aedca8c\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"6f8da3c3cc8d08d9cf882700efa049280aedca8c\"].push_back(BWAPI::Position(3635, 1387));\n\tmainChokes[\"6f8da3c3cc8d08d9cf882700efa049280aedca8c\"].push_back(BWAPI::Position(439, 1752));\n\n\tnaturalChokes[\"6f8da3c3cc8d08d9cf882700efa049280aedca8c\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"6f8da3c3cc8d08d9cf882700efa049280aedca8c\"].push_back(BWAPI::Position(3336, 859));\n\tnaturalChokes[\"6f8da3c3cc8d08d9cf882700efa049280aedca8c\"].push_back(BWAPI::Position(694, 2234));\n\n\t// (3)Aztec.scx ---- ba2fc0ed637e4ec91cc70424335b3c13e131b75a\n\tmainChokes[\"ba2fc0ed637e4ec91cc70424335b3c13e131b75a\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"ba2fc0ed637e4ec91cc70424335b3c13e131b75a\"].push_back(BWAPI::Position(3158, 481));\n\tmainChokes[\"ba2fc0ed637e4ec91cc70424335b3c13e131b75a\"].push_back(BWAPI::Position(3049, 3589));\n\tmainChokes[\"ba2fc0ed637e4ec91cc70424335b3c13e131b75a\"].push_back(BWAPI::Position(522, 1865));\n\n\tnaturalChokes[\"ba2fc0ed637e4ec91cc70424335b3c13e131b75a\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"ba2fc0ed637e4ec91cc70424335b3c13e131b75a\"].push_back(BWAPI::Position(3158, 481));\n\tnaturalChokes[\"ba2fc0ed637e4ec91cc70424335b3c13e131b75a\"].push_back(BWAPI::Position(3049, 3589));\n\tnaturalChokes[\"ba2fc0ed637e4ec91cc70424335b3c13e131b75a\"].push_back(BWAPI::Position(522, 1865));\n\n\t// (3)Tau Cross.scx ---- 9bfc271360fa5bab3707a29e1326b84d0ff58911\n\tmainChokes[\"9bfc271360fa5bab3707a29e1326b84d0ff58911\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"9bfc271360fa5bab3707a29e1326b84d0ff58911\"].push_back(BWAPI::Position(274, 894));\n\tmainChokes[\"9bfc271360fa5bab3707a29e1326b84d0ff58911\"].push_back(BWAPI::Position(3825, 1134));\n\tmainChokes[\"9bfc271360fa5bab3707a29e1326b84d0ff58911\"].push_back(BWAPI::Position(2219, 3677));\n\n\tnaturalChokes[\"9bfc271360fa5bab3707a29e1326b84d0ff58911\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"9bfc271360fa5bab3707a29e1326b84d0ff58911\"].push_back(BWAPI::Position(891, 591));\n\tnaturalChokes[\"9bfc271360fa5bab3707a29e1326b84d0ff58911\"].push_back(BWAPI::Position(3406, 1392));\n\tnaturalChokes[\"9bfc271360fa5bab3707a29e1326b84d0ff58911\"].push_back(BWAPI::Position(1675, 3419));\n\n\t// (4)Andromeda.scx ---- 1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\n\tmainChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"].push_back(BWAPI::Position(3716, 1023));\n\tmainChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"].push_back(BWAPI::Position(346, 1031));\n\tmainChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"].push_back(BWAPI::Position(338, 3026));\n\tmainChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"].push_back(BWAPI::Position(3690, 3041));\n\n\tnaturalChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"].push_back(BWAPI::Position(3028, 1052));\n\tnaturalChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"].push_back(BWAPI::Position(1004, 1034));\n\tnaturalChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"].push_back(BWAPI::Position(914, 3101));\n\tnaturalChokes[\"1e983eb6bcfa02ef7d75bd572cb59ad3aab49285\"].push_back(BWAPI::Position(3075, 3064));\n\n\t// (4)Circuit Breaker.scx ---- 450a792de0e544b51af5de578061cb8a2f020f32\n\tmainChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"].push_back(BWAPI::Position(3948, 797));\n\tmainChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"].push_back(BWAPI::Position(143, 800));\n\tmainChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"].push_back(BWAPI::Position(171, 3285));\n\tmainChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"].push_back(BWAPI::Position(3906, 3289));\n\n\tnaturalChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"].push_back(BWAPI::Position(3489, 1115));\n\tnaturalChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"].push_back(BWAPI::Position(589, 1113));\n\tnaturalChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"].push_back(BWAPI::Position(602, 3005));\n\tnaturalChokes[\"450a792de0e544b51af5de578061cb8a2f020f32\"].push_back(BWAPI::Position(3487, 3008));\n\n\t// (4)Empire of the Sun.scm ---- a220d93efdf05a439b83546a579953c63c863ca7\n\tmainChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"].push_back(BWAPI::Position(3325, 3831));\n\tmainChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"].push_back(BWAPI::Position(3344, 304));\n\tmainChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"].push_back(BWAPI::Position(738, 287));\n\tmainChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"].push_back(BWAPI::Position(753, 3815));\n\n\tnaturalChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"].push_back(BWAPI::Position(2945, 3547));\n\tnaturalChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"].push_back(BWAPI::Position(2927, 487));\n\tnaturalChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"].push_back(BWAPI::Position(1128, 522));\n\tnaturalChokes[\"a220d93efdf05a439b83546a579953c63c863ca7\"].push_back(BWAPI::Position(1143, 3507));\n\n\t// (4)Fortress.scx ---- 83320e505f35c65324e93510ce2eafbaa71c9aa1\n\tmainChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"].push_back(BWAPI::Position(1810, 3863));\n\tmainChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"].push_back(BWAPI::Position(3667, 2181));\n\tmainChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"].push_back(BWAPI::Position(397, 1904));\n\tmainChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"].push_back(BWAPI::Position(2188, 249));\n\n\tnaturalChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"].push_back(BWAPI::Position(1559, 3612));\n\tnaturalChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"].push_back(BWAPI::Position(3471, 2477));\n\tnaturalChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"].push_back(BWAPI::Position(583, 1628));\n\tnaturalChokes[\"83320e505f35c65324e93510ce2eafbaa71c9aa1\"].push_back(BWAPI::Position(2492, 506));\n\n\t// (4)Python.scx ---- de2ada75fbc741cfa261ee467bf6416b10f9e301\n\tmainChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"] = std::vector<BWAPI::Position>();\n\tmainChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"].push_back(BWAPI::Position(2064, 114));\n\tmainChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"].push_back(BWAPI::Position(2001, 3957));\n\tmainChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"].push_back(BWAPI::Position(3874, 1812));\n\tmainChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"].push_back(BWAPI::Position(156, 2262));\n\n\tnaturalChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"] = std::vector<BWAPI::Position>();\n\tnaturalChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"].push_back(BWAPI::Position(1803, 607));\n\tnaturalChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"].push_back(BWAPI::Position(2218, 3553));\n\tnaturalChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"].push_back(BWAPI::Position(3391, 2047));\n\tnaturalChokes[\"de2ada75fbc741cfa261ee467bf6416b10f9e301\"].push_back(BWAPI::Position(618, 2058));\n}\n\nBWAPI::Position HardCodedInfo::getChokepoint(ChokeType type, BWAPI::Player * player)\n{\n\t// get and assert we know where this player is\n\tBWTA::BaseLocation * mainBaseLocation = BWTA::getStartLocation(player);\n\tassert(mainBaseLocation);\n\n\t// get the position of the main base\n\tBWAPI::Position mainBasePosition = mainBaseLocation->getPosition();\n\n\t// find the closest main choke point to this location\n\tdouble closestDist = 10000;\n\tBWAPI::Position closestPos(10000,10000);\n\n\tstd::vector<BWAPI::Position> & chokes = (type == MAIN_CHOKE) \n\t\t? mainChokes[BWAPI::Broodwar->mapHash()] : naturalChokes[BWAPI::Broodwar->mapHash()];\n\n\tBOOST_FOREACH (BWAPI::Position p, chokes)\n\t{\n\t\tdouble dist = p.getDistance(mainBasePosition);\n\t\tif (dist < closestDist)\n\t\t{\n\t\t\tclosestDist = dist;\n\t\t\tclosestPos = p;\n\t\t}\n\t}\n\n\tassert(closestPos.isValid());\n\n\treturn closestPos;\n}\n\nvoid HardCodedInfo::drawChokePoints()\n{\n\tBOOST_FOREACH(BWAPI::Position p, mainChokes[BWAPI::Broodwar->mapHash()])\n\t{\n\t\tif (Options::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawCircleMap(p.x(), p.y(), 10, BWAPI::Colors::Purple, true);\n\t}\n\n\tBOOST_FOREACH(BWAPI::Position p, naturalChokes[BWAPI::Broodwar->mapHash()])\n\t{\n\t\tif (Options::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawCircleMap(p.x(), p.y(), 10, BWAPI::Colors::Purple, true);\n\t}\n}*/"
  },
  {
    "path": "UAlbertaBot/Source/research/HardCodedInfo.h",
    "content": "/*#pragma once\n\n#include \"Common.h\"\n#include \"BWTA.h\"\n\n#include <map>\n\nclass HardCodedInfo {\n\n\tstd::ofstream logStream;\n\tstd::string logFile;\n\n\tHardCodedInfo();\n\tstatic HardCodedInfo *\t\t\t\tinstance;\n\n\tvoid\tsetChokeDefendLocations();\n\n\t\n\tstd::map<std::string, std::vector<BWAPI::Position>>\t\tmainChokes;\n\tstd::map<std::string, std::vector<BWAPI::Position>>\t\tnaturalChokes;\n\npublic:\n\n\tenum ChokeType {MAIN_CHOKE, NATURAL_CHOKE, CHOKE_TYPES};\n\n\tstatic HardCodedInfo *\tInstance;\n\n\tvoid drawChokePoints();\n\n\tBWAPI::Position getChokepoint(ChokeType type, BWAPI::Player * player);\n};\n*/"
  },
  {
    "path": "UAlbertaBot/Source/research/MapGrid.cpp",
    "content": "#include \"Common.h\"\n#include \"MapGrid.h\"\n#include \"Global.h\"\n\nusing namespace UAlbertaBot;\n\nMapGrid::MapGrid() \n{\n    mapWidth = BWAPI::Broodwar->mapWidth()*32;\n    mapHeight = BWAPI::Broodwar->mapHeight()*32;\n    cellSize =  Config::Tools::MAP_GRID_SIZE;\n    cols = (mapWidth + cellSize - 1) / cellSize;\n    rows = (mapHeight + cellSize - 1) / cellSize;\n    cells = std::vector<GridCell>(rows * cols);\n    lastUpdated = 0;\n\n    calculateCellCenters();\n}\n\t\nBWAPI::Position MapGrid::getNaturalExpansion() \n{\n\treturn naturalExpansion;\n}\n\nBWAPI::Position MapGrid::getLeastExplored() \n{\n\tint minSeen = 1000000;\n\tdouble minSeenDist = 0;\n\tint leastRow(0), leastCol(0);\n\n\tfor (int r=0; r<rows; ++r)\n\t{\n\t\tfor (int c=0; c<cols; ++c)\n\t\t{\n\t\t\t// get the center of this cell\n\t\t\tBWAPI::Position cellCenter = getCellCenter(r,c);\n\n\t\t\t// don't worry about places that aren't connected to our start locatin\n\t\t\tif (Global::Map().getGroundDistance(cellCenter, BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation())) > 0)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tBWAPI::Position home(BWAPI::Broodwar->self()->getStartLocation());\n\t\t\tdouble dist = home.getDistance(getCellByIndex(r, c).center);\n            int lastVisited = getCellByIndex(r, c).timeLastVisited;\n\t\t\tif (lastVisited < minSeen || ((lastVisited == minSeen) && (dist > minSeenDist)))\n\t\t\t{\n\t\t\t\tleastRow = r;\n\t\t\t\tleastCol = c;\n\t\t\t\tminSeen = getCellByIndex(r, c).timeLastVisited;\n\t\t\t\tminSeenDist = dist;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn getCellCenter(leastRow, leastCol);\n}\n\nvoid MapGrid::calculateCellCenters()\n{\n    PROFILE_FUNCTION();\n\n\tfor (int r=0; r < rows; ++r)\n\t{\n\t\tfor (int c=0; c < cols; ++c)\n\t\t{\n\t\t\tGridCell & cell = getCellByIndex(r,c);\n\n\t\t\tint centerX = (c * cellSize) + (cellSize / 2);\n\t\t\tint centerY = (r * cellSize) + (cellSize / 2);\n\n\t\t\t// if the x position goes past the end of the map\n\t\t\tif (centerX > mapWidth)\n\t\t\t{\n\t\t\t\t// when did the last cell start\n\t\t\t\tint lastCellStart\t\t= c * cellSize;\n\n\t\t\t\t// how wide did we go\n\t\t\t\tint tooWide\t\t\t\t= mapWidth - lastCellStart;\n\t\t\t\t\n\t\t\t\t// go half the distance between the last start and how wide we were\n\t\t\t\tcenterX = lastCellStart + (tooWide / 2);\n\t\t\t}\n\t\t\telse if (centerX == mapWidth)\n\t\t\t{\n\t\t\t\tcenterX -= 50;\n\t\t\t}\n\n\t\t\tif (centerY > mapHeight)\n\t\t\t{\n\t\t\t\t// when did the last cell start\n\t\t\t\tint lastCellStart\t\t= r * cellSize;\n\n\t\t\t\t// how wide did we go\n\t\t\t\tint tooHigh\t\t\t\t= mapHeight - lastCellStart;\n\t\t\t\t\n\t\t\t\t// go half the distance between the last start and how wide we were\n\t\t\t\tcenterY = lastCellStart + (tooHigh / 2);\n\t\t\t}\n\t\t\telse if (centerY == mapHeight)\n\t\t\t{\n\t\t\t\tcenterY -= 50;\n\t\t\t}\n\n\t\t\tcell.center = BWAPI::Position(centerX, centerY);\n\t\t\tassert(cell.center.isValid());\n\t\t}\n\t}\n}\n\nBWAPI::Position MapGrid::getCellCenter(int row, int col)\n{\n\treturn getCellByIndex(row, col).center;\n}\n\n// clear the vectors in the grid\nvoid MapGrid::clearGrid() { \n\n\tfor (size_t i(0); i<cells.size(); ++i) \n\t{\n\t\tcells[i].ourUnits.clear();\n\t\tcells[i].oppUnits.clear();\n\t}\n}\n\n// populate the grid with units\nvoid MapGrid::update() \n{\n    PROFILE_FUNCTION();\n\n    if (Config::Debug::DrawMapGrid) \n    {\n\t    for (int i=0; i<cols; i++) \n\t    {\n\t        BWAPI::Broodwar->drawLineMap(i*cellSize, 0, i*cellSize, mapHeight, BWAPI::Colors::Blue);\n\t    }\n\n\t    for (int j=0; j<rows; j++) \n\t    {\n\t\t    BWAPI::Broodwar->drawLineMap(0, j*cellSize, mapWidth, j*cellSize, BWAPI::Colors::Blue);\n\t    }\n\n\t    for (int r=0; r < rows; ++r)\n\t    {\n\t\t    for (int c=0; c < cols; ++c)\n\t\t    {\n\t\t\t    GridCell & cell = getCellByIndex(r,c);\n\t\t\t\n\t\t\t    BWAPI::Broodwar->drawTextMap(cell.center.x, cell.center.y, \"Last Seen %d\", cell.timeLastVisited);\n\t\t\t    BWAPI::Broodwar->drawTextMap(cell.center.x, cell.center.y+10, \"Row/Col (%d, %d)\", r, c);\n\t\t    }\n\t    }\n\n\n    }\n\n\t// clear the grid\n\tclearGrid();\n\n\t//BWAPI::Broodwar->printf(\"MapGrid info: WH(%d, %d)  CS(%d)  RC(%d, %d)  C(%d)\", mapWidth, mapHeight, cellSize, rows, cols, cells.size());\n\n\t// add our units to the appropriate cell\n\tfor (auto & unit : BWAPI::Broodwar->self()->getUnits()) \n\t{\n\t\tgetCell(unit).ourUnits.insert(unit);\n\t\tgetCell(unit).timeLastVisited = BWAPI::Broodwar->getFrameCount();\n\t}\n\n\t// add enemy units to the appropriate cell\n\tfor (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) \n\t{\n\t\tif (unit->getHitPoints() > 0) \n\t\t{\n\t\t\tgetCell(unit).oppUnits.insert(unit);\n\t\t\tgetCell(unit).timeLastOpponentSeen = BWAPI::Broodwar->getFrameCount();\n\t\t}\n\t}\n}\n\nvoid MapGrid::GetUnits(BWAPI::Unitset & units, BWAPI::Position center, int radius, bool ourUnits, bool oppUnits)\n{\n\tconst int x0(std::max( (center.x - radius) / cellSize, 0));\n\tconst int x1(std::min( (center.x + radius) / cellSize, cols-1));\n\tconst int y0(std::max( (center.y - radius) / cellSize, 0));\n\tconst int y1(std::min( (center.y + radius) / cellSize, rows-1));\n\tconst int radiusSq(radius * radius);\n\tfor(int y(y0); y<=y1; ++y)\n\t{\n\t\tfor(int x(x0); x<=x1; ++x)\n\t\t{\n\t\t\tint row = y;\n\t\t\tint col = x;\n\n\t\t\tGridCell & cell(getCellByIndex(row,col));\n\t\t\tif(ourUnits)\n\t\t\t{\n\t\t\t\tfor (auto & unit : cell.ourUnits)\n\t\t\t\t{\n\t\t\t\t\tBWAPI::Position d(unit->getPosition() - center);\n\t\t\t\t\tif(d.x * d.x + d.y * d.y <= radiusSq)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!units.contains(unit)) \n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tunits.insert(unit);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(oppUnits)\n\t\t\t{\n\t\t\t\tfor (auto & unit : cell.oppUnits) if (unit->getType() != BWAPI::UnitTypes::Unknown && unit->isVisible())\n\t\t\t\t{\n\t\t\t\t\tBWAPI::Position d(unit->getPosition() - center);\n\t\t\t\t\tif(d.x * d.x + d.y * d.y <= radiusSq)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!units.contains(unit))\n\t\t\t\t\t\t{ \n\t\t\t\t\t\t\tunits.insert(unit); \n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/research/MapGrid.h",
    "content": "#pragma once\n\n#include <Common.h>\n#include \"MicroManager.h\"\n\nnamespace UAlbertaBot\n{\n\nclass GridCell\n{\npublic:\n\n\tint             timeLastVisited;\n    int             timeLastOpponentSeen;\n\tBWAPI::Unitset  ourUnits;\n\tBWAPI::Unitset  oppUnits;\n\tBWAPI::Position center;\n\n\tGridCell() \n        : timeLastVisited(0)\n        , timeLastOpponentSeen(0)\n    {\n    }\n};\n\n\nclass MapGrid \n{\n    friend class Global;\n\n\tMapGrid();\n\n\tint\t\t\t\t\t\t\tcellSize;\n\tint\t\t\t\t\t\t\tmapWidth, mapHeight;\n\tint\t\t\t\t\t\t\trows, cols;\n\tint\t\t\t\t\t\t\tlastUpdated;\n\n\tstd::vector<GridCell>\t\tcells;\n\n\tvoid\t\t\t\t\t\tcalculateCellCenters();\n\n\tvoid\t\t\t\t\t\tclearGrid();\n\tBWAPI::Position\t\t\t\tgetCellCenter(int x, int y);\n\n\tBWAPI::Position\t\t\t\tnaturalExpansion;\n\npublic:\n\n\tvoid\t\t\t\tupdate();\n\tvoid\t\t\t\tGetUnits(BWAPI::Unitset & units, BWAPI::Position center, int radius, bool ourUnits, bool oppUnits);\n\tBWAPI::Position\t\tgetLeastExplored();\n\tBWAPI::Position\t\tgetNaturalExpansion();\n\n\tGridCell & getCellByIndex(int r, int c)\t\t{ return cells[r*cols + c]; }\n\tGridCell & getCell(BWAPI::Position pos)\t\t{ return getCellByIndex(pos.y / cellSize, pos.x / cellSize); }\n\tGridCell & getCell(BWAPI::Unit unit)\t\t{ return getCell(unit->getPosition()); }\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/combatpredictor/CombatPredictor.cpp",
    "content": "#include \"CombatPredictor.h\"\n\nusing namespace UAlbertaBot;\n\n\nCombat::Combat(std::vector<BWAPI::UnitInterface*> & ou, std::vector<UnitInfo> &eu, bool meOBS, bool oppOBS)\n{\n    ourCombatUnits.clear(); enemyCombatUnits.clear();\n\tHP.clear(); combatTime.clear(); unitTypes.clear(); unitIDS.clear();\n    std::vector<int> startHp;\n\tforceFinish = false;\n\tI_have_Observers = meOBS;\n\tbothInvisUnits = false;\n\n\tif (ou.size() < 1 || eu.size() < 1) // NOT VALID\n\t{\n\t\tfinished = true;\n\t\treturn;\n\t}\n\n    for (auto u : ou)\n    {\n\t\tint t = u->getType();\n\t\tint id = u->getID();\n\t\tint hp = (u->getHitPoints() + u->getShields());\n        ourCombatUnits.push_back(u);\n        startHp.push_back(u->getHitPoints() + u->getShields());\n\n\t\t//special case for DTs, 61 - visible, 74 - invisible\n\t\tif (t == 61 && !oppOBS)\n\t\t{\n\t\t\tunitTypes.push_back(t + 13); \n\t\t\tbothInvisUnits = true;\n\t\t}\n\t\telse \n\t\t\tunitTypes.push_back(t);\n\n\t\tunitIDS.push_back(id);\n    }\n\n\tunitTypes.push_back(-1);\n\tbool dtFlag = false;\n\n\tfor (auto u : eu)\n\t{\n\t\tenemyCombatUnits.push_back(u);\n\n\t\t//special case for DTs\n\t\tif (u.type == 61 && !meOBS)\n\t\t{\n\t\t\tint hp_last = u.lastHealth;\n\t\t\tif (hp_last < 1) //if I saw it before keep the hp otherwise max hp for DT\n\t\t\t\thp_last = 120;\n\t\t\tstartHp.push_back(hp_last);\n\t\t\tunitTypes.push_back(u.type+13);\n\t\t\tdtFlag = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstartHp.push_back(u.lastHealth);\n\t\t\tunitTypes.push_back(u.type);\n\t\t}\n\t\tunitIDS.push_back(u.unitID);\n    }\n\n    HP.push_back(startHp);\n    combatStartTime = BWAPI::Broodwar->getFrameCount();\n    combatTime.push_back(0);\n    finished = false;\n\tif (!dtFlag) bothInvisUnits = false;\n    ID = CombatPredictor::Instance().combatID;\n    CombatPredictor::Instance().combatID += 1;\n}\n\nbool Combat::isOneSideDead()\n{\n\tbool meDead = true;\n\tfor (auto u : ourCombatUnits)\n\t{\n\t\tif (u->getHitPoints() + u->getShields() > 0)\n\t\t{\n\t\t\tmeDead = false;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (meDead) return true;\n\n\tbool himDead = true;\n\tfor (auto u : enemyCombatUnits)\n\t{\n\t\tint hp = CombatPredictor::Instance().observedHPs[u.unitID];\n\t\t//if (search != temp.end() && search->second.lastHealth > 0)\n\t\tif (hp > 0)\n\t\t{\t\n\t\t\thimDead = false;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn himDead;\n}\n\nvoid Combat::update()\n{ \n\n    int const elapsedTime = BWAPI::Broodwar->getFrameCount() - combatStartTime;\n    bool process = false;\n\n\t//need to check if one of the players\n\t//has no units left \n\tif (isOneSideDead())\n\t{\n\t\t//need to finish battle and log it off!\n\t\tprocess = true;\n\t\tforceFinish = true;\n\t}\n\n    if (process || forceFinish)\n    {\n        //save new hp values\n        combatTime.push_back(elapsedTime);\n        std::vector<int> startHp;\n\n        //for me, already have pointers\n        for (auto u : ourCombatUnits)\n        {\n            startHp.push_back(u->getHitPoints() + u->getShields());\n        }\n\n        //for enemy, need to look in information manager    \n        for (auto u : enemyCombatUnits)\n        {\t\n\t\t\tint hp = CombatPredictor::Instance().observedHPs[u.unitID];\n\n\t\t\t//special case for invisible DTs\n\t\t\tif (u.type == BWAPI::UnitTypes::Protoss_Dark_Templar && !I_have_Observers)\n\t\t\t{\n\t\t\t\tif (hp < 1) //if I saw it before keep the hp otherwise max hp for DT\n\t\t\t\t\thp = 120;\n\t\t\t}\n\n\t\t\tstartHp.push_back(hp);\n        }\n        HP.push_back(startHp);\n    } \n    \n\tif ((elapsedTime > 801) || forceFinish  ) //finish fight, flush to disk\n    {\n\t\tstd::ostringstream oss;\n\t\tint id = ID;  //CombatPredictor::Instance().combatID;\n\n\t\t//I don't want extremely short fights ...\n\t\tint total_startHP = std::accumulate(HP[0].begin(), HP[0].end(), 0);\n\t\tint total_endHP = std::accumulate(HP.back().begin(), HP.back().end(), 0);\n\n\t\t//if either 100hp damage total or 20% of inital hp\n\t\tint difHP = std::abs(total_endHP - total_startHP);\n\n\t\tif ((difHP < 100 && difHP*5 < total_startHP )|| bothInvisUnits)\n\t\t{\n\t\t\t//SHORT battle, don't log\n\t\t\toss << defWriteFolder << \"s_battle_\" << CombatPredictor::Instance().getSuffix() << \"_\" << id << \".txt\";\n\t\t\twriteToFile(oss.str(),false);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//PROPER battle\n\t\t\toss << defWriteFolder << \"battle_\" << CombatPredictor::Instance().getSuffix() << \"_\" << id << \".txt\";\n\t\t\twriteToFile(oss.str(),true);\n\t\t}\n        finished = true;\n    }\n}\n\nvoid CombatPredictor::addCombat(Combat &c)\n{\n\tobservedIDs;\n\tbool reinforcements = false;\n\tfor (auto id : c.unitIDS)\n\t{\n\t\tUAB_ASSERT(id < 2000, \"Too many units !!!\");\n\n\t\tif (!observedIDs[id]) //not observed, need to end previous battles  - REINFORCEMENTS\n\t\t{\n\t\t\treinforcements = true;\n\t\t\tobservedIDs[id] = 1;\n\t\t\t//break;\n\t\t}\n\t}\n\n\tif (!reinforcements)\n\t\t//add combat\n\t\t//combats.push_back(c);\n\t\t// OR MAYBE NOT ADD COMBAT, IRRELEVANT? \n\t\t;\n\telse\n\t{\t//need to finish all previous combats\n\t\tfor (unsigned int i = 0; i < combats.size(); i++)\n\t\t{\n\t\t\tif (!combats[i].isFinished())\n\t\t\t{\n\t\t\t\t//force update, and finish\n\t\t\t\tcombats[i].forceFinish = true; \n\t\t\t\tcombats[i].update();\n\t\t\t}\n\t\t}\n\n\t\t//then add new combat\n\t\tcombats.push_back(c);\n\n\t}\n}\n\nvoid Combat::writeToFile(std::string filename, bool valid4Train)\n{\n\t//this is the debug file\n    std::ofstream logStream(filename);\n\n\tlogStream << \"Frame: \" << combatStartTime << std::endl;\n\t\n\tlogStream << \"Unit Types: \";\n\tint otherPlayerIDX = 0, j = 0;\n\n\tfor (int i : unitTypes)\n\t{\n\t\tif (i < 0)\n\t\t{\n\t\t\tlogStream << \" | \";\n\t\t\totherPlayerIDX = j;\n\t\t}\n\t\telse\n\t\t\tlogStream << i << \" \";\n\t\tj++;\n\t}\n\tlogStream << std::endl;\n\tlogStream << \"  Unit IDs: \";\n\n\tj = 0;\n\tfor (int i : unitIDS)\n\t{\n\t\tif (j == otherPlayerIDX)\n\t\t\tlogStream << \" | \" << i << \" \";\n\t\telse\n\t\t\tlogStream << i << \" \";\n\t\tj++;\n\t}\n\tlogStream << std::endl;\n\tlogStream << \"-------------------------------\" << std::endl;\n    //write frame| HPs\n    int i = 0;\n\n    for (auto h : HP)\n    {\n        logStream << combatTime[i++] << \" | \";\n        for (auto u : h)\n            logStream << u << \" \";\n        logStream << std::endl;\n    }\n\n    logStream.flush();\n    logStream.close();\n\n\tif (valid4Train)\n\t{\n\t\t//this is the MATLAB training file (accumulator)\n\t\tstd::ofstream trainStream(defWriteFolder + \"train_\" + CombatPredictor::Instance().getSuffix() + \".txt\", std::ofstream::app);\n\n\t\tint counter = 0;\n\t\ttrainStream << 0 << \" \" << combatTime.back() << \" \";\n\t\tcounter += 2;\n\n\t\t//write initial conditions\n\t\tbool p1 = true;\n\t\tfor (unsigned int i = 0; i < unitTypes.size(); i++)\n\t\t{\n\t\t\tif (unitTypes[i] < 0) //switch players\n\t\t\t{\n\t\t\t\tp1 = false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (p1) trainStream << unitTypes[i] << \" \" << (HP[0])[i] << \" \";\n\t\t\t\tif (!p1) trainStream << unitTypes[i] + MAX_UNIT_TYPES << \" \" << (HP[0])[i - 1] << \" \";\n\t\t\t\tcounter += 2;\n\t\t\t}\n\t\t}\n\n\t\t//need to add -1s to keep length to 150, easier for matlab to read\n\t\twhile (counter++ < 150)\n\t\t\ttrainStream << -1 << \" \";\n\t\ttrainStream << std::endl;\n\n\n\t\t//write result\n\t\tcounter = 0;\n\t\ttrainStream << 0 << \" \" << combatTime.back() << \" \";\n\t\tcounter += 2;\n\n\t\tp1 = true;\n\t\tfor (unsigned int i = 0; i < unitTypes.size(); i++)\n\t\t{\n\t\t\tif (unitTypes[i] < 0) //switch players\n\t\t\t{\n\t\t\t\tp1 = false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (p1) trainStream << unitTypes[i] << \" \" << (HP.back())[i] << \" \";\n\t\t\t\tif (!p1) trainStream << unitTypes[i] + MAX_UNIT_TYPES << \" \" << (HP.back())[i - 1] << \" \";\n\t\t\t\tcounter += 2;\n\t\t\t}\n\t\t}\n\n\t\t//need to add -1s to keep length to 150, easier for matlab to read\n\t\twhile (counter++ < 150)\n\t\t\ttrainStream << -1 << \" \";\n\t\ttrainStream << std::endl;\n\n\t\ttrainStream.flush();\n\t\ttrainStream.close();\n\n\t\t//write down results to compare % acccuracy\n\t\tstd::ofstream resultStream(defWriteFolder + \"results_\" + CombatPredictor::Instance().getSuffix() + \".txt\", std::ofstream::app);\n\n\t\tstd::pair<float, float> ltd = LTD2();\n\t\tif (ltd.first > ltd.second *1.1) // P1 win\n\t\t\tresultStream << SparcraftPrediction << \" \" << MATLAB_Prediction << \" \" << 1 << \" \" << ltd.first / (ltd.second + 0.01) << std::endl;\n\t\telse if (ltd.second > ltd.first * 1.1) // P2 win\n\t\t\tresultStream << SparcraftPrediction << \" \" << MATLAB_Prediction << \" \" << -1 << \" \" << ltd.second / (ltd.first + 0.01) << std::endl;\n\n\t\tresultStream.flush();\n\t\tresultStream.close();\n\t}\n}\n\nstd::pair<float, float> Combat::LTD2()\n{\n\tbool p1 = true;\n\tfloat LTD_p1 = 0;\n\tfloat LTD_p2 = 0;\n\n\tfloat currentSum = 0;\n\t//float totalSum = 0;\n\n\n\tfor (unsigned int i = 0; i < unitTypes.size(); i++)\n\t{\n\t\tif (unitTypes[i] < 0) //switch players\n\t\t{\n\t\t\tp1 = false;\n\t\t\tLTD_p1 = currentSum;\n\t\t\tcurrentSum = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (p1)\n\t\t\t{\n\t\t\t\tBWAPI::UnitType t = BWAPI::UnitType(unitTypes[i]);\n\t\t\t\tfloat dpf = CombatPredictor::Instance().dpf(t);\n\n\t\t\t\tcurrentSum += sqrtf((float)(HP.back())[i]) * dpf;\n\t\t\t}\n\n\t\t\tif (!p1)\n\t\t\t{\n\t\t\t\tBWAPI::UnitType t = BWAPI::UnitType(unitTypes[i]);\n\t\t\t\tfloat dpf = CombatPredictor::Instance().dpf(t);\n\n\t\t\t\tcurrentSum += sqrtf((float)(HP.back())[i-1]) * dpf;\n\t\t\t}\n\t\t}\n\t}\n\n\tLTD_p2 = currentSum;\n\treturn std::pair<float, float>(LTD_p1, LTD_p2);\n}\n\n\nCombatPredictor::CombatPredictor() {\n\n}\n\nCombatPredictor & CombatPredictor::Instance()\n{\n    static CombatPredictor instance;\n    return instance;\n}\n\nconst float CombatPredictor::dpf(BWAPI::UnitType &ut)\n{\n    float damage = BWAPI::UnitTypes::Protoss_Zealot ?\n        2 * (float)ut.groundWeapon().damageAmount() :\n        (float)ut.groundWeapon().damageAmount();\n\n    float attackCooldown = (float)ut.groundWeapon().damageCooldown();\n\n    return (float)std::max(0.0f, damage / (attackCooldown + 1));\n}\n\n\n\nvoid CombatPredictor::initUnitList()\n{\n\tstd::srand((unsigned int)std::time(0));\n\tuniqSuffix = BWAPI::Broodwar->enemy()->getName() + \"_\" + std::to_string(rand() % 1000);\n    \n\tauto set = BWAPI::UnitTypes::allUnitTypes();\n    int len = set.size();\n\n    //pre-allocate memory\n    //no more than 256 different unit types in StarCraft\n    MaxHP.resize(256, 0);\n\tobservedIDs.resize(2000, 0);\n\tobservedHPs.resize(2000, -1);\n\n\tstd::ofstream logStream(defWriteFolder +\"predictorInit.txt\");\n\n    for (auto type : set)\n    {\n        int maxHP = type.maxHitPoints() + type.maxShields();\n        int ID = type.getID();\n        logStream << ID << \" \" \n                  //<< type.getName() << \" \"\n                  << maxHP << \" \"\n                  << dpf(type)*maxHP << std::endl;\n\n        //save the info\n        MaxHP[ID] = maxHP;\n    }\n\n    logStream.flush();\n    logStream.close();\n    Sfeatures.clear();\n    SfA.clear(); SfB.clear();\n\n\t//READ FEATURES\n\tstd::string enemyFeatures = \"f_\" + BWAPI::Broodwar->enemy()->getName() + \".txt\";\n\tstd::string enemyFile(defReadFolder + enemyFeatures);\n\tstd::ifstream features; // (defReadFolder + enemyFeatures);\n\tfeatures.open(enemyFile);\n\tif (features.is_open() && features.good())\n\t{\n\t\tCombatPredictor::Instance().vsTrainedOpp = true;\n\t}\n\telse\n\t{\n\t\t//default features\n\t\t//std::ifstream features(defReadFolder + \"features.txt\");\n\t\tfeatures.open(defReadFolder + \"f_default.txt\");\n\t\tUAB_ASSERT(features.is_open() && features.good(), \"Couldn't open file %sf_default.txt\", defReadFolder.c_str());\n\t\tCombatPredictor::Instance().vsTrainedOpp = false;\n\t}\n\n\tif (features.is_open() && features.good())\n    {\n        // read away\n        std::string line;\n\n        while (getline(features, line))\n        {\n            double d = std::stod(line);\n            Sfeatures.push_back(d);\n        }\n\n        features.close();\n        int nrS = Sfeatures.size() / 2;\n\n        SfA = std::vector<double>(&Sfeatures[0], &Sfeatures[nrS - 1]);\n        SfB = std::vector<double>(&Sfeatures[nrS], &Sfeatures[nrS * 2 - 1]);\n    }\n}\n\nconst SparCraft::ScoreType CombatPredictor::predictCombat(const HLUnitData &myUnits, const HLUnitData &oppUnits)\n{\n\n\tbool I_haveOBS = false;\n\tbool He_hasOBS = false;\n\n\tint nrA = 0;\n\tint nrB = 0;\n\tdouble sumA = 0.0;\n\tdouble sumB = 0.0;\n\n\tfor (auto &iter : oppUnits.getUnits())\n\t{\n\t\tconst UnitInfo & ui(iter.second);\n\t\tif (ui.completed && ui.type.isDetector()) He_hasOBS = true;\n\t}\n\n\tfor(auto &iter: myUnits.getUnits())\n\t{\n\t\tconst UnitInfo & ui(iter.second);\n\n\t\tif (ui.completed && ui.type.isDetector()) I_haveOBS = true;\n\n\t\tif (ui.completed &&\n\t\t\t(ui.type.canAttack() || ui.type.isWorker()\n\t\t\t|| ui.type.isDetector()\n\t\t\t|| ui.type == BWAPI::UnitTypes::Terran_Medic\n\t\t\t|| ui.type == BWAPI::UnitTypes::Protoss_Reaver\n\t\t\t|| ui.type == BWAPI::UnitTypes::Terran_Bunker))\n\t\t{\n\t\t\tif (ui.type == BWAPI::UnitTypes::Protoss_Dark_Templar && !He_hasOBS) //invisible DT, unit ID 74\n\t\t\t\tsumA += SfA[74] * ui.lastHealth / MaxHP[74];\n\t\t\telse //visible DT or something else\n\t\t\t\tsumA += SfA[ui.type] * ui.lastHealth / MaxHP[ui.type];\n\n\t\t\tnrA += 1;\n\t\t}\n\t}\n\n\tfor(auto &iter: oppUnits.getUnits())\n\t{\n\t\tconst UnitInfo & ui(iter.second);\n\n\t\tif (ui.completed &&\n\t\t\t(ui.type.canAttack() || ui.type.isWorker()\n\t\t\t|| ui.type.isDetector()\n\t\t\t|| ui.type == BWAPI::UnitTypes::Terran_Medic\n\t\t\t|| ui.type == BWAPI::UnitTypes::Protoss_Reaver\n\t\t\t|| ui.type == BWAPI::UnitTypes::Terran_Bunker))\n\t\t{\n\t\t\tif (ui.type == BWAPI::UnitTypes::Protoss_Dark_Templar && !He_hasOBS) //invisible DT\n\t\t\t{\n\t\t\t\t//TODO: make sure ui.lastHealth is not 0 for invisible DTs\n\t\t\t\tUAB_ASSERT(ui.lastHealth > 0, \"Invisible DT has HP zero ?!\");\n\t\t\t\tsumB += SfB[74] * ui.lastHealth / MaxHP[74];\n\t\t\t\t\n\t\t\t}\n\t\t\telse //visible DT or something else\n\t\t\t\tsumB += SfB[ui.type] * ui.lastHealth / MaxHP[ui.type];\n\n\t\t\tnrB += 1;\n\t\t}\n\t}\n\n\treturn (int)((pow(nrA, power - 1)*sumA - pow(nrB, power - 1)*sumB)*100.0);\n}\n\nSparCraft::ScoreType  CombatPredictor::predictCombat(std::vector<std::pair<int, int>> &ArmyA,\n    std::vector<std::pair<int, int>> &ArmyB)\n{\n    int nrA = 0;\n    int nrB = 0;\n    double sumA = 0.0;\n    double sumB = 0.0;\n\n    for (auto p : ArmyA)\n    {   //p.first = ID of unit\n        //p.secont = current HP+shielcs of unit\n        sumA += SfA[p.first] * p.second / MaxHP[p.first];\n        nrA += 1;\n    }\n\n    for (auto p : ArmyB)\n    {   //p.first = ID of unit\n        //p.secont = current HP+shielcs of unit\n        sumB += SfB[p.first] * p.second / MaxHP[p.first];\n        nrB += 1;\n    }\n\n    return (int) ((pow(nrA, power - 1)*sumA - pow(nrB, power - 1)*sumB)*10.0);\n    //convert to LTD2 ? for now it only matters if > 0 or < 0, so no need. \n}\n"
  },
  {
    "path": "UAlbertaBot/Source/research/combatpredictor/CombatPredictor.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"MapGrid.h\"\n#include \"HLUnitData.h\"\n\n#ifdef USING_VISUALIZATION_LIBRARIES\n#include \"Visualizer.h\"\n#endif\n\n#include \"..\\..\\SparCraft\\source\\GameState.h\"\n#include \"..\\..\\SparCraft\\source\\Game.h\"\n#include \"..\\..\\SparCraft\\source\\Unit.h\"\n#include \"..\\..\\SparCraft\\source\\AllPlayers.h\"\n#include \"InformationManager.h\"\n#include <numeric>\n\nnamespace UAlbertaBot\n{\n\tconst int MAX_UNIT_TYPES = 234 ; //TODO: double check\n\tconst std::string defWriteFolder = \"bwapi-data/write/\";\n\tconst std::string defReadFolder = \"bwapi-data/\";\n\t\nclass Combat\n{\n    std::vector<BWAPI::UnitInterface*> ourCombatUnits;\n    std::vector<UnitInfo> enemyCombatUnits;\n\tstd::vector<int> unitTypes;\n\n    std::vector<std::vector<int> > HP;\n    int combatStartTime;\n\tstd::vector<int> combatTime; \n    bool finished;\n\tbool bothInvisUnits;\n    int ID;\n\tbool I_have_Observers; \n\npublic:\n\tint SparcraftPrediction;\n\tint MATLAB_Prediction;\n\tbool  forceFinish;\n\tstd::vector<int> unitIDS;\n    Combat(std::vector<BWAPI::UnitInterface*> & ou, std::vector<UnitInfo> &eu, bool meOBS, bool oppOBS);\n    void update();\n    void writeToFile(std::string filename, bool valid4train);\n    bool isFinished(){ return finished; }\n\tbool isOneSideDead();\n\tstd::pair<float, float> LTD2();\n};\n\n\nclass CombatPredictor\n{\n    double power = 1.52;\n    \n    std::vector<double> Sfeatures;\n    std::vector<double> SfA;\n    std::vector<double> SfB;\n    std::vector<int> MaxHP;\n\tstd::vector<int> observedIDs; \n\tstd::string uniqSuffix;\n\npublic:\n\tbool vsTrainedOpp = false;\n    int combatID = 0;\n    std::vector<Combat> combats;\n\tstd::vector<int> observedHPs;\n    CombatPredictor();\n    static CombatPredictor & Instance();\n    void initUnitList();\n\tstd::string getSuffix(){ return uniqSuffix; };\n    const float CombatPredictor::dpf(BWAPI::UnitType &ut);\n\tconst SparCraft::ScoreType predictCombat(const HLUnitData &myUnits, const HLUnitData &oppUnits);\n\n    //predict combat, for each army need {ID, current HP+shields} x each unit\n    SparCraft::ScoreType  predictCombat(std::vector<std::pair<int,int>> &ArmyA,\n                                        std::vector<std::pair<int,int>> &ArmyB);\n\n    void updateFeatures(int afterHowManyNewBattles);\n    void retrainMATLAB_model();\n\tvoid addCombat(Combat &c);\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLCombatCommander.cpp",
    "content": "#include \"HLCombatCommander.h\"\n\nusing namespace UAlbertaBot;\n\nHLCombatCommander::HLCombatCommander(){\n}\n\n\nHLCombatCommander::~HLCombatCommander()\n{\n}\n\nvoid HLCombatCommander::update(std::set<BWAPI::UnitInterface*> combatUnits)\n{\n\t//if (squadUpdateFrame())\n\t//{\n\t//\t// clear all squad data\n\t//\tsquadData.clearSquadData();\n\n\t//\t// give back combat workers to worker manager\n\t//\tWorkerManager::Instance().finishedWithCombatWorkers();\n\n\t//\tfor (auto& s : HLSearch::Instance().getSquads(combatUnits)){\n\t//\t\tsquadData.addSquad(s);\n\t//\t}\n\t//}\n\n\t//squadData.update();\n\n\n\tcombatCommander.update(combatUnits);\n}\n\n\nbool HLCombatCommander::squadUpdateFrame() const\n{\n\treturn BWAPI::Broodwar->getFrameCount() % 24 == 0;\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLCombatCommander.h",
    "content": "#pragma once\n#include \"Common.h\"\n#include \"Squad.h\"\n#include \"HLSearch.h\"\n#include \"SquadData.h\"\n#include \"CombatCommander.h\"\n\nnamespace UAlbertaBot\n{\n\tclass HLCombatCommander\n\t{\n\t\tSquadData\t\t\tsquadData;\n\t\tCombatCommander\t\tcombatCommander;\n\tpublic:\n\t\tHLCombatCommander();\n\t\t~HLCombatCommander();\n\t\tvoid update(std::set<BWAPI::UnitInterface*> combatUnits);\n\t\tbool squadUpdateFrame() const;\n\t};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLManager.cpp",
    "content": "#include \"HLManager.h\"\n#include \"base/ProductionManager.h\"\n\nusing namespace UAlbertaBot;\n\nHLManager::HLManager()\n{\n\tBWAPI::Broodwar->printf(\"High Level Manager Instantiated\");\n\tLogger::LogAppendToFile(UAB_LOGFILE, \"State size: %d\", sizeof(HLState));\n}\n\n\nHLManager::~HLManager()\n{\n}\n\nHLManager &\tHLManager::Instance()\n{\n\tstatic HLManager instance;\n\treturn instance;\n}\n\nvoid HLManager::update()\n{\n\t//static bool firstRun = true;\n\t//static int frame = 0;\n\n\t//if ((firstRun && !ProductionManager::Instance().runningOpeningBook())\n\t//\t||(!firstRun && (++frame%2000==0)))\n\t//{\n\t//\tfirstRun = false;\n\n\t\tstatic int cumulativeSearchTime = 0;\n\t\tif (cumulativeSearchTime>39000)\n\t\t{\n\t\t\tBWAPI::Broodwar->printf(\"Too much time searching, skipping HL search\");\n\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"\\nToo much time searching, skipping HL search\");\n\t\t\tcumulativeSearchTime+= _search.search(0, 0, 0);\n\n\t\t\treturn;\n\t\t}\n\t\telse if (cumulativeSearchTime > 36000)\n\t\t{\n\t\t\tBWAPI::Broodwar->printf(\"Too much time searching, short HL search: %d[ms]\", 42000 - cumulativeSearchTime);\n\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"\\nToo much time searching, short HL search: %d[ms]\", 42000 - cumulativeSearchTime);\n\t\t\tcumulativeSearchTime+=_search.search(42000 - cumulativeSearchTime, 10000, 40);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcumulativeSearchTime+=_search.search(6000, 10000, 40);\n\t\t}\n\n\t\tauto move = _search.getBestMove();\n\t\tStrategyManager::Instance().setCurrentStrategy(move.getStrategy(),move.getChoices());\n\t\tBWAPI::Broodwar->printf(\"Setting move %s\\n\", move.toString().c_str());\n\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"Setting move %s\\n\", move.toString().c_str());\n\n\t//\tProductionManager::Instance().purgeQueue();\n\t//}\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLManager.h",
    "content": "#pragma once\n#include \"Common.h\"\n#include \"Squad.h\"\n#include \"HLSearch.h\"\n#include \"ScoutManager.h\"\nnamespace UAlbertaBot\n{\n\tclass HLManager\n\t{\n\t\t//ScoutManager scoutManager;\n\t\tHLManager();\n\t\t~HLManager();\n\t\tHLSearch _search;\n\t\t\n\tpublic:\n\t\tstatic\tHLManager &\tInstance();\n\n\t\tvoid update();\n\t\t//void update(\n\t\t//\tstd::set<BWAPI::UnitInterface*> combatUnits, \n\t\t//\tstd::set<BWAPI::UnitInterface*> scoutUnits, \n\t\t//\tstd::set<BWAPI::UnitInterface*> workerUnits);\n\t};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLSearch.cpp",
    "content": "#include \"HLSearch.h\"\n#include \"../../BOSS/source/BOSS.h\"\n\nusing namespace UAlbertaBot;\n\nHLSearch::HLSearch() :_tt(20000), _cache(20000), _bestMove(StrategyManager::ProtossHighLevelSearch)\n{\n}\n\n\nHLSearch::~HLSearch()\n{\n}\n\nlong long HLSearch::search(double timeLimit, int frameLimit, int maxHeight)\n{\n\t\n\t_stats.clear();\n\t_stats.startTimer();\n\t_timeUp = false;\n\t_timeLimitMs = timeLimit;\n\t\n\n\tHLState state(BWAPI::Broodwar, BWAPI::Broodwar->self(), BWAPI::Broodwar->enemy());\n\tint currentEval = state.evaluate(BWAPI::Broodwar->self()->getID());\n\tLogger::LogAppendToFile(UAB_LOGFILE, \"\\n\\nStarting search at frame %d, static eval: %d\\n\", \n\t\tBWAPI::Broodwar->getFrameCount(), \n\t\tcurrentEval);\n\n\n\t//if (currentEval > 150 || currentEval < -200)\n\t//{\n\t//\tLogger::LogAppendToFile(UAB_LOGFILE, \"Game seems decided, skipping HL search\\n\");\n\t//\treturn _stats.getRunningTimeMilliSecs();\n\t//}\n\t_minFrame = 1000000;\n\tLogger::LogAppendToFile(UAB_LOGFILE, _stats.header() + \" score\\tbest move\\tmin frame\\tmax frame\\n\"); \n\t//for (int height = 2; height <= maxHeight && !_timeUp; height += 2)\n\t//{\n\tint height = maxHeight;\n\tfor (int frames = 2000; frames <= frameLimit && !_timeUp; frames += 2000)\n\t{\n\t\t_maxFrame = 0;\n\t\tint prevFrame = _minFrame;\n\t\t_minFrame = 1000000;\n\t\tint score = alphaBeta(state, 0, height, state.currentFrame() + frames, BWAPI::Broodwar->self()->getID(), HLMove(), MIN_SCORE, MAX_SCORE);\n\t\tLogger::LogAppendToFile(UAB_LOGFILE, _stats.toString());\n\t\tLogger::LogAppendToFile(UAB_LOGFILE, \" %d %s %d %d\\n\", score, _bestMove.toString().c_str(), _minFrame - state.currentFrame(), _maxFrame - state.currentFrame());\n\t\tif (prevFrame == _minFrame || (_minFrame - state.currentFrame()) > frameLimit)\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn _stats.getRunningTimeMilliSecs();\n}\n\nint HLSearch::alphaBeta(const HLState& state, int depth, int height, int frameLimit, int turn, const HLMove &firstSideMove, int alpha, int beta)\n{\n\t_stats.incNodeCount();\n\t\n\tif (firstSideMove.isEmpty() && (height <=0 || state.currentFrame() >= frameLimit || state.gameOver())){\n\t\tif (state.currentFrame() < _minFrame)\n\t\t{\n\t\t\t_minFrame = state.currentFrame();\n\t\t}\n\t\tif (state.currentFrame() > _maxFrame)\n\t\t{\n\t\t\t_maxFrame = state.currentFrame();\n\t\t}\n\t\treturn state.evaluate(turn);\n\t}\n\tif (_stats.getNodeCount() % 10 && _stats.getRunningTimeMilliSecs() > _timeLimitMs)\n\t{\n\t\t_timeUp = true;\n\t}\n\tint score = MIN_SCORE;\n\tint al = alpha;\n\tHLMove bestMove;\n\tint i = 0;\n\tHLMove ttBest;\n\tif (firstSideMove.isEmpty())\n\t{\n\t\t_stats.incTTquery();\n\t\tconst HLEntry &e = _tt.lookup(state);\n\t\tif (e._hash == state.getHash())\n\t\t{\n\t\t\t_stats.incTTfound();\n\t\t\tttBest = e._bestMove;\n\t\t}\n\t}\n\telse\n\t{\n\t\t_stats.incTTquery();\n\t\tconst HLEntry &e = _tt.lookup(state, depth,firstSideMove);\n\t\tif (e._hash == state.getHash(depth, firstSideMove))\n\t\t{\n\t\t\t_stats.incTTfound();\n\t\t\tttBest = e._bestMove;\n\t\t}\n\t}\n\t////todo: use value to return or at least shrink alpha-beta window?\n\n\tauto &moves = state.getMoves(turn);\n\tUAB_ASSERT(moves.size() != 0, \"No moves generated at depth %d\", depth);\n\tif (!ttBest.isEmpty())\n\t{\n\t\tauto it=std::find(moves.begin(), moves.end(), ttBest);\n\t\tUAB_ASSERT(it != moves.end(), \"Couldn't find best move among valid moves\");\n\t\tif (it != moves.end())\n\t\t{\n\t\t\tstd::iter_swap(it, moves.begin());\n\t\t}\n\t}\n\t//std::sort(moves.begin(), moves.end(), [this, &state, depth](const HLMove &m1, const HLMove &m2)\n\t//{\n\t//\t_stats.incTTquery();\n\t//\tconst HLEntry &e1 = _tt.lookup(state, depth, m1);\n\t//\tif (e1._hash != state.getHash(depth, m1))\n\t//\t{\n\t//\t\treturn false;\n\t//\t}\n\t//\t_stats.incTTfound();\n\t//\t_stats.incTTquery();\n\t//\tconst HLEntry &e2 = _tt.lookup(state, depth, m2);\n\t//\tif (e2._hash != state.getHash(depth, m2))\n\t//\t{\n\t//\t\treturn true;\n\t//\t}\n\t//\t_stats.incTTfound();\n\t//\treturn e1._value > e2._value;\n\t//});\n\t\n\tfor (auto it = moves.begin(); it != moves.end() && !_timeUp;it++){\n\t\tauto m = *it;\n\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Searching depth %d, move %s, move %s\\n\", depth, firstSideMove.toString().c_str(), m.toString().c_str());\n\n\t\tint value;\n\t\tif (firstSideMove.isEmpty()){\n\t\t\tvalue = alphaBeta(state, depth + 1, height - 1, frameLimit, 1 - turn, m, -beta, -al);\n\t\t}\n\t\telse{\n\n\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Start frame: %d\\n\", newState.currentFrame());\n\n\t\t\tstd::array < HLMove, 2 > movePair;\n\t\t\tif (turn == 1){\n\t\t\t\tmovePair = std::array < HLMove, 2 > { {firstSideMove, m} };\n\t\t\t}\n\t\t\telse{//move for player 1 first\n\t\t\t\tmovePair = std::array < HLMove, 2 > { {m, firstSideMove} };\n\t\t\t}\n\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Turn %d depth %d Checking moves: %s %s hash: %u\\n\", turn, depth,\n\t\t\t//\tfirstSideMove.toString().c_str(), m.toString().c_str(), state.getHash(depth,movePair));\n\t\t\ttry\n\t\t\t{\n\t\t\t\t_stats.incCacheQuery();\n\t\t\t\tconst auto &entry = _cache.lookup(state, depth, movePair);\n\t\t\t\tif (entry._hash == state.getHash(depth, movePair))//found\n\t\t\t\t{\n\t\t\t\t\t_stats.incCacheFound();\n\t\t\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Moves \"+ firstSideMove.toString() + m.toString()+\" matches\\n\");\n\t\t\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \" hashes: %u %u\\n\", entry._hash, entry._state.getHash());\n\t\t\t\t\tif (state.currentFrame() == entry._state.currentFrame()){//didn't progress\n\t\t\t\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"No progress (cached)\");\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} \n\t\t\t\t\tvalue = alphaBeta(entry._state, depth + 1, height - 1, frameLimit, 1 - turn, HLMove(), -beta, -al);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHLState newState(state);\n\t\t\t\t\tnewState.applyAndForward(depth, frameLimit-newState.currentFrame(), movePair);\n\t\t\t\t\tif (state.currentFrame() == newState.currentFrame()){//didn't progress\n\t\t\t\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"No progress\");\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t_stats.addFwd(newState.currentFrame() - state.currentFrame());\n\t\t\t\t\t_cache.store(state, depth, movePair, newState);\n\t\t\t\t\tvalue = alphaBeta(newState, depth + 1, height - 1, frameLimit, 1 - turn, HLMove(), -beta, -al);\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tcatch (const BOSS::Assert::BOSSException &){\n\t\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"No Legal build order\");\n\t\t\t\tcontinue;//couldn't find legal build order, skip\n\t\t\t}\n\t\t\t\n\t\t}\n\n\t\ti++;\n\t\tif (value > score){\n\t\t\tscore = value;\n\t\t\tbestMove = m;\n\t\t\tif (value > alpha){\n\t\t\t\tal = value;\n\t\t\t\tif (al >= beta){\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t//break;//temporary, let's only check 1 move wide\n\t}\n\tif (!_timeUp)\n\t{\n\t\t_stats.addBF(i);\n\n\t\tif (firstSideMove.isEmpty())\n\t\t{\n\t\t\t_tt.store(state, bestMove, score, alpha, beta, height);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_tt.store(state, depth, firstSideMove, bestMove, score, alpha, beta, height);\n\t\t}\n\t}\n\tif (depth == 0){\n\t\tif (!bestMove.isEmpty())\n\t\t{\n\t\t\t_bestMove = bestMove;\n\t\t}\n\t\telse if (height == 2)//only use default move if first ID iteration\n\t\t{\n\t\t\t//_bestMove = HLMove(StrategyManager::ProtossHighLevelSearch);\n\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"Couldn't find a strategy, using default\\n\");\n\t\t}\n\t}\n\n\treturn score;\n}\n\nHLMove HLSearch::getBestMove()\n{\n\treturn _bestMove;\n}\n\n//std::vector<Squad> HLSearch::getSquads(const std::set<BWAPI::UnitInterface*> & combatUnits)\n//{\n//\tauto searchSquads = _bestMove.getSquads();\n//\tstd::set<BWAPI::UnitInterface*> unitsToAdd(combatUnits.begin(),combatUnits.end());\n//\t\n//\t//remove non combat units\n//\tfor (auto &s : searchSquads){\n//\t\tfor (unsigned int i = 0; i < s.getUnits().size();i++){\n//\t\t\tauto &u = s.getUnits()[i];\n//\t\t\tif (combatUnits.count(u) == 0){//if unit is not combat, remove it from squad\n//\t\t\t\ts.removeUnit(u);\n//\t\t\t\ti--;\n//\t\t\t}\n//\t\t\telse{//unit already assigned\n//\t\t\t\tunitsToAdd.erase(u);\n//\t\t\t}\n//\t\t}\n//\t}\n//\n//\t//assign remaining units\n//\tfor (auto &u : unitsToAdd){\n//\t\tbool assigned=false;\n//\t\tfor (auto &s : searchSquads){\n//\t\t\tif (u->getRegion() == s.getRegion()){\n//\t\t\t\ts.addUnit(u);\n//\t\t\t\tassigned = true;\n//\t\t\t\tbreak;\n//\t\t\t}\n//\t\t}\n//\t\tif (!assigned){//create new squad\n//\t\t\tstd::vector<BWAPI::UnitInterface *> unit(1, u);\n//\t\t\tsearchSquads.push_back(HLSquad(unit, SquadOrder()));\n//\t\t}\n//\t}\n//\n//\tstd::vector<Squad> squads(searchSquads.size());\n//\t//transform HLSquad into Squad\n//\tstd::transform(searchSquads.begin(), searchSquads.end(), squads.begin(),\n//\t\t[](const HLSquad &s){return static_cast<Squad>(s); });\n//\n//\treturn squads;\n//}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLSearch.h",
    "content": "#pragma once\n#include \"Common.h\"\n#include \"Squad.h\"\n#include \"HLState.h\"\n#include \"HLStatistics.h\"\n#include \"HLTranspositionTable.h\"\n\nnamespace UAlbertaBot\n{\n\tconst static int MIN_SCORE = std::numeric_limits<int>::min() + 1, MAX_SCORE = std::numeric_limits<int>::max() - 1;\n\tclass HLSearch\n\t{\n\t\t//std::list<std::pair<int, int> >\t\t_strategicPV;//frame,strategy\n\t\t//std::list<std::pair<int, Squad> >\t_tacticalPV;//frame,squad\n\t\t//todo:switch these to priority_queues?\n\n\n\t\tHLStatistics _stats;\n\n\t\tHLMove _bestMove;\t//saved by the search\n\t\tint alphaBeta(const HLState& state, int depth, int height, int frameLimit, int turn, const HLMove &firstSideMove, int alpha, int beta);\n\t\t//void uct(const HLState &state, int playouts);\n\t\t//const int _defaultStrategy = 0;\n\t\tHLTranspositionTable _tt;\n\t\tHLCacheTable _cache;\n\t\tbool _timeUp;\n\t\tint _timeLimitMs;\n\t\tint _maxFrame,_minFrame;\n\tpublic:\n\t\tHLSearch(const UAlbertaBot::HLSearch &) = delete;\n\t\tHLSearch();\n\t\t~HLSearch();\n\t\tlong long search(double timeLimit, int frameLimit, int maxHeight);\n\n\t\t//std::vector<Squad> getSquads(const std::set<BWAPI::UnitInterface*> & combatUnits);//get Squads and orders\n\t\t//std::set<BWAPI::UnitInterface*> getScouts();\n\t\tHLMove getBestMove();\n\t};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLSquad.cpp",
    "content": "#include \"HLSquad.h\"\n\nusing namespace UAlbertaBot;\n\nHLSquadOrder::HLSquadOrder()\n\t: _type(None)\n{\n}\n\nHLSquadOrder::HLSquadOrder(OrderType type, BWTA::Region* target)\n\t: _type(type)\n\t, _target(target)\n{\n}\n\nHLSquad::HLSquad(const std::vector<UnitInfo> & units, BWTA::Region *region) :\n_currentRegion(region),\n_framesTravelled(0),\n//_units(units.begin(),units.end()),\n_order(),\n_speed(std::min_element(units.begin(), units.end(), [](const UnitInfo &u1, const UnitInfo &u2)\n{\n\treturn u1.type.topSpeed() < u2.type.topSpeed();\n})->type.topSpeed()),\n_strengthCalculated(false)\n{\n\tfor (const auto &unit : units)\n\t{\n\t\t_units[unit.unitID] = unit;\n\t}\n\n\tUAB_ASSERT(_currentRegion != NULL, \"Current region is null!\");\n}\n\nvoid HLSquad::addUnit(const UnitInfo &unit)\n{\n\t_speed = std::min(_speed, unit.type.topSpeed());\n\t_strengthCalculated = false;\n\t_units[unit.unitID]=unit;\n}\n\nint HLSquad::travel(int frames)\n{\n\t_framesTravelled += frames;\n\n\tif (!_path.empty())\n\t{\n\t\tint framesToNext;\n\t\twhile (!_path.empty() && \n\t\t\t(_framesTravelled > \n\t\t\t(framesToNext = _currentRegion->getCenter().getDistance(_path.front()->getCenter()) / _speed)))\n\t\t{\n\t\t\t_currentRegion = _path.front();\n\t\t\tUAB_ASSERT(_currentRegion != NULL, \"Current region is null!\");\n\t\t\t_path.pop_front();\n\t\t\t_framesTravelled -= framesToNext;\n\t\t}\n\t}\n\n\tif (_path.empty())//reached destination\n\t{\n\t\tint remainingFrames = _framesTravelled;\n\t\t_framesTravelled = 0;\n\t\treturn remainingFrames;\n\t}\n\treturn 0;\n}\n\nvoid HLSquad::order(HLSquadOrder order)\n{\n\tif (order._type == HLSquadOrder::Attack || order._type == HLSquadOrder::Defend)\n\t{\n\t\tUAB_ASSERT(_currentRegion != NULL, \"Current region is null!\");\n\t\t_path = getPath(_currentRegion, order._target);\n\t}\n\telse if (order._type ==HLSquadOrder::None)\n\t{\n\t\t_path.clear();\n\t}\n\t_order = order;\n\t_framesTravelled = 0;\n\n}\nint HLSquad::getStrength() const\n{\n\tif (!_strengthCalculated)\n\t{\n\t\tcalculateStrength();\n\t}\n\treturn _strength;\n}\nint HLSquad::getGroundStrength() const\n{\n\tif (!_strengthCalculated)\n\t{\n\t\tcalculateStrength();\n\t}\n\treturn _groundStrength;\n}\nint HLSquad::getAntiAirStrength() const\n{\n\tif (!_strengthCalculated)\n\t{\n\t\tcalculateStrength();\n\t}\n\treturn _antiAirStrength;\n}\nint HLSquad::getFlyingStrength() const\n{\n\tif (!_strengthCalculated)\n\t{\n\t\tcalculateStrength();\n\t}\n\treturn _flyingStrength;\n}\nvoid HLSquad::calculateStrength() const\n{\n\t_groundStrength = _flyingStrength = _antiAirStrength = _strength = 0;\n\tfor (auto u : _units)\n\t{\n\t\tif (u.second.type.airWeapon() != BWAPI::WeaponTypes::None)\n\t\t{\n\t\t\t_antiAirStrength++;\n\t\t}\n\t\tif (u.second.type.groundWeapon() != BWAPI::WeaponTypes::None)\n\t\t{\n\t\t\t_groundStrength++;\n\t\t}\n\t\tif (u.second.type.airWeapon() != BWAPI::WeaponTypes::None || u.second.type.groundWeapon() != BWAPI::WeaponTypes::None)\n\t\t{\n\t\t\tif (u.second.isFlyer())\n\t\t\t{\n\t\t\t\t_flyingStrength++;\n\t\t\t}\n\t\t\t_strength++;\n\t\t}\n\t}\n}\n\n//class Node{\n//\tconst BWTA::Region* region;\n//\tint gscore, hscore;\n//public:\n//\tint f_score() const{ return gscore + hscore; }\n//\tint g_score() const{ return gscore; }\n//\tNode(const BWTA::Region* r, int g, int h) :region(r), gscore(g), hscore(h){}\n//\tconst BWTA::Region* getRegion() const{ return region; }\n//\tbool operator==(const Node &other){ return this->region == other.region; }\n//};\nstruct NodeComp{\n\tconst std::unordered_map<BWTA::Region *, int> &_g_score, &_f_score;\n\tNodeComp(const std::unordered_map<BWTA::Region *, int> &g_score, const std::unordered_map<BWTA::Region *, int> &f_score) :\n\t\t_g_score(g_score), _f_score(f_score){}\n\tbool operator()(BWTA::Region *r1, BWTA::Region *r2) const{\n\t\treturn _f_score.at(r1) < _f_score.at(r2);\n\t};\n};\n//namespace std{\n//\ttemplate<>struct hash < Node > {\n//\t\tsize_t operator()(const Node &n){\n//\t\t\treturn std::hash<const BWTA::Region*>()(n.getRegion());\n//\t\t}\n//\t};\n//}\n\nstd::list<BWTA::Region*> reconstruct_path(const std::unordered_map<BWTA::Region *, BWTA::Region *> &came_from, BWTA::Region *current)\n{\n\tstd::list<BWTA::Region*> total_path;\n\ttotal_path.push_front(current);\n\twhile (came_from.count(current) > 0)\n\t{\n\t\tcurrent = came_from.at(current);\n\t\ttotal_path.push_front(current);\n\t}\n\treturn total_path;\n}\nstd::list<BWTA::Region*> UAlbertaBot::getPath(BWTA::Region *from, BWTA::Region *to)\n{\n\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Performing A*\");\n\t\n\tstd::unordered_set <BWTA::Region *> closed;\n\tstd::unordered_set <BWTA::Region *> open;\n\tstd::vector<BWTA::Region *> open_queue;\n\tstd::unordered_map<BWTA::Region *, BWTA::Region *> came_from;\n\tstd::unordered_map<BWTA::Region *, int> g_score;\n\tstd::unordered_map<BWTA::Region *, int> f_score;\n\tNodeComp comp(g_score,f_score);\n\topen.insert(from);\n\topen_queue.push_back(from);\n\tg_score[from] = 0;\n\tf_score[from] = g_score[from] + from->getCenter().getApproxDistance(to->getCenter());\n\tstd::make_heap(open_queue.begin(), open_queue.end(), comp);\n\t\n\n\n\n\t//while openset is not empty\n\twhile (!open_queue.empty())\n\t{\n\t\t//current : = the node in openset having the lowest f_score[] value\n\t\tauto current = open_queue.front();\n\n\n\t\t//if current = goal\n\t\tif (current == to)\n\t\t{\n\t\t\treturn reconstruct_path(came_from, to);\n\t\t}\n\t\t\n\t\t//\tremove current from openset\n\t\tstd::pop_heap(open_queue.begin(), open_queue.end(), comp);\n\t\topen_queue.pop_back();\n\t\topen.erase(current);\n\t\n\t\t\n\t\t//\tfor each neighbor in neighbor_nodes(current)\n\t\tfor (auto n : getNeighbours(current))\n\t\t{\n\t\t\t//\t\tif neighbor in closedset\n\t\t\tif (closed.find(n) != closed.end())\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t//tentative_g_score: = g_score[current] + dist_between(current, neighbor)\n\t\t\tint tentative_g_score = g_score.at(current) + current->getCenter().getApproxDistance(n->getCenter());\n\n\n\t\t\t//\t\t\t\t\t\t\tif neighbor not in openset or tentative_g_score < g_score[neighbor]\n\t\t\tauto stored = open.find(n);\n\t\t\tif (stored == open.end() || tentative_g_score < g_score.at(n))\n\t\t\t{\n\t\t\t\t//\t\t\t\t\t\t\t\tcame_from[neighbor] : = current\n\t\t\t\tcame_from[n] = current;\n\t\t\t\t//\t\t\t\t\t\t\t\tg_score[neighbor] : = tentative_g_score\n\t\t\t\tg_score[n] = tentative_g_score;\n\t\t\t\t//\t\t\t\t\t\t\t\tf_score[neighbor] : = g_score[neighbor] + heuristic_cost_estimate(neighbor, goal)\n\t\t\t\tf_score[n] = g_score.at(n) + n->getCenter().getApproxDistance(to->getCenter());\n\t\t\t\t//\t\t\t\t\t\t\t\tif neighbor not in openset\n\t\t\t\tif (stored == open.end())\n\t\t\t\t\t//\t\t\t\t\t\t\t\t\tadd neighbor to openset\n\t\t\t\t{\n\t\t\t\t\topen.insert(n);\n\t\t\t\t\topen_queue.push_back(n);\n\t\t\t\t\tstd::push_heap(open_queue.begin(), open_queue.end(), comp);\n\t\t\t\t}\n\t\t\t\telse//value updated, need to re-sort\n\t\t\t\t{\n\t\t\t\t\tstd::make_heap(open_queue.begin(), open_queue.end(), comp);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t//\tadd current to closedset\n\t\tclosed.insert(current);\n\n\t}\n}\n\nstd::unordered_set<BWTA::Region*> UAlbertaBot::getNeighbours(const BWTA::Region *region)\n{\n\tstd::unordered_set<BWTA::Region*> neighbours;\n\tfor (auto c : region->getChokepoints())\n\t{\n\t\tif (c->getRegions().first != region)\n\t\t{\n\t\t\tneighbours.insert(c->getRegions().first);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tneighbours.insert(c->getRegions().second);\n\t\t}\n\t}\n\treturn neighbours;\n}\n\n\nstd::string HLSquad::toString() const\n{\n\tstd::stringstream ss;\n\n\tss << \"Squad at \" << _currentRegion->getCenter() << \", Units: \";\n\tfor (auto u : _units)\n\t{\n\t\tss << u.second.type.getName() << \" \";\n\t}\n\n\n\treturn ss.str();\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLSquad.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"HLUnitData.h\"\n\nnamespace UAlbertaBot{\n\tclass HLSquadOrder\n\t{\n\tpublic:\n\n\t\tenum OrderType { None, Attack, Defend, SquadOrderTypes };\n\n\t\tOrderType\t\t\t_type;\n\t\tBWTA::Region*\t\t_target;\n\n\t\tHLSquadOrder();\n\n\t\tHLSquadOrder(OrderType type, BWTA::Region* target);\n\n\t};\n\n\tclass HLSquad{\n\t\tBWTA::Region *_currentRegion;\n\t\tstd::list<BWTA::Region*>  _path;\n\t\tint _framesTravelled;\n\t\tstd::unordered_map<int,UnitInfo> _units;\n\t\tHLSquadOrder _order;\n\t\tdouble _speed;\n\t\tmutable int _groundStrength;\n\t\tmutable int _flyingStrength;\n\t\tmutable int _antiAirStrength;\n\t\tmutable int _strength;\n\t\tmutable bool _strengthCalculated;\n\tpublic:\n\t\tHLSquad(const std::vector<UnitInfo> & units, BWTA::Region *region);\n\t\t~HLSquad(){};\n\t\tvoid addUnit(const UnitInfo &unit);\n\t\tdouble getSpeed() const{ return _speed; }\n\t\tbool hasPath() const{ return !_path.empty(); }\n\t\tBWTA::Region* getNextRegion() const{ return _path.front(); }\n\t\tBWTA::Region* getCurrentRegion() const{ return _currentRegion; }\n\t\tint getTravelledTime() const{ return _framesTravelled; }\n\t\tint travel(int frames);\n\t\tint getGroundStrength() const;\n\t\tint getStrength() const;\n\t\tint getAntiAirStrength() const;\n\t\tint getFlyingStrength() const;\n\t\tvoid calculateStrength() const;\n\t\tvoid order(HLSquadOrder order);\n\t\tHLSquadOrder order() const{ return _order; }\n\t\t//std::vector<UnitInfo>& getUnits()  { return _units; }\n\t\t//const std::vector<UnitInfo>& getUnits() const { return _units; }\n\t\tvoid removeUnit(const UnitInfo &unit){ _units.erase(unit.unitID);  }\n\t\tvoid removeUnit(int id){ _units.erase(id); _strengthCalculated = false; }\n\t\t//void removeUnit(const std::unordered_set<UnitInfo>::iterator &unit){ _units.erase(unit); _strengthCalculated = false; }\n\t\t//void updateUnit(const UnitInfo &unit)\n\t\t//{ \n\t\t//\tremoveUnit(unit);\n\t\t//\taddUnit(unit);\n\t\t//}\n\t\tstd::unordered_map<int,UnitInfo>::iterator begin(){ return _units.begin(); }\n\t\tstd::unordered_map<int, UnitInfo>::iterator end(){ return _units.end(); }\n\t\tstd::unordered_map<int, UnitInfo>::const_iterator begin() const{ return _units.begin(); }\n\t\tstd::unordered_map<int, UnitInfo>::const_iterator end() const{ return _units.end(); }\n\t\tUnitInfo& operator[](const int &id){ return _units[id]; }\n\t\tUnitInfo& at(const int &id){ return _units.at(id); }\n\t\tbool empty() const{ return _units.empty(); }\n\t\tstd::string toString() const;\n\t\t//HLSquad(const Squad &squad);//implicit conversion\n\t\t//bool done();//check if order completed\n\t\t//BWAPI::Region getRegion() const{ return region; }\n\t\t//void addUnit(BWAPI::UnitInterface *u){ Squad::addUnit(u); }\n\t\t//bool removeUnit(BWAPI::UnitInterface *u){ return Squad::removeUnit(u); }\n\t};\n\tstd::list<BWTA::Region*> getPath(BWTA::Region *from, BWTA::Region *to);\n\tstd::unordered_set<BWTA::Region*> getNeighbours(const BWTA::Region *region);\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLState.cpp",
    "content": "#include \"HLState.h\"\n#include <random>\n#include \"CombatPredictor.h\"\n\nusing namespace UAlbertaBot;\n\nunsigned int HLState::_zobristChoice[20][StrategyManager::NumProtossStrategies][20][10];\nunsigned int HLState::_zobristStrategy[20][StrategyManager::NumProtossStrategies];\n//_dummy_static_initializer _dummy;\n\n\nHLState::HLState(BWAPI::GameWrapper & game, BWAPI::PlayerInterface * player, BWAPI::PlayerInterface * enemy)\n{\n\n\tUAB_ASSERT(player->getID() < 2, \"Only player ids 0 and 1 supported\");\n\tUAB_ASSERT(enemy->getID() < 2, \"Only player ids 0 and 1 supported\");\n\t_state[player->getID()] = BOSS::GameState(game, player);\n\t_state[enemy->getID()] = BOSS::GameState(game, enemy);\n\t_players[player->getID()] = player;\n\t_players[enemy->getID()] = enemy;\n\n\taddSquads(player);\n\taddSquads(enemy);\n\n\t//_buildOrderIndex[0] = 0;\n\t//_buildOrderIndex[1] = 0;\n\n\t//TODO:change this to take UnitData as parameter\n\t_unitData[player->getID()] = HLUnitData(InformationManager::Instance().getUnitData(player),player);\n\t_unitData[enemy->getID()] = HLUnitData(InformationManager::Instance().getUnitData(enemy), player);\n\n\t_workerData[player->getID()] = WorkerManager::Instance().getData();\n\t_workerData[enemy->getID()]\t= WorkerData();\n\tfor (auto &u : enemy->getUnits()){\n\t\tif (u->getType().isWorker()){\n\t\t\t_workerData[enemy->getID()].addWorker(u);\n\t\t}\n\t}\n\t//_opening[0] = false;\n\t//_opening[1] = false;\n\n\t//todo: assign worker jobs\n\t//3 per gas, 3 per mineral patch, 1 to build, and if scout outside nexus region\n\n\tstatic std::mt19937 rng(1);//todo:use a seed?\n\tfor (int depth = 0; depth < 20; depth++){\n\t\tfor (int s = 0; s < StrategyManager::NumProtossStrategies; s++){\n\t\t\t_zobristStrategy[depth][s] = rng();\n\t\t\tfor (int point = 0; point < 20; point++){\n\t\t\t\tfor (auto c = 0; c < 10; c++){\n\t\t\t\t\t_zobristChoice[depth][s][point][c] = rng();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t_hash = rng();\n}\n\nbool HLState::isNonWorkerCombatUnit(const BWAPI::UnitInterface *unit)\n{\n\t//if (unit->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar)\n\t//{\n\t//\tUAB_ASSERT(InformationManager::Instance().isCombatUnit(unit->getType())\n\t//\t\t&& SparCraft::System::isSupportedUnitType(unit->getType()), \"Dark templar is not supported :(\");\n\t//}\n\treturn unit\n\t\t&&unit->isCompleted()\n\t\t&& unit->getHitPoints() > 0\n\t\t&& unit->exists()\n\t\t&& unit->getType() != BWAPI::UnitTypes::Unknown\n\t\t&& unit->getPosition().isValid()\n\t\t&& InformationManager::Instance().isCombatUnit(unit->getType()) \n\t\t&& SparCraft::System::isSupportedUnitType(unit->getType());\n}\nbool HLState::isNonWorkerCombatUnit(const UnitInfo &unit)\n{\n\t//if (unit.type == BWAPI::UnitTypes::Protoss_Dark_Templar)\n\t//{\n\t//\tUAB_ASSERT(InformationManager::Instance().isCombatUnit(unit.type)\n\t//\t\t&& SparCraft::System::isSupportedUnitType(unit.type), \"Dark templar is not supported :(\");\n\t//}\n\t\n\treturn  unit.completed\n\t\t&& unit.lastHealth > 0\n\t\t&& unit.type != BWAPI::UnitTypes::Unknown\n\t\t&& unit.lastPosition.isValid()\n\t\t&& InformationManager::Instance().isCombatUnit(unit.type) \n\t\t&& SparCraft::System::isSupportedUnitType(unit.type);\n}\nvoid HLState::addSquads(const BWAPI::PlayerInterface *player)\n{\n\tstd::unordered_map < BWTA::Region*, std::vector<UnitInfo> > units;\n\tfor (auto &unit : player->getUnits()){\n\t\tif (isNonWorkerCombatUnit(unit))\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tunits[BWTA::getRegion(unit->getPosition())].push_back(UnitInfo(unit));\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"Exception while running BWTA::getRegion(%d, %d), ignoring this unit\", unit->getPosition().x, unit->getPosition().y);\n\t\t\t}\n\t\t}\n\t}\n\tfor (auto &it : units)\n\t{\n\t\tif (it.first == nullptr)//skip null region\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\tint totalDamage = 0;\n\t\tfor (auto &unit : it.second)\n\t\t{\n\t\t\ttotalDamage += (unit.damage(true) + unit.damage(false));\n\t\t}\n\t\tif (totalDamage == 0)//skip squads with all observers\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\t_squad[player->getID()].push_back(HLSquad(it.second, it.first));\n\t}\n}\n\nHLState::~HLState()\n{\n}\n\n//void HLState::forwardGameState(int frames, int playerID)\n//{\n//\tif (_buildOrderIndex[playerID] >= _buildOrder[playerID].size()){\n//\n//\t\tUAB_ASSERT(BOSS::Races::GetRace(_state[playerID].getRace()) == BWAPI::Races::Protoss, \"Non protoss?\");\n//\n//\t\t//get goal units\n//\t\tauto goalUnits = StrategyManager::Instance().getBuildOrderGoal(\n//\t\t\t_unitData[playerID],\n//\t\t\t_unitData[1 - playerID],\n//\t\t\t_workerData[playerID],\n//\t\t\t_state[playerID].getCurrentFrame(),\n//\t\t\t0,//strategy\n//\t\t\tgetRace(playerID));\n//\n//\t\ttry{\n//\t\t\tBOSS::BuildOrderSearchGoal goal(_state[playerID].getRace());\n//\n//\t\t\tfor (size_t i = 0; i < goalUnits.size(); ++i)\n//\t\t\t{\n//\t\t\t\tMetaType type = goalUnits[i].first;\n//\t\t\t\tBOSS::ActionType actionType;\n//\t\t\t\tif (type.isUnit())\n//\t\t\t\t{\n//\t\t\t\t\tactionType = type.unitType;\n//\t\t\t\t}\n//\t\t\t\telse if (type.isUpgrade())\n//\t\t\t\t{\n//\t\t\t\t\tactionType = type.upgradeType;\n//\t\t\t\t}\n//\t\t\t\telse if (type.isTech())\n//\t\t\t\t{\n//\t\t\t\t\tactionType = type.techType;\n//\t\t\t\t}\n//\t\t\t\telse{\n//\t\t\t\t\tUAB_ASSERT(false, \"Should have found a valid type here\");\n//\t\t\t\t}\n//\t\t\t\tgoal.setGoal(actionType, goalUnits[i].second);\n//\t\t\t}\n//\t\t\t//perform search\n//\t\t\tBOSS::DFBB_BuildOrderSmartSearch smartSearch(_state[playerID].getRace());\n//\t\t\tsmartSearch.setGoal(goal);\n//\t\t\tsmartSearch.setState(_state[playerID]);\n//\t\t\tsmartSearch.setTimeLimit(1000);\n//\t\t\tsmartSearch.search();\n//\n//\n//\t\t\t//get build order from search\n//\t\t\tif (smartSearch.getResults().solved){\n//\t\t\t\t_buildOrder[playerID] = smartSearch.getResults().buildOrder;\n//\t\t\t\tBWAPI::Broodwar->printf(\"Build order found\");\n//\t\t\t}\n//\t\t\telse{\n//\t\t\t\tBOSS::NaiveBuildOrderSearch nbos(smartSearch.getParameters().initialState, smartSearch.getParameters().goal);\n//\t\t\t\t_buildOrder[playerID] = nbos.solve();\n//\t\t\t\tBWAPI::Broodwar->printf(\"Build order not found, using naive\");\n//\t\t\t}\n//\n//\t\t}catch (BOSS::Assert::BOSSException &e){\n//\t\t\tBWAPI::Broodwar->printf(e.what());\n//\t\t}\n//\t}\n//\t//move forward the world, executing the build order\n//\tint remainingFrames = frames;\n//\tfor (; _buildOrderIndex[playerID] < _buildOrder[playerID].size(); _buildOrderIndex[playerID]++){\n//\t\t//BWAPI::Broodwar->printf(\"Frame: %d, next action: %s\",initialState.getCurrentFrame(),order[i].getMetaName().c_str());\n//\t\tint nextActionStart = _state[playerID].whenCanPerform(_buildOrder[playerID][_buildOrderIndex[playerID]]);\n//\t\tif (nextActionStart < remainingFrames){\n//\t\t\t_state[playerID].doAction(_buildOrder[playerID][_buildOrderIndex[playerID]]);\n//\t\t\tremainingFrames -= nextActionStart;\n//\t\t}\n//\t\telse{\n//\t\t\tbreak;\n//\t\t}\n//\t}\n//\t//TODO: add new units to unitdata. Create squad defending home base with new units.\n//\t//TODO: check case where the build order (preexistent or newly acquired) is too short and we need to get a second one\n//\tif (remainingFrames > 0){\n//\t\t_state[playerID].fastForward(remainingFrames);\n//\t}\n//\tBWAPI::Broodwar->printf(\"Final Frame: %d\", _state[playerID].getCurrentFrame());\n//\n//\t//TODO: execute squad orders\n//}\n\nbool HLState::checkChoicePoint(const HLMove &move, int playerID) const\n{\n\ttry{\n\t\tStrategyManager::Instance().getBuildOrderGoal(\n\t\t\t_unitData[playerID],\n\t\t\t_unitData[1 - playerID],\n\t\t\t_workerData[playerID],\n\t\t\tcurrentFrame(),\n\t\t\tmove.getStrategy(),\n\t\t\tgetRace(playerID),\n\t\t\tmove.getChoices());\n\t}\n\tcatch (const ChoicePoint &){\n\t\treturn true;//if some script hit an internal choice point\n\t}\n\treturn false;\n}\n\nBOSS::BuildOrder HLState::getBuildOrder(const HLMove &move, int playerID) const\n{\n\tMetaPairVector goalUnits;\n\ttry{\n\t\tgoalUnits = StrategyManager::Instance().getBuildOrderGoal(\n\t\t\t_unitData[playerID],\n\t\t\t_unitData[1 - playerID],\n\t\t\t_workerData[playerID],\n\t\t\tcurrentFrame(),\n\t\t\tmove.getStrategy(),\n\t\t\tgetRace(playerID),\n\t\t\tmove.getChoices());\n\t}\n\n\tcatch (const ChoicePoint &){\n\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"Hit choice point at beginning\\n\");\n\t\treturn BOSS::BuildOrder();//if some script hit an internal choice point\n\t}\n\n\tBOSS::BuildOrder\t\tbuildOrder;\n\n\tBOSS::BuildOrderSearchGoal goal(_state[playerID].getRace());\n\n\tfor (size_t i = 0; i < goalUnits.size(); ++i)\n\t{\n\t\tMetaType type = goalUnits[i].first;\n\t\tBOSS::ActionType actionType;\n\t\tif (type.isUnit())\n\t\t{\n\t\t\tactionType = type.unitType;\n\t\t}\n\t\telse if (type.isUpgrade())\n\t\t{\n\t\t\tactionType = type.upgradeType;\n\t\t}\n\t\telse if (type.isTech())\n\t\t{\n\t\t\tactionType = type.techType;\n\t\t}\n\t\telse{\n\t\t\tUAB_ASSERT(false, \"Should have found a valid type here\");\n\t\t}\n\t\tgoal.setGoal(actionType, goalUnits[i].second);\n\t}\n\n\tBOSS::NaiveBuildOrderSearch nbos(_state[playerID], goal);\n\tbuildOrder = nbos.solve();\n\n\treturn buildOrder;\n}\n\n\n\nvoid HLState::applyAndForward(int depth, int frames, const std::array<HLMove, 2> &moves)\n{\n\tint forwardedFrames = 0;\n\n\t_hash = getHash(depth, moves);\n\tUAB_ASSERT(getRace(0) == BWAPI::Races::Protoss, \"Non protoss?\");\n\tUAB_ASSERT(getRace(1) == BWAPI::Races::Protoss, \"Non protoss?\");\n\n\tBOSS::BuildOrder buildOrder[2];\n\t\n\t\n\tfor (int playerId = 0; playerId < 2; playerId++)\n\t{\n\t\tif (buildOrder[playerId].empty())\n\t\t{\n\t\t\tbuildOrder[playerId] = getBuildOrder(moves[playerId], playerId);\n\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Using build order planning, size: %d\\n\", buildOrder[playerId].size());\n\t\t}\n\t}\n\n\n\n\t//execute build orders\n\tunsigned int buildOrderIndex[2] = { 0, 0 };\n\n\twhile (buildOrderIndex[0] < buildOrder[0].size() &&\n\t\tbuildOrderIndex[1] < buildOrder[1].size()){\n\t\tint nextActionStart[2];\n\t\tfor (int playerID = 0; playerID < 2; playerID++){\n\t\t\tnextActionStart[playerID] = _state[playerID].whenCanPerform(buildOrder[playerID][buildOrderIndex[playerID]]);\n\t\t}\n\n\t\t\n\t\tint nextPlayer = nextActionStart[0] < nextActionStart[1] ? 0 : 1;\n\t\tint framesToForward = nextActionStart[nextPlayer] - _state[nextPlayer].getCurrentFrame();\n\t\tif (forwardedFrames + framesToForward>frames)\n\t\t{\n\t\t\tframesToForward = frames - forwardedFrames;\n\t\t\tsynchronizeNewUnits(0, _state[0].fastForward(_state[0].getCurrentFrame() + framesToForward));\n\t\t\tsynchronizeNewUnits(1, _state[1].fastForward(_state[1].getCurrentFrame() + framesToForward));\n\t\t\tif (framesToForward > 0)\n\t\t\t{\n\t\t\t\tforwardSquads(framesToForward);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tforwardedFrames += framesToForward;\n\t\tconst BOSS::ActionType& action = buildOrder[nextPlayer][buildOrderIndex[nextPlayer]++];\n\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Start new unit: %s to player %d frame %d\\n\", action.getName().c_str(), nextPlayer, _state[nextPlayer].getCurrentFrame());\n\n\n\t\tsynchronizeNewUnits(nextPlayer, _state[nextPlayer].doAction(action), action);\n\t\tif (checkChoicePoint(moves[1 - nextPlayer], 1 - nextPlayer))\n\t\t{\n\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Hit choice point while forwarding 1\\n\");\n\t\t\tbreak;//if some script hit an internal choice point\n\t\t}\n\n\t\tif (nextActionStart[0] == nextActionStart[1]){\n\t\t\tconst BOSS::ActionType& action = buildOrder[1 - nextPlayer][buildOrderIndex[1 - nextPlayer]++];\n\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Start new unit: %s to player %d frame %d\\n\", action.getName().c_str(), 1 - nextPlayer, _state[1 - nextPlayer].getCurrentFrame());\n\n\t\t\tsynchronizeNewUnits(1 - nextPlayer, _state[1 - nextPlayer].doAction(action), action);\n\t\t\tif (checkChoicePoint(moves[nextPlayer], nextPlayer))\n\t\t\t{\n\t\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Hit choice point while forwarding 1\\n\");\n\t\t\t\tbreak;;//if some script hit an internal choice point\n\t\t\t}\n\t\t}\n\t\telse{\n\n\t\t\tsynchronizeNewUnits(1 - nextPlayer, _state[1 - nextPlayer].fastForward(nextActionStart[nextPlayer]));\n\t\t}\n\t\tif (framesToForward > 0)\n\t\t{\n\t\t\tforwardSquads(framesToForward);\n\t\t}\n\t\tUAB_ASSERT(_state[0].getMinerals() >= 0, \"negative minerals: \" + _state[0].getMinerals());\n\t\tUAB_ASSERT(_state[1].getMinerals() >= 0, \"negative minerals: \" + _state[1].getMinerals());\n\t}\n\n\t//make sure both states are at the same frame\n\tint frameDiff = _state[0].getCurrentFrame() - _state[1].getCurrentFrame();\n\tif (frameDiff < 0){\n\t\tsynchronizeNewUnits(0, _state[0].fastForward(_state[1].getCurrentFrame()));\n\t}\n\telse if (frameDiff > 0){\n\t\tsynchronizeNewUnits(1, _state[1].fastForward(_state[0].getCurrentFrame()));\n\t}\n\tif (std::abs(frameDiff) > 0)\n\t{\n\t\tforwardSquads(std::abs(frameDiff));\n\t}\n\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Finished forwarding\\n\");\n}\n\n//void HLState::doAction(int playerID, const BOSS::ActionType action){\n//\t_state[playerID].doAction(action);\n//\tif (action.isUnit()){\n//\t\t_unitData[playerID].updateUnit();\n//\t\tif (action.isWorker()){\n//\t\t\t_workerData[playerID].addWorker();\n//\t\t}\n//\t}\n//}\nvoid HLState::synchronizeNewUnits(int playerID, const std::vector<BOSS::ActionType> &finishedUnits)\n{\n\tfor (auto &unit : finishedUnits){\n\t\tif (unit.isUnit()){\n\t\t\tif ((_unitData[playerID].getNumUnits(unit.getUnitType()) ==\n\t\t\t\t_unitData[playerID].getNumCompletedUnits(unit.getUnitType())) ||\n\t\t\t\t!_unitData[playerID].finishUnit(unit.getUnitType()))//units of this type were in progress, let's finish them\n\t\t\t{//let's add a new finished unit\n\n\t\t\t\tauto parentType = unit.getUnitType().whatBuilds().first;\n\t\t\t\t//BWAPI::Position pos;\n\t\t\t\t//for (auto temp : _unitData[playerID].getUnitVector()){//let's take the position of the first building that can build it \n\t\t\t\t//\tif (temp.type == parentType){\n\t\t\t\t//\t\tpos = temp.lastPosition;\n\t\t\t\t//\t\tbreak;\n\t\t\t\t//\t}\n\t\t\t\t//}\n\t\t\t\tBWAPI::Position pos(_players[playerID]->getStartLocation());//everything spawns at the main base\n\n\t\t\t\tint newID = std::max(_unitData[playerID].highestID(), _unitData[1 - playerID].highestID()) + 1;\n\t\t\t\tUnitInfo newUnit(newID, _players[playerID], pos, unit.getUnitType(), true);\n\n\t\t\t\t_unitData[playerID].addUnit(newUnit);\n\t\t\t\taddNewUnitToSquad(newUnit);\n\t\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Added new unit: %s to player %d frame %d\\n\", newUnit.type.getName().c_str(), playerID, _state[playerID].getCurrentFrame());\n\t\t\t\tif (unit.isWorker()){\n\t\t\t\t\t//todo:for now we'll ignore new workers \n\t\t\t\t\t//_workerData[playerID].addWorker();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse{\n\t\t\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Finished new unit: %s to player %d frame %d\\n\", unit.getName().c_str(), playerID, _state[playerID].getCurrentFrame());\n\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nvoid HLState::synchronizeNewUnits(int playerID, const std::vector<BOSS::ActionType> &finishedUnits, const \tBOSS::ActionType &startedUnit)\n{\n\tif (startedUnit.isUnit()){\n\t\tauto parentType = startedUnit.getUnitType().whatBuilds().first;\n\t\tBWAPI::Position pos(_players[playerID]->getStartLocation());//everything spawns at the main base\n\n\t\tint newID = std::max(_unitData[playerID].highestID(), _unitData[1 - playerID].highestID()) + 1;\n\t\tUnitInfo newUnit(newID, _players[playerID], pos, startedUnit.getUnitType(), false);\n\n\t\t_unitData[playerID].addUnit(newUnit);\n\t\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Started new unit: %s to player %d frame %d\\n\", newUnit.type.getName().c_str(), playerID, _state[playerID].getCurrentFrame());\n\t\tif (startedUnit.isWorker()){\n\t\t\t//todo:for now we'll ignore new workers \n\t\t\t//_workerData[playerID].addWorker();\n\t\t}\n\t}\n\n\tsynchronizeNewUnits(playerID, finishedUnits);\n\t\n}\n\nvoid HLState::synchronizeDeadUnits(const std::array<std::vector<UnitInfo>,2> &units)\n{\n\tfor (int p = 0; p < 2; p++)\n\t{\n\t\tfor (const auto &u : units[p])\n\t\t{\n\t\t\t_state[p].removeCompletedAction(BOSS::ActionType(u.type));\n\t\t\t_unitData[p].removeUnit(u.unitID);\n\t\t\t_workerData[p].workerDestroyed(u.unit);\n\t\t\t//_squad updated previously\n\t\t}\n\t}\n}\n\nvoid HLState::addNewUnitToSquad(const UnitInfo &newUnit)\n{\n\tif (isNonWorkerCombatUnit(newUnit))\n\t{\n\t\t//todo:find squad in region, or create new squad\n\t\tBWTA::Region *r = BWTA::getRegion(newUnit.lastPosition);\n\t\tbool added = false;\n\t\tfor (auto &s : _squad[newUnit.player->getID()])\n\t\t{\n\t\t\tif (s.getCurrentRegion() == r)\n\t\t\t{\n\t\t\t\ts.addUnit(newUnit);\n\t\t\t\tadded = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!added)\n\t\t{\n\t\t\tstd::vector<UnitInfo> v(1,newUnit);\n\t\t\t_squad[newUnit.player->getID()].push_back(HLSquad(v, r));\n\t\t}\n\t}\n}\n\nvoid HLState::assignDefenseSquads()\n{\n\tfor (int playerId = 0; playerId < 2; playerId++)\n\t{\n\t\t//check if we need to defend any of our regions\n\t\tfor ( BWTA::Region *r: _unitData[playerId].getBaseRegions())\n\t\t{\n\t\t\tint enemyFlyingStrength = 0;\n\t\t\tint enemyGroundStrength = 0;\n\t\t\tfor (auto &s : _squad[1 - playerId])\n\t\t\t{\n\t\t\t\tif (s.getCurrentRegion() == r)\n\t\t\t\t{\n\t\t\t\t\tenemyFlyingStrength += s.getFlyingStrength();\n\t\t\t\t\tenemyGroundStrength += s.getGroundStrength();\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\tstd::vector<bool> skip(_squad[playerId].size(),false);\n\t\t\t//assign closest squads to region to defend until we outnumber enemies\n\t\t\twhile (enemyFlyingStrength > 0)\n\t\t\t{\n\t\t\t\tint i = getClosestUnassignedSquad(playerId, r, skip);\n\t\t\t\tif (i < 0)break;\n\t\t\t\tHLSquad &s = _squad[playerId][i];\n\n\t\t\t\tif ((enemyFlyingStrength > 0) && (s.getAntiAirStrength() > 0))\n\t\t\t\t{\n\t\t\t\t\ts.order(HLSquadOrder(HLSquadOrder::Defend, r));\n\t\t\t\t\tenemyFlyingStrength -= s.getAntiAirStrength();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tskip[i] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tskip = std::vector<bool>(_squad[playerId].size(), false);\n\t\t\twhile (enemyGroundStrength > 0)\n\t\t\t{\n\t\t\t\tint i = getClosestUnassignedSquad(playerId, r, skip);\n\t\t\t\tif (i < 0)break;\n\t\t\t\tHLSquad &s = _squad[playerId][i];\n\n\t\t\t\tif ((enemyGroundStrength > 0) && (s.getGroundStrength() > 0))\n\t\t\t\t{\n\t\t\t\t\ts.order(HLSquadOrder(HLSquadOrder::Defend, r));\n\t\t\t\t\tenemyGroundStrength -= s.getGroundStrength();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tskip[i] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n}\nvoid HLState::assignAttackSquads()\n{\n\tfor (int playerId = 0; playerId < 2; playerId++)\n\t{\n\t\t//if there are unassigned squads, send them to the closest enemy region\n\t\ttry\n\t\t{\n\t\t\tBWTA::Region *r = getClosestBaseLocation(1 - playerId, BWTA::getStartLocation(_players[playerId])->getRegion())->getRegion();\n\t\t\twhile (1)\n\t\t\t{\n\t\t\t\tHLSquad &s = getUnassignedSquad(playerId);\n\t\t\t\ts.order(HLSquadOrder(HLSquadOrder::OrderType::Attack, r));\n\t\t\t}\n\t\t}\n\t\tcatch (...)\n\t\t{\n\n\t\t}\n\t}\n}\n\nstd::vector<std::array<std::vector<int>, 2 > > HLState::getCombats() const\n{\n\tstd::vector<std::array<std::vector<int>, 2 > > combats;\n\n\tfor (auto r : BWTA::getRegions())\n\t{\n\t\tstd::vector<int> first;\n\t\tfor (size_t s = 0; s < _squad[0].size();s++)\n\t\t{\n\t\t\tif (_squad[0][s].getCurrentRegion() == r && _squad[0][s].getStrength() > 0)\n\t\t\t{\n\t\t\t\tfirst.push_back(s);\n\t\t\t}\n\t\t}\n\t\tif (!first.empty())\n\t\t{\n\t\t\tstd::vector<int> second;\n\t\t\tfor (size_t s = 0; s < _squad[1].size(); s++)\n\t\t\t{\n\t\t\t\tif (_squad[1][s].getCurrentRegion() == r && _squad[1][s].getStrength() > 0)\n\t\t\t\t{\n\t\t\t\t\tsecond.push_back(s);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!second.empty())\n\t\t\t{\n\t\t\t\tcombats.push_back(std::array < std::vector<int>, 2 > {{ first, second }});\n\t\t\t}\n\t\t}\n\t}\n\treturn combats;\n}\n\n\nvoid HLState::forwardCombat(const std::array<std::vector<int>,2 > &squadIndex, int frames)\n{\n\tif (frames < 20)//don't simulate extremely short combats\n\t{\n\t\treturn;\n\t}\n\tCombatSimulation sim;\n\tSparCraft::GameState state;\n\tstatic std::random_device rd;\n\tstatic std::mt19937 gen(rd());\n\tstatic std::uniform_int_distribution<> X(100,200);\n\tstatic std::uniform_int_distribution<> Y(-200, 200);\n\tfor (int p = 0; p < 2; p++)\n\t{\n\t\tUAB_ASSERT(!squadIndex[p].empty(), \"Adding no squads!\");\n\t\tfor (size_t i = 0; i < squadIndex[p].size(); i++)\n\t\t{\n\t\t\tconst HLSquad &squad = _squad[p][squadIndex[p][i]];\n\t\t\tUAB_ASSERT(!squad.empty(), \"Adding empty squad!\");\n\t\t\tBWAPI::Position squadPos=squad.getCurrentRegion()->getCenter();\n\n\t\t\tfor (auto it = squad.begin(); it != squad.end();it++)\n\t\t\t{\n\t\t\t\tconst UnitInfo &unit = it->second;\n\t\t\t\tif (InformationManager::Instance().isCombatUnit(unit.type)\n\t\t\t\t\t&& SparCraft::System::isSupportedUnitType(unit.type))\n\t\t\t\t{\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tint newX = squadPos.x + (p == 0 ? -1 : 1)*X(gen);\n\t\t\t\t\t\tif (newX < 0)newX = 0;\n\t\t\t\t\t\tint newY = squadPos.y + Y(gen);\n\t\t\t\t\t\tif (newY < 0)newY = 0;\n\t\t\t\t\t\tSparCraft::Unit u(unit.type,\n\t\t\t\t\t\t\tSparCraft::Position(newX,newY),\n\t\t\t\t\t\t\tunit.unitID,\n\t\t\t\t\t\t\tsim.getSparCraftPlayerID(unit.player),\n\t\t\t\t\t\t\tunit.lastHealth,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tcurrentFrame(),\n\t\t\t\t\t\t\tcurrentFrame());\n\t\t\t\t\t\tstate.addUnitWithID(u);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (int e) \n\t\t\t\t\t{\n\t\t\t\t\t\te = 1;\n\t\t\t\t\t\tLogger::LogAppendToFile(UAB_LOGFILE,\"Problem Adding Unit with ID: %d\", unit.unitID);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tstate.finishedMoving();\n\tUAB_ASSERT(state.numUnits(SparCraft::Players::Player_One) > 0 && state.numUnits(SparCraft::Players::Player_Two) > 0,\n\t\t\"Someone has 0 units in this battle!\");\n\tif (state.numUnits(SparCraft::Players::Player_One) <= 0 || state.numUnits(SparCraft::Players::Player_Two) <= 0)\n\t{\n\t\tLogger::LogAppendToFile(UAB_LOGFILE, state.toString());\n\t\tfor (int p = 0; p < 2; p++)\n\t\t{\n\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"Player %d\\n\", p);\n\t\t\tfor (size_t i = 0; i < squadIndex[p].size(); i++)\n\t\t\t{\n\t\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"Squad %d\\n\", i);\n\t\t\t\tconst HLSquad &squad = _squad[p][squadIndex[p][i]];\n\t\t\t\tBWAPI::Position squadPos = squad.getCurrentRegion()->getCenter();\n\n\t\t\t\tfor (auto it = squad.begin(); it != squad.end(); it++)\n\t\t\t\t{\n\t\t\t\t\tconst UnitInfo &unit = it->second;\n\t\t\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"\t%s\", unit.type.getName().c_str());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tstd::array<std::vector<UnitInfo>, 2> deadUnits;\n\ttry\n\t{\n\n\t\tSparCraft::PlayerPtr selfNOK(new SparCraft::Player_NOKDPS(SparCraft::Players::Player_One));\n\n\t\tSparCraft::PlayerPtr enemyNOK(new SparCraft::Player_NOKDPS(SparCraft::Players::Player_Two));\n\n\t\tSparCraft::Game g(state, selfNOK, enemyNOK, frames);\n\t\t\n\t\tint prev = g.getState().evalLTD2(SparCraft::Players::Player_One);\n\t\tg.play();\n\t\tUAB_ASSERT(prev!=g.getState().evalLTD2(SparCraft::Players::Player_One),\n\t\t\t\"LTD2 == before and after combat! Length: %d frames\\n%s\",frames,state.toString());\n\t\t//todo:get dead units\n\t\tfor (int p = 0; p < 2; p++)\n\t\t{\n\t\t\tfor (size_t i = 0; i < squadIndex[p].size(); i++)\n\t\t\t{\t\n\t\t\t\tauto it = _squad[p][squadIndex[p][i]].begin();\n\t\t\t\twhile (it != _squad[p][squadIndex[p][i]].end())\n\t\t\t\t{\n\t\t\t\t\tint id = it->first;\n\t\t\t\t\tUnitInfo unit = it->second;\n\t\t\t\t\tit++;\n\t\t\t\t\ttry{\n\t\t\t\t\t\tauto &sparUnit = g.getState().getUnitByID(p, id);\n\t\t\t\t\t\tif (!sparUnit.isAlive()){\n\t\t\t\t\t\t\t_squad[p][squadIndex[p][i]].removeUnit(id);\n\t\t\t\t\t\t\tdeadUnits[p].push_back(unit);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse//unit alive, health might have changed\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_squad[p][squadIndex[p][i]][id].lastHealth = sparUnit.currentHP();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (int){\n\t\t\t\t\t\t_squad[p][squadIndex[p][i]].removeUnit(id);\n\t\t\t\t\t\tdeadUnits[p].push_back(unit);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tcatch (int)\n\t{\n\t\tBWAPI::Broodwar->printf(\"SparCraft FatalError, simulateCombat() threw\");\n\n\t\tUAB_ASSERT(false, \"SparCraft FatalError, simulateCombat() threw\");\n\t}\n\n\n\n\tsynchronizeDeadUnits(deadUnits);\n\n\t//Logger::LogAppendToFile(UAB_LOGFILE, \"Combat executed for %d frames\", frames);\n}\n\nBWTA::BaseLocation * HLState::getClosestBaseLocation(int playerId, BWTA::Region *r) const\n{\n\tint min = std::numeric_limits<int>::max();\n\tBWTA::BaseLocation *min_base = NULL;\n\tfor (auto l : BWTA::getBaseLocations())\n\t{\n\t\tint d = l->getRegion()->getCenter().getApproxDistance(r->getCenter());\n\t\tif (d<min)\n\t\t{\n\t\t\tmin = d;\n\t\t\tmin_base = l;\n\t\t}\n\t}\n\treturn min_base;\n}\nint HLState::getClosestUnassignedSquad(int playerId, const BWTA::Region *r, const std::vector<bool> skip)\n{\n\tint min = std::numeric_limits<int>::max(), min_i = -1;\n\tfor (size_t i = 0; i < _squad[playerId].size(); i++)\n\t{\n\t\tif (skip[i])continue;\n\t\tauto &s = _squad[playerId][i];\n\t\tif ((s.order()._type == HLSquadOrder::None))\n\t\t{\n\t\t\tint d = s.getCurrentRegion()->getCenter().getApproxDistance(r->getCenter());\n\t\t\tif (d < min)\n\t\t\t{\n\t\t\t\tmin = d;\n\t\t\t\tmin_i = i;\n\t\t\t}\n\t\t}\n\t}\n\treturn min_i;\n}\nHLSquad & HLState::getUnassignedSquad(int playerId)\n{\n\tfor (auto &s : _squad[playerId])\n\t{\n\t\tif (s.order()._type == HLSquadOrder::None)\n\t\t{\n\t\t\treturn s;\n\t\t}\n\t}\n\tthrow 1;\n}\nvoid HLState::clearOrders()\n{\n\tfor (int playerId = 0; playerId < 2; playerId++)\n\t{\n\t\tfor (auto &s : _squad[playerId])\n\t\t{\n\t\t\ts.order(HLSquadOrder());\n\t\t}\n\t}\n}\n\nvoid HLState::forwardSquads(int frames)\n{\n\t//delete empty squads\n\tfor (int playerId = 0; playerId < 2; playerId++)\n\t{\n\t\t_squad[playerId].erase(\n\t\t\tstd::remove_if(_squad[playerId].begin(), _squad[playerId].end(), \n\t\t\t\t[](const HLSquad &s){return s.empty(); }),\n\t\t\t_squad[playerId].end());\n\t}\n\n\t//merge squads in same region\n\tfor (int playerId = 0; playerId < 2; playerId++)\n\t{\n\t\tfor (auto it1 = _squad[playerId].begin(); it1 != _squad[playerId].end(); it1++)\n\t\t{\n\t\t\tauto it2 = it1;\n\t\t\tit2++;\n\t\t\tfor (; it2 != _squad[playerId].end(); it2++)\n\t\t\t{\n\t\t\t\tif (it1->getCurrentRegion() == it2->getCurrentRegion())\n\t\t\t\t{\n\t\t\t\t\tfor (auto unit : *it2)\n\t\t\t\t\t{\n\t\t\t\t\t\tit1->addUnit(unit.second);\n\t\t\t\t\t}\n\t\t\t\t\t_squad[playerId].erase(it2);\n\t\t\t\t\tbreak;//todo: this assumes only 2 squads in same region, if there are three, it will merge the first 2 only\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t//assign orders to squads\n\tif ((currentFrame()-lastSquadUpdate)>100)\n\t{\n\t\tlastSquadUpdate = currentFrame();\n\t\tclearOrders();\n\t\tassignDefenseSquads();\n\t\tassignAttackSquads();\n\t}\n\t\t\n\tstd::vector<bool> doneSquads[2] = { std::vector<bool>(_squad[0].size(),false), \n\t\tstd::vector<bool>(_squad[1].size(),false) };\n\n\t//execute orders\n\t\t//if enemy in same region or path\n\t\t\t//do combat\n\tfor (auto &combat : getCombats()){\n\t\tforwardCombat(combat, frames);\n\t\tfor (int s : combat.at(0))\n\t\t{\n\t\t\tdoneSquads[0][s] = true;\n\t\t}\n\t\tfor (int s : combat.at(1))\n\t\t{\n\t\t\tdoneSquads[1][s] = true;\n\t\t}\n\t}\n\n\t\t//move towards destination\n\tfor (int playerId = 0; playerId < 2; playerId++)\n\t{\n\t\tfor (size_t s = 0; s < doneSquads[playerId].size(); s++)\n\t\t{\n\t\t\tif (!doneSquads[playerId][s])\n\t\t\t{\n\t\t\t\t_squad[playerId][s].travel(frames);\n\t\t\t}\n\t\t}\n\t}\n}\n\nstd::vector<HLMove> HLState::getMoves(int playerID, int strategy, const std::unordered_map<short, short> &choices) const\n{\n\tstd::vector<HLMove> moves;\n\ttry{\n\t\tauto goalUnits = StrategyManager::Instance().getBuildOrderGoal(\n\t\t\t_unitData[playerID],\n\t\t\t_unitData[1 - playerID],\n\t\t\t_workerData[playerID],\n\t\t\t_state[playerID].getCurrentFrame(),\n\t\t\tstrategy,\n\t\t\tgetRace(playerID),\n\t\t\tchoices);\n\t\tmoves.push_back(HLMove(strategy, choices));\n\t}\n\tcatch (const ChoicePoint &c){\n\t\tfor (int option = 0; option < c._options; option++){\n\t\t\tauto newChoices = choices;\n\t\t\tnewChoices[c._point] = option;\n\t\t\tauto temp = getMoves(playerID, strategy, newChoices);\n\t\t\tmoves.insert(moves.end(), temp.begin(), temp.end());\n\t\t}\n\t}\n\treturn moves;\n}\nstd::vector<HLMove> HLState::getMoves(int playerID) const\n{\n\tstd::vector<HLMove> moves;\n\t//if (_opening[playerID]){\n\t//\tstd::vector<HLMove> moves;\n\t//\tfor (int s = 0; s < StrategyManager::getNumStrategies(getRace(playerID)); s++)\n\t//\t{\n\t//\t\tmoves.push_back(HLMove(s));\n\t//\t}\n\t//\treturn moves;\n\t//}\n\n\t//for (int s = 0; s < StrategyManager::getNumStrategies(getRace(playerID));s++){\n\t\n\tint s = StrategyManager::ProtossHighLevelSearch; \n\t//auto enemy = BWAPI::Broodwar->enemy();\n\t//if (enemy->getID() == playerID)\n\t//{\n\t//\tif (enemy->getName().compare(\"Skynet\") == 0)\n\t//\t{\n\t//\t\ts=StrategyManager::ProtossDarkTemplar;\n\t//\t}\n\t//\telse if (enemy->getName().compare(\"UAlbertaBot\") == 0)\n\t//\t{\n\t//\t\ts = StrategyManager::ProtossZealotRush;\n\t//\t}\n\t//}\n\n\ttry{\n\t\tauto goalUnits = StrategyManager::Instance().getBuildOrderGoal(\n\t\t\t_unitData[playerID],\n\t\t\t_unitData[1 - playerID],\n\t\t\t_workerData[playerID],\n\t\t\t_state[playerID].getCurrentFrame(),\n\t\t\ts,//strategy\n\t\t\tgetRace(playerID),\n\t\t\tstd::unordered_map<short, short>());\n\t\tmoves.push_back(HLMove(s));\n\t}\n\tcatch (const ChoicePoint &c){\n\t\tfor (int option = 0; option < c._options; option++){\n\t\t\tstd::unordered_map<short, short> choices;\n\t\t\tchoices[c._point] = option;\n\t\t\tauto temp = getMoves(playerID, s, choices);\n\t\t\tmoves.insert(moves.end(), temp.begin(), temp.end());\n\t\t}\n\t}\n\t//}\n\n\treturn moves;\n\n\t////do nothing move\n\t//HLMove move(0);\n\t//for (const auto &s : _squad[playerID]){\n\t//\tmove.addSquad(s);\n\t//}\n\t//moves.push_back(move);\n\n\t////merge squads move\n\t//move= HLMove(0);\n\t//if (_squad[playerID].size() > 1){\n\t//\tfor (int i = 0; i < _squad[playerID].size()-1; i+=2){\n\t//\t\tmove.addSquad(merge(_squad[playerID][i], _squad[playerID][i + 1]));\n\t//\t}\n\t//\tif (_squad[playerID].size() % 2 == 1){\n\t//\t\tmove.addSquad(_squad[playerID].back());\n\t//\t}\n\t//}\n\t//moves.push_back(move);\n\n\t////attack move, just attack first neighbouring region\n\t//move = HLMove(0);\n\t//for (auto &s : _squad[playerID]){\n\t//\tBWAPI::Position pos = (*s.getUnits().front()->getRegion()->getNeighbors().begin())->getCenter();\n\t//\tint radius = 1000;\n\t//\ts.setSquadOrder(SquadOrder(SquadOrder::Attack, pos, radius));\n\t//\tmove.addSquad(s);\n\t//}\n\t//moves.push_back(move);\n\n\t//return moves;\n}\n\n//HLSquad HLState::merge(const HLSquad& s1, const HLSquad &s2)\n//{\n//\tauto units = s1.getUnits();\n//\tauto units2 = s2.getUnits();\n//\tunits.insert(units.end(), units2.begin(),units2.end());\n//\treturn HLSquad(units, s1.getSquadOrder());\n//}\n\nint HLState::evaluate(int playerID) const\n{\n\tif (Options::Modules::USING_COMBAT_PREDICTOR)\n\t{\n\t\treturn CombatPredictor::Instance().predictCombat(_unitData[playerID], _unitData[1 - playerID]);\n\t}\n\n\n\tfloat sum[2] = { 0.0f, 0.0f };\n\tfloat dragFactor = 0.6; \n\tfor (auto &unit : _unitData[playerID].getUnits()){\n\t\tif (unit.second.completed)\n\t\t{\n\t\t//if (unit.second.type==BWAPI::UnitTypes::Protoss_Dark_Templar)\n\t\t//\tsum[playerID] += 1000;\n\t\t\n\t\tsum[playerID] += sqrtf(unit.second.lastHealth) * unit.second.dpf();\n\n\t\t//\tint score = unit.second.type == BWAPI::UnitTypes::Protoss_Dragoon ? unit.second.type.destroyScore() * dragFactor : unit.second.type.destroyScore();\n\t\t//\tsum[playerID] += ((float)unit.second.lastHealth) / unit.second.type.maxHitPoints() * score;\n\t\t}\n\t}\n\n\tfor (auto &unit : _unitData[1 - playerID].getUnits()){\n\t\tif (unit.second.completed)\n\t\t{\n\t\t//if (unit.second.type == BWAPI::UnitTypes::Protoss_Dark_Templar)\n\t\t//\tsum[1-playerID] += 1000;\n\t\t\n\t\tsum[1-playerID] += sqrtf(unit.second.lastHealth) * unit.second.dpf();\n\t\t\n\n\t\t//\tint score = unit.second.type == BWAPI::UnitTypes::Protoss_Dragoon ? unit.second.type.destroyScore() * dragFactor : unit.second.type.destroyScore();\n\t\t//\tsum[1 - playerID] += ((float)unit.second.lastHealth) / unit.second.type.maxHitPoints() * score;\n\t\t}\n\t} \n\n\treturn sum[playerID] - sum[1 - playerID];\n\n\t\n}\n\nbool HLState::gameOver() const\n{\n\treturn false;\n}\n\n\n//HLMove::HLMove(int strategy, const std::vector<HLSquad> &squads) :_strategy(strategy), _squads(squads)\n//{\n//\n//}\n\nHLMove::HLMove(int strategy, const std::unordered_map<short, short> &choices) :_strategy(strategy), _choices(choices)\n{\n\n}\n\nHLMove::HLMove(int strategy) :_strategy(strategy)\n{\n\n}\nHLMove::HLMove() : _strategy(-1)\n{\n\n}\n//void HLMove::addSquad(const HLSquad &squad)\n//{\n//\t_squads.push_back(squad);\n//}\n\nstd::string HLMove::toString() const\n{\n\tstd::ostringstream ss;\n\tss << \"[strat:\"<<_strategy<<\", \";\n\tfor (auto &c : _choices){\n\t\tss << \"[\" << c.first << \", \" << c.second << \"] \";\n\t}\n\tss << \"]\";\n\treturn ss.str();\n}\n\nint HLState::currentFrame() const\n{\n\treturn std::min(_state[0].getCurrentFrame(), _state[1].getCurrentFrame());\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLState.h",
    "content": "#pragma once\n#include \"Common.h\"\n#include \"../../BOSS/source/BOSS.h\"\n#include \"Squad.h\"\n#include \"HLUnitData.h\"\n#include \"HLSquad.h\"\n#include <random>\n#include <array>\n\nnamespace UAlbertaBot{\n\n\tclass HLMove{\n\t\tint _strategy;\t\t\t\t//build order\n\t\tstd::unordered_map<short, short> _choices;\n\t\t//std::vector<HLSquad> _squads;\t//units and their orders\n\t\t//int _frames;\t\t\t\t\t//length of the move\n\tpublic:\n\t\t//HLMove(int strategy, const std::vector<HLSquad> &squads);\n\t\tHLMove(int strategy, const std::unordered_map<short, short> &choices);\n\t\tHLMove(int strategy);\n\t\tHLMove();\n\t\t//void addSquad(const HLSquad &squad);\n\t\t//const std::vector<HLSquad>& getSquads() const{\n\t\t//\treturn _squads;\n\t\t//};\n\t\tconst std::unordered_map<short, short>& getChoices() const{\n\t\t\treturn _choices;\n\t\t};\n\t\tint getStrategy() const{\n\t\t\treturn _strategy;\n\t\t};\n\t\tbool isEmpty() const{ return _strategy == -1; };\n\t\tstd::string toString() const;\n\t\tbool operator==(const HLMove &m) const\n\t\t{\n\t\t\treturn _strategy == m._strategy && _choices == m._choices;\n\t\t}\n\t\t//HLMove& operator=(const HLMove &m)\n\t\t//{\n\t\t//\t_strategy = m._strategy;\n\t\t//\t_choices = m._choices;\n\n\t\t//\treturn *this;\n\t\t//}\n\t};\n\n\n\tclass HLState\n\t{\n\n\t\tBOSS::GameState\t\t\t_state[2];\t\t//includes all we need for the economic part, includes frame\n\t\tstd::vector<HLSquad>\t_squad[2]; //combat units\n\t\tBWAPI::Player\t\t\t_players[2];\n\n\t\tHLUnitData\t\t\t\t_unitData[2];\n\t\tWorkerData\t\t\t\t_workerData[2];\n\n\n\n\t\tstatic unsigned int\t\t\t\t_zobristChoice[20][StrategyManager::NumProtossStrategies][20][10];//10 depth, 5 strategies, 20 choice points, 10 choices each\n\t\tstatic unsigned int\t\t\t\t_zobristStrategy[20][StrategyManager::NumProtossStrategies];\n\n\t\tunsigned int\t\t\t\t\t\t_hash;\n\t\t//bool\t\t\t\t\t_opening[2];\n\t\t//BOSS::BuildOrder\t\t_buildOrder[2];\n\t\t//int\t\t\t\t\t\t_buildOrderIndex[2];\n\t\tint lastSquadUpdate=0;\n\t\tvoid addSquads(const BWAPI::PlayerInterface *player);\n\t\t//static HLSquad merge(const HLSquad& s1, const HLSquad &s2);//merge s2 into s1, keeps order of s1\n\t\t//void forwardGameState(int frames, int playerID);\n\t\tvoid synchronizeNewUnits(int playerID, const std::vector<BOSS::ActionType> &newUnits);\n\t\tvoid synchronizeNewUnits(int playerID, const std::vector<BOSS::ActionType> &newUnits, const BOSS::ActionType &startedUnit);\n\t\tvoid synchronizeDeadUnits(const std::array<std::vector<UnitInfo>, 2> &units);\n\t\tBOSS::BuildOrder getBuildOrder(const HLMove &move, int playerID) const;\n\t\tbool checkChoicePoint(const HLMove &move, int playerID) const;\n\t\tvoid forwardSquads(int frames);\n\t\tvoid assignDefenseSquads();\n\t\tvoid assignAttackSquads();\n\t\tvoid forwardCombat(const std::array<std::vector<int>, 2 > &squads, int frames);\n\t\tBWTA::BaseLocation * getClosestBaseLocation(int playerId, BWTA::Region *r) const;\n\t\tint getClosestUnassignedSquad(int playerId, const BWTA::Region *r, const std::vector<bool> skip);\n\t\tHLSquad & getUnassignedSquad(int playerId);\n\t\tvoid clearOrders();\n\t\tstd::vector<std::array<std::vector<int>, 2 > > getCombats() const;\n\t\tvoid addNewUnitToSquad(const UnitInfo &newUnit);\n\t\tstd::vector<HLMove> getMoves(int playerID, int strategy, const std::unordered_map<short, short> &choices) const;\n\n\tpublic:\n\t\tHLState(){}\n\t\tHLState(BWAPI::GameWrapper & game, BWAPI::PlayerInterface * player, BWAPI::PlayerInterface * enemy);\n\t\t~HLState();\n\n\t\tstd::vector<HLState> getChildren() const;\n\t\tstd::vector<HLMove> getMoves(int playerID) const;\n\t\tvoid applyAndForward(int depth, int frames, const std::array<HLMove, 2> &moves);\n\t\tint evaluate(int playerID) const;\n\t\tbool gameOver() const;\n\t\tfriend class HLSearch;\n\t\tint currentFrame() const;\n\t\tBWAPI::Race getRace(int playerID) const{\n\t\t\treturn BOSS::Races::GetRace(_state[playerID].getRace());\n\t\t};\n\t\t//bool undecidedChoicePoint(int playerID, int strategy, const std::unordered_map<short, short> choices) const;\n\t\t//void HLState::doAction(int playerID, const BOSS::ActionType action);\n\t\tstatic bool HLState::isNonWorkerCombatUnit(const BWAPI::UnitInterface *unit);\n\t\tstatic bool HLState::isNonWorkerCombatUnit(const UnitInfo &unit);\n\t\tunsigned int getHash(int depth, const std::array < HLMove, 2 >  &moves) const\n\t\t{\n\t\t\tunsigned int hash = _hash;\n\t\t\tfor (int p = 0; p < 2; p++)\n\t\t\t{\n\t\t\t\thash ^= _zobristStrategy[depth-p][moves.at(p).getStrategy()];\n\t\t\t\tfor (auto c : moves.at(p).getChoices())\n\t\t\t\t{\n\t\t\t\t\thash ^= _zobristChoice[depth - p][moves.at(p).getStrategy()][c.first][c.second];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn hash;\n\t\t}\n\t\tunsigned int getHash(int depth, const HLMove  &move) const\n\t\t{\n\t\t\tunsigned int hash = _hash;\n\t\t\thash ^= _zobristStrategy[depth][move.getStrategy()];\n\t\t\tfor (auto c : move.getChoices())\n\t\t\t{\n\t\t\t\thash ^= _zobristChoice[depth][move.getStrategy()][c.first][c.second];\n\t\t\t}\n\n\t\t\treturn hash;\n\t\t}\n\t\tunsigned int getHash() const { return _hash; }\n\t//\tfriend struct _dummy_static_initializer;\n\t};\n\n\t//struct _dummy_static_initializer{\n\t//\t_dummy_static_initializer(){\n\t//\t\tstd::mt19937 rng(1);//todo:use a seed?\n\t//\t\tfor (int depth = 0; depth < 10; depth++){\n\t//\t\t\tfor (int s = 0; s < 5; s++){\n\t//\t\t\t\tHLState::_zobristStrategy[depth][s] = rng();\n\t//\t\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"\\n\");\n\t//\t\t\t\tfor (int point = 0; point < 20; point++){\n\t//\t\t\t\t\tfor (auto c = 0; c < 10; c++){\n\t//\t\t\t\t\t\tHLState::_zobristChoice[depth][s][point][c] = rng();\n\t//\t\t\t\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"%u \", HLState::_zobristChoice[depth][s][point][c]);\n\t//\t\t\t\t\t}\n\t//\t\t\t\t}\n\t//\t\t\t}\n\t//\t\t}\n\t//\t}\n\t//};\n\n\t\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLStatistics.cpp",
    "content": "#include \"HLStatistics.h\"\n\nusing namespace UAlbertaBot;\n\nHLStatistics::~HLStatistics()\n{\n}\nHLStatistics::HLStatistics() {\n\t// TODO Auto-generated constructor stub\n\tclear();\n}\n\nstd::string HLStatistics::toString() const{\n\tchar buff[80];\n\tsprintf_s(buff, 80, \"%6.3f [%10d %.2e %5d %5d %5d %5d %5.3f %5.1f]\",\n\t\tgetRunningTimeMilliSecs() / 1000.0,\n\t\tgetNodeCount(),\n\t\tgetNodesSec(),\n\t\tgetTTqueries(),\n\t\tgetTTfound(),\n\t\tgetCacheQueries(),\n\t\tgetCacheFound(),\n\t\tgetAvgBf(),\n\t\tgetAvgFwd());\n\treturn buff;\n}\nstd::string HLStatistics::header() const {\n\treturn \"Time       nodes    nodes/sec TtQ\tTtF\tCacheQ\tCacheF  AvgBF\tAvgFwd\";\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLStatistics.h",
    "content": "#pragma once\n#include <chrono>\n#include <string>\n\nnamespace UAlbertaBot{\n\tclass HLStatistics\n\t{\n\tprivate:\n\t\tstd::chrono::time_point<std::chrono::high_resolution_clock>  startTime;\n\t\tint nodeCount;\n\t\tint TTqueries;\n\t\tint TTfound;\n\t\tint cacheQueries;\n\t\tint cacheFound;\n\t\tint branches;\n\t\tint searches;\n\t\t//int hashCol;\n\t\tint forwardLength;\n\t\tint numForwards;\n\tpublic:\n\t\tHLStatistics();\n\t\tvoid clear(){\n\t\t\tnodeCount = 0;\n\t\t\tTTqueries = 0;\n\t\t\tTTfound = 0;\n\t\t\tcacheQueries = 0;\n\t\t\tcacheFound = 0;\n\t\t\tbranches = 0;\n\t\t\tsearches = 0;\n\t\t\tforwardLength = 0;\n\t\t\tnumForwards = 0;\n\t\t}\n\n\t\tvoid startTimer(){\n\t\t\tstartTime = std::chrono::high_resolution_clock::now();\n\t\t}\n\t\tlong long getRunningTimeSecs() const{\n\t\t\treturn  std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() - startTime).count();\n\t\t}\n\t\tlong long getRunningTimeMilliSecs() const{\n\t\t\treturn  std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startTime).count();\n\t\t}\n\n\t\tvoid incNodeCount(){\n\t\t\tnodeCount++;\n\t\t}\n\t\tint getNodeCount() const{\n\t\t\treturn nodeCount;\n\t\t}\n\t\tdouble getNodesSec() const{\n\t\t\treturn ((float)nodeCount) / getRunningTimeMilliSecs()*1000.0;\n\t\t}\n\t\tvoid incTTquery(){\n\t\t\tTTqueries++;\n\t\t}\n\t\tint getTTqueries() const{\n\t\t\treturn TTqueries;\n\t\t}\n\t\tvoid incTTfound(){\n\t\t\tTTfound++;\n\t\t}\n\t\tint getTTfound() const{\n\t\t\treturn TTfound;\n\t\t}\n\t\tvoid incCacheQuery(){\n\t\t\tcacheQueries++;\n\t\t}\n\t\tint getCacheQueries() const{\n\t\t\treturn cacheQueries;\n\t\t}\n\t\tvoid incCacheFound(){\n\t\t\tcacheFound++;\n\t\t}\n\t\tint getCacheFound() const{\n\t\t\treturn cacheFound;\n\t\t}\n\n\t\tvoid addFwd(int length){\n\t\t\tforwardLength += length;\n\t\t\tnumForwards++;\n\t\t}\n\t\tvoid addBF(int nodesSearched){\n\t\t\tsearches++;\n\t\t\tbranches += nodesSearched;\n\t\t}\n\t\tfloat getAvgBf() const{\n\n\t\t\treturn searches>0?((float)branches) / searches:-1.0f;\n\t\t}\n\t\tfloat getAvgFwd() const{\n\n\t\t\treturn numForwards>0 ? ((float)forwardLength) / numForwards : -1.0f;\n\t\t}\n\t\tstd::string toString() const;\n\t\tstd::string header() const;\n\n\t\t~HLStatistics();\n\t};\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLStrategyManager.cpp",
    "content": "#include \"Common.h\"\n#include \"StrategyManager.h\"\n\nusing namespace UAlbertaBot;\n\nstd::unordered_map<int, std::unordered_map<int, std::unordered_map<short, short> > > StrategyManager::defaultStrategyChoices;\n// constructor\nStrategyManager::StrategyManager() \n\t: firstAttackSent(false)\n\t, currentStrategy(0)\n\t, selfRace(BWAPI::Broodwar->self()->getRace())\n\t, enemyRace(BWAPI::Broodwar->enemy()->getRace())\n{\n\taddStrategies();\n\tsetStrategy();\n}\n\n// get an instance of this\nStrategyManager & StrategyManager::Instance() \n{\n\tstatic StrategyManager instance;\n\treturn instance;\n}\n\nvoid StrategyManager::addStrategies() \n{\n\t\n\n\t////protossOpeningBook[ProtossZealotRush]\t= \"0 0 0 0 1 0 0 3 0 0 3 0 1 3 0 4 4 4 4 4 1 0 4 4 4\";\n //   protossOpeningBook[ProtossZealotRush]\t= \"0 0 0 0 1 0 3 3 0 0 4 1 4 4 0 4 4 0 1 4 3 0 1 0 4 0 4 4 4 4 1 0 4 4 4\";\n\t////protossOpeningBook[ProtossZealotRush]\t= \"0\";\n\t////protossOpeningBook[ProtossDarkTemplar]\t= \"0 0 0 0 1 3 0 7 5 0 0 12 3 13 0 22 22 22 22 0 1 0\";\n //   protossOpeningBook[ProtossDarkTemplar]\t=     \"0 0 0 0 1 0 3 0 7 0 5 0 12 0 13 3 22 22 1 22 22 0 1 0\";\n\t//protossOpeningBook[ProtossDragoons]\t\t= \"0 0 0 0 1 0 0 3 0 7 0 0 5 0 0 3 8 6 1 6 6 0 3 1 0 6 6 6\";\n\t//terranOpeningBook[TerranMarineRush]\t\t= \"0 0 0 0 0 1 0 0 3 0 0 3 0 1 0 4 0 0 0 6\";\n\t//zergOpeningBook[ZergZerglingRush]\t\t= \"0 0 0 0 0 1 0 0 0 2 3 5 0 0 0 0 0 0 1 6\";\n\n\tif (selfRace == BWAPI::Races::Protoss)\n\t{\n\t\tresults = std::vector<IntPair>(NumProtossStrategies);\n\n\t\tif (enemyRace == BWAPI::Races::Protoss)\n\t\t{\n\t\t\tusableStrategies.push_back(ProtossZealotRush);\n\t\t\tusableStrategies.push_back(ProtossDarkTemplar);\n\t\t\tusableStrategies.push_back(ProtossDragoons);\n\t\t}\n\t\telse if (enemyRace == BWAPI::Races::Terran)\n\t\t{\n\t\t\tusableStrategies.push_back(ProtossZealotRush);\n\t\t\tusableStrategies.push_back(ProtossDarkTemplar);\n\t\t\tusableStrategies.push_back(ProtossDragoons);\n\t\t}\n\t\telse if (enemyRace == BWAPI::Races::Zerg)\n\t\t{\n\t\t\tusableStrategies.push_back(ProtossZealotRush);\n\t\t\tusableStrategies.push_back(ProtossDragoons);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tBWAPI::Broodwar->printf(\"Enemy Race Unknown\");\n\t\t\tusableStrategies.push_back(ProtossZealotRush);\n\t\t\tusableStrategies.push_back(ProtossDragoons);\n\t\t}\n\t}\n\telse if (selfRace == BWAPI::Races::Terran)\n\t{\n\t\tresults = std::vector<IntPair>(NumTerranStrategies);\n\t\tusableStrategies.push_back(TerranMarineRush);\n\t}\n\telse if (selfRace == BWAPI::Races::Zerg)\n\t{\n\t\tresults = std::vector<IntPair>(NumZergStrategies);\n\t\tusableStrategies.push_back(ZergZerglingRush);\n\t}\n\n\tif (Options::Modules::USING_STRATEGY_IO)\n\t{\n\t\treadResults();\n\t}\n}\n\nvoid StrategyManager::readResults()\n{\n\t// read in the name of the read and write directories from settings file\n\tstruct stat buf;\n\n\t// if the file doesn't exist something is wrong so just set them to default settings\n\tif (stat(Options::FileIO::FILE_SETTINGS, &buf) == -1)\n\t{\n\t\treadDir = \"bwapi-data/testio/read/\";\n\t\twriteDir = \"bwapi-data/testio/write/\";\n\t}\n\telse\n\t{\n\t\tstd::ifstream f_in(Options::FileIO::FILE_SETTINGS);\n\t\tgetline(f_in, readDir);\n\t\tgetline(f_in, writeDir);\n\t\tf_in.close();\n\t}\n\n\t// the file corresponding to the enemy's previous results\n\tstd::string readFile = readDir + BWAPI::Broodwar->enemy()->getName() + \".txt\";\n\n\t// if the file doesn't exist, set the results to zeros\n\tif (stat(readFile.c_str(), &buf) == -1)\n\t{\n\t\tstd::fill(results.begin(), results.end(), IntPair(0,0));\n\t}\n\t// otherwise read in the results\n\telse\n\t{\n\t\tstd::ifstream f_in(readFile.c_str());\n\t\tstd::string line;\n\t\tgetline(f_in, line);\n\t\tresults[ProtossZealotRush].first = atoi(line.c_str());\n\t\tgetline(f_in, line);\n\t\tresults[ProtossZealotRush].second = atoi(line.c_str());\n\t\tgetline(f_in, line);\n\t\tresults[ProtossDarkTemplar].first = atoi(line.c_str());\n\t\tgetline(f_in, line);\n\t\tresults[ProtossDarkTemplar].second = atoi(line.c_str());\n\t\tgetline(f_in, line);\n\t\tresults[ProtossDragoons].first = atoi(line.c_str());\n\t\tgetline(f_in, line);\n\t\tresults[ProtossDragoons].second = atoi(line.c_str());\n\t\tf_in.close();\n\t}\n\n\tBWAPI::Broodwar->printf(\"Results (%s): (%d %d) (%d %d) (%d %d)\", BWAPI::Broodwar->enemy()->getName().c_str(), \n\t\tresults[0].first, results[0].second, results[1].first, results[1].second, results[2].first, results[2].second);\n}\n\nvoid StrategyManager::writeResults()\n{\n\tstd::string writeFile = writeDir + BWAPI::Broodwar->enemy()->getName() + \".txt\";\n\tstd::ofstream f_out(writeFile.c_str());\n\n\tf_out << results[ProtossZealotRush].first   << \"\\n\";\n\tf_out << results[ProtossZealotRush].second  << \"\\n\";\n\tf_out << results[ProtossDarkTemplar].first  << \"\\n\";\n\tf_out << results[ProtossDarkTemplar].second << \"\\n\";\n\tf_out << results[ProtossDragoons].first     << \"\\n\";\n\tf_out << results[ProtossDragoons].second    << \"\\n\";\n\n\tf_out.close();\n}\n\nvoid StrategyManager::setStrategy()\n{\n\t// if we are using file io to determine strategy, do so\n\tif (Options::Modules::USING_STRATEGY_IO)\n\t{\n\t\tdouble bestUCB = -1;\n\t\tint bestStrategyIndex = 0;\n\n\t\t// UCB requires us to try everything once before using the formula\n\t\tfor (size_t strategyIndex(0); strategyIndex<usableStrategies.size(); ++strategyIndex)\n\t\t{\n\t\t\tint sum = results[usableStrategies[strategyIndex]].first + results[usableStrategies[strategyIndex]].second;\n\n\t\t\tif (sum == 0)\n\t\t\t{\n\t\t\t\tcurrentStrategy = usableStrategies[strategyIndex];\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// if we have tried everything once, set the maximizing ucb value\n\t\tfor (size_t strategyIndex(0); strategyIndex<usableStrategies.size(); ++strategyIndex)\n\t\t{\n\t\t\tdouble ucb = getUCBValue(usableStrategies[strategyIndex]);\n\n\t\t\tif (ucb > bestUCB)\n\t\t\t{\n\t\t\t\tbestUCB = ucb;\n\t\t\t\tbestStrategyIndex = strategyIndex;\n\t\t\t}\n\t\t}\n\t\t\n\t\tcurrentStrategy = usableStrategies[bestStrategyIndex];\n\t}\n\telse if (Options::Modules::USING_HIGH_LEVEL_SEARCH)\n\t{\n\t\tcurrentStrategy = ProtossHighLevelSearch;\n\t\tdefaultStrategyChoices[BWAPI::Races::Protoss.getID()][ProtossHighLevelSearch][0] = 0;\n\t\tdefaultStrategyChoices[BWAPI::Races::Protoss.getID()][ProtossHighLevelSearch][1] = 0;\n\t\tdefaultStrategyChoices[BWAPI::Races::Protoss.getID()][ProtossHighLevelSearch][2] = 0;\n\t\tstrategyChoices[BWAPI::Races::Protoss.getID()][ProtossHighLevelSearch];//to create the empty map\n\t}\n\telse\n\t{\n\t\t// otherwise return a random strategy\n\n        std::string enemyName(BWAPI::Broodwar->enemy()->getName());\n        \n        if (enemyName.compare(\"Skynet\") == 0)\n        {\n            currentStrategy = ProtossDarkTemplar;\n        }\n        else\n        {\n            currentStrategy = ProtossZealotRush;\n        }\n\t}\n\n}\n\nvoid StrategyManager::onEnd(const bool isWinner)\n{\n\t// write the win/loss data to file if we're using IO\n\tif (Options::Modules::USING_STRATEGY_IO)\n\t{\n\t\t// if the game ended before the tournament time limit\n\t\tif (BWAPI::Broodwar->getFrameCount() < Options::Tournament::GAME_END_FRAME)\n\t\t{\n\t\t\tif (isWinner)\n\t\t\t{\n\t\t\t\tresults[getCurrentStrategy()].first = results[getCurrentStrategy()].first + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresults[getCurrentStrategy()].second = results[getCurrentStrategy()].second + 1;\n\t\t\t}\n\t\t}\n\t\t// otherwise game timed out so use in-game score\n\t\telse\n\t\t{\n\t\t\tif (getScore(BWAPI::Broodwar->self()) > getScore(BWAPI::Broodwar->enemy()))\n\t\t\t{\n\t\t\t\tresults[getCurrentStrategy()].first = results[getCurrentStrategy()].first + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresults[getCurrentStrategy()].second = results[getCurrentStrategy()].second + 1;\n\t\t\t}\n\t\t}\n\t\t\n\t\twriteResults();\n\t}\n}\n\nconst double StrategyManager::getUCBValue(const size_t & strategy) const\n{\n\tdouble totalTrials(0);\n\tfor (size_t s(0); s<usableStrategies.size(); ++s)\n\t{\n\t\ttotalTrials += results[usableStrategies[s]].first + results[usableStrategies[s]].second;\n\t}\n\n\tdouble C\t\t= 0.7;\n\tdouble wins\t\t= results[strategy].first;\n\tdouble trials\t= results[strategy].first + results[strategy].second;\n\n\tdouble ucb = (wins / trials) + C * sqrt(std::log(totalTrials) / trials);\n\n\treturn ucb;\n}\n\nconst int StrategyManager::getScore(BWAPI::PlayerInterface * player) const\n{\n\treturn player->getBuildingScore() + player->getKillScore() + player->getRazingScore() + player->getUnitScore();\n}\n\n\nstd::vector<MetaType>\tStrategyManager::getOpeningBookBuildOrder(int strategy, BWAPI::Race race)\n{\n\tif (race == BWAPI::Races::Protoss)\n\t{\n\t\tif (strategy == ProtossZealotRush)\n\t\t{\n\t\t\treturn OpeningBuildOrders::ProtossZealotRush();\n\t\t}\n\t\telse if (strategy == ProtossDragoons)\n\t\t{\n\t\t\treturn OpeningBuildOrders::ProtossDragoonRush();\n\t\t}\n\t\telse if (strategy == ProtossDarkTemplar)\n\t\t{\n\t\t\treturn OpeningBuildOrders::ProtossDarkTemplarRush();\n\t\t}\n\t\telse if (strategy == ProtossHighLevelSearch)\n\t\t{\n\t\t\treturn OpeningBuildOrders::ProtossHighLevelSearch();\n\t\t}\n\n\t}\n\telse if (race == BWAPI::Races::Terran)\n\t{\n\t\tif (strategy == TerranMarineRush)\n\t\t{\n\t\t\treturn OpeningBuildOrders::TerranMarineRush();\n\t\t}\n\t}\n\telse if (race == BWAPI::Races::Zerg)\n\t{\n\t\tif (strategy == ZergZerglingRush)\n\t\t{\n\t\t\treturn OpeningBuildOrders::TerranMarineRush();\n\t\t}\n\t}\n\n\t// something wrong, return the protoss one\n\tBWAPI::Broodwar->printf(\"Strategy not found, returning empty initial build order\");\n\treturn std::vector<MetaType>();\n}\nconst std::vector<MetaType> StrategyManager::getOpeningBookBuildOrder() const\n{\n\treturn getOpeningBookBuildOrder(currentStrategy, selfRace);\n}\n\n// when do we want to defend with our workers?\n// this function can only be called if we have no fighters to defend with\nconst int StrategyManager::defendWithWorkers()\n{\n\tif (!Options::Micro::WORKER_DEFENSE)\n\t{\n\t\treturn false;\n\t}\n\n\t// our home nexus position\n\tBWAPI::Position homePosition = BWTA::getStartLocation(BWAPI::Broodwar->self())->getPosition();;\n\n\t// enemy units near our workers\n\tint enemyUnitsNearWorkers = 0;\n\n\t// defense radius of nexus\n\tint defenseRadius = 300;\n\n\t// fill the set with the types of units we're concerned about\n\tfor (BWAPI::UnitInterface * unit : BWAPI::Broodwar->enemy()->getUnits())\n\t{\n\t\t// if it's a zergling or a worker we want to defend\n\t\tif (unit->getType() == BWAPI::UnitTypes::Zerg_Zergling)\n\t\t{\n\t\t\tif (unit->getDistance(homePosition) < defenseRadius)\n\t\t\t{\n\t\t\t\tenemyUnitsNearWorkers++;\n\t\t\t}\n\t\t}\n\t}\n\n\t// if there are enemy units near our workers, we want to defend\n\treturn enemyUnitsNearWorkers;\n}\n\n// called by combat commander to determine whether or not to send an attack force\n// freeUnits are the units available to do this attack\nconst bool StrategyManager::doAttack(const std::set<BWAPI::UnitInterface*> & freeUnits)\n{\n\tint ourForceSize = (int)freeUnits.size();\n\n\tint numUnitsNeededForAttack = 1;\n\n\tbool doAttack  = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Dark_Templar) >= 1\n\t\t\t\t\t|| ourForceSize >= numUnitsNeededForAttack;\n\n\tif (doAttack)\n\t{\n\t\tfirstAttackSent = true;\n\t}\n\n\treturn doAttack || firstAttackSent;\n}\n\nconst bool StrategyManager::expandProtossZealotRush() const\n{\n\treturn expandProtossZealotRush(\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()),\n\t\tWorkerManager::Instance().getData(),\n\t\tBWAPI::Broodwar->getFrameCount());\n}\n\nbool StrategyManager::expandProtossZealotRush(const HLUnitData &unitData, const WorkerData &selfWorkerData, int frame, \n\tint frameAdjust, int zealotAdjust)\n{\n\t// if there is no place to expand to, we can't expand\n\tif (MapTools::Instance().getNextExpansion(unitData.player()) == BWAPI::TilePositions::None)\n\t{\n\t\treturn false;\n\t}\n\n\tint numNexus = unitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus);\n\tint numZealots = unitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Zealot);\n\n\n\t// if there are more than 10 idle workers, expand\n\tif (selfWorkerData.getNumIdleWorkers() > 10)\n\t{\n\t\treturn true;\n\t}\n\n\t// 2nd Nexus Conditions:\n\t//\t\tWe have 12 or more zealots\n\t//\t\tIt is past frame 7000\n\tif ((numNexus < 2) && (numZealots >(12 + zealotAdjust) || frame  > (9000 + frameAdjust)))\n\t{\n\t\treturn true;\n\t}\n\n\t// 3nd Nexus Conditions:\n\t//\t\tWe have 24 or more zealots\n\t//\t\tIt is past frame 12000\n\tif ((numNexus < 3) && (numZealots >(24 + zealotAdjust) || frame  > (15000 + frameAdjust)))\n\t{\n\t\treturn true;\n\t}\n\n\tif ((numNexus < 4) && (numZealots >(24 + zealotAdjust) || frame  > (21000 + frameAdjust)))\n\t{\n\t\treturn true;\n\t}\n\n\tif ((numNexus < 5) && (numZealots >(24 + zealotAdjust) || frame  > (26000 + frameAdjust)))\n\t{\n\t\treturn true;\n\t}\n\n\tif ((numNexus < 6) && (numZealots >(24 + zealotAdjust) || frame  > (30000 + frameAdjust)))\n\t{\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nconst MetaPairVector StrategyManager::getBuildOrderGoal()\n{\n\tif (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Protoss)\n\t{\n\t\tif (getCurrentStrategy() == ProtossZealotRush)\n\t\t{\n\t\t\treturn getProtossZealotRushBuildOrderGoal();\n\t\t}\n\t\telse if (getCurrentStrategy() == ProtossDarkTemplar)\n\t\t{\n\t\t\treturn getProtossDarkTemplarBuildOrderGoal();\n\t\t}\n\t\telse if (getCurrentStrategy() == ProtossDragoons)\n\t\t{\n\t\t\treturn getProtossDragoonsBuildOrderGoal();\n\t\t}\n\t\telse if (getCurrentStrategy() == ProtossHighLevelSearch)\n\t\t{\n\t\t\treturn getProtossHighLevelSearchBuildOrderGoal();\n\t\t}\n\t\t// if something goes wrong, use zealot goal\n\t\treturn getProtossZealotRushBuildOrderGoal();\n\t}\n\telse if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran)\n\t{\n\t\treturn getTerranBuildOrderGoal();\n\t}\n\telse\n\t{\n\t\treturn getZergBuildOrderGoal();\n\t}\n}\n\nMetaPairVector StrategyManager::getBuildOrderGoal(\n\tconst HLUnitData &selfUnitData,\n\tconst HLUnitData &enemyUnitData,\n\tconst WorkerData &selfWorkerData,\n\tint frame,\n\tint strategy,\n\tBWAPI::Race race,\n\tconst std::unordered_map<short, short> &choices)\n{\n\tif (race == BWAPI::Races::Protoss)\n\t{\n\t\tswitch (strategy){\n\t\tcase ProtossZealotRush:\n\t\t\treturn getProtossZealotRushBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame);\n\t\t\tbreak;\n\t\tcase ProtossDarkTemplar:\n\t\t\treturn getProtossDarkTemplarBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame);\n\t\t\tbreak;\n\t\tcase ProtossDragoons:\n\t\t\treturn getProtossDragoonsBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame);\n\t\t\tbreak;\n\t\tcase ProtossHighLevelSearch:\n\t\t\treturn getProtossHighLevelSearchBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame, choices, false);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tUAB_ASSERT(false,\"Non existing Protoss strategy %d, using default\", strategy);\n\t\t\t//return getProtossZealotRushBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame, choices);\n\t\t\tbreak;\n\t\t}\n\t}\n\telse if (race == BWAPI::Races::Terran){\n\t\tswitch (strategy){\n\t\tcase TerranMarineRush:\n\t\t\treturn getTerranBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tBWAPI::Broodwar->printf(\"Non existing Terran strategy %d, using default\", strategy);\n\t\t\treturn getTerranBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame);\n\t\t\tbreak;\n\t\t}\n\t}\n\telse if (race == BWAPI::Races::Zerg){\n\t\tswitch (strategy){\n\t\tcase ZergZerglingRush:\n\t\t\treturn getZergBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tBWAPI::Broodwar->printf(\"Non existing Zerg strategy %d, using default\", strategy);\n\t\t\treturn getZergBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame);\n\t\t\tbreak;\n\t\t}\n\t}\n\telse{\n\t\tUAB_ASSERT(false, \"Unknown race when selecting strategy\");\n\t\treturn MetaPairVector();//to silence warning\n\t}\n}\n\nconst MetaPairVector StrategyManager::getProtossDragoonsBuildOrderGoal() const\n{\n\treturn getProtossDragoonsBuildOrderGoal(\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()),\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()),\n\t\tWorkerManager::Instance().getData(),\n\t\tBWAPI::Broodwar->getFrameCount());\n}\n\nMetaPairVector StrategyManager::getProtossDragoonsBuildOrderGoal(\n\tconst HLUnitData &selfUnitData,\n\tconst HLUnitData &enemyUnitData,\n\tconst WorkerData &selfWorkerData,\n\tint frame)\n{\n\t\t// the goal to return\n\tMetaPairVector goal;\n\n\tint numDragoons =\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dragoon);\n\tint numProbes =\t\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Probe);\n\tint numNexusCompleted =\t\tselfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Nexus);\n\tint numNexusAll =\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus);\n\tint numCyber =\t\t\t\tselfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Cybernetics_Core);\n\tint numCannon =\t\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon);\n\n\tint dragoonsWanted = numDragoons > 0 ? numDragoons + 6 : 2;\n\n\tif (enemyUnitData.hasCloakedUnits())\n\t{\n\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1));\n\t\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1));\n\t\t}\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1));\n\t\t}\n\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n\t\t}\n\t}\n\n\tif (expandProtossZealotRush(selfUnitData,selfWorkerData,frame))\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1));\n\t}\n\n\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon,\tdragoonsWanted));\n\t//goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Gateway,\tgatewayWanted));\n\t//goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Probe,\tstd::min(90, probesWanted)));\n\n\treturn goal;\n}\n\nconst MetaPairVector StrategyManager::getProtossDarkTemplarBuildOrderGoal() const\n{\n\treturn getProtossDarkTemplarBuildOrderGoal(\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()),\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()),\n\t\tWorkerManager::Instance().getData(),\n\t\tBWAPI::Broodwar->getFrameCount());\n}\n\nMetaPairVector StrategyManager::getProtossDarkTemplarBuildOrderGoal(\n\tconst HLUnitData &selfUnitData,\n\tconst HLUnitData &enemyUnitData,\n\tconst WorkerData &selfWorkerData,\n\tint frame)\n{\n\t// the goal to return\n\tMetaPairVector goal;\n\n\tint numDarkTemplar =\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dark_Templar);\n\tint numDragoons =\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dragoon);\n\tint numProbes =\t\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Probe);\n\tint numNexusCompleted =\t\tselfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Nexus);\n\tint numNexusAll =\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus);\n\tint numCyber =\t\t\t\tselfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Cybernetics_Core);\n\tint numCannon =\t\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon);\n\n\tint darkTemplarWanted = 4;\n\tint dragoonsWanted = numDragoons + 6;\n\n\n\n\tif (enemyUnitData.hasCloakedUnits())\n\t{\n\t\t\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1));\n\t\t\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1));\n\t\t}\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n\t\t}\n\t}\n\n\tif (numNexusAll >= 2 || frame > 9000)\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1));\n\t}\n\n\tif (numDragoons > 0)\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UpgradeTypes::Singularity_Charge, 1));\n\t}\n\n\tif (numNexusCompleted >= 3)\n\t{\n\t\tdragoonsWanted = numDragoons + 6;\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n\t}\n\n\tif (expandProtossZealotRush(selfUnitData, selfWorkerData, frame))\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1));\n\t}\n\n\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon,\tdragoonsWanted));\n\tif (numDarkTemplar < darkTemplarWanted)\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dark_Templar, darkTemplarWanted));\n\t}\n\t\n\treturn goal;\n}\n\nconst MetaPairVector StrategyManager::getProtossZealotRushBuildOrderGoal() const\n{\n\treturn getProtossZealotRushBuildOrderGoal(\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()),\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()),\n\t\tWorkerManager::Instance().getData(),\n\t\tBWAPI::Broodwar->getFrameCount());\n}\n\nMetaPairVector StrategyManager::getProtossZealotRushBuildOrderGoal(\n\tconst HLUnitData &selfUnitData,\n\tconst HLUnitData &enemyUnitData,\n\tconst WorkerData &selfWorkerData,\n\tint frame)\n{\n\t// the goal to return\n\tMetaPairVector goal;\n\n\tint numZealots = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Zealot);\n\tint numDragoons = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dragoon);\n\tint numProbes = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Probe);\n\tint numNexusCompleted = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Nexus);\n\tint numNexusAll = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus);\n\tint numCyber = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Cybernetics_Core);\n\tint numCannon = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon);\n\n\tint zealotsWanted = numZealots + 8;\n\tint dragoonsWanted = numDragoons;\n\n\tif (enemyUnitData.hasCloakedUnits())\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1));\n\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1));\n\t\t}\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n\t\t}\n\t}\n\n\tif (numNexusAll >= 2 || frame > 9000)\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Assimilator, 1));\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Cybernetics_Core, 1));\n\t}\n\n\tif (numCyber > 0)\n\t{\n\t\tdragoonsWanted = numDragoons + 2;\n\t\tgoal.push_back(MetaPair(BWAPI::UpgradeTypes::Singularity_Charge, 1));\n\t}\n\n\tif (numNexusCompleted >= 3)\n\t{\n\t\tdragoonsWanted = numDragoons + 6;\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n\t}\n\n\tif (expandProtossZealotRush(selfUnitData, selfWorkerData, frame))\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1));\n\t}\n\n\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, dragoonsWanted));\n\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, zealotsWanted));\n\n\treturn goal;\n}\n\nconst MetaPairVector StrategyManager::getProtossHighLevelSearchBuildOrderGoal() const\n{\n\treturn getProtossHighLevelSearchBuildOrderGoal(\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()),\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()),\n\t\tWorkerManager::Instance().getData(),\n\t\tBWAPI::Broodwar->getFrameCount(),\n\t\tstrategyChoices.at(BWAPI::Races::Protoss.getID()).at(ProtossHighLevelSearch),\n\t\ttrue);\n}\n\nMetaPairVector StrategyManager::getProtossHighLevelSearchBuildOrderGoal(\n\tconst HLUnitData &selfUnitData,\n\tconst HLUnitData &enemyUnitData,\n\tconst WorkerData &selfWorkerData,\n\tint frame,\n\tconst std::unordered_map<short, short> &choices,\n\tbool execution)\n{\n\t// the goal to return\n\tMetaPairVector goal;\n\n\tint numZealots = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Zealot);\n\tint numDragoons = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dragoon);\n\tint numProbes = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Probe);\n\tint numNexusCompleted = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Nexus);\n\tint numNexusAll = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus);\n\tint numCyber = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Cybernetics_Core);\n\tint numCannon = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon);\n\tint numDarkTemplar = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dark_Templar);\n\n\tint zealotsWanted = numZealots;\n\tint dragoonsWanted = numDragoons;\n\tint darkTemplarWanted = numDarkTemplar;\n\n\t//dragoons or zealots\n\tint choice = defaultStrategyChoices.at(BWAPI::Races::Protoss.getID()).at(ProtossHighLevelSearch).at(0);\n\tif (choices.find(0) == choices.end() )\n\t{\n\t\tif (!execution)\n\t\t{\n\t\t\tthrow ChoicePoint(0, 4);\n\t\t}\n\t}\n\telse\n\t{\n\t\tchoice = choices.at(0);\n\t}\n\tswitch (choice){\n\tcase 0:\n\t\tzealotsWanted += 8;\n\t\tbreak;\n\tcase 1:\n\t\tdragoonsWanted += 6;\n\t\tbreak;\n\tcase 2:\n\t\tzealotsWanted += 4;\n\t\tdragoonsWanted += 3; \n\t\tbreak;\n\tcase 3:\n\t\tdarkTemplarWanted = 4;\n\t\tif (numDarkTemplar >= 3)\n\t\t{\n\t\t\tdragoonsWanted += 6;\n\t\t\t//darkTemplarWanted = numDarkTemplar + 1;\n\t\t} \n\t\tbreak;\n\tdefault:\n\t\tUAB_ASSERT(false, \"Wrong choice point option\");\n\t}\n\n\tif (numDragoons < dragoonsWanted) goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, dragoonsWanted));\n\tif (numZealots < zealotsWanted) goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, zealotsWanted));\n\tif (numDarkTemplar < darkTemplarWanted) goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dark_Templar, darkTemplarWanted));\n\n\tif (enemyUnitData.hasCloakedUnits())\n\t{\n\t\tif (selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon) < 2)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Photon_Cannon, 2));\n\t\t}\n\t\tif (selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) < 1)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1));\n\t\t}\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0 &&\n\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Observatory) < 1)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1));\n\t\t}\n\t\tif (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0 &&\n\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Observer) < 1)\n\t\t{\n\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n\t\t}\n\t}\n\n\tif (numNexusAll >= 2 || frame > 9000)\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Assimilator, 1));\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Cybernetics_Core, 1));\n\t}\n\n\tif ((numCyber > 0) && ((numDragoons + dragoonsWanted)>0))\n\t{\n\t\t//dragoonsWanted = numDragoons + 2;\n\t\tgoal.push_back(MetaPair(BWAPI::UpgradeTypes::Singularity_Charge, 1));\n\t}\n\n\tif (numNexusCompleted >= 3)\n\t{\n\t\t//dragoonsWanted = numDragoons + 6;\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1));\n\t}\n\n\n\tif (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, 0, 0))\n\t{\n\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1));\n\t}\n\t//if (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, -2, -1000))\n\t//{\n\t//\t//choice 1: expand or not\n\t//\tint choice = defaultStrategyChoices.at(BWAPI::Races::Protoss.getID()).at(ProtossZealotRush).at(1);\n\t//\tif (choices.find(1) == choices.end())\n\t//\t{\n\t//\t\tif (!execution)\n\t//\t\t{\n\t//\t\t\tthrow ChoicePoint(1, 3);\n\t//\t\t}\n\t//\t}\n\t//\telse\n\t//\t{\n\t//\t\tchoice = choices.at(1);\n\t//\t}\n\t//\tswitch (choice){\n\t//\tcase 0://aggressive\n\t//\t\t//if (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, -2, -1000))\n\t//\t\t//{\n\t//\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1));\n\t//\t\t//}\n\t//\t\tbreak;\n\t//\tcase 1://normal\n\t//\t\tif (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, 0, 0))\n\t//\t\t{\n\t//\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1));\n\t//\t\t}\n\t//\t\tbreak;\n\t//\tcase 2://passive\n\t//\t\tif (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, 2, 1000))\n\t//\t\t{\n\t//\t\t\tgoal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1));\n\t//\t\t}\n\t//\t\tbreak;\n\t//\tdefault:\n\t//\t\tUAB_ASSERT(false, \"Wrong choice point option\");\n\t//\t}\n\t//}\n\n\treturn goal;\n}\n\n\nconst MetaPairVector StrategyManager::getTerranBuildOrderGoal() const\n{\n\treturn getTerranBuildOrderGoal(\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()),\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()),\n\t\tWorkerManager::Instance().getData(),\n\t\tBWAPI::Broodwar->getFrameCount());\n}\n\nMetaPairVector StrategyManager::getTerranBuildOrderGoal(\n\tconst HLUnitData &selfUnitData,\n\tconst HLUnitData &enemyUnitData,\n\tconst WorkerData &selfWorkerData,\n\tint frame)\n{\n\t// the goal to return\n\tstd::vector<MetaPair> goal;\n\n\tint numMarines =\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Terran_Marine);\n\tint numMedics =\t\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Terran_Medic);\n\tint numWraith =\t\t\t\tselfUnitData.getNumUnits(BWAPI::UnitTypes::Terran_Wraith);\n\n\tint marinesWanted = numMarines + 12;\n\tint medicsWanted = numMedics + 2;\n\tint wraithsWanted = numWraith + 4;\n\n\tgoal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Marine,\tmarinesWanted));\n\n\treturn (const std::vector<MetaPair>)goal;\n}\n\nconst MetaPairVector StrategyManager::getZergBuildOrderGoal() const\n{\n\treturn getZergBuildOrderGoal(\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()),\n\t\tHLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()),\n\t\tWorkerManager::Instance().getData(),\n\t\tBWAPI::Broodwar->getFrameCount());\n}\n\nMetaPairVector StrategyManager::getZergBuildOrderGoal(const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame)\n{\n\t// the goal to return\n\tstd::vector<MetaPair> goal;\n\t\n\tint numMutas  = selfUnitData.getNumUnits(BWAPI::UnitTypes::Zerg_Mutalisk);\n\tint numHydras = selfUnitData.getNumUnits(BWAPI::UnitTypes::Zerg_Hydralisk);\n\n\tint mutasWanted = numMutas + 6;\n\tint hydrasWanted = numHydras + 6;\n\n\tgoal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Zerg_Zergling, 4));\n\t//goal.push_back(std::pair<MetaType, int>(BWAPI::TechTypes::Stim_Packs,\t1));\n\n\t//goal.push_back(std::pair<MetaType, int>(BWAPI::UnitTypes::Terran_Medic,\t\tmedicsWanted));\n\n\treturn (const std::vector<MetaPair>)goal;\n}\n\n const int StrategyManager::getCurrentStrategy() const\n {\n\t return currentStrategy;\n }\n\n void StrategyManager::setCurrentStrategy(int newStrategy, const std::unordered_map<short, short> &choices)\n {\n\t currentStrategy = newStrategy;\n\t strategyChoices[BWAPI::Broodwar->self()->getRace().getID()][currentStrategy] = choices;\n }\n\n int StrategyManager::getNumStrategies(BWAPI::Race race)\n {\n\t if (race == BWAPI::Races::Protoss)\n\t {\n\t\t return NumProtossStrategies;\n\t }\n\t else if (race == BWAPI::Races::Zerg){\n\t\t return NumZergStrategies;\n\t }\n\t else if (race == BWAPI::Races::Terran){\n\t\t return NumTerranStrategies;\n\t }\n\t else{\n\t\t UAB_ASSERT(false, \"Unknown race\");\n\t }\n }"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLStrategyManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BWTA.h\"\n#include \"BuildOrderQueue.h\"\n#include \"InformationManager.h\"\n#include \"WorkerManager.h\"\n#include <sys/stat.h>\n#include <cstdlib>\n#include \"OpeningBuildOrders.h\"\n#include \"HLUnitData.h\"\n\nnamespace UAlbertaBot\n{\n\ntypedef std::pair<int, int> IntPair;\ntypedef std::pair<MetaType, size_t> MetaPair;\ntypedef std::vector<MetaPair> MetaPairVector;\n\nclass StrategyManager \n{\n\tStrategyManager();\n\t~StrategyManager() {}\n\n\tstd::string\t\t\t\t\treadDir;\n\tstd::string\t\t\t\t\twriteDir;\n\tstd::vector<IntPair>\t\tresults;\n\tstd::vector<int>\t\t\tusableStrategies;\n\tint\t\t\t\t\t\t\tcurrentStrategy;\n\tstd::unordered_map<int ,std::unordered_map<int, std::unordered_map<short, short> > > strategyChoices;//race->strategy->choicepoint->option\n\tstatic std::unordered_map<int, std::unordered_map<int, std::unordered_map<short, short> > > defaultStrategyChoices;\n\n\tBWAPI::Race\t\t\t\t\tselfRace;\n\tBWAPI::Race\t\t\t\t\tenemyRace;\n\n\tbool\t\t\t\t\t\tfirstAttackSent;\n\n\tvoid\taddStrategies();\n\tvoid\tsetStrategy();\n\tvoid\treadResults();\n\tvoid\twriteResults();\n\n\tconst\tint\t\t\t\t\tgetScore(BWAPI::PlayerInterface * player) const;\n\tconst\tdouble\t\t\t\tgetUCBValue(const size_t & strategy) const;\n\t\n\t// protoss strategy\n\tconst\tbool\t\t\t\texpandProtossZealotRush() const;\n\tstatic bool\t\t\t\t\texpandProtossZealotRush(\n\t\tconst HLUnitData &selfUnitData,\n\t\tconst WorkerData &selfWorkerData,\n\t\tint frame,\n\t\tint frameAdjust = 0,\n\t\tint zealotAdjust = 0);\n\tconst\tMetaPairVector\t\tgetProtossZealotRushBuildOrderGoal() const;\n\tstatic\tMetaPairVector\t\tgetProtossZealotRushBuildOrderGoal(\n\t\tconst HLUnitData &selfUnitData,\n\t\tconst HLUnitData &enemyUnitData,\n\t\tconst WorkerData &selfWorkerData,\n\t\tint frame);\n\n\tconst\tMetaPairVector\t\tgetProtossDarkTemplarBuildOrderGoal() const;\n\tstatic\tMetaPairVector\t\tgetProtossDarkTemplarBuildOrderGoal(\n\t\tconst HLUnitData &selfUnitData,\n\t\tconst HLUnitData &enemyUnitData,\n\t\tconst WorkerData &selfWorkerData,\n\t\tint frame);\n\n\tconst\tMetaPairVector\t\tgetProtossDragoonsBuildOrderGoal() const;\n\tstatic \tMetaPairVector\t\tgetProtossDragoonsBuildOrderGoal(\n\t\tconst HLUnitData &selfUnitData,\n\t\tconst HLUnitData &enemyUnitData,\n\t\tconst WorkerData &selfWorkerData,\n\t\tint frame);\n\n\tconst\tMetaPairVector\t\tgetProtossHighLevelSearchBuildOrderGoal() const;\n\tstatic\tMetaPairVector\t\tgetProtossHighLevelSearchBuildOrderGoal(\n\t\tconst HLUnitData &selfUnitData,\n\t\tconst HLUnitData &enemyUnitData,\n\t\tconst WorkerData &selfWorkerData,\n\t\tint frame,\n\t\tconst std::unordered_map<short, short> &choices,\n\t\tbool useDefaultChoicesIfNeeded);\n\n\tconst\tMetaPairVector\t\tgetTerranBuildOrderGoal() const;\n\tstatic \tMetaPairVector\t\tgetTerranBuildOrderGoal(\n\t\tconst HLUnitData &selfUnitData,\n\t\tconst HLUnitData &enemyUnitData,\n\t\tconst WorkerData &selfWorkerData,\n\t\tint frame); \n\t\n\tconst\tMetaPairVector\t\tgetZergBuildOrderGoal() const;\n\tstatic \tMetaPairVector\t\tgetZergBuildOrderGoal(\n\t\tconst HLUnitData &selfUnitData,\n\t\tconst HLUnitData &enemyUnitData,\n\t\tconst WorkerData &selfWorkerData,\n\t\tint frame);\n\n\t//const\tMetaPairVector\t\tgetProtossOpeningBook() const;\n\t//const\tMetaPairVector\t\tgetTerranOpeningBook() const;\n\t//const\tMetaPairVector\t\tgetZergOpeningBook() const;\n\npublic:\n\n\tenum { ProtossZealotRush=0, ProtossDarkTemplar=1, ProtossDragoons=2, ProtossHighLevelSearch=3, NumProtossStrategies=4 };\n\tenum { TerranMarineRush=0, NumTerranStrategies=1 };\n\tenum { ZergZerglingRush=0, NumZergStrategies=1 };\n\n\tstatic\tStrategyManager &\tInstance();\n\n\t\t\tvoid\t\t\t\tonEnd(const bool isWinner);\n\t\n\tconst\tbool\t\t\t\tregroup(int numInRadius);\n\tconst\tbool\t\t\t\tdoAttack(const std::set<BWAPI::UnitInterface*> & freeUnits);\n\tconst\tint\t\t\t\t    defendWithWorkers();\n\tconst\tbool\t\t\t\trushDetected();\n\n\tconst\tint\t\t\t\t\tgetCurrentStrategy() const;\n\tstatic int\t\t\t\t\tgetNumStrategies(BWAPI::Race race);\n\tvoid\t\t\t\t\t\tsetCurrentStrategy(int newStrategy, const std::unordered_map<short, short> &choices);//for high level search to set the strategy\n\tconst\tMetaPairVector\t\tgetBuildOrderGoal();\n\tconst\tstd::vector<MetaType>\tgetOpeningBookBuildOrder() const;\n\n\tstatic std::vector<MetaType>\tgetOpeningBookBuildOrder(int strategy, BWAPI::Race race);\n\tstatic MetaPairVector\t\tgetBuildOrderGoal(\n\t\tconst HLUnitData &selfUnitData,\n\t\tconst HLUnitData &enemyUnitData,\n\t\tconst WorkerData &selfWorkerData,\n\t\tint frame,\n\t\tint strategy,\n\t\tBWAPI::Race race,\n\t\tconst std::unordered_map<short, short> &choices);\n};\nstruct ChoicePoint{\n\tshort _point, _options;\n\tChoicePoint(short point, short options) :_point(point), _options(options){};\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLTranspositionTable.cpp",
    "content": "#include \"HLTranspositionTable.h\"\n\nusing namespace UAlbertaBot;\n\nHLTranspositionTable::HLTranspositionTable(int size) :_size(size), _entries(new HLEntry[size])\n{\n}\n\n\nHLTranspositionTable::~HLTranspositionTable()\n{\n}\nvoid HLTranspositionTable::store(const HLState &origState, const HLMove &bestMove, int value, int alpha, int beta, int height)\n{\n\tunsigned int hash = origState.getHash();\n\n\t_entries[hash%_size]._bestMove = bestMove;\n\t_entries[hash%_size]._hash = hash;\n\t_entries[hash%_size]._value = value;\n\t_entries[hash%_size]._height = height;\n\tif (value <= alpha){\n\t\t_entries[hash%_size]._exact = false;\n\t\t_entries[hash%_size]._upper = true;\n\t}\n\telse if (value >= beta){\n\t\t_entries[hash%_size]._exact = false;\n\t\t_entries[hash%_size]._upper = false;\n\t}\n\telse{\n\t\t_entries[hash%_size]._exact = true;\n\t\t_entries[hash%_size]._upper = false;\n\t}\n}\nvoid HLTranspositionTable::store(const HLState &origState, int depth, const HLMove &move, const HLMove &bestMove, int value, int alpha, int beta, int height)\n{\n\tunsigned int hash = origState.getHash(depth, move);\n\n\t_entries[hash%_size]._bestMove = bestMove;\n\t_entries[hash%_size]._hash = hash;\n\t_entries[hash%_size]._value = value;\n\t_entries[hash%_size]._height = height;\n\tif (value <= alpha){\n\t\t_entries[hash%_size]._exact = false;\n\t\t_entries[hash%_size]._upper = true;\n\t}\n\telse if (value >= beta){\n\t\t_entries[hash%_size]._exact = false;\n\t\t_entries[hash%_size]._upper = false;\n\t}\n\telse{\n\t\t_entries[hash%_size]._exact = true;\n\t\t_entries[hash%_size]._upper = false;\n\t}\n}\nconst HLEntry& HLTranspositionTable::lookup(const HLState &state, int depth, const HLMove &move)\n{\n\treturn _entries[state.getHash(depth, move) % _size];\n}\nconst HLEntry& HLTranspositionTable::lookup(const HLState &state)\n{\n\treturn _entries[state.getHash() % _size];\n}\n\nHLCacheTable::HLCacheTable(int size) : _size(size), _entries(new HLCacheEntry[size])\n{\n\n}\nHLCacheTable::~HLCacheTable()\n{\n\n}\nvoid HLCacheTable::store(const HLState &origState, int depth, const std::array < HLMove, 2 > &movePair, const HLState &newState)\n{\n\tunsigned int hash = origState.getHash(depth, movePair);\n\t_entries[hash%_size]._hash = hash;\n\t_entries[hash%_size]._state = newState;\n}\nconst HLCacheEntry& HLCacheTable::lookup(const HLState &state, int depth, const std::array < HLMove, 2 > &movePair)\n{\n\treturn _entries[state.getHash(depth, movePair) % _size];\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLTranspositionTable.h",
    "content": "#pragma once\n#include \"HLState.h\"\n\nnamespace UAlbertaBot\n{\n\tstruct HLEntry{\n\t\tHLMove _bestMove;\n\t\tunsigned int _hash;\n\t\tint _value;\n\t\tint _height;\n\t\tbool _exact;\n\t\tbool _upper;\n\t};\n\tclass HLTranspositionTable\n\t{\n\t\tint _size;\n\t\tstd::unique_ptr<HLEntry[]> _entries;\n\tpublic:\n\t\tHLTranspositionTable(int size);\n\t\t~HLTranspositionTable();\n\t\tvoid store(const HLState &origState, const HLMove &bestMove, int value, int alpha, int beta, int height);\n\t\tvoid store(const HLState &origState, int depth, const HLMove &move, const HLMove &bestMove, int value, int alpha, int beta, int height);\n\t\tconst HLEntry& lookup(const HLState &state, int depth, const HLMove &move);\n\t\tconst HLEntry& lookup(const HLState &state);\n\t};\n\n\tstruct HLCacheEntry{\n\t\tHLState _state;\n\t\tunsigned int _hash;\n\t};\n\tclass HLCacheTable\n\t{\n\t\tint _size;\n\t\tstd::unique_ptr<HLCacheEntry[]> _entries;\n\tpublic:\n\t\tHLCacheTable(int size);\n\t\t~HLCacheTable();\n\t\tvoid store(const HLState &origState, int depth, const std::array < HLMove, 2 > &movePair, const HLState &newState);\n\t\tconst HLCacheEntry& lookup(const HLState &state, int depth, const std::array < HLMove, 2 > &movePair);\n\t};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLUnitData.cpp",
    "content": "#include \"HLUnitData.h\"\nusing namespace UAlbertaBot;\n\nHLUnitData::HLUnitData() :_highestID(-1), mineralsLost(0), gasLost(0), _player(NULL)\n{\n\tint maxTypeID(0);\n\tfor (const BWAPI::UnitType & t : BWAPI::UnitTypes::allUnitTypes())\n\t{\n\t\tmaxTypeID = maxTypeID > t.getID() ? maxTypeID : t.getID();\n\t}\n\n\tnumDeadUnits = std::vector<int>(maxTypeID + 1, 0);\n\tnumUnits = std::vector<int>(maxTypeID + 1, 0);\n\tnumCompletedUnits = std::vector<int>(maxTypeID + 1, 0);\n}\nHLUnitData::HLUnitData(BWAPI::Player player) :HLUnitData()\n{\n\t_player = player;\n}\n\nHLUnitData::HLUnitData(const UnitData &data, BWAPI::Player player) : HLUnitData(player)\n{\n\tfor (auto unit : data.getUnits()){\n\t\taddUnit(unit.second);\n\t}\n\tmineralsLost = data.getMineralsLost();\n\tgasLost = data.getGasLost();\n}\n\nHLUnitData::~HLUnitData()\n{\n}\n\n\n//virtual methods\nvoid\tHLUnitData::getCloakedUnits(std::set<UnitInfo> & v)\t\t\t\tconst\n{\n\n\tfor (auto item : _unitMap)\n\t{\n\t\tconst UnitInfo & ui(item.second);\n\n\t\tif (ui.canCloak())\n\t\t{\n\t\t\tv.insert(ui);\n\t\t}\n\t}\n}\n\nint\t\tHLUnitData::numCloakedUnits()\t\t\t\t\t\t\t\t\tconst\n{\n\tint count = 0;\n\tfor (auto item : _unitMap)\n\t{\n\t\tconst UnitInfo & ui(item.second);\n\n\t\tif (ui.canCloak())\n\t\t{\n\t\t\tcount++;\n\t\t}\n\t}\n\treturn count;\n}\n\nvoid\tHLUnitData::getDetectorUnits(std::set<UnitInfo> & v)\t\t\tconst\n{\n\n\n\tfor (auto item : _unitMap)\n\t{\n\t\tconst UnitInfo & ui(item.second);\n\n\t\tif (ui.isDetector())\n\t\t{\n\t\t\tv.insert(ui);\n\t\t}\n\t}\n}\n\nvoid\tHLUnitData::getFlyingUnits(std::set<UnitInfo> & v)\t\t\t\tconst\n{\n\n\n\tfor (auto item : _unitMap)\n\t{\n\t\tconst UnitInfo & ui(item.second);\n\n\t\tif (ui.isFlyer())\n\t\t{\n\t\t\tv.insert(ui);\n\t\t}\n\t}\n}\n\nbool\tHLUnitData::hasCloakedUnits()\t\t\t\t\t\t\t\t\tconst\n{\n\n\tfor (auto item : _unitMap)\n\t{\n\t\tconst UnitInfo & ui(item.second);\n\n\t\tif (ui.canCloak())\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n\n}\n\nbool\tHLUnitData::hasDetectorUnits()\t\t\t\t\t\t\t\t\tconst\n{\n\n\tfor (auto item : _unitMap)\n\t{\n\t\tconst UnitInfo & ui(item.second);\n\n\t\tif (ui.isDetector())\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n\n}\n\nint\t\tHLUnitData::getNumUnits(BWAPI::UnitType t)\t\t\t\t\t\tconst\n{\n\treturn numUnits[t.getID()];\n}\n\nint\t\tHLUnitData::getNumCompletedUnits(BWAPI::UnitType t)\t\t\t\tconst\n{\n\treturn numCompletedUnits[t.getID()];\n}\n\nint\t\tHLUnitData::getNumDeadUnits(BWAPI::UnitType t)\t\t\t\t\tconst\n{\n\treturn numDeadUnits[t.getID()];\n}\n\n//new methods\nvoid HLUnitData::removeUnit(int id)\n{\n\tif (_unitMap.find(id) != _unitMap.end()){\n\t\tconst UnitInfo &unit = _unitMap.at(id);\n\t\tnumDeadUnits[unit.type.getID()]++;\n\t\tnumCompletedUnits[unit.type.getID()]--;\n\t\tnumUnits[unit.type.getID()]--;\n\t\t_unitMap.erase(id);\n\t}\n\n\t//todo:decrease highest ID?\n\t//todo:update _baseRegions?\n}\n\nvoid HLUnitData::addUnit(const UnitInfo &unit)\n{\n\tif (_unitMap.find(unit.unitID) == _unitMap.end()){\n\t\t_unitMap[unit.unitID] = unit;\n\t\tif (unit.completed){\n\t\t\tnumCompletedUnits[unit.type.getID()]++;\n\t\t}\n\t\tnumUnits[unit.type.getID()]++;\n\t\tif (unit.unitID > _highestID){\n\t\t\t_highestID = unit.unitID;\n\t\t}\n\t}\n\telse{//update info\n\t\t_unitMap[unit.unitID].completed = unit.completed;\n\t\t_unitMap[unit.unitID].lastHealth = unit.lastHealth;\n\t\t_unitMap[unit.unitID].lastPosition = unit.lastPosition;\n\t}\n\tif (unit.type.isBuilding())\n\t{\n\t\ttry\n\t\t{\n\t\t\t_baseRegions.insert(BWTA::getRegion(unit.lastPosition));\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tLogger::LogAppendToFile(UAB_LOGFILE, \"Exception at BWTA::getRegion(%d, %d), ignoring unit\", unit.lastPosition.x, unit.lastPosition.y);\n\t\t}\n\t}\n}\n\nbool HLUnitData::finishUnit(BWAPI::UnitType type)\n{\n\tbool found = false;\n\tfor (auto &item : _unitMap){\n\t\tif (item.second.type.getID() == type.getID() && !item.second.completed){\n\t\t\titem.second.completed = true;\n\t\t\tnumCompletedUnits[type.getID()]++;\n\t\t\tfound = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tUAB_ASSERT(found,\"Couldn't find unit to finish: %s\\n\",type.getName().c_str());\n\treturn found;\n}\n\n//std::vector<UnitInfo> HLUnitData::getUnitVector()\t\t\t\t\t\tconst\n//{\n//\tstd::vector<UnitInfo> v;\n//\tstd::transform(_unitMap.begin(), _unitMap.end(), std::back_inserter(v),\n//\t\t[](const std::pair<int, UnitInfo> &item){\n//\t\treturn item.second;\n//\t});\n//\treturn v;\n//}\n"
  },
  {
    "path": "UAlbertaBot/Source/research/hlsearch/HLUnitData.h",
    "content": "#pragma once\n#include \"UnitData.h\"\n\nnamespace UAlbertaBot{\n\tclass HLUnitData\n\t{\n\t\tstd::vector<int>\t\t\t\t\t\tnumDeadUnits;\n\t\tstd::vector<int>\t\t\t\t\t\tnumUnits;\n\t\tstd::vector<int>\t\t\t\t\t\tnumCompletedUnits;\n\n\t\tint\t\t\t\t\t\t\t\t\t\tmineralsLost;\n\t\tint\t\t\t\t\t\t\t\t\t\tgasLost;\n\n\t\tstd::unordered_map<int, UnitInfo>\t\t_unitMap;//id->info\n\t\tint\t\t\t\t\t\t\t\t\t\t_highestID;\n\t\tstd::unordered_set<BWTA::Region *>\t\t_baseRegions;//regions with buildings\n\n\t\tBWAPI::Player\t\t\t\t\t\t\t_player;\n\tpublic:\n\t\tHLUnitData();\n\t\tHLUnitData(BWAPI::Player player);\n\t\tHLUnitData(const UnitData &data, BWAPI::Player player);\n\t\tvirtual ~HLUnitData();\n\n\t\t//virtual methods\n\t\tvoid\tgetCloakedUnits(std::set<UnitInfo> & v)\t\t\t\tconst;\n\t\tint\t\tnumCloakedUnits()\t\t\t\t\t\t\t\t\tconst;\n\t\tvoid\tgetDetectorUnits(std::set<UnitInfo> & v)\t\t\tconst;\n\t\tvoid\tgetFlyingUnits(std::set<UnitInfo> & v)\t\t\t\tconst;\n\t\tbool\thasCloakedUnits()\t\t\t\t\t\t\t\t\tconst;\n\t\tbool\thasDetectorUnits()\t\t\t\t\t\t\t\t\tconst;\n\t\tint\t\tgetNumUnits(BWAPI::UnitType t)\t\t\t\t\t\tconst;\n\t\tint\t\tgetNumCompletedUnits(BWAPI::UnitType t)\t\t\t\tconst;\n\t\tint\t\tgetNumDeadUnits(BWAPI::UnitType t)\t\t\t\t\tconst;\n\t\tconst\tstd::unordered_map<int, UnitInfo> & getUnits()\t\tconst\t{ return _unitMap; }\n\n\t\t//new methods\n\t\tvoid\tremoveUnit(int id);\n\t\tvoid\taddUnit(const UnitInfo &unit);\n\t\tbool\tfinishUnit(BWAPI::UnitType type);\n\t\t//std::vector<UnitInfo> getUnitVector()\t\t\t\t\t\tconst;\n\t\tint\t\thighestID()\t\t\t\t\t\t\t\t\t\t\tconst {return _highestID;}\n\t\tconst std::unordered_set<BWTA::Region*>& getBaseRegions()\tconst { return _baseRegions; }\n\t\tconst BWAPI::Player player() const { return _player; }\n\t};\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/research/sparcraft/SparCraftManager.cpp",
    "content": "#include \"SparCraftManager.h\"\n\nusing namespace UAlbertaBot;\n\nSparCraftManager::SparCraftManager() \n    : gameOver(false)\n\n{\n    SparCraft::init();\n}\n\n\nvoid SparCraftManager::onStart()\n{\n    SparCraft::GameState state(extractGameState());\n\n}\n\nvoid SparCraftManager::update()\n{\n    if (!gameOver)\n    {\n        // for each unit that we control, do some book keeping\n        for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->self()->getUnits())\n        {\n            BWAPI::Broodwar->drawTextMap(unit->getPosition().x-20, unit->getPosition().y-12, \"%d\", unit->getID());\n\n            // if it is a combat unit\n            if (isCombatUnit(unit))\n            {\n                if (Config::Debug::DrawUnitTargetInfo && unit->getTarget())\n                {\n                    BWAPI::Broodwar->drawLineMap(unit->getPosition().x-2, unit->getPosition().y-2, \tunit->getTarget()->getPosition().x, unit->getTarget()->getPosition().y, BWAPI::Colors::White);\n                }\n            }\n        }\n\n        performSparCraft();\n    }\n}\n\nvoid SparCraftManager::getMoves(SparCraft::GameState & state, std::vector<SparCraft::UnitAction> & moveVec)\n{\n    const SparCraft::IDType playerID = getPlayerID(BWAPI::Broodwar->self());\n    SparCraft::MoveArray moves;\n    state.generateMoves(moves, playerID);\n\n    SparCraft::PlayerPtr gsPlayer(new SparCraft::Player_PortfolioGreedySearch(playerID, SparCraft::PlayerModels::NOKDPS, 1, 0, 0));\n\n    gsPlayer->getMoves(state, moves, moveVec);\n}\n\nvoid SparCraftManager::performSparCraft()\n{\n    SparCraft::GameState currentState = extractGameState();\n\n    int currentFrame = BWAPI::Broodwar->getFrameCount();\n\n    for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        BWAPI::Broodwar->drawTextMap(unit->getPosition().x, unit->getPosition().y, \"%d\", unit->getGroundWeaponCooldown());\n    }\n\n    // draw our units\n    for (size_t u(0); u<currentState.numUnits(SparCraft::Players::Player_One); ++u)\n    {\n        SparCraft::Unit & unit = currentState.getUnit(SparCraft::Players::Player_One, u);\n        BWAPI::Broodwar->drawCircleMap(unit.x(), unit.y(), 5, BWAPI::Colors::Green);\n        BWAPI::Broodwar->drawCircleMap(unit.x(), unit.y(), unit.range(), BWAPI::Colors::Grey);\n\n        std::pair<int, int> cooldown = getUnitCooldown(BWAPI::Broodwar->getUnit(unit.ID()), unit);\n\n        BWAPI::UnitInterface* realUnit = getUnit(unit);\n\n        BWAPI::Broodwar->drawTextMap(unit.x(), unit.y(), \"%d (%d %d %d)\", unit.ID(), cooldown.first-currentFrame, cooldown.second-currentFrame, BWAPI::Broodwar->getUnit(unit.ID())->getGroundWeaponCooldown());\n        BWAPI::Broodwar->drawLineMap(unit.x(), unit.y(), realUnit->getPosition().x, realUnit->getPosition().y, BWAPI::Colors::Purple);\n    }\n\n    // TODO: Check why zealots aren't being given commands\n\n    // draw their units\n    for (size_t u(0); u<currentState.numUnits(SparCraft::Players::Player_Two); ++u)\n    {\n        SparCraft::Unit & unit = currentState.getUnit(SparCraft::Players::Player_Two, u);\n        drawUnitHP(BWAPI::Broodwar->getUnit(unit.ID()));\n        //BWAPI::Broodwar->drawCircleMap(unit.x, unit.y, 5, BWAPI::Colors::Red);\n    }\n\n    // draw our moves if we are the player to move\n    const SparCraft::IDType whoCanMove = currentState.whoCanMove();\n    if ((whoCanMove == SparCraft::Players::Player_One) || (whoCanMove == SparCraft::Players::Player_Both))\n    {\n        // get the best move tuple from the current state\n        //MoveTuple bestTuple = getMoveTuple(currentState, Search::PlayerModels::AlphaBeta);\n        std::vector<SparCraft::UnitAction> moveVec;\n        getMoves(currentState, moveVec);\n\n        // extract all of the moves possible from the current state\n        SparCraft::MoveArray moves;\n        currentState.generateMoves(moves, SparCraft::Players::Player_One);\n\n        // draw the best move for each unit\n        for (size_t u(0); u<moves.numUnits(); ++u)\n        {\n            // the move for the first unit to move\n            SparCraft::UnitAction move = moveVec[u];\n\n            // the unit for which the move is to be performed\n            SparCraft::Unit & unit = currentState.getUnit(SparCraft::Players::Player_One, move.unit());\n            BWAPI::Broodwar->drawCircleMap(unit.x(), unit.y(), 5, BWAPI::Colors::Red);\n\n            // draw the move this unit should do\n            drawUnitMove(currentState, unit, move);\n            drawUnitCooldown(BWAPI::Broodwar->getUnit(unit.ID()));\n            drawUnitHP(BWAPI::Broodwar->getUnit(unit.ID()));\n\n            // do the move\n            doUnitMove(currentState, unit, move);\n        }\n    }\n}\n\nvoid SparCraftManager::doUnitMove(SparCraft::GameState & currentState, SparCraft::Unit & unit, SparCraft::UnitAction & move)\n{\n    SparCraft::IDType enemyPlayer = (unit.player() + 1) % 2;\n\n    BWAPI::UnitInterface* u = BWAPI::Broodwar->getUnit(unit.ID());\n\n    if (move._moveType == SparCraft::UnitActionTypes::ATTACK)\n    {\n        BWAPI::Broodwar->drawTextMap(unit.x()+5, unit.y()+5, \"A\");\n\n        SparCraft::Unit & enemyUnit(currentState.getUnit(enemyPlayer, move._moveIndex));\n\n        UnitCommandManager::Instance().smartAttackUnit(u, BWAPI::Broodwar->getUnit(enemyUnit.ID()));\n    }\n    else if (move._moveType == SparCraft::UnitActionTypes::MOVE)\n    {\n        BWAPI::Broodwar->drawTextMap(unit.x()+5, unit.y()+5, \"M\");\n\n        SparCraft::Position pos(SparCraft::Constants::Move_Dir[move._moveIndex][0], SparCraft::Constants::Move_Dir[move._moveIndex][1]);\n        SparCraft::Position dest(unit.x() + (pos.x() * 4*SparCraft::Constants::Move_Distance), unit.y() + (pos.y() * 4*SparCraft::Constants::Move_Distance));\n\n        UnitCommandManager::Instance().smartMove(u, BWAPI::Position(dest.x(), dest.y()));\n    }\n    else if (move._moveType == SparCraft::UnitActionTypes::RELOAD)\n    {\n        UnitCommandManager::Instance().smartReload(u);\n    }\n}\n\nvoid SparCraftManager::drawAttackDebug()\n{\n    char * trueFix = \"\\x07\";\n    char * falseFix = \"\\x06\";\n\n    for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        int x = unit->getPosition().x;\n        int y = unit->getPosition().y + 9;\n\n        BWAPI::Broodwar->drawTextMap(x, y, \"%s isAttacking\", unit->isAttacking() ? trueFix : falseFix);\n        BWAPI::Broodwar->drawTextMap(x, y+10, \"%s isAttackFrame\", unit->isAttackFrame() ? trueFix : falseFix);\n        BWAPI::Broodwar->drawTextMap(x, y+20, \"%s isMoving\", unit->isMoving() ? trueFix : falseFix);\n    }\n}\n\nvoid SparCraftManager::drawUnitMove(SparCraft::GameState & currentState, SparCraft::Unit & unit, SparCraft::UnitAction & move)\n{\n    SparCraft::IDType enemyPlayer = (unit.player() + 1) % 2;\n\n    if (move._moveType == SparCraft::UnitActionTypes::ATTACK)\n    {\n        SparCraft::Unit & enemyUnit(currentState.getUnit(enemyPlayer,move._moveIndex));\n\n        BWAPI::Broodwar->drawLineMap(unit.x(), unit.y(), enemyUnit.x(), enemyUnit.y(), BWAPI::Colors::Cyan);\n    }\n    else if (move._moveType == SparCraft::UnitActionTypes::MOVE)\n    {\n        SparCraft::Position pos(SparCraft::Constants::Move_Dir[move._moveIndex][0], SparCraft::Constants::Move_Dir[move._moveIndex][1]);\n        SparCraft::Position dest(unit.x() + (pos.x() * 32), unit.y() + (pos.y() * 32));\n\n        BWAPI::Broodwar->drawLineMap(unit.x(), unit.y(), dest.x(), dest.y(), BWAPI::Colors::Yellow);\n    }\n}\n\nvoid SparCraftManager::drawUnitCooldown(BWAPI::UnitInterface* unit)\n{\n    double totalCooldown = unit->getType().groundWeapon().damageCooldown();\n    double remainingCooldown = unit->getGroundWeaponCooldown();\n    double percCooldown = remainingCooldown / (totalCooldown+1);\n\n    int w = 32;\n    int h = 4;\n\n    int cw = w - (int)(w * percCooldown);\n    int ch = h;\n\n    int x1 = unit->getPosition().x - w/2;\n    int y1 = unit->getPosition().y - 16;\n\n    BWAPI::Broodwar->drawBoxMap(x1, y1, x1 + w, y1 + h, BWAPI::Colors::Grey, true);\n    BWAPI::Broodwar->drawBoxMap(x1, y1, x1 + cw, y1 + ch, BWAPI::Colors::Red, true);\n}\n\nvoid SparCraftManager::drawUnitHP(BWAPI::UnitInterface* unit)\n{\n    double totalHP = unit->getType().maxHitPoints() + unit->getType().maxShields();\n    double currentHP = unit->getHitPoints() + unit->getShields();\n    double percHP = currentHP / (totalHP+1);\n\n    int w = 32;\n    int h = 4;\n\n    int cw = (int)(w * percHP);\n    int ch = h;\n\n    int x1 = unit->getPosition().x - w/2;\n    int y1 = unit->getPosition().y - 12;\n\n    BWAPI::Broodwar->drawBoxMap(x1, y1, x1 + w, y1 + h, BWAPI::Colors::Grey, true);\n    BWAPI::Broodwar->drawBoxMap(x1, y1, x1 + cw, y1 + ch, BWAPI::Colors::Green, true);\n}\n\nconst SparCraft::IDType SparCraftManager::getPlayerID(BWAPI::PlayerInterface * player) const\n{\n    return (player == BWAPI::Broodwar->self()) ? SparCraft::Players::Player_One : SparCraft::Players::Player_Two;\n}\n\nconst bool SparCraftManager::isCombatUnit(BWAPI::UnitInterface* unit) const\n{\n    assert(unit != NULL);\n\n    // no workers or buildings allowed\n    if (unit && unit->getType().isWorker() || unit->getType().isBuilding())\n    {\n        return false;\n    }\n\n    // check for various types of combat units\n    if (unit->getType().canAttack() || \n        unit->getType() == BWAPI::UnitTypes::Terran_Medic ||\n        unit->getType() == BWAPI::UnitTypes::Protoss_High_Templar ||\n        unit->getType() == BWAPI::UnitTypes::Protoss_Observer)\n    {\n        return true;\n    }\n\n    return false;\n}\n\nBWAPI::UnitInterface* SparCraftManager::getUnit(SparCraft::Unit & unit)\n{\n    for (BWAPI::UnitInterface* u : BWAPI::Broodwar->getAllUnits())\n    {\n        if (u->getID() == unit.ID())\n        {\n            return u;\n        }\n    }\n\n    return NULL;\n}\n\nconst std::pair<int, int> SparCraftManager::getUnitCooldown(BWAPI::UnitInterface* unit, SparCraft::Unit & u) const\n{\n    int attackCooldown(0);\n    int moveCooldown(0);\n\n    BWAPI::UnitCommand lastCommand = unit->getLastCommand();\n    int lastCommandFrame = unit->getLastCommandFrame();\n    int currentFrame = BWAPI::Broodwar->getFrameCount();\n    int framesSinceCommand = currentFrame - lastCommandFrame;\n\n    if ((unit->getType() == BWAPI::UnitTypes::Protoss_Dragoon) && (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Unit))\n    {\n        // dragoons are one of only 2 unit types whose attack can be canceled by the in-game targeter being called too early so\n        // this hack makes up for that by taking it's stop-delay into account\n        attackCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, unit->getGroundWeaponCooldown()-SparCraft::AnimationFrameData::getAttackFrames(unit->getType()).first);\n    }\n    else\n    {\n        attackCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, unit->getGroundWeaponCooldown()-2);\n    }\n\n    // if the last attack was an attack command\n    if (lastCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit)\n    {\n        moveCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, u.attackInitFrameTime() - framesSinceCommand);\n\n        //BWAPI::Broodwar->drawTextScreen(100,100, \"%d, %d\", attackCooldown-currentFrame, moveCooldown-currentFrame);\n    }\n    // if the last command was a move command\n    else if (lastCommand.getType() == BWAPI::UnitCommandTypes::Move)\n    {\n        moveCooldown = currentFrame;\n    }\n\n    if (moveCooldown - BWAPI::Broodwar->getFrameCount() < 4 || unit->isMoving())\n    {\n        moveCooldown = currentFrame;\n    }\n\n    moveCooldown = std::min(moveCooldown, attackCooldown);\n\n    return std::pair<int, int>(attackCooldown, moveCooldown);\n}\n\n//Unit(const BWAPI::UnitType unitType, const Position & pos, const IDType & unitID, const IDType & playerID, \n//\t\t const HealthType & hp, const HealthType & energy, const TimeType & tm, const TimeType & ta);\nSparCraft::Unit SparCraftManager::getSparCraftUnit(const BWAPI::UnitInterface* bwapiUnit, BWAPI::GameWrapper & game)\n{\n    BWAPI::UnitType         type        = bwapiUnit->getType();\n    SparCraft::Position     pos         = SparCraft::Position(bwapiUnit->getPosition().x, bwapiUnit->getPosition().y); \n    SparCraft::IDType       unitID      = (SparCraft::IDType)bwapiUnit->getID();\n    SparCraft::IDType       playerID    = (SparCraft::IDType)getPlayerID(bwapiUnit->getPlayer());\n    SparCraft::HealthType   health      = (SparCraft::HealthType)(bwapiUnit->getHitPoints() + bwapiUnit->getShields());\n    SparCraft::HealthType   energy      = (SparCraft::HealthType)(bwapiUnit->getEnergy());\n    SparCraft::TimeType     timeCanMove = (SparCraft::TimeType)(game->getFrameCount());\n    SparCraft::TimeType     timeCanAtk  = (SparCraft::TimeType)(game->getFrameCount() + bwapiUnit->getGroundWeaponCooldown() + bwapiUnit->getAirWeaponCooldown());\n\n    return SparCraft::Unit(type, pos, unitID, playerID, health, energy, timeCanMove, timeCanAtk);\n}\n\n// constructor based on a BWAPI unit, used by UAlbertaBot\n/*Unit::Unit(BWAPI::UnitInterface* unit, BWAPI::Game * game, const IDType & playerID, const TimeType & gameTime)\n    : _unitType             (unit->getType() == BWAPI::UnitTypes::Terran_Medic ? BWAPI::UnitTypes::Terran_Marine : unit->getType())\n    , _range                (unit->getType().groundWeapon().maxRange() + 32)\n    , _position             (Position(unit->getPosition().x, unit->getPosition().y))\n    , _unitID               ((IDType)unit->getID())\n    , _playerID             (playerID)\n    , _currentHP            ((HealthType)(unit->getHitPoints() + unit->getShields()))\n    , _currentEnergy        ((HealthType)unit->getEnergy())\n    , _timeCanMove          ((TimeType)(game->getFrameCount()))\n    , _timeCanAttack        ((TimeType)(game->getFrameCount() + unit->getGroundWeaponCooldown() + unit->getAirWeaponCooldown()))\n    , _previousActionTime   (gameTime)\n    , _prevCurrentPosTime   (0)\n    , _previousPosition     (Position(unit->getPosition().x, unit->getPosition().y))\n{\n}*/\n\n// get an abstract GameState object from the current BWAPI state\nSparCraft::GameState SparCraftManager::extractGameState()\n{\n    // construct a state with the current time\n    SparCraft::GameState state;\n    state.setTime(BWAPI::Broodwar->getFrameCount());\n\n    // add each of our fighting units\n    for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        if (isCombatUnit(unit))\n        {\n            SparCraft::Unit u = getSparCraftUnit(unit, BWAPI::Broodwar);\n            std::pair<int, int> cd = getUnitCooldown(unit, u);\n            u.setCooldown(cd.first, cd.second);\n            state.addUnitWithID(u);\n        }\n    }\n\n    for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->enemy()->getUnits())\n    {\n        if (isCombatUnit(unit))\n        {\n            SparCraft::Unit u = getSparCraftUnit(unit, BWAPI::Broodwar);\n            u.setCooldown(BWAPI::Broodwar->getFrameCount(), BWAPI::Broodwar->getFrameCount() + unit->getGroundWeaponCooldown());\n            state.addUnitWithID(u);\n        }\n    }\n\n    if (state.numUnits(0) == 0 && state.numUnits(1) == 0)\n    {\n        gameOver = true;\n    }\n    else if (state.numUnits(1) == 0)\n    {\n        gameOver = true;\n    }\n    else if (state.numUnits(0) == 0)\n    {\n        gameOver = true;\n    }\n\n    if (gameOver)\n    {\t\n        BWAPI::Broodwar->restartGame();\n    }\n\n    state.finishedMoving();\n    return state;\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/research/sparcraft/SparCraftManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BWAPI.h\"\n#include \"GameCommander.h\"\n#include \"UnitCommandManager.h\"\n#include \"../../SparCraft/Source/SparCraft.h\"\n\nnamespace UAlbertaBot\n{\nclass SparCraftManager\n{\n\tbool gameOver;\n    \npublic:\n\n\tSparCraftManager();\n\n\tSparCraft::GameState\t\t\t\textractGameState();\n\t\t\n\tconst SparCraft::IDType\t\t\t\tgetPlayerID(BWAPI::PlayerInterface * player) const;\n\tconst bool\t\t\t\t\t\t\tisCombatUnit(BWAPI::UnitInterface* unit) const;\n\tvoid                        \t\tgetMoves(SparCraft::GameState & state, std::vector<SparCraft::UnitAction> & moveVec);\n\n\tvoid update();\n\tvoid onStart();\n\t\n\tvoid doUnitMove(SparCraft::GameState & currentState, SparCraft::Unit & unit, SparCraft::UnitAction & move);\n\tvoid drawUnitMove(SparCraft::GameState & currentState, SparCraft::Unit & unit, SparCraft::UnitAction & move);\n\tvoid drawUnitCooldown(BWAPI::UnitInterface* unit);\n\tvoid drawUnitHP(BWAPI::UnitInterface* unit);\n\tvoid drawSearchResults(int x, int y);\n\tvoid drawAttackDebug();\n\tvoid performSparCraft();\n\n    SparCraft::Unit getSparCraftUnit(const BWAPI::UnitInterface* bwapiUnit, BWAPI::GameWrapper & game);\n\tBWAPI::UnitInterface* getUnit(SparCraft::Unit & unit);\n\tconst std::pair<int, int> getUnitCooldown(BWAPI::UnitInterface* unit, SparCraft::Unit & u) const;\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/sparcraft/UnitCommandData.cpp",
    "content": "#include \"UnitCommandData.h\"\n\nusing namespace UAlbertaBot;\n\nUnitCommandData::UnitCommandData()\n\t: _unit(NULL)\n\t, _phase(UnitCommandData::NONE)\n\t, _enteredReady(0)\n\t, _enteredAttacking(0)\n\t, _enteredReloading(0)\n\t, _waitCommandGiven(0)\n{\n\n}\n\nUnitCommandData::UnitCommandData(BWAPI::UnitInterface* unit)\n\t: _unit(unit)\n\t, _phase(UnitCommandData::NONE)\n\t, _enteredReady(0)\n\t, _enteredAttacking(0)\n\t, _enteredReloading(0)\n\t, _waitCommandGiven(0)\n{\n}\n\nconst bool UnitCommandData::isWaiting() const\n{\n\treturn (getPhase() == RELOADING) && (_waitCommandGiven > _enteredReloading);\n}\n\nconst int UnitCommandData::getPhase() const\n{\n\treturn _phase;\n}\n\nvoid UnitCommandData::waitCommand() \n{\n\t_waitCommandGiven = BWAPI::Broodwar->getFrameCount();\n}\n\nvoid UnitCommandData::update()\n{\n\tint currentFrame = BWAPI::Broodwar->getFrameCount();\n\n\tif (_phase == NONE)\n\t{\n\t\tif (_unit->getGroundWeaponCooldown() == 0)\n\t\t{\n\t\t\t_phase = READY;\n\t\t\t_enteredReady = currentFrame;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_phase = RELOADING;\n\t\t\t_enteredReloading = currentFrame;\n\t\t}\n\t}\n\telse if (_phase == READY)\n\t{\n\t\tif (_unit->isAttackFrame() || _unit->isStartingAttack())\n\t\t{\n\t\t\t_phase = ATTACKING;\n\t\t\t_enteredAttacking = currentFrame;\n\t\t}\n\t}\n\telse if (_phase == ATTACKING)\n\t{\n\t\tif (_unit->getGroundWeaponCooldown() == 0)\n\t\t{\n\t\t\t_phase = READY;\n\t\t\t_enteredReady = currentFrame;\n\t\t}\n\t\telse if (!_unit->isAttackFrame() || ((currentFrame - _enteredAttacking) > SparCraft::AnimationFrameData::getAttackFrames(_unit->getType()).first))\n\t\t{\n\t\t\t_phase = RELOADING;\n\t\t\t_enteredReloading = currentFrame;\n\t\t}\n\t}\n\telse if (_phase == RELOADING)\n\t{\n\t\tif (_unit->getGroundWeaponCooldown() == 0)\n\t\t{\n\t\t\t_phase = READY;\n\t\t\t_enteredReady = currentFrame;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "UAlbertaBot/Source/research/sparcraft/UnitCommandData.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BWAPI.h\"\n\n#include \"..\\..\\SparCraft\\source\\SparCraft.h\"\n\nnamespace UAlbertaBot\n{\nclass UnitCommandData\n{\t\n\tBWAPI::UnitInterface* _unit;\n\n\tint\t\t_phase,\n\t\t\t_enteredReady,\n\t\t\t_enteredAttacking,\n\t\t\t_enteredReloading,\n\t\t\t_waitCommandGiven;\n\npublic:\n\n\tenum\t{ NONE, READY, ATTACKING, RELOADING };\n\n\tUnitCommandData();\n\tUnitCommandData(BWAPI::UnitInterface* unit);\n\n\tvoid update();\n\tvoid waitCommand();\n\tvoid attackCommand();\n\tconst bool isWaiting() const;\n\tconst int getPhase() const;\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/sparcraft/UnitCommandManager.cpp",
    "content": "#include \"UnitCommandManager.h\"\n\nusing namespace UAlbertaBot;\n\nUnitCommandManager::UnitCommandManager() {}\n\n// get an instance of this\nUnitCommandManager & UnitCommandManager::Instance() \n{\n\tstatic UnitCommandManager instance;\n\treturn instance;\n}\n\nvoid UnitCommandManager::update()\n{\n\tfor (BWAPI::UnitInterface* unit : BWAPI::Broodwar->self()->getUnits())\n\t{\n\t\tif (unit->getType().canAttack())\n\t\t{\n\t\t\tupdateUnit(unit);\n\t\t}\n\t}\n}\n\nUnitCommandData & UnitCommandManager::getUnitData(BWAPI::UnitInterface* unit)\n{\n\treturn map[unit];\n}\n\nvoid UnitCommandManager::updateUnit(BWAPI::UnitInterface* unit)\n{\n    if (!unit)\n    {\n        return;\n\n    }\n\t// if it's not in our map, add a default entry\n\tif (!exists(unit))\n\t{\n\t\taddUnit(unit);\n\t}\n\n\tgetUnitData(unit).update();\n}\n\nvoid UnitCommandManager::addUnit(BWAPI::UnitInterface* unit)\n{\n\tmap[unit] = UnitCommandData(unit);\n}\n\nvoid UnitCommandManager::removeUnit(BWAPI::UnitInterface* unit)\n{\n\tmap.erase(unit);\n}\n\nbool UnitCommandManager::exists(BWAPI::UnitInterface* unit) const\n{\n\treturn map.find(unit) != map.end();\n}\n\nbool UnitCommandManager::commandWillInterruptAttack(BWAPI::UnitInterface* unit)\n{\n\tconst UnitCommandData & unitData(getUnitData(unit));\n\n\tif (unitData.getPhase() == UnitCommandData::ATTACKING)\n\t{\n\t\treturn true;\n\t}\n\n\t//BWAPI::Broodwar->drawTextScreen(20, 20, \"ATTACK PASS!\");\n\n\treturn false;\n}\n\nbool UnitCommandManager::canIssueAttackCommand(BWAPI::UnitInterface* attacker, BWAPI::UnitInterface* target)\n{\n\tBWAPI::UnitCommand currentCommand(attacker->getLastCommand());\n\tBWAPI::UnitCommandType commandType = currentCommand.getType();\n\n\t// if we have already given a command this frame, don't issue another one\n\t//if (commandType != BWAPI::UnitCommandTypes::None && BWAPI::Broodwar->getFrameCount() - attacker->getLastCommandFrame() <= 7)\n\t//{\n\t//\tdrawDebugPlate(attacker, \"A FRAME\");\n\t//\treturn false;\n\t//}\n\n\t// if the last command given was an attack command\n\tif (currentCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit)\n\t{\n\t\t// if the target is the same as the current one, we don't need to switch\n\t\tif (currentCommand.getTarget() == target)\n\t\t{\n\t\t\tdrawDebugPlate(attacker, \"SAME\");\n\t\t\treturn false;\n\t\t}\n\t}\n\t\t\n\t//return true;\n\treturn !commandWillInterruptAttack(attacker);\n}\n\nbool UnitCommandManager::canIssueMoveCommand(BWAPI::UnitInterface* unit, BWAPI::Position & position)\n{\n\tBWAPI::UnitCommand currentCommand(unit->getLastCommand());\n\tBWAPI::UnitCommandType commandType = currentCommand.getType();\n\n\tint threshold = 5;\n\n\t// if we have already given a command this frame, don't issue another one\n\t//if (commandType != BWAPI::UnitCommandTypes::None && BWAPI::Broodwar->getFrameCount() - unit->getLastCommandFrame() <= 7)\n\t//{\n\t//\tdrawDebugPlate(unit, \"M FRAME\");\n\t//\treturn false;\n\t//}\n\n\t//if (getUnitData(unit).isWaiting())\n\t//{\n\t//\tdrawDebugPlate(unit, \"WAIT\");\n\t//\treturn false;\n\t//}\n\n\t// if the last command given was an attack command\n\tif (currentCommand.type == BWAPI::UnitCommandTypes::Move)\n\t{\n\t\tif (!unit->isMoving())\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn unit->getDistance(position) < 28;\n\t\t}\n\t}\n\n\treturn !commandWillInterruptAttack(unit);\n}\n\nbool UnitCommandManager::canIssueStopCommand(BWAPI::UnitInterface* unit)\n{\n\t// if the last move was attacking a unit do nothing\n\tif (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Unit)\n\t{\n\t\treturn false;\n\t}\n\n\treturn !commandWillInterruptAttack(unit);\n}\n\nvoid UnitCommandManager::drawDebugPlate(BWAPI::UnitInterface* unit, char * string)\n{\n\tBWAPI::Broodwar->drawBoxMap(unit->getPosition().x-15, unit->getPosition().y-10, unit->getPosition().x + 10, unit->getPosition().y, BWAPI::Colors::Black, true);\n\tBWAPI::Broodwar->drawTextMap(unit->getPosition().x-15, unit->getPosition().y-10, string);\n}\n\nvoid UnitCommandManager::drawCommandStatus(BWAPI::UnitInterface* unit)\n{\n\tBWAPI::UnitType type = unit->getType();\n\tint width = type.dimensionRight();\n\tint height = type.dimensionDown()/6;\n\n\tint x1 = unit->getPosition().x - width;\n\tint x2 = unit->getPosition().y + width;\n\tint y1 = unit->getPosition().y - height;\n\tint y2 = unit->getPosition().y + height;\n}\n\nvoid UnitCommandManager::waitCommand(BWAPI::UnitInterface* unit)\n{\n\tgetUnitData(unit).waitCommand();\n}\n\nvoid UnitCommandManager::smartReload(BWAPI::UnitInterface* unit)\n{\n\tassert(unit);\n\n\tif (!canIssueStopCommand(unit))\n\t{\n\t\treturn;\n\t}\n\n\tunit->stop();\n\twaitCommand(unit);\n}\n\nvoid UnitCommandManager::smartAttackUnit(BWAPI::UnitInterface* attacker, BWAPI::UnitInterface* target)\n{\n\tassert(attacker && target);\n\n\tif (!canIssueAttackCommand(attacker, target))\n\t{\n\t\treturn;\n\t}\n\n\tattacker->attack(target);\n\n\tif (Config::Debug::DrawUnitTargetInfo) \n\t{\n\t\tBWAPI::Broodwar->drawLineMap(attacker->getPosition().x+3, attacker->getPosition().y+3, target->getPosition().x+3, target->getPosition().y+3, BWAPI::Colors::Red );\n\t}\n}\n\nvoid UnitCommandManager::smartMove(BWAPI::UnitInterface* attacker, BWAPI::Position targetPosition)\n{\n\tassert(attacker);\n\n\tif (!canIssueMoveCommand(attacker, targetPosition))\n\t{\n\t\treturn;\n\t}\n\t\n\tattacker->move(targetPosition);\n\n\tif (Config::Debug::DrawUnitTargetInfo) \n\t{\n\t\tBWAPI::Broodwar->drawLineMap(attacker->getPosition().x, attacker->getPosition().y, targetPosition.x, targetPosition.y, BWAPI::Colors::Orange);\n\t}\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/sparcraft/UnitCommandManager.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"BWAPI.h\"\n#include \"UnitCommandData.h\"\n\nnamespace UAlbertaBot\n{\n\nclass UnitCommandManager\n{\n\tstd::map<BWAPI::UnitInterface*, UnitCommandData> map;\n\n\tUnitCommandData & getUnitData(BWAPI::UnitInterface* unit);\n\n\tUnitCommandManager();\n\npublic:\n\n\tstatic UnitCommandManager &\tInstance();\n\n\tvoid update();\n\tvoid updateUnit(BWAPI::UnitInterface* unit);\n\tvoid addUnit(BWAPI::UnitInterface* unit);\n\tvoid removeUnit(BWAPI::UnitInterface* unit);\n\tvoid drawDebugPlate(BWAPI::UnitInterface* unit, char * string);\n\tvoid drawCommandStatus(BWAPI::UnitInterface* unit);\n\n\tbool exists(BWAPI::UnitInterface* unit) const;\n\tbool commandWillInterruptAttack(BWAPI::UnitInterface* unit);\n\tbool canIssueAttackCommand(BWAPI::UnitInterface* attacker, BWAPI::UnitInterface* target);\n\tbool canIssueMoveCommand(BWAPI::UnitInterface* unit, BWAPI::Position & position);\n\tbool canIssueStopCommand(BWAPI::UnitInterface* unit);\n\tint attackAnimStartTime(BWAPI::UnitInterface* unit);\n\n\tvoid smartAttackUnit(BWAPI::UnitInterface* attacker, BWAPI::UnitInterface* target);\n\tvoid smartMove(BWAPI::UnitInterface* attacker, BWAPI::Position targetPosition);\n\tvoid smartReload(BWAPI::UnitInterface* unit);\n\n\tvoid waitCommand(BWAPI::UnitInterface* unit);\n\tvoid attackCommand(BWAPI::UnitInterface* unit);\n};\n\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/visualizer/Display.cpp",
    "content": "#include \"Common.h\"\n#include \"Display.h\"\n\n#include <BWAPI.h>\n#include <BWTA.h>\nusing namespace BWAPI;\n\n#ifdef USE_SDL\n\n#include <SDL.h>\n#include <SDL_opengl.h>\n\nDisplay::Display() : windowSizeX(640), windowSizeY(480), bl(false), br(false), bu(false), bd(false)\n{\n\tif(SDL_Init(SDL_INIT_VIDEO) != 0)\n\t{\n\t\tthrow std::runtime_error(\"Unable to initialise SDL\");\n\t}\n}\n\nDisplay::~Display()\n{\n\tSDL_Quit();\n}\n\nvoid Display::OnStart()\n{\n\tmapWidth\t\t= Broodwar->mapWidth();\n\tmapHeight\t\t= Broodwar->mapHeight();\n\n\tmapPixelWidth\t= mapWidth * 32;\n\tmapPixelHeight\t= mapHeight * 32;\n\n\tconst BWAPI::Position position(Broodwar->self()->getStartLocation());\n\tcameraX\t\t\t= position.x() - windowSizeX / 2;\n\tcameraY\t\t\t= position.y() - windowSizeY / 2;\n\n\tSDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);\n\tSDL_SetVideoMode(windowSizeX, windowSizeY, 32, SDL_OPENGL);\n}\n\nvoid Display::OnFrame()\n{\n\t// Handle input events\n\tHandleEvents();\n\n\t// Render the frame\n\tglClear(GL_COLOR_BUFFER_BIT);\n\tRenderMainMap();\n\tRenderMinimap();\n\tSDL_GL_SwapBuffers();\n}\n\nvoid Display::HandleEvents()\n{\n\t// Handle SDL events\n\tSDL_Event event;\n\twhile(SDL_PollEvent(&event))\n\t{\n\t\tswitch(event.type)\n\t\t{\n\t\tcase SDL_KEYDOWN:\n\t\tcase SDL_KEYUP:\n\t\t\t{\n\t\t\t\tconst bool pressed(event.key.state == SDL_PRESSED);\n\t\t\t\tswitch(event.key.keysym.sym)\n\t\t\t\t{\n\t\t\t\tcase SDLK_LEFT:\t\tbl = pressed; break;\n\t\t\t\tcase SDLK_RIGHT:\tbr = pressed; break;\n\t\t\t\tcase SDLK_UP:\t\tbu = pressed; break;\n\t\t\t\tcase SDLK_DOWN:\t\tbd = pressed; break;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SDL_QUIT:\n\t\t\tthrow std::runtime_error(\"The user is a quitter\");\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Move the camera\n\tconst int cameraSpeed(128);\n\tif(bl) cameraX -= cameraSpeed;\n\tif(br) cameraX += cameraSpeed;\n\tif(bu) cameraY -= cameraSpeed;\n\tif(bd) cameraY += cameraSpeed;\n\n\tcameraX = std::max(0, std::min(cameraX, mapPixelWidth-windowSizeX));\n\tcameraY = std::max(0, std::min(cameraY, mapPixelHeight-windowSizeY));\n}\n\nvoid Display::RenderMainMap()\n{\n\tglPushAttrib(GL_ALL_ATTRIB_BITS);\n\n\tglMatrixMode(GL_PROJECTION);\n\tglPushMatrix();\n\tglOrtho(0,windowSizeX,windowSizeY,0,-1,1);\n\n\tglMatrixMode(GL_MODELVIEW);\n\tglPushMatrix();\n\tglTranslatef(static_cast<float>(-cameraX),static_cast<float>(-cameraY),0);\n\n\tconst int vx0(cameraX), vx1(cameraX+windowSizeX);\n\tconst int vy0(cameraY), vy1(cameraY+windowSizeY);\n\n\tRenderTerrain(\tstd::max(vx0>>3,0), std::max(vy0>>3,0), \n\t\t\t\t\tstd::min((vx1>>3) + 1, mapWidth*4),\n\t\t\t\t\tstd::min((vy1>>3) + 1, mapHeight*4));\n\tRenderTerrainAnalysis();\n\tRenderUnits();\n\n\tglPopMatrix();\n\tglMatrixMode(GL_PROJECTION);\n\tglPopMatrix();\n\n\tglPopAttrib();\n}\n\nvoid Display::RenderMinimap()\n{\n\tglPushAttrib(GL_ALL_ATTRIB_BITS);\n\n\tglMatrixMode(GL_PROJECTION);\n\tglPushMatrix();\n\n\tglOrtho(0,windowSizeX,0,windowSizeY,-1,1);\n\tglBegin(GL_QUADS);\n\tglVertex2i(0,0);\n\tglVertex2i(mapWidth+1,0);\n\tglVertex2i(mapWidth+1,mapHeight+1);\n\tglVertex2i(0,mapHeight+1);\n\tglEnd();\n\n\tglLoadIdentity();\n\tglOrtho(0,mapPixelWidth,mapPixelHeight,0,-1,1);\n\tglViewport(0,0,mapWidth,mapHeight);\n\n\tRenderTerrain(0,0,mapWidth*4,mapHeight*4);\n\tRenderUnits();\n\n\t// Render outline around viewport on minimap\n\t{\n\t\tconst int vpx0(cameraX), vpx1(vpx0 + windowSizeX);\n\t\tconst int vpy0(cameraY), vpy1(vpy0 + windowSizeY);\n\n\t\tglBegin(GL_LINE_STRIP);\n\t\tglColor3f(1,1,1);\n\t\tglVertex2i(vpx0,vpy0);\n\t\tglVertex2i(vpx1,vpy0);\n\t\tglVertex2i(vpx1,vpy1);\n\t\tglVertex2i(vpx0,vpy1);\n\t\tglVertex2i(vpx0,vpy0);\n\t\tglEnd();\n\t}\n\n\tglPopMatrix();\n\tglPopAttrib();\n}\n\nvoid Display::RenderTerrain(int wx0, int wy0, int wx1, int wy1) const\n{\n\tglBegin(GL_QUADS);\n\tfor(int y(wy0); y<wy1; ++y)\n\t{\n\t\tfor(int x(wx0); x<wx1; ++x)\n\t\t{\n\t\t\t// Determine coordinates of walk tile\n\t\t\tconst int x0(x * 8), x1(x0 + 8);\n\t\t\tconst int y0(y * 8), y1(y0 + 8);\n\n\t\t\tglColor3fv(GetWalkTileColor(x,y));\n\t\t\tglVertex2i(x0,y0);\n\t\t\tglVertex2i(x1,y0);\n\t\t\tglVertex2i(x1,y1);\n\t\t\tglVertex2i(x0,y1);\n\t\t}\n\t}\n\tglEnd();\n}\n\nvoid Display::RenderTerrainAnalysis() const\n{\n\tglBegin(GL_LINES);\n\n\t// Draw polygon outlines of regions in green\n\tglColor3f(0,1,0);\n\tBOOST_FOREACH(BWTA::Region * region, BWTA::getRegions())\n\t{\n\t\tconst BWTA::Polygon & polygon(region->getPolygon());\n\t\tfor(size_t i(0); i<polygon.size(); ++i)\n\t\t{\n\t\t\tconst Position & v0(polygon[i]);\n\t\t\tconst Position & v1(polygon[(i+1) % polygon.size()]);\n\t\t\tglVertex2i(v0.x(), v0.y());\n\t\t\tglVertex2i(v1.x(), v1.y());\n\t\t}\n\t}\n\n\t// Draw chokepoints in red\n\tglColor3f(1,0,0);\n\tBOOST_FOREACH(BWTA::Region * region, BWTA::getRegions())\n\t{\n\t\tBOOST_FOREACH(BWTA::Chokepoint * choke, region->getChokepoints())\n\t\t{\n\t\t\tconst Position & v0(choke->getSides().first);\n\t\t\tconst Position & v1(choke->getSides().second);\n\t\t\tglVertex2i(v0.x(), v0.y());\n\t\t\tglVertex2i(v1.x(), v1.y());\n\t\t}\n\t}\n\n\tglEnd();\n}\n\nvoid Display::RenderUnits() const\n{\n\tstatic const float3 factionColors[12] = \n\t{\n\t\tfloat3(1,0,0),\t\tfloat3(0,0,1),\t\t\tfloat3(0,1,0.5f),\tfloat3(0.5f,0,1),\n\t\tfloat3(1,0.5f,0),\tfloat3(0.5f,0.25f,0),\tfloat3(1,1,1),\t\tfloat3(1,1,0),\n\t\tfloat3(0,0,0),\t\tfloat3(0,0,0),\t\t\tfloat3(0,0,0),\t\tfloat3(0,1,1)\n\t};\n\n\tglBegin(GL_QUADS);\n\tBOOST_FOREACH(Unit * unit, Broodwar->getAllUnits())\n\t{\n\t\tconst UnitType type(unit->getType());\n\t\tconst int x0(unit->getPosition().x() - type.dimensionLeft());\n\t\tconst int x1(unit->getPosition().x() + type.dimensionRight());\n\t\tconst int y0(unit->getPosition().y() - type.dimensionUp());\n\t\tconst int y1(unit->getPosition().y() + type.dimensionDown());\n\n\t\tglColor3fv(factionColors[unit->getPlayer()->getID()]);\n\t\tglVertex2i(x0,y0);\n\t\tglVertex2i(x1,y0);\n\t\tglVertex2i(x1,y1);\n\t\tglVertex2i(x0,y1);\n\t}\n\tglEnd();\n}\n\nfloat3 Display::GetWalkTileColor(int x, int y) const\n{\n\t// Unexplored areas return black\n\tconst TilePosition pos(x/4,y/4);\n\tif(!Broodwar->isExplored(pos))\n\t{\n\t\treturn 0;\n\t}\n\n\t// Basic terrain color\n\tfloat3 color(0.2f);\n\tif(Broodwar->isWalkable(x,y))\n\t{\n\t\tcolor = 0.4f + Broodwar->getGroundHeight(x,y) * 0.2f;\n\t\tif(!Broodwar->isBuildable(pos))\n\t\t{\n\t\t\tcolor *= float3(1,0.5f,0.5f);\n\t\t}\n\t}\n\n\t// Adjust for creep\n\tif(Broodwar->hasCreep(pos))\n\t{\n\t\tcolor = float3(0.2f,0,0.3f);\n\t}\n\n\t// Adjust for fog of war\n\tif(!Broodwar->isVisible(pos))\n\t{\n\t\tcolor /= 2;\n\t}\n\treturn color;\n}\n\n#else\n\nDisplay::Display() {}\nDisplay::~Display() {}\nvoid Display::OnStart() {}\nvoid Display::OnFrame() {}\n\n#endif"
  },
  {
    "path": "UAlbertaBot/Source/research/visualizer/Display.h",
    "content": "#ifndef DISPLAY_H\n#define DISPLAY_H\n\nstruct float3\n{\n\tfloat x,y,z;\n\n\tfloat3() {}\n\tfloat3(float f) : x(f), y(f), z(f) {}\n\tfloat3(float x, float y, float z) : x(x), y(y), z(z) {}\n\n\toperator const float * () const { return &x; }\n\tfloat3 operator + (const float3 & v) const { return float3(x+v.x,y+v.y,z+v.z); }\n\tfloat3 operator - (const float3 & v) const { return float3(x-v.x,y-v.y,z-v.z); }\n\tfloat3 operator * (const float3 & v) const { return float3(x*v.x,y*v.y,z*v.z); }\n\tfloat3 operator / (const float3 & v) const { return float3(x/v.x,y/v.y,z/v.z); }\n\n\toperator float * () { return &x; }\n\tconst float3 & operator += (const float3 & v) { x+=v.x; y+=v.y; z+=v.z; return *this; }\n\tconst float3 & operator -= (const float3 & v) { x-=v.x; y-=v.y; z-=v.z; return *this; }\n\tconst float3 & operator *= (const float3 & v) { x*=v.x; y*=v.y; z*=v.z; return *this; }\n\tconst float3 & operator /= (const float3 & v) { x/=v.x; y/=v.y; z/=v.z; return *this; }\n};\n\nclass Display\n{\n\tint\twindowSizeX;\n\tint windowSizeY;\n\n\tint cameraX;\n\tint cameraY;\n\n\tint mapWidth;\n\tint mapHeight;\n\n\tint mapPixelWidth;\n\tint mapPixelHeight;\n\n\tbool bl,br,bd,bu;\n\n\tvoid HandleEvents();\n\tvoid RenderMainMap();\n\tvoid RenderMinimap();\n\n\tvoid RenderTerrain(int wx0, int wy0, int wx1, int wy1) const;\n\tvoid RenderTerrainAnalysis() const;\n\tvoid RenderUnits() const;\n\n\tfloat3 GetWalkTileColor(int x, int y) const;\npublic:\n\tDisplay();\n\t~Display();\n\n\tvoid OnStart();\n\tvoid OnFrame();\n};\n\n#endif"
  },
  {
    "path": "UAlbertaBot/Source/research/visualizer/EnhancedInterface.hpp",
    "content": "#pragma once\n\n#include <vector>\n#include <map>\n#include \"BWAPI.h\"\n\nnamespace UAlbertaBot\n{\nclass ControlGroupData\n{\n\tstd::map<BWAPI::Key, std::set<BWAPI::UnitInterface*>> keyMap;\n\npublic:\n\n\tControlGroupData() {}\n\t~ControlGroupData() {}\n\n\tvoid update()\n\t{\n\t\t\n\t\t\n\t}\n\n\tvoid onUnitDestroy(BWAPI::UnitInterface* unit)\n\t{\n\t\ttypedef std::map<BWAPI::Key, std::set<BWAPI::UnitInterface*>> mapType;\n\t\tfor (mapType::value_type & t : keyMap)\n\t\t{\n\t\t\tt.second.erase(unit);\n\t\t}\n\t}\n\n\t// sets control group to only selected units\n\tvoid newControlGroup(BWAPI::Key k)\n\t{\n\t\tBWAPI::Broodwar->printf(\"New control group %d\", k-BWAPI::K_0);\n\n\t\tkeyMap[k] = std::set<BWAPI::UnitInterface*>();\n\n\t\tfor (BWAPI::UnitInterface* unit : BWAPI::Broodwar->getSelectedUnits())\n\t\t{\n\t\t\tif (unit->getPlayer() == BWAPI::Broodwar->self())\n\t\t\t{\n\t\t\t\tkeyMap[k].insert(unit);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid addToControlGroup(BWAPI::Key k)\n\t{\n\t\tBWAPI::Broodwar->printf(\"Add to control group %d\", k-BWAPI::K_0);\n\n\t\tif (!controlGroupExists(k))\n\t\t{\n\t\t\tkeyMap[k] = std::set<BWAPI::UnitInterface*>();\n\t\t}\n\n\t\tfor (BWAPI::UnitInterface* unit : BWAPI::Broodwar->getSelectedUnits())\n\t\t{\n\t\t\tif (unit->getPlayer() == BWAPI::Broodwar->self())\n\t\t\t{\n\t\t\t\tkeyMap[k].insert(unit);\n\t\t\t}\n\t\t}\n\t}\n\n\tbool controlGroupExists(BWAPI::Key k)\n\t{\n\t\treturn keyMap.find(k) != keyMap.end();\n\t}\n\n\tstd::set<BWAPI::UnitInterface*> * getControlGroupUnits(BWAPI::Key k)\n\t{\n\t\tif (!controlGroupExists(k))\n\t\t{\n\t\t\tkeyMap[k] = std::set<BWAPI::UnitInterface*>();\n\t\t}\n\n\t\treturn &keyMap[k];\n\t}\n};\n\nclass EnhancedInterface\n{\n\tint lastKeyEvent;\n\tint lastControlGroup;\n\tstd::vector<BWAPI::Key> keys;\n\n\tControlGroupData data;\n\n\tstd::set<BWAPI::UnitInterface*> * selectedUnits;\n\npublic:\n\n\tEnhancedInterface() \n\t\t: lastKeyEvent(0)\n\t\t, lastControlGroup(0)\n\t\t, selectedUnits(NULL)\n\t{\n\t\t// numbers\n\t\tkeys.push_back(BWAPI::K_0);\n\t\tkeys.push_back(BWAPI::K_1);\n\t\tkeys.push_back(BWAPI::K_2);\n\t\tkeys.push_back(BWAPI::K_3);\n\t\tkeys.push_back(BWAPI::K_4);\n\t\tkeys.push_back(BWAPI::K_5);\n\t\tkeys.push_back(BWAPI::K_6);\n\t\tkeys.push_back(BWAPI::K_7);\n\t\tkeys.push_back(BWAPI::K_8);\n\t\tkeys.push_back(BWAPI::K_9);\n\n\t\t// letters\n\t\tkeys.push_back(BWAPI::K_A);\n\t\tkeys.push_back(BWAPI::K_B);\n\t\tkeys.push_back(BWAPI::K_C);\n\t\tkeys.push_back(BWAPI::K_D);\n\t\tkeys.push_back(BWAPI::K_E);\n\t\tkeys.push_back(BWAPI::K_F);\n\t\tkeys.push_back(BWAPI::K_G);\n\t\tkeys.push_back(BWAPI::K_H);\n\t\tkeys.push_back(BWAPI::K_I);\n\t\tkeys.push_back(BWAPI::K_J);\n\t\tkeys.push_back(BWAPI::K_K);\n\t\tkeys.push_back(BWAPI::K_L);\n\t\tkeys.push_back(BWAPI::K_M);\n\t\tkeys.push_back(BWAPI::K_N);\n\t\tkeys.push_back(BWAPI::K_O);\n\t\tkeys.push_back(BWAPI::K_P);\n\t\tkeys.push_back(BWAPI::K_Q);\n\t\tkeys.push_back(BWAPI::K_R);\n\t\tkeys.push_back(BWAPI::K_S);\n\t\tkeys.push_back(BWAPI::K_T);\n\t\tkeys.push_back(BWAPI::K_U);\n\t\tkeys.push_back(BWAPI::K_V);\n\t\tkeys.push_back(BWAPI::K_W);\n\t\tkeys.push_back(BWAPI::K_X);\n\t\tkeys.push_back(BWAPI::K_Y);\n\t\tkeys.push_back(BWAPI::K_Z);\n\t}\n\t\n\t~EnhancedInterface() {}\n\n\tvoid onUnitDestroy(BWAPI::UnitInterface* unit)\n\t{\n\t\tdata.onUnitDestroy(unit);\n\t}\n\n\tvoid update() \n\t{\n\t\tdata.update();\n\t\tprocessKeyboardEvents();\n\t\tprocessMouseEvents();\n\n\t\tif (selectedUnits)\n\t\t{\n\t\t\tdrawSelectedUnits(175,275);\n\t\t}\n\t}\n\n\tvoid processKeyboardEvents()\n\t{\n\t\tfor (BWAPI::Key k : keys)\n\t\t{\n\t\t\tif (BWAPI::Broodwar->getKeyState(k))\n\t\t\t{\n\t\t\t\tkeyboardEvent(k);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid processMouseEvents()\n\t{\n\t\tif (BWAPI::Broodwar->getMouseState(BWAPI::M_RIGHT))\n\t\t{\n\t\t\tmouseEvent(BWAPI::M_RIGHT);\n\t\t}\n\t}\n\n\tvoid mouseEvent(BWAPI::MouseButton m)\n\t{\n\t\tint mouseMapX = BWAPI::Broodwar->getMousePosition().x + BWAPI::Broodwar->getScreenPosition().x;\n\t\tint mouseMapY = BWAPI::Broodwar->getMousePosition().y + BWAPI::Broodwar->getScreenPosition().y;\n\n\t\tif (m == BWAPI::M_RIGHT)\n\t\t{\n\t\t\tif (selectedUnits)\n\t\t\t{\n\t\t\t\tfor (BWAPI::UnitInterface* unit : *selectedUnits)\n\t\t\t\t{\n\t\t\t\t\tunit->rightClick(BWAPI::Position(mouseMapX, mouseMapY));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid keyboardEvent(BWAPI::Key k)\n\t{\n\t\tif (!validKeyEvent())\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tbool control = BWAPI::Broodwar->getKeyState(BWAPI::K_CONTROL);\n\t\tbool shift = BWAPI::Broodwar->getKeyState(BWAPI::K_SHIFT);\n\n\t\tstd::string prefix = std::string(\"\") + (control ? \"CTRL + \" : \"\") + (shift ? \"SHIFT + \" : \"\");\n\t\t\n\t\t//BWAPI::Broodwar->printf(\"Key Pressed: %s %d\", prefix.c_str(), k);\n\n\t\tswitch (k) \n\t\t{\n\t\t\tcase BWAPI::K_D : \n\t\t\t\tOptions::Debug::DRAW_DEBUG_INTERFACE = false;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (k >= BWAPI::K_0 && k <= BWAPI::K_9)\n\t\t{\n\t\t\tif (shift && control)\n\t\t\t{\n\t\t\t\tdata.newControlGroup(k);\n\t\t\t\tselectedUnits = data.getControlGroupUnits(k);\n\t\t\t\tlastControlGroup = k;\n\t\t\t}\n\t\t\telse if (control)\n\t\t\t{\n\t\t\t\tdata.addToControlGroup(k);\n\t\t\t\tselectedUnits = data.getControlGroupUnits(k);\n\t\t\t\tlastControlGroup = k;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tselectedUnits = data.getControlGroupUnits(k);\n\t\t\t\tlastControlGroup = k;\n\t\t\t}\n\t\t}\n\n\t\tlastKeyEvent = BWAPI::Broodwar->getFrameCount();\n\t}\n\n\tbool validKeyEvent()\n\t{\n\t\treturn (BWAPI::Broodwar->getFrameCount() - lastKeyEvent) > 20;\n\t}\n\n\tvoid drawSelectedUnits(int x, int y)\n\t{\n\t\t\n\t\tint col = 0;\n\t\tint row = 0;\n\t\tint cols = 12;\n\n\t\tBWAPI::Broodwar->drawBoxScreen(x-5, y-15, x+10+cols*22, y+100, BWAPI::Colors::Black, true);\n\n\t\tBWAPI::Broodwar->drawTextScreen(x, y-13,\t\"\\x07%d Selected Units: Group %d\", selectedUnits->size(), lastControlGroup - BWAPI::K_0);\n\t\tint yskip = 0;\n\n\t\tint xx = x;\n\t\tint yy = y;\n\n\n\t\tfor (BWAPI::UnitInterface* unit : *selectedUnits)\n\t\t{\n\t\t\txx = x + (col%cols) * 22;\n\t\t\tyy = y + (col/cols) * 26;\n\n\t\t\tBWAPI::Broodwar->drawCircleMap(unit->getPosition().x, unit->getPosition().y, unit->getType().dimensionLeft(), BWAPI::Colors::Green, false);\n\t\t\t\n\t\t\tif (unit->getType().isBuilding())\n\t\t\t{\n\t\t\t\tBWAPI::Broodwar->drawLineMap(unit->getPosition().x, unit->getPosition().y, unit->getRallyPosition().x, unit->getRallyPosition().y, BWAPI::Colors::White);\n\t\t\t}\n\n\t\t\t\n\t\t\tdrawUnit(unit, xx, yy);\n\n\t\t\tcol++;\n\t\t}\n\t}\n\n\tvoid drawUnit(BWAPI::UnitInterface* unit, int x, int y)\n\t{\n\t\tint BOX_HEIGHT = 20;\n\t\tint BOX_WIDTH = 20;\n\n\t\tint unitHealth = unit->getHitPoints() + unit->getShields();\n\t\tint maxUnitHealth = unit->getType().maxHitPoints() + unit->getType().maxShields();\n\n\t\tchar unitChar = unit->getType().getName()[8];\n\n\t\tstd::string prefixColor = \"\\x07\";\n\n\t\tBWAPI::Color boxColor = BWAPI::Colors::Green;\n\n\t\tif (unitHealth < maxUnitHealth / 3)\n\t\t{\n\t\t\tboxColor = BWAPI::Colors::Red;\n\t\t\tprefixColor = \"\\x08\";\n\t\t}\n\t\telse if (unitHealth < 2 * maxUnitHealth / 3)\n\t\t{\n\t\t\tboxColor = BWAPI::Colors::Orange;\n\t\t\tprefixColor = \"\\x11\";\n\t\t}\n\n\t\tBWAPI::Broodwar->drawBoxScreen(x, y, x + BOX_WIDTH, y + BOX_HEIGHT, BWAPI::Colors::Black, true);\n\t\tBWAPI::Broodwar->drawBoxScreen(x, y, x + BOX_WIDTH, y + BOX_HEIGHT, boxColor, false);\n\t\tBWAPI::Broodwar->drawTextScreen(x + 2, y + 1, \"%s%c\", prefixColor.c_str(), unitChar);\n\n\t\tBWAPI::Color statusColor = getUnitColor(unit);\n\n\t\tint SUB_BOX_HEIGHT = 5;\n\n\t\tBWAPI::Broodwar->drawBoxScreen(x, y+BOX_HEIGHT+1, x+(int)(getBoxWidth(unit)*BOX_WIDTH), y+BOX_HEIGHT+SUB_BOX_HEIGHT, statusColor, true);\n\t}\n\n\tBWAPI::Color getUnitColor(BWAPI::UnitInterface* unit)\n\t{\n\t\tif (unit->getType().isWorker())\n\t\t{\n\t\t\tif (unit->isGatheringMinerals())\n\t\t\t{\n\t\t\t\treturn BWAPI::Colors::Cyan;\n\t\t\t}\n\n\t\t\tif (unit->isGatheringGas())\n\t\t\t{\n\t\t\t\treturn BWAPI::Colors::Green;\n\t\t\t}\n\n\t\t\tif (unit->isIdle())\n\t\t\t{\n\t\t\t\treturn BWAPI::Colors::Grey;\n\t\t\t}\n\t\t}\n\n\t\tif (unit->getType().isBuilding())\n\t\t{\n\t\t\tif (unit->isTraining())\n\t\t\t{\n\t\t\t\treturn BWAPI::Colors::Grey;\n\t\t\t}\n\n\t\t\treturn BWAPI::Colors::Black;\n\t\t}\n\n\t\treturn BWAPI::Colors::Red;\n\t}\n\n\tdouble getBoxWidth(BWAPI::UnitInterface* unit)\n\t{\n\t\tif (unit->isTraining())\n\t\t{\n\t\t\treturn 1 - (double)unit->getRemainingTrainTime() / unit->getTrainingQueue().front().buildTime();\n\t\t}\n\n\t\treturn 1;\n\t}\n};\n}"
  },
  {
    "path": "UAlbertaBot/Source/research/visualizer/ReplayVisualizer.cpp",
    "content": "#include \"ReplayVisualizer.h\"\n\n#ifdef USING_VISUALIZATION_LIBRARIES\n\n/*\nReplayVisualizer::ReplayVisualizer() \n\t: map(BWAPI::Broodwar)\n{\n\t\n}\n\nvoid ReplayVisualizer::launchSimulation(const BWAPI::Position & center, const int & radius)\n{\n\t// set up the display object\n\tSparCraft::Display display(SparCraft::Display(BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight()));\n\tdisplay.OnStart();\n\tdisplay.LoadMapTexture(&map, 19);\n\n\t// extract the state from the current state of BWAPI\n\tSparCraft::GameState state;\n\tsetCombatUnits(state, center, radius);\n\tstate.setMap(&map);\n\n\t// get search player objects for us and the opponent\n\tPlayerPtr selfPlayer(getSearchPlayer(SparCraft::PlayerToMove::Alternate, SparCraft::Players::Player_One, SparCraft::EvaluationMethods::Playout, 40));\n\tPlayerPtr enemyPlayer(SparCraft::AllPlayers::getPlayerPtr(SparCraft::Players::Player_Two, SparCraft::PlayerModels::AttackClosest));\n\n\t// set up the game\n\tSparCraft::Game g(state, selfPlayer, enemyPlayer, 1000);\n\tg.disp = &display;\n\n\t// play the game to the end\n\tg.play();\n}\n\nvoid ReplayVisualizer::setCombatUnits(SparCraft::GameState & state, const BWAPI::Position & center, const int radius)\n{\n\n\tint selfUnits = 0;\n\tBOOST_FOREACH (BWAPI::UnitInterface* unit, BWAPI::Broodwar->getPlayer(1)->getUnits())\n\t{\n\t\tbool inRadius = unit->getDistance(center) < radius;\n\n\t\tif (selfUnits < 8 && inRadius && isCombatUnit(unit->getType()))\n\t\t{\n\t\t\tselfUnits++;\n\t\t\t// FIX state.addUnit(SparCraft::Unit(unit, SparCraft::Players::Player_One, BWAPI::Broodwar->getFrameCount()));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// FIX state.addNeutralUnit(SparCraft::Unit(unit, SparCraft::Players::Player_One, BWAPI::Broodwar->getFrameCount()));\n\t\t}\n\t}\n\n\tint enemyUnits = 0;\n\tBOOST_FOREACH (BWAPI::UnitInterface* unit, BWAPI::Broodwar->getPlayer(0)->getUnits())\n\t{\n\t\tif (enemyUnits >= 8)\n\t\t{\n\t\t\tbreak;\n\t\t}\n\n\t\tbool inRadius = unit->getDistance(center) < radius;\n\n\t\tif (enemyUnits < 8 && inRadius && isCombatUnit(unit->getType()) && !unit->getType().isFlyer())\n\t\t{\n\t\t\tenemyUnits++;\n\t\t\t// FIX state.addUnit(SparCraft::Unit(unit,Search::Players::Player_Two, BWAPI::Broodwar->getFrameCount()));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// FIX state.addNeutralUnit(SparCraft::Unit(unit, Search::Players::Player_Two, BWAPI::Broodwar->getFrameCount()));\n\t\t}\n\t}\n\n\tint neutralUnits = 0;\n\tBOOST_FOREACH (BWAPI::UnitInterface* unit, BWAPI::Broodwar->getAllUnits())\n\t{\n\t\tneutralUnits++;\n\n\t\tconst IDType player(getPlayer(unit->getPlayer()));\n\n\t\tif (unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field ||\n\t\t\tunit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser)\n\t\t{\n\t\t\t// FIX state.addNeutralUnit(SparCraft::Unit(unit, Search::Players::Player_None, BWAPI::Broodwar->getFrameCount()));\n\t\t}\n\t}\n\n\tstate.finishedMoving();\n}\n\nbool ReplayVisualizer::isCombatUnit(BWAPI::UnitType type) const\n{\n\tif (type == BWAPI::UnitTypes::Zerg_Lurker || type == BWAPI::UnitTypes::Protoss_Dark_Templar)\n\t{\n\t\treturn false;\n\t}\n\n\t// no workers or buildings allowed\n\tif (type.isWorker())\n\t{\n\t\treturn false;\n\t}\n\n\t// check for various types of combat units\n\tif (type.canAttack() || type == BWAPI::UnitTypes::Terran_Medic)\n\t{\n\t\treturn true;\n\t}\n\t\t\n\treturn false;\n}\n\nPlayerPtr ReplayVisualizer::getSearchPlayer(const IDType & playerToMoveMethod, const IDType & playerID, const IDType & evalMethod, const size_t & timeLimitMS)\n{\n    IDType bestResponseTo = SparCraft::PlayerModels::NOKDPS;\n\n\t// base parameters to use in search\n\tSparCraft::AlphaBetaSearchParameters baseParameters;\n\tbaseParameters.setMaxPlayer(playerID);\n\tbaseParameters.setSearchMethod(SparCraft::SearchMethods::IDAlphaBeta);\n\tbaseParameters.setEvalMethod(evalMethod);\n\tbaseParameters.setMaxDepth(SparCraft::Constants::Max_Search_Depth);\n    //baseParameters.setScriptMoveFirstMethod(SparCraft::PlayerModels::NOKDPS);\n\tbaseParameters.setTimeLimit(timeLimitMS);\n\t\n\t// IF USING OPPONENT MODELING SET IT HERE\n\tbaseParameters.setModelSimMethod(bestResponseTo);\n\tbaseParameters.setPlayerModel(Search::Players::Player_Two, bestResponseTo, true);\n\n\tbaseParameters.setPlayerToMoveMethod(playerToMoveMethod);\n\treturn PlayerPtr(new MicroSearch::Player_AlphaBeta(playerID, baseParameters, MicroSearch::TTPtr(new MicroSearch::TranspositionTable())));\n}\n\nconst MicroSearch::Unit ReplayVisualizer::getUnit(const UnitInfo & ui, const IDType & playerID) const\n{\n\tBWAPI::UnitType type = ui.type;\n\n\treturn MicroSearch::Unit(ui.type, MicroSearch::Position(ui.lastPosition.x, ui.lastPosition.y), ui.unitID, playerID, ui.lastHealth, 0,\n\t\tBWAPI::Broodwar->getFrameCount(), BWAPI::Broodwar->getFrameCount());\t\n}\n\nconst IDType ReplayVisualizer::getPlayer(BWAPI::UnitInterface* unit) const\n{\n\treturn getPlayer(unit->getPlayer());\n}\n\nconst IDType ReplayVisualizer::getPlayer(BWAPI::PlayerInterface * player) const\n{\n\tif (player == BWAPI::Broodwar->self())\n\t{\n\t\treturn SparCraft::Players::Player_Two;\n\t}\n\telse if (player == BWAPI::Broodwar->enemy())\n\t{\n\t\treturn SparCraft::Players::Player_One;\n\t}\n\n\treturn SparCraft::Players::Player_None;\n}\n*/\n#endif"
  },
  {
    "path": "UAlbertaBot/Source/research/visualizer/ReplayVisualizer.h",
    "content": "#pragma once\n\n#include \"..\\..\\SparCraft\\source\\SparCraft.h\"\n\n#ifdef USING_VISUALIZATION_LIBRARIES\n\n#include <Common.h>\n\n#include \"InformationManager.h\"\n#include \"MapGrid.h\"\n\nnamespace UAlbertaBot\n{\nclass ReplayVisualizer \n{\n\tSparCraft::Map map;\n\n\tconst IDType getPlayer(BWAPI::UnitInterface* unit) const;\n\tconst IDType getPlayer(BWAPI::PlayerInterface * player) const;\n\tvoid setCombatUnits(SparCraft::GameState & s, const BWAPI::Position & center, const int radius);\n\tconst SparCraft::Unit getUnit(const UnitInfo & ui, const IDType & playerID) const;\n\tbool isCombatUnit(BWAPI::UnitType type) const;\n\n\tSparCraft::PlayerPtr getSearchPlayer(const IDType & playerToMoveMethod, const IDType & playerID, const IDType & evalMethod, const size_t & timeLimitMS);\n\npublic:\n\n\tReplayVisualizer();\n\tvoid ReplayVisualizer::launchSimulation(const BWAPI::Position & pos, const int & radius);\n};\n}\n\n#endif"
  },
  {
    "path": "UAlbertaBot/Source/research/visualizer/Visualizer.cpp",
    "content": "#include \"Visualizer.h\"\n\n#ifdef USING_VISUALIZATION_LIBRARIES\n\nVisualizer & Visualizer::Instance() \n{\n\tstatic Visualizer instance;\n\treturn instance;\n}\n\nVisualizer::Visualizer() \n\t: display(SparCraft::Display(BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight()))\n{\n\tmap = SparCraft::Map(BWAPI::Broodwar);\n\tmap.write(\"C:\\\\test.txt\");\n\tdisplay.OnStart();\n\t\n\tdisplay.LoadMapTexture(&map, 19);\n}\n\nvoid Visualizer::setBWAPIState()\n{\n\tSparCraft::GameState state;\n\tstate.setMap(&map);\n\n\tBOOST_FOREACH (BWAPI::UnitInterface* unit, BWAPI::Broodwar->getAllUnits())\n\t{\n\t\tconst IDType player(getPlayer(unit->getPlayer()));\n\n\t\tif (player == SparCraft::Players::Player_One || player == SparCraft::Players::Player_Two)\n\t\t{\n\t\t\t// FIX state.addUnit(SparCraft::Unit(unit, player, BWAPI::Broodwar->getFrameCount()));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field ||\n\t\t\t\tunit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser)\n\t\t\t{\n\t\t\t\t// FIX state.addNeutralUnit(SparCraft::Unit(unit, SparCraft::Players::Player_None, BWAPI::Broodwar->getFrameCount()));\n\t\t\t}\n\t\t}\n\t}\n\n\tsetState(state);\n}\n\nvoid Visualizer::setState(const SparCraft::GameState & state)\n{\n\tdisplay.SetState(state);\n}\n\nvoid Visualizer::onFrame()\n{\n\tdisplay.OnFrame();\n}\n\nconst IDType Visualizer::getPlayer(BWAPI::UnitInterface* unit) const\n{\n\treturn getPlayer(unit->getPlayer());\n}\n\nconst IDType Visualizer::getPlayer(BWAPI::PlayerInterface * player) const\n{\n\tif (player == BWAPI::Broodwar->self())\n\t{\n\t\treturn SparCraft::Players::Player_One;\n\t}\n\telse if (player == BWAPI::Broodwar->enemy())\n\t{\n\t\treturn SparCraft::Players::Player_Two;\n\t}\n\n\treturn SparCraft::Players::Player_None;\n}\n\n#endif"
  },
  {
    "path": "UAlbertaBot/Source/research/visualizer/Visualizer.h",
    "content": "#pragma once\n\n#include \"..\\..\\SparCraft\\source\\SparCraft.h\"\n\n#ifdef USING_VISUALIZATION_LIBRARIES\n\n#include <Common.h>\n\nnamespace UAlbertaBot\n{\nclass Visualizer \n{\n\tVisualizer();\n\tVisualizer(int mapWidth, int mapHeight, int cellSize);\n\n\tSparCraft::Display display;\n\tSparCraft::GameState state;\n\tSparCraft::Map map;\n\n\tconst IDType getPlayer(BWAPI::UnitInterface* unit) const;\n\tconst IDType getPlayer(BWAPI::PlayerInterface * player) const;\n\npublic:\n\n\t// yay for singletons!\n\tstatic Visualizer &\tInstance();\n\t\n\tvoid setBWAPIState();\n\tvoid setState(const SparCraft::GameState & state);\n\tvoid onFrame();\n};\n}\n#endif"
  },
  {
    "path": "UAlbertaBot/Source/stardraft/BaseBorderFinder.hpp",
    "content": "#pragma once\n\n#include \"Grid2D.hpp\"\n#include \"StarDraftMap.hpp\"\n#include <algorithm>\n\n#include <vector>\n\n// a base is just a rectangle encompassing some portion of the map\n// if translated back to BWAPI, just add all the resources in the rectabgle\nstruct BaseBorder\n{\n    int left    = std::numeric_limits<int>::max();\n    int right   = std::numeric_limits<int>::min();\n    int top     = std::numeric_limits<int>::max();\n    int bottom  = std::numeric_limits<int>::min();\n\n    bool contains(int x, int y) const\n    {\n        return (x >= left) && (x <= right) && (y >= top) && (y <= bottom);\n    }\n};\n\nstruct Cluster\n{\n    std::vector<Tile> minerals;\n    std::vector<Tile> gas;\n    std::vector<Tile> allResources;\n};\n\nclass BaseBorderFinder\n{    \n    struct Direction { char x = 0, y = 0; };\n\n    const StarDraftMap *    m_map = nullptr;\n    std::vector<BaseBorder> m_baseBorders;\n    Grid2D<int>             m_resourceDist;\n    Grid2D<int>             m_resourceClusterLabels;\n    int                     m_maxDepth = 5;\n    int                     m_ops = 0;\n    std::vector<Tile>       m_stack;\n    std::vector<Direction>  m_actions = { {0,1}, {0,-1}, {1,0}, {-1,0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1} };\n    std::vector<Cluster>    m_resourceClusters;\n    \n    void resourceDistanceBFS(int x, int y)\n    {\n        m_stack.clear();\n\n        m_stack.push_back({x, y});\n        m_resourceDist.set(x, y, 0);\n\n        // iterate until the current pointer meets the end\n        for (size_t i = 0; i < m_stack.size(); i++)\n        {\n            // get a copy of the cell and its distance to avoid future lookups\n            Tile tile = m_stack[i];\n            int dist = m_resourceDist.get(tile.x, tile.y);\n\n            // if we've gone far enough away, stop\n            if (dist == m_maxDepth) { return; }\n\n            // look out in each direction\n            for (size_t a = 0; a < m_actions.size(); a++)\n            {\n                // calculate the child cell\n                Tile next ={tile.x + m_actions[a].x, tile.y + m_actions[a].y};\n\n                // if this child is a valid cell we can do stuff with it\n                if (m_map->isValid(next.x, next.y) && m_map->isWalkable(next.x, next.y))\n                {\n                    // save the distance to the next cell to avoid another lookup\n                    auto nval = m_resourceDist.get(next.x, next.y);\n\n                    // if we haven't seen this cell before\n                    if (nval == -1)\n                    {\n                        // add it to the stack and set the distance\n                        m_stack.emplace_back(next);\n                        m_ops++;\n                        m_resourceDist.set(next.x, next.y, dist + 1);\n                    }\n                }\n            }\n        }\n    }\n\n    // this will form a cluster of resource tiles by BFSing from x,y\n    // x, y will be a resource tile of unassigned cluster\n    Cluster resourceClusterFormationBFS(int x, int y, int clusterNumber)\n    {\n        m_stack.clear();\n        m_stack.push_back({x, y});\n\n        // the vector of resource tiles for this cluster\n        Cluster cluster;\n\n        // iterate until the current pointer meets the end\n        for (size_t i = 0; i < m_stack.size(); i++)\n        {\n            // get a copy of the cell and its distance to avoid future lookups\n            Tile tile = m_stack[i];\n\n            if (m_map->isMineral(tile.x, tile.y)) { cluster.minerals.push_back(tile); }\n            if (m_map->isGas(tile.x, tile.y)) { cluster.gas.push_back(tile); }\n            if (m_map->isResource(tile.x, tile.y)) { cluster.allResources.push_back(tile); }\n\n            // look out in each direction\n            for (size_t a = 0; a < m_actions.size(); a++)\n            {\n                // calculate the child cell\n                Tile next ={tile.x + m_actions[a].x, tile.y + m_actions[a].y};\n\n                // test the child tile for validity\n                if (m_map->isValid(next.x, next.y) &&               // if this child is a valid cell\n                    m_resourceDist.get(next.x, next.y) != -1 &&     //    and it has a valid distance\n                    m_resourceClusterLabels.get(next.x, next.y) == -1)    //    and it hasn't been given a cluster yet\n                {\n                    // mark this tile as being part of this cluster\n                    m_resourceClusterLabels.set(next.x, next.y, clusterNumber);\n                    m_stack.emplace_back(next);\n                    m_ops++;\n                }\n            }\n        }\n\n        return cluster;\n    }\n\n\npublic:\n\n    BaseBorderFinder()\n    {\n        m_stack.reserve(1024);\n    }\n\n    BaseBorderFinder(const StarDraftMap & map)\n        : m_map(&map)\n    {\n        m_stack.reserve(1024);\n\n        computeBases(map);\n    }\n\n    void computeBases(const StarDraftMap & map)\n    {\n        m_map = &map;\n\n        m_baseBorders ={};\n        m_resourceDist = Grid2D<int>(m_map->width(), m_map->height(), -1);\n        m_resourceClusterLabels = Grid2D<int>(m_map->width(), m_map->height(), -1);\n\n        // Step 1. BFS outward from resources\n        for (auto resourceTile : m_map->resourceTiles())\n        {\n            resourceDistanceBFS(resourceTile.x, resourceTile.y);\n        }\n\n        // Step 2. Label each resource cluster\n        int clusterNumber = 0;\n        for (auto resourceTile : m_map->resourceTiles())\n        {\n            // if this tile has already been clustered skip it \n            if (m_resourceClusterLabels.get(resourceTile.x, resourceTile.y) != -1) { continue; }\n\n            // perform the BFS on this un-clustered resource tile to assign it a cluster number \n            m_resourceClusters.push_back(resourceClusterFormationBFS(resourceTile.x, resourceTile.y, clusterNumber++));\n        }\n\n        // Step 3. Form Base objects out of each cluster, if they are valid\n        for (auto & cluster : m_resourceClusters)\n        {\n            // if there aren't enough resources in the cluster, it won't be a base\n            if (cluster.minerals.size() < 4) { continue; }\n\n            BaseBorder border;\n\n            for (auto tile : cluster.allResources)\n            {\n                border.left     = std::min(border.left, tile.x);\n                border.right    = std::max(border.right, tile.x);\n                border.top      = std::min(border.top, tile.y);\n                border.bottom   = std::max(border.bottom, tile.y);\n            }\n\n            m_baseBorders.push_back(border);\n        }\n    }\n    \n    const Grid2D<int> & getResourceDist() const\n    {\n        return m_resourceDist;\n    }\n\n    const Grid2D<int> & getClusterLabels() const\n    {\n        return m_resourceClusterLabels;\n    }\n\n    const std::vector<BaseBorder> & getBaseBorders() const\n    {\n        return m_baseBorders;\n    }\n\n};"
  },
  {
    "path": "UAlbertaBot/Source/stardraft/Grid2D.hpp",
    "content": "#pragma once\n\n#include <vector>\n#include <iostream>\n\ntemplate <class T>\nclass Grid2D\n{\n    size_t m_width = 0;\n    size_t m_height = 0;\n\n    std::vector<std::vector<T>> m_grid;\n\npublic:\n\n    Grid2D() {}\n\n    Grid2D(size_t width, size_t height, T val)\n        : m_width(width)\n        , m_height(height)\n        , m_grid(width, std::vector<T>(height, val))\n    {\n\n    }\n\n    T& get(size_t x, size_t y)\n    {\n        return m_grid[x][y];\n    }\n\n    T& get(int x, int y)\n    {\n        return m_grid[x][y];\n    }\n\n    const T& get(size_t x, size_t y) const\n    {\n        return m_grid[x][y];\n    }\n\n    const T& get(int x, int y) const\n    {\n        return m_grid[x][y];\n    }\n\n    void set(size_t x, size_t y, T val)\n    {\n        m_grid[x][y] = val;\n    }\n\n    void set(int x, int y, T val)\n    {\n        m_grid[x][y] = val;\n    }\n\n    size_t width() const\n    {\n        return m_width;\n    }\n\n    size_t height() const\n    {\n        return m_height;\n    }\n\n};"
  },
  {
    "path": "UAlbertaBot/Source/stardraft/StarDraft.h",
    "content": "#pragma once\n\n#include \"StarDraftMap.hpp\"\n#include \"BaseBorderFinder.hpp\""
  },
  {
    "path": "UAlbertaBot/Source/stardraft/StarDraftMap.hpp",
    "content": "#pragma once\n\n#include \"Grid2D.hpp\"\n#include <fstream>\n#include <iostream>\n\nnamespace TileType\n{\n    enum \n    {\n        Unwalkable  = 'U',\n        Walk        = 'W',\n        BuildAll    = 'B',\n        NoDepot     = 'D',\n        Mineral     = 'M',\n        Gas         = 'G',\n        Neutral     = 'N'\n    };\n}\n\nstruct Tile \n{ \n    int x = 0, y = 0; \n};\n\nclass StarDraftMap\n{\n    Grid2D<char>          m_buildTiles;\n    Grid2D<char>          m_walkTiles;\n    std::vector<Tile>   m_mineralTiles;\n    std::vector<Tile>   m_gasTiles;\n    std::vector<Tile>   m_resourceTiles;\n    std::vector<Tile>   m_startTiles;\n\n    inline bool isWalkable(char tile) const noexcept\n    {\n        return (tile == TileType::Walk) || (tile == TileType::BuildAll) || (tile == TileType::NoDepot);\n    }\n\n    inline bool canBuild(char tile) const noexcept\n    {\n        return tile == (TileType::BuildAll) || (tile == TileType::NoDepot);\n    }\n\n    inline bool canBuildDepot(char tile) const noexcept\n    {\n        return tile == TileType::BuildAll;\n    }\n\npublic:\n\n    StarDraftMap() {}\n\n    StarDraftMap(const std::string & path)\n    {\n        load(path);\n    }\n\n    StarDraftMap(size_t width, size_t height)\n        : m_buildTiles(width, height, 0)\n        , m_walkTiles(width*4, height*4, false)\n    {\n        \n    }\n\n    inline bool isValid(int x, int y) const\n    {\n        return (x >= 0) && (x < (int)m_buildTiles.width()) && (y >= 0) && (y < (int)m_buildTiles.height());\n    }\n\n    inline void set(int x, int y, char val)\n    {\n        m_buildTiles.set(x, y, val);\n\n        if (val == TileType::Mineral) \n        { \n            m_mineralTiles.push_back({x, y}); \n            m_resourceTiles.push_back({x, y}); \n        }\n        else if (val == TileType::Gas) \n        { \n            m_gasTiles.push_back({x, y}); \n            m_resourceTiles.push_back({x, y}); \n        }\n    }\n\n    inline void setWalk(int x, int y, bool val)\n    {\n        m_walkTiles.set(x, y, val);\n    }\n        \n    inline void addStartTile(int x, int y)\n    {\n        m_startTiles.push_back({x, y});\n    }\n\n    inline bool isMineral(int x, int y) const\n    {\n        return get(x, y) == 'M';\n    }\n\n    inline bool isGas(int x, int y) const\n    {\n        return get(x, y) == 'G';\n    }\n\n    inline bool isResource(int x, int y) const\n    {\n        return isMineral(x,y) || isGas(x,y);\n    }\n    \n    inline size_t width() const\n    {\n        return m_buildTiles.width();\n    }\n\n    inline size_t height() const\n    {\n        return m_buildTiles.height();\n    }\n\n    inline char get(int x, int y) const\n    {\n        return m_buildTiles.get(x, y);\n    }\n\n    inline char getWalk(int x, int y) const\n    {\n        return m_walkTiles.get(x, y);\n    }\n\n    inline bool isWalkable(int x, int y) const\n    {\n        return isWalkable(get(x, y));\n    }\n\n    inline bool canBuild(int x, int y) const\n    {\n        return canBuild(get(x,y));\n    }\n\n    inline bool canBuildDepot(int x, int y) const\n    {\n        return canBuildDepot(get(x,y));\n    }\n\n    inline const std::vector<Tile> & startTiles() const\n    {\n        return m_startTiles;\n    }\n\n    inline const std::vector<Tile> & mineralTiles() const\n    {\n        return m_mineralTiles;\n    }\n\n    inline const std::vector<Tile> & gasTiles() const\n    {\n        return m_gasTiles;\n    }\n\n    inline const std::vector<Tile> & resourceTiles() const\n    {\n        return m_resourceTiles;\n    }\n\n    inline void load(const std::string & path)\n    {\n        std::ifstream fin(path);\n        int w, h, n, sx, sy;\n        char c;\n\n        // first line is width height\n        fin >> w >> h; \n\n        m_buildTiles = Grid2D<char>(w, h, 0);\n        m_walkTiles  = Grid2D<char>(4*w, 4*h, 0);\n\n        // next line is the start tile locations\n        fin >> n;\n        for (int i=0; i<n; i++)\n        {\n            fin >> sx >> sy;\n            m_startTiles.push_back({sx, sy});\n        }\n\n        // followed by the int values in the grid\n        for (size_t y=0; y < m_buildTiles.height(); y++)\n        {\n            for (size_t x=0; x < m_buildTiles.width(); x++)\n            {\n                fin >> c;\n                set(x, y, c);\n            }   \n        }\n\n        // followed by the walk tiles\n        for (size_t y=0; y < m_walkTiles.height(); y++)\n        {\n            for (size_t x=0; x < m_walkTiles.width(); x++)\n            {\n                fin >> c;\n                m_walkTiles.set(x, y, c);\n            }   \n        }\n    }\n\n    inline void save(const std::string & path) const\n    {\n        std::ofstream fout(path);\n\n        // first line is width height\n        fout << m_buildTiles.width() << \" \" << m_buildTiles.height() << \"\\n\";\n        \n        // next line is the start tile locations\n        fout << m_startTiles.size();\n        for (auto & tile : m_startTiles)\n        {\n            fout << \" \" << tile.x << \" \" << tile.y;\n        }   fout << \"\\n\";\n\n        // followed by the int values in the grid\n        for (size_t y=0; y<m_buildTiles.height(); y++)\n        {\n            for (size_t x=0; x < m_buildTiles.width(); x++)\n            {\n                fout << m_buildTiles.get(x, y);\n            }   fout << \"\\n\";\n        }\n\n        // set the walk tiles\n        for (size_t y=0; y<m_walkTiles.height(); y++)\n        {\n            for (size_t x=0; x<m_walkTiles.width(); x++)   \n            {\n                fout << (m_walkTiles.get(x,y) ? '1' : '0');\n            }   fout << \"\\n\";\n        }\n    }\n};\n"
  },
  {
    "path": "UAlbertaBot/VisualStudio/StarterBot.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\starterbot\\main.cpp\" />\n    <ClCompile Include=\"..\\starterbot\\MapTools.cpp\" />\n    <ClCompile Include=\"..\\starterbot\\StarterBot.cpp\" />\n    <ClCompile Include=\"..\\starterbot\\Tools.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\starterbot\\Grid.hpp\" />\n    <ClInclude Include=\"..\\starterbot\\MapTools.h\" />\n    <ClInclude Include=\"..\\starterbot\\StarterBot.h\" />\n    <ClInclude Include=\"..\\starterbot\\Tools.h\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectName>StarterBot</ProjectName>\n    <ProjectGuid>{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}</ProjectGuid>\n    <RootNamespace>ExampleAIModule</RootNamespace>\n    <Keyword>Win32Proj</Keyword>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <CharacterSet>NotSet</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v142</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)\\..\\bin\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</IntDir>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">true</LinkIncremental>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)\\..\\bin\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</IntDir>\n    <IgnoreImportLibrary Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">true</IgnoreImportLibrary>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</LinkIncremental>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">BasicDesignGuidelineRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n    <RunCodeAnalysis Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</RunCodeAnalysis>\n    <CodeAnalysisIgnoreGeneratedCode Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</CodeAnalysisIgnoreGeneratedCode>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectName)_d</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>../BOSS/source;../SparCraft/source;../source;$(BWTA_DIR)/include;$(BWAPI_DIR)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;EXAMPLEAIMODULE_EXPORTS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n      <WholeProgramOptimization>false</WholeProgramOptimization>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>$(BWAPI_DIR)/Debug/BWAPILIB.lib;$(BWAPI_DIR)/Debug/BWAPIClient.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <TargetMachine>MachineX86</TargetMachine>\n      <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(BWAPI_DIR)/include;$(BWTA_DIR)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;EXAMPLEAIMODULE_EXPORTS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>None</DebugInformationFormat>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n      <EnablePREfast>false</EnablePREfast>\n      <WholeProgramOptimization>true</WholeProgramOptimization>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <ProgramDataBaseFileName />\n    </ClCompile>\n    <ProjectReference>\n      <LinkLibraryDependencies>true</LinkLibraryDependencies>\n    </ProjectReference>\n    <Link>\n      <AdditionalDependencies>$(BWAPI_DIR)/Release/BWAPILIB.lib;$(BWAPI_DIR)/Release/BWAPIClient.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <TargetMachine>MachineX86</TargetMachine>\n      <GenerateMapFile>false</GenerateMapFile>\n      <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>\n      <ProgramDatabaseFile>No</ProgramDatabaseFile>\n      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n    </Link>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "UAlbertaBot/VisualStudio/StarterBot.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\starterbot\\main.cpp\" />\n    <ClCompile Include=\"..\\starterbot\\StarterBot.cpp\" />\n    <ClCompile Include=\"..\\starterbot\\Tools.cpp\" />\n    <ClCompile Include=\"..\\starterbot\\MapTools.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\starterbot\\StarterBot.h\" />\n    <ClInclude Include=\"..\\starterbot\\Tools.h\" />\n    <ClInclude Include=\"..\\starterbot\\MapTools.h\" />\n    <ClInclude Include=\"..\\starterbot\\Grid.hpp\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "UAlbertaBot/VisualStudio/UAlbertaBot.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31005.135\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"UAlbertaBot\", \"UAlbertaBot.vcxproj\", \"{2E63AE74-758A-4607-9DE4-D28E814A6E13}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078} = {66236439-5968-4756-B2E7-8A29BEA99078}\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127} = {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SparCraft\", \"..\\..\\SparCraft\\VisualStudio\\SparCraft.vcxproj\", \"{66236439-5968-4756-B2E7-8A29BEA99078}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"BOSS\", \"..\\..\\BOSS\\VisualStudio\\BOSS.vcxproj\", \"{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"StarterBot\", \"StarterBot.vcxproj\", \"{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Itanium = Debug|Itanium\n\t\tDebug|Win32 = Debug|Win32\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|Itanium = Release|Itanium\n\t\tRelease|Win32 = Release|Win32\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{2E63AE74-758A-4607-9DE4-D28E814A6E13}.Debug|Itanium.ActiveCfg = Debug|Win32\n\t\t{2E63AE74-758A-4607-9DE4-D28E814A6E13}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{2E63AE74-758A-4607-9DE4-D28E814A6E13}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{2E63AE74-758A-4607-9DE4-D28E814A6E13}.Debug|x64.ActiveCfg = Debug|Win32\n\t\t{2E63AE74-758A-4607-9DE4-D28E814A6E13}.Release|Itanium.ActiveCfg = Release|Win32\n\t\t{2E63AE74-758A-4607-9DE4-D28E814A6E13}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{2E63AE74-758A-4607-9DE4-D28E814A6E13}.Release|Win32.Build.0 = Release|Win32\n\t\t{2E63AE74-758A-4607-9DE4-D28E814A6E13}.Release|x64.ActiveCfg = Release|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Itanium.ActiveCfg = Debug|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Debug|x64.Build.0 = Debug|x64\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Release|Itanium.ActiveCfg = Release|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Release|Win32.Build.0 = Release|Win32\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Release|x64.ActiveCfg = Release|x64\n\t\t{66236439-5968-4756-B2E7-8A29BEA99078}.Release|x64.Build.0 = Release|x64\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Itanium.ActiveCfg = Debug|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|x64.ActiveCfg = Debug|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Itanium.ActiveCfg = Release|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Win32.Build.0 = Release|Win32\n\t\t{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|x64.ActiveCfg = Release|Win32\n\t\t{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Debug|Itanium.ActiveCfg = Debug|Win32\n\t\t{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Debug|x64.ActiveCfg = Debug|Win32\n\t\t{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Release|Itanium.ActiveCfg = Release|Win32\n\t\t{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Release|Win32.Build.0 = Release|Win32\n\t\t{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Release|x64.ActiveCfg = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {E6A802E3-72DC-4E90-8C2C-FD125D583E39}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "UAlbertaBot/VisualStudio/UAlbertaBot.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectName>UAlbertaBot</ProjectName>\n    <ProjectGuid>{2E63AE74-758A-4607-9DE4-D28E814A6E13}</ProjectGuid>\n    <RootNamespace>ExampleAIModule</RootNamespace>\n    <Keyword>Win32Proj</Keyword>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <CharacterSet>NotSet</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v142</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)\\..\\bin\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</IntDir>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">true</LinkIncremental>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)\\..\\bin\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)\\$(Configuration)\\$(ProjectName)\\</IntDir>\n    <IgnoreImportLibrary Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">true</IgnoreImportLibrary>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</LinkIncremental>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">BasicDesignGuidelineRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n    <RunCodeAnalysis Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</RunCodeAnalysis>\n    <CodeAnalysisIgnoreGeneratedCode Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</CodeAnalysisIgnoreGeneratedCode>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectName)_d</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>../BOSS/source;../SparCraft/source;../source;$(BWTA_DIR)/include;$(BWAPI_DIR)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;EXAMPLEAIMODULE_EXPORTS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n      <WholeProgramOptimization>false</WholeProgramOptimization>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>$(BWAPI_DIR)/Debug/BWAPILIB.lib;$(BWAPI_DIR)/Debug/BWAPIClient.lib;$(Configuration)/SparCraft/SparCraft_d.lib;../../BOSS/bin/BOSS_d.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <TargetMachine>MachineX86</TargetMachine>\n      <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <Optimization>Full</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>../BOSS/source;../SparCraft/source;../source;$(BWAPI_DIR)/include;$(BWTA_DIR)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;EXAMPLEAIMODULE_EXPORTS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n      <EnablePREfast>false</EnablePREfast>\n      <WholeProgramOptimization>true</WholeProgramOptimization>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\n    </ClCompile>\n    <ProjectReference>\n      <LinkLibraryDependencies>true</LinkLibraryDependencies>\n    </ProjectReference>\n    <Link>\n      <AdditionalDependencies>$(BWAPI_DIR)/Release/BWAPILIB.lib;$(BWAPI_DIR)/Release/BWAPIClient.lib;$(Configuration)/SparCraft/SparCraft.lib;../../BOSS/bin/BOSS.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <TargetMachine>MachineX86</TargetMachine>\n      <GenerateMapFile>true</GenerateMapFile>\n      <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\Source\\AutoObserver.cpp\" />\n    <ClCompile Include=\"..\\Source\\BaseLocation.cpp\" />\n    <ClCompile Include=\"..\\Source\\BaseLocationManager.cpp\" />\n    <ClCompile Include=\"..\\Source\\BOSSManager.cpp\" />\n    <ClCompile Include=\"..\\Source\\BuildingData.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildingManager.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildingPlacerManager.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildOrder.cpp\" />\n    <ClCompile Include=\"..\\source\\BuildOrderQueue.cpp\" />\n    <ClCompile Include=\"..\\Source\\CombatSimulation.cpp\" />\n    <ClCompile Include=\"..\\Source\\CombatCommander.cpp\" />\n    <ClCompile Include=\"..\\Source\\Common.cpp\" />\n    <ClCompile Include=\"..\\source\\DetectorManager.cpp\" />\n    <ClCompile Include=\"..\\Source\\DistanceMap.cpp\" />\n    <ClCompile Include=\"..\\Source\\Global.cpp\" />\n    <ClCompile Include=\"..\\Source\\main.cpp\" />\n    <ClCompile Include=\"..\\Source\\GameCommander.cpp\" />\n    <ClCompile Include=\"..\\Source\\InformationManager.cpp\" />\n    <ClCompile Include=\"..\\source\\JSONTools.cpp\" />\n    <ClCompile Include=\"..\\Source\\Logger.cpp\" />\n    <ClCompile Include=\"..\\Source\\MapTools.cpp\" />\n    <ClCompile Include=\"..\\Source\\MedicManager.cpp\" />\n    <ClCompile Include=\"..\\source\\MeleeManager.cpp\" />\n    <ClCompile Include=\"..\\source\\MetaType.cpp\" />\n    <ClCompile Include=\"..\\source\\MicroManager.cpp\" />\n    <ClCompile Include=\"..\\Source\\Config.cpp\" />\n    <ClCompile Include=\"..\\Source\\Micro.cpp\" />\n    <ClCompile Include=\"..\\Source\\ParseUtils.cpp\" />\n    <ClCompile Include=\"..\\source\\ProductionManager.cpp\" />\n    <ClCompile Include=\"..\\source\\RangedManager.cpp\" />\n    <ClCompile Include=\"..\\source\\ScoutManager.cpp\" />\n    <ClCompile Include=\"..\\Source\\Squad.cpp\" />\n    <ClCompile Include=\"..\\Source\\SquadData.cpp\" />\n    <ClCompile Include=\"..\\Source\\StrategyManager.cpp\" />\n    <ClCompile Include=\"..\\Source\\TankManager.cpp\" />\n    <ClCompile Include=\"..\\source\\TimerManager.cpp\" />\n    <ClCompile Include=\"..\\source\\TransportManager.cpp\" />\n    <ClCompile Include=\"..\\Source\\UABAssert.cpp\" />\n    <ClCompile Include=\"..\\Source\\UAlbertaBotModule.cpp\" />\n    <ClCompile Include=\"..\\Source\\UnitData.cpp\" />\n    <ClCompile Include=\"..\\Source\\UnitUtil.cpp\" />\n    <ClCompile Include=\"..\\source\\WorkerData.cpp\" />\n    <ClCompile Include=\"..\\source\\WorkerManager.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\Source\\AutoObserver.h\" />\n    <ClInclude Include=\"..\\Source\\BaseLocation.h\" />\n    <ClInclude Include=\"..\\Source\\BaseLocationManager.h\" />\n    <ClInclude Include=\"..\\Source\\BOSSManager.h\" />\n    <ClInclude Include=\"..\\Source\\BuildingData.h\" />\n    <ClInclude Include=\"..\\source\\BuildingManager.h\" />\n    <ClInclude Include=\"..\\source\\BuildingPlacerManager.h\" />\n    <ClInclude Include=\"..\\source\\BuildOrder.h\" />\n    <ClInclude Include=\"..\\source\\BuildOrderQueue.h\" />\n    <ClInclude Include=\"..\\Source\\CombatSimulation.h\" />\n    <ClInclude Include=\"..\\Source\\CombatCommander.h\" />\n    <ClInclude Include=\"..\\Source\\Common.h\" />\n    <ClInclude Include=\"..\\source\\DetectorManager.h\" />\n    <ClInclude Include=\"..\\Source\\DistanceMap.h\" />\n    <ClInclude Include=\"..\\Source\\GameCommander.h\" />\n    <ClInclude Include=\"..\\Source\\Global.h\" />\n    <ClInclude Include=\"..\\Source\\Grid.hpp\" />\n    <ClInclude Include=\"..\\Source\\InformationManager.h\" />\n    <ClInclude Include=\"..\\source\\JSONTools.h\" />\n    <ClInclude Include=\"..\\Source\\Logger.h\" />\n    <ClInclude Include=\"..\\Source\\MapTools.h\" />\n    <ClInclude Include=\"..\\Source\\MedicManager.h\" />\n    <ClInclude Include=\"..\\source\\MeleeManager.h\" />\n    <ClInclude Include=\"..\\source\\MetaType.h\" />\n    <ClInclude Include=\"..\\source\\MicroManager.h\" />\n    <ClInclude Include=\"..\\Source\\Config.h\" />\n    <ClInclude Include=\"..\\Source\\Micro.h\" />\n    <ClInclude Include=\"..\\Source\\ParseUtils.h\" />\n    <ClInclude Include=\"..\\source\\ProductionManager.h\" />\n    <ClInclude Include=\"..\\Source\\Profiler.hpp\" />\n    <ClInclude Include=\"..\\source\\RangedManager.h\" />\n    <ClInclude Include=\"..\\source\\ScoutManager.h\" />\n    <ClInclude Include=\"..\\Source\\Squad.h\" />\n    <ClInclude Include=\"..\\Source\\SquadData.h\" />\n    <ClInclude Include=\"..\\Source\\SquadOrder.h\" />\n    <ClInclude Include=\"..\\Source\\StrategyManager.h\" />\n    <ClInclude Include=\"..\\Source\\TankManager.h\" />\n    <ClInclude Include=\"..\\source\\TimerManager.h\" />\n    <ClInclude Include=\"..\\source\\TransportManager.h\" />\n    <ClInclude Include=\"..\\Source\\UABAssert.h\" />\n    <ClInclude Include=\"..\\Source\\UAlbertaBotModule.h\" />\n    <ClInclude Include=\"..\\Source\\UnitData.h\" />\n    <ClInclude Include=\"..\\Source\\UnitUtil.h\" />\n    <ClInclude Include=\"..\\source\\WorkerData.h\" />\n    <ClInclude Include=\"..\\source\\WorkerManager.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "UAlbertaBot/VisualStudio/UAlbertaBot.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"util\">\n      <UniqueIdentifier>{59599488-4576-44ab-8522-7d65a6425e15}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"micro\">\n      <UniqueIdentifier>{8e8c1957-bc1d-4bc8-90b0-95beab19d8a9}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"macro\">\n      <UniqueIdentifier>{a78e9ab8-4a81-4640-b6eb-f1eed3e4b1af}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"common\">\n      <UniqueIdentifier>{849d54bf-a76a-4425-8399-099fbe0360c4}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\Source\\CombatCommander.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\CombatSimulation.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\Common.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\UABAssert.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BuildingManager.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\ProductionManager.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\WorkerData.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\WorkerManager.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\MetaType.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\Config.cpp\">\n      <Filter>common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\AutoObserver.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\JSONTools.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\ParseUtils.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\UnitUtil.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\Logger.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\main.cpp\" />\n    <ClCompile Include=\"..\\Source\\UAlbertaBotModule.cpp\" />\n    <ClCompile Include=\"..\\Source\\Global.cpp\" />\n    <ClCompile Include=\"..\\Source\\BuildingData.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BuildingPlacerManager.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\Squad.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\SquadData.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\BOSSManager.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BuildOrder.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\BuildOrderQueue.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\DistanceMap.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\InformationManager.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\MapTools.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\StrategyManager.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\TimerManager.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\UnitData.cpp\">\n      <Filter>util</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\DetectorManager.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\MedicManager.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\MeleeManager.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\Micro.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\MicroManager.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\RangedManager.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\TankManager.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\TransportManager.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\source\\ScoutManager.cpp\">\n      <Filter>micro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\GameCommander.cpp\" />\n    <ClCompile Include=\"..\\Source\\BaseLocation.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\Source\\BaseLocationManager.cpp\">\n      <Filter>macro</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\Source\\CombatCommander.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\Common.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\UABAssert.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\CombatSimulation.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BuildingManager.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\ProductionManager.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\WorkerData.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\WorkerManager.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\MetaType.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\Config.h\">\n      <Filter>common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\AutoObserver.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\JSONTools.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\ParseUtils.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\UnitUtil.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\Logger.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\UAlbertaBotModule.h\" />\n    <ClInclude Include=\"..\\Source\\Global.h\" />\n    <ClInclude Include=\"..\\Source\\BuildingData.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BuildingPlacerManager.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\Squad.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\SquadData.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\SquadOrder.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\BOSSManager.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BuildOrder.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\BuildOrderQueue.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\DistanceMap.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\Grid.hpp\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\InformationManager.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\MapTools.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\Profiler.hpp\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\StrategyManager.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\TimerManager.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\UnitData.h\">\n      <Filter>util</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\DetectorManager.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\MedicManager.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\MeleeManager.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\Micro.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\MicroManager.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\RangedManager.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\TankManager.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\TransportManager.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\source\\ScoutManager.h\">\n      <Filter>micro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\GameCommander.h\" />\n    <ClInclude Include=\"..\\Source\\BaseLocationManager.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Source\\BaseLocation.h\">\n      <Filter>macro</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "UAlbertaBot/bin/UAlbertaBot_Config.txt",
    "content": "{\n    \"Bot Info\" :\n    {\n        \"BotName\"                   : \"UAlbertaBot\",\n        \"Authors\"                   : \"David Churchill\",\n        \"PrintInfoOnStart\"          : false\n    },\n        \n    \"BWAPI\" : \n    {\n        \"SetLocalSpeed\"             : 0,\n        \"SetFrameSkip\"              : 0,\n        \"UserInput\"                 : true,\n        \"CompleteMapInformation\"    : false\n    },\n    \n    \"Micro\" :\n    {\n        \"UseSparcraftSimulation\"    : true,\n        \"KiteWithRangedUnits\"       : true,\n        \"KiteLongerRangedUnits\"     : [\"Mutalisk\", \"Vulture\"],\n        \"WorkersDefendRush\"         : true,\n        \"RetreatMeleeUnitShields\"   : 0,\n        \"RetreatMeleeUnitHP\"        : 0,\n        \"InCombatRadius\"            : 1000,\n        \"RegroupRadius\"             : 300,\n        \"UnitNearEnemyRadius\"       : 600\n    },\n    \n    \"Macro\" :\n    {\n        \"BOSSFrameLimit\"            : 160,\n        \"WorkersPerRefinery\"        : 3,\n        \"BuildingSpacing\"           : 1,\n        \"PylonSpacing\"              : 3\n    },\n\n    \"Debug\" :\n    {\n        \"ErrorLogFilename\"          : \"bwapi-data/AI/UAlbertaBot_ErrorLog.txt\",\n        \"LogAssertToErrorFile\"      : false,\n        \n        \"DrawGameInfo\"              : true,   \n        \"DrawUnitHealthBars\"        : true,\n        \"DrawProductionInfo\"        : true,\n        \"DrawWalkableSectors\"       : false,\n        \"DrawTileInfo\"              : false,       \n        \"DrawBuildOrderSearchInfo\"  : false,\n        \"DrawScoutInfo\"             : false,\n        \"DrawEnemyUnitInfo\"         : false,\n        \"DrawModuleTimers\"          : false,\n        \"DrawResourceInfo\"          : false,\n        \"DrawCombatSimInfo\"         : false,\n        \"DrawUnitTargetInfo\"        : false,\n        \"DrawBWTAInfo\"              : false,\n        \"DrawMapGrid\"               : false,\n        \"DrawSquadInfo\"             : false,\n        \"DrawWorkerInfo\"            : false,\n        \"DrawMouseCursorInfo\"       : false,\n        \"DrawBuildingInfo\"          : false,\n        \"DrawReservedBuildingTiles\" : false,\n        \"DrawBOSSStateInfo\"         : false,\n        \"PrintModuleTimeout\"        : false\n    },\n    \n    \"Modules\" :\n    {\n        \"UseGameCommander\"          : true,\n        \"UseScoutManager\"           : true,\n        \"UseCombatCommander\"        : true,\n        \"UseBuildOrderSearch\"       : true,\n        \"UseStrategyIO\"             : true,\n        \"UseAutoObserver\"           : false\n    },\n    \n    \"Tools\" :\n    {\n        \"MapGridSize\"               : 320\n    },\n    \n    \"Strategy\" :\n    {\n        \"Protoss\"                   : \"Protoss_ZealotRush\",\n        \"Terran\"                    : \"Terran_MarineRush\",\n        \"Zerg\"                      : \"Zerg_ZerglingRush\",\n        \n        \"ScoutGasSteal\"             : false,\n        \"ScoutHarassEnemy\"          : true,\n        \n        \"ReadDirectory\"             : \"bwapi-data/read/\",\n        \"WriteDirectory\"            : \"bwapi-data/write/\",\n                \n        \"UseEnemySpecificStrategy\"  : true,\n        \"EnemySpecificStrategy\"     :\n        {\n            \"BotName1\"              : { \"Protoss\" : \"Protoss_ZealotRush\", \"Terran\" : \"Terran_VultureRush\", \"Zerg\" : \"Zerg_ZerglingRush\" },\n            \"BotName2\"              : { \"Protoss\" : \"Protoss_DragoonRush\", \"Terran\" : \"Terran_MarineRush\", \"Zerg\" : \"Zerg_ZerglingRush\" },\n            \"LetaBot\"               : { \"Protoss\" : \"Protoss_ZealotRush\", \"Terran\" : \"Terran_4RaxMarines\", \"Zerg\" : \"Zerg_ZerglingRush\" }\n        },\n        \n        \"Strategies\" :\n        {\n            \"Protoss_ZealotRush\"    : { \"Race\" : \"Protoss\", \"OpeningBuildOrder\" : [\"Probe\", \"Probe\", \"Probe\", \"Probe\", \"Pylon\", \"Probe\", \"Gateway\", \"Gateway\", \"Probe\", \"Probe\", \"Zealot\", \"Pylon\", \"Zealot\", \"Zealot\",  \"Probe\", \"Zealot\", \"Zealot\", \"Probe\", \"Pylon\", \"Zealot\", \"Gateway\", \"Probe\", \"Pylon\", \"Probe\", \"Zealot\", \"Probe\", \"Zealot\", \"Zealot\", \"Zealot\", \"Zealot\", \"Pylon\", \"Probe\", \"Zealot\", \"Zealot\", \"Zealot\" ]},\n            \"Protoss_DragoonRush\"   : { \"Race\" : \"Protoss\", \"OpeningBuildOrder\" : [\"Probe\", \"Probe\", \"Probe\", \"Probe\", \"Pylon\", \"Probe\", \"Probe\", \"Gateway\", \"Probe\", \"Assimilator\", \"Probe\", \"Probe\", \"Cybernetics_Core\", \"Probe\", \"Probe\", \"Gateway\", \"Singularity_Charge\", \"Dragoon\", \"Gateway\", \"Pylon\", \"Dragoon\", \"Dragoon\", \"Probe\", \"Gateway\", \"Pylon\", \"Probe\", \"Dragoon\", \"Dragoon\", \"Dragoon\"]},\n            \"Protoss_DTRush\"        : { \"Race\" : \"Protoss\", \"OpeningBuildOrder\" : [\"Probe\", \"Probe\", \"Probe\", \"Probe\", \"Pylon\", \"Probe\", \"Gateway\", \"Probe\", \"Assimilator\", \"Probe\", \"Cybernetics_Core\", \"Probe\", \"Citadel_of_Adun\", \"Probe\", \"Templar_Archives\", \"Gateway\", \"Dark_Templar\", \"Dark_Templar\", \"Pylon\", \"Dark_Templar\", \"Dark_Templar\", \"Probe\", \"Pylon\", \"Probe\" ]},\n            \"Protoss_Drop\"          : { \"Race\" : \"Protoss\", \"OpeningBuildOrder\" : [\"Probe\", \"Probe\", \"Probe\", \"Probe\", \"Pylon\", \"Probe\", \"Probe\", \"Gateway\", \"Probe\", \"Assimilator\", \"Probe\", \"Probe\", \"Cybernetics_Core\", \"Probe\", \"Gateway\", \"Robotics Facility\"]},\n            \"Terran_MarineRush\"     : { \"Race\" : \"Terran\",  \"OpeningBuildOrder\" : [\"SCV\", \"SCV\", \"SCV\", \"SCV\", \"SCV\", \"Supply Depot\", \"SCV\"]},\n            \"Terran_TankPush\"       : { \"Race\" : \"Terran\",  \"OpeningBuildOrder\" : [\"SCV\", \"SCV\", \"SCV\", \"SCV\", \"SCV\", \"Supply Depot\", \"SCV\", \"Barracks\", \"Refinery\", \"SCV\", \"SCV\", \"SCV\", \"SCV\", \"Factory\", \"Factory\", \"SCV\", \"SCV\", \"SCV\", \"SCV\", \"Machine Shop\", \"Machine Shop\", \"Supply Depot\", \"Tank Siege Mode\", \"Siege Tank Tank Mode\", \"Siege Tank Tank Mode\", \"Siege Tank Tank Mode\", \"Siege Tank Tank Mode\"]},\n            \"Terran_4RaxMarines\"    : { \"Race\" : \"Terran\",  \"OpeningBuildOrder\" : [\"Barracks\", \"SCV\", \"SCV\", \"Marine\", \"SCV\", \"Marine\", \"Supply Depot\", \"Marine\", \"Marine\", \"Marine\", \"Marine\", \"Marine\", \"Marine\"]},\n            \"Terran_VultureRush\"    : { \"Race\" : \"Terran\",  \"OpeningBuildOrder\" : [\"SCV\", \"SCV\", \"SCV\", \"SCV\", \"SCV\", \"Supply Depot\", \"SCV\", \"SCV\", \"Barracks\", \"Refinery\", \"SCV\", \"SCV\", \"SCV\", \"SCV\", \"Supply Depot\", \"Factory\", \"SCV\", \"SCV\", \"SCV\", \"Vulture\", \"Vulture\"]},\n            \"Zerg_ZerglingRush\"     : { \"Race\" : \"Zerg\",    \"OpeningBuildOrder\" : [\"Drone\", \"Spawning Pool\", \"Zergling\", \"Zergling\", \"Zergling\", \"Zergling\"] },\n            \"Zerg_9Pool\"            : { \"Race\" : \"Zerg\",    \"OpeningBuildOrder\" : [\"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Spawning Pool\", \"Drone\", \"Extractor\", \"Overlord\", \"Drone\", \"Zergling\", \"Zergling\", \"Zergling\", \"Hydralisk Den\", \"Drone\", \"Drone\", \"Drone\", \"Drone\"] },\n            \"Zerg_2HatchHydra\"      : { \"Race\" : \"Zerg\",    \"OpeningBuildOrder\" : [\"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Overlord\", \"Drone\", \"Drone\", \"Drone\", \"Hatchery\", \"Spawning Pool\", \"Drone\", \"Extractor\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Hydralisk Den\", \"Drone\", \"Overlord\", \"Drone\", \"Drone\", \"Drone\", \"Grooved_Spines\", \"Hydralisk\",\"Hydralisk\",\"Hydralisk\",\"Hydralisk\", \"Hydralisk\",\"Hydralisk\",\"Hydralisk\",\"Hydralisk\", \"Hydralisk\",\"Hydralisk\",\"Hydralisk\",\"Hydralisk\", \"Hatchery\", \"Extractor\" ] },\n            \"Zerg_3HatchMuta\"       : { \"Race\" : \"Zerg\",    \"OpeningBuildOrder\" : [\"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Overlord\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Hatchery\", \"Drone\", \"Drone\", \"Spawning_Pool\", \"Drone\", \"Drone\", \"Extractor\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\",\"Lair\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Spire\", \"Overlord\", \"Drone\", \"Overlord\", \"Hatchery\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Mutalisk\", \"Hatchery\"]},\n            \"Zerg_3HatchScourge\"    : { \"Race\" : \"Zerg\",    \"OpeningBuildOrder\" : [\"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Overlord\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Hatchery\", \"Drone\", \"Drone\", \"Spawning_Pool\", \"Drone\", \"Drone\", \"Extractor\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\",\"Lair\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Spire\", \"Overlord\", \"Drone\", \"Overlord\", \"Hatchery\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Drone\", \"Hatchery\", \"Drone\", \"Extractor\", \"Drone\", \"Hatchery\", \"Scourge\", \"Scourge\", \"Scourge\", \"Scourge\", \"Scourge\", \"Scourge\", \"Scourge\", \"Scourge\", \"Scourge\", \"Scourge\", \"Scourge\", \"Scourge\", \"Hatchery\", \"Extractor\", \"Extractor\", \"Hatchery\"]}\n        }\n    }\n}"
  },
  {
    "path": "UAlbertaBot/starterbot/Grid.hpp",
    "content": "#pragma once\n\n#include <vector>\n\ntemplate <class T>\nclass Grid\n{\n    size_t m_width = 0;\n    size_t m_height = 0;\n\n    std::vector<std::vector<T>> m_grid;\n\npublic:\n\n    Grid() {}\n\n    Grid(size_t width, size_t height, T val)\n        : m_width(width)\n        , m_height(height)\n        , m_grid(width, std::vector<T>(height, val))\n    {\n\n    }\n\n    inline T & get(size_t x, size_t y)\n    {\n        return m_grid[x][y];\n    }\n\n    inline const T & get(size_t x, size_t y) const\n    {\n        return m_grid[x][y];\n    }\n\n    inline void set(size_t x, size_t y, T val)\n    {\n        m_grid[x][y] = val;\n    }\n\n    inline size_t width() const\n    {\n        return m_width;\n    }\n\n    inline size_t height() const\n    {\n        return m_height;\n    }\n};"
  },
  {
    "path": "UAlbertaBot/starterbot/MapTools.cpp",
    "content": "#include \"MapTools.h\"\n\n#include <iostream>\n#include <sstream>\n#include <fstream>\n#include <array>\n\n// constructor for MapTools\nMapTools::MapTools()\n{\n    \n}\n\nvoid MapTools::onStart()\n{\n    m_width          = BWAPI::Broodwar->mapWidth();\n    m_height         = BWAPI::Broodwar->mapHeight();\n    m_walkable       = Grid<int>(m_width, m_height, 1);\n    m_buildable      = Grid<int>(m_width, m_height, 0);\n    m_depotBuildable = Grid<int>(m_width, m_height, 0);\n    m_lastSeen       = Grid<int>(m_width, m_height, 0);\n\n    // Set the boolean grid data from the Map\n    for (int x(0); x < m_width; ++x)\n    {\n        for (int y(0); y < m_height; ++y)\n        {\n            m_buildable.set(x, y, canBuild(x, y));\n            m_depotBuildable.set(x, y, canBuild(x, y));\n            m_walkable.set(x, y, m_buildable.get(x,y) || canWalk(x, y));\n        }\n    }\n\n    // set tiles that static resources are on as unbuildable\n    for (auto & resource : BWAPI::Broodwar->getStaticNeutralUnits())\n    {\n        if (!resource->getType().isResourceContainer())\n        {\n            continue;\n        }\n\n        const int tileX = resource->getTilePosition().x;\n        const int tileY = resource->getTilePosition().y;\n\n        for (int x=tileX; x<tileX+resource->getType().tileWidth(); ++x)\n        {\n            for (int y=tileY; y<tileY+resource->getType().tileHeight(); ++y)\n            {\n                m_buildable.set(x, y, false);\n\n                // depots can't be built within 3 tiles of any resource\n                for (int rx=-3; rx<=3; rx++)\n                {\n                    for (int ry=-3; ry<=3; ry++)\n                    {\n                        if (!BWAPI::TilePosition(x+rx, y+ry).isValid())\n                        {\n                            continue;\n                        }\n\n                        m_depotBuildable.set(x+rx, y+ry, 0);\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid MapTools::onFrame()\n{\n    for (int x=0; x<m_width; ++x)\n    {\n        for (int y=0; y<m_height; ++y)\n        {\n            if (isVisible(x, y))\n            {\n                m_lastSeen.set(x, y, BWAPI::Broodwar->getFrameCount());\n            }\n        }\n    }\n\n    if (m_drawMap)\n    {\n        draw();\n    }\n}\n\nvoid MapTools::toggleDraw()\n{\n    m_drawMap = !m_drawMap;\n}\n\nbool MapTools::isExplored(const BWAPI::TilePosition & pos) const\n{\n    return isExplored(pos.x, pos.y);\n}\n\nbool MapTools::isExplored(const BWAPI::Position & pos) const\n{\n    return isExplored(BWAPI::TilePosition(pos));\n}\n\nbool MapTools::isExplored(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY)) { return false; }\n\n    return BWAPI::Broodwar->isExplored(tileX, tileY);\n}\n\nbool MapTools::isVisible(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY)) { return false; }\n\n    return BWAPI::Broodwar->isVisible(BWAPI::TilePosition(tileX, tileY));\n}\n\nbool MapTools::isPowered(int tileX, int tileY) const\n{\n    return BWAPI::Broodwar->hasPower(BWAPI::TilePosition(tileX, tileY));\n}\n\nbool MapTools::isValidTile(int tileX, int tileY) const\n{\n    return tileX >= 0 && tileY >= 0 && tileX < m_width && tileY < m_height;\n}\n\nbool MapTools::isValidTile(const BWAPI::TilePosition & tile) const\n{\n    return isValidTile(tile.x, tile.y);\n}\n\nbool MapTools::isValidPosition(const BWAPI::Position & pos) const\n{\n    return isValidTile(BWAPI::TilePosition(pos));\n}\n\nbool MapTools::isBuildable(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY))\n    {\n        return false;\n    }\n\n    return m_buildable.get(tileX, tileY);\n}\n\nbool MapTools::isBuildable(const BWAPI::TilePosition & tile) const\n{\n    return isBuildable(tile.x, tile.y);\n}\n\nvoid MapTools::printMap() const\n{\n    std::stringstream ss;\n    for (int y(0); y < m_height; ++y)\n    {\n        for (int x(0); x < m_width; ++x)\n        {\n            ss << isWalkable(x, y);\n        }\n\n        ss << \"\\n\";\n    }\n\n    std::ofstream out(\"map.txt\");\n    out << ss.str();\n    out.close();\n}\n\nbool MapTools::isDepotBuildableTile(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY))\n    {\n        return false;\n    }\n\n    return m_depotBuildable.get(tileX, tileY);\n}\n\nbool MapTools::isWalkable(int tileX, int tileY) const\n{\n    if (!isValidTile(tileX, tileY))\n    {\n        return false;\n    }\n\n    return m_walkable.get(tileX, tileY);\n}\n\nbool MapTools::isWalkable(const BWAPI::TilePosition & tile) const\n{\n    return isWalkable(tile.x, tile.y);\n}\n\nint MapTools::width() const\n{\n    return m_width;\n}\n\nint MapTools::height() const\n{\n    return m_height;\n}\n\nvoid MapTools::drawTile(int tileX, int tileY, const BWAPI::Color & color) const\n{\n    const int padding   = 2;\n    const int px        = tileX*32 + padding;\n    const int py        = tileY*32 + padding;\n    const int d         = 32 - 2*padding;\n\n    BWAPI::Broodwar->drawLineMap(px,     py,     px + d, py,     color);\n    BWAPI::Broodwar->drawLineMap(px + d, py,     px + d, py + d, color);\n    BWAPI::Broodwar->drawLineMap(px + d, py + d, px,     py + d, color);\n    BWAPI::Broodwar->drawLineMap(px,     py + d, px,     py,     color);\n}\n\nbool MapTools::canWalk(int tileX, int tileY) const\n{\n    for (int i=0; i<4; ++i)\n    {\n        for (int j=0; j<4; ++j)\n        {\n            if (!BWAPI::Broodwar->isWalkable(tileX*4 + i, tileY*4 + j))\n            {\n                return false;\n            }\n        }\n    }\n\n    return true;\n}\n\nbool MapTools::canBuild(int tileX, int tileY) const\n{\n    return BWAPI::Broodwar->isBuildable(BWAPI::TilePosition(tileX, tileY));\n}\n\nvoid MapTools::draw() const\n{\n    const BWAPI::TilePosition screen(BWAPI::Broodwar->getScreenPosition());\n    const int sx = screen.x;\n    const int sy = screen.y;\n    const int ex = sx + 20;\n    const int ey = sy + 15;\n\n    for (int x = sx; x < ex; ++x)\n    {\n        for (int y = sy; y < ey; y++)\n        {\n            const BWAPI::TilePosition tilePos(x,y);\n            if (!tilePos.isValid()) { continue; }\n\n            if (true)\n            {\n                BWAPI::Color color = isWalkable(x, y) ? BWAPI::Color(0, 255, 0) : BWAPI::Color(255, 0, 0);\n                if (isWalkable(x, y) && !isBuildable(x, y)) { color = BWAPI::Color(255, 255, 0); }\n                if (isBuildable(x, y) && !isDepotBuildableTile(x, y)) { color = BWAPI::Color(127, 255, 255); }\n                drawTile(x, y, color);\n            }\n        }\n    }\n\n    const char red = '\\x08';\n    const char green = '\\x07';\n    const char white = '\\x04';\n    const char yellow = '\\x03';\n\n    BWAPI::Broodwar->drawBoxScreen(0, 0, 200, 100, BWAPI::Colors::Black, true);\n    BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Huge);\n    BWAPI::Broodwar->drawTextScreen(10, 5, \"%cMap Legend\", white);\n    BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Default);\n    BWAPI::Broodwar->drawTextScreen(10, 30, \"%cRed: \", red);\n    BWAPI::Broodwar->drawTextScreen(60, 30, \"%cCan't Walk or Build\", white);\n    BWAPI::Broodwar->drawTextScreen(10, 45, \"%cGreen:\", green);\n    BWAPI::Broodwar->drawTextScreen(60, 45, \"%cCan Walk and Build\", white);\n    BWAPI::Broodwar->drawTextScreen(10, 60, \"%cYellow:\", yellow);\n    BWAPI::Broodwar->drawTextScreen(60, 60, \"%cResource Tile, Can't Build\", white);\n    BWAPI::Broodwar->drawTextScreen(10, 75, \"Teal:\");\n    BWAPI::Broodwar->drawTextScreen(60, 75, \"%cCan't Build Depot\", white);\n\n    \n}\n"
  },
  {
    "path": "UAlbertaBot/starterbot/MapTools.h",
    "content": "#pragma once\n\n#include \"Grid.hpp\"\n\n#include <BWAPI.h>\n#include <vector>\n\nclass MapTools\n{\n    Grid<int>   m_walkable;       // whether a tile is buildable (includes static resources)          \n    Grid<int>   m_buildable;      // whether a tile is buildable (includes static resources)\n    Grid<int>   m_depotBuildable; // whether a depot is buildable on a tile (illegal within 3 tiles of static resource)\n    Grid<int>   m_lastSeen;       // the last time any of our units has seen this position on the map\n    int         m_width = 0;\n    int         m_height = 0;\n    int         m_frame = 0;\n    bool        m_drawMap = false;\n\n    bool canBuild(int tileX, int tileY) const;\n    bool canWalk(int tileX, int tileY) const;\n    void printMap() const;\n\n\npublic:\n\n    MapTools();\n\n    void    onStart();\n    void    onFrame();\n    void    draw() const;\n    void    toggleDraw();\n\n    int     width() const;\n    int     height() const;\n\n    bool    isValidTile(int tileX, int tileY) const;\n    bool    isValidTile(const BWAPI::TilePosition & tile) const;\n    bool    isValidPosition(const BWAPI::Position & pos) const;\n    bool    isPowered(int tileX, int tileY) const;\n    bool    isExplored(int tileX, int tileY) const;\n    bool    isExplored(const BWAPI::Position & pos) const;\n    bool    isExplored(const BWAPI::TilePosition & pos) const;\n    bool    isVisible(int tileX, int tileY) const;\n    bool    isWalkable(int tileX, int tileY) const;\n    bool    isWalkable(const BWAPI::TilePosition& tile) const;\n    bool    isBuildable(int tileX, int tileY) const;\n    bool    isBuildable(const BWAPI::TilePosition& tile) const;\n    bool    isDepotBuildableTile(int tileX, int tileY) const;\n    void    drawTile(int tileX, int tileY, const BWAPI::Color & color) const;\n};"
  },
  {
    "path": "UAlbertaBot/starterbot/StarterBot.cpp",
    "content": "#include \"StarterBot.h\"\n#include \"Tools.h\"\n#include \"MapTools.h\"\n\nStarterBot::StarterBot()\n{\n    \n}\n\n// Called when the bot starts!\nvoid StarterBot::onStart()\n{\n    // Set our BWAPI options here    \n\tBWAPI::Broodwar->setLocalSpeed(10);\n    BWAPI::Broodwar->setFrameSkip(0);\n    \n    // Enable the flag that tells BWAPI top let users enter input while bot plays\n    BWAPI::Broodwar->enableFlag(BWAPI::Flag::UserInput);\n\n    // Call MapTools OnStart\n    m_mapTools.onStart();\n}\n\n// Called whenever the game ends and tells you if you won or not\nvoid StarterBot::onEnd(bool isWinner) \n{\n    std::cout << \"We \" << (isWinner ? \"won!\" : \"lost!\") << \"\\n\";\n}\n\n// Called on each frame of the game\nvoid StarterBot::onFrame()\n{\n    // Update our MapTools information\n    m_mapTools.onFrame();\n\n    // Send our idle workers to mine minerals so they don't just stand there\n    sendIdleWorkersToMinerals();\n\n    // Train more workers so we can gather more income\n    trainAdditionalWorkers();\n\n    // Build more supply if we are going to run out soon\n    buildAdditionalSupply();\n\n    // Draw unit health bars, which brood war unfortunately does not do\n    Tools::DrawUnitHealthBars();\n\n    // Draw some relevent information to the screen to help us debug the bot\n    drawDebugInformation();\n}\n\n// Send our idle workers to mine minerals so they don't just stand there\nvoid StarterBot::sendIdleWorkersToMinerals()\n{\n    // Let's send all of our starting workers to the closest mineral to them\n    // First we need to loop over all of the units that we (BWAPI::Broodwar->self()) own\n    const BWAPI::Unitset& myUnits = BWAPI::Broodwar->self()->getUnits();\n    for (auto& unit : myUnits)\n    {\n        // Check the unit type, if it is an idle worker, then we want to send it somewhere\n        if (unit->getType().isWorker() && unit->isIdle())\n        {\n            // Get the closest mineral to this worker unit\n            BWAPI::Unit closestMineral = Tools::GetClosestUnitTo(unit, BWAPI::Broodwar->getMinerals());\n\n            // If a valid mineral was found, right click it with the unit in order to start harvesting\n            if (closestMineral) { unit->rightClick(closestMineral); }\n        }\n    }\n}\n\n// Train more workers so we can gather more income\nvoid StarterBot::trainAdditionalWorkers()\n{\n    const BWAPI::UnitType workerType = BWAPI::Broodwar->self()->getRace().getWorker();\n    const int workersWanted = 20;\n    const int workersOwned = Tools::CountUnitsOfType(workerType, BWAPI::Broodwar->self()->getUnits());\n    if (workersOwned < workersWanted)\n    {\n        // get the unit pointer to my depot\n        const BWAPI::Unit myDepot = Tools::GetDepot();\n\n        // if we have a valid depot unit and it's currently not training something, train a worker\n        // there is no reason for a bot to ever use the unit queueing system, it just wastes resources\n        if (myDepot && !myDepot->isTraining()) { myDepot->train(workerType); }\n    }\n}\n\n// Build more supply if we are going to run out soon\nvoid StarterBot::buildAdditionalSupply()\n{\n    // Get the amount of supply supply we currently have unused\n    const int unusedSupply = Tools::GetTotalSupply(true) - BWAPI::Broodwar->self()->supplyUsed();\n\n    // If we have a sufficient amount of supply, we don't need to do anything\n    if (unusedSupply >= 2) { return; }\n\n    // Otherwise, we are going to build a supply provider\n    const BWAPI::UnitType supplyProviderType = BWAPI::Broodwar->self()->getRace().getSupplyProvider();\n\n    const bool startedBuilding = Tools::BuildBuilding(supplyProviderType);\n    if (startedBuilding)\n    {\n        BWAPI::Broodwar->printf(\"Started Building %s\", supplyProviderType.getName().c_str());\n    }\n}\n\n// Draw some relevent information to the screen to help us debug the bot\nvoid StarterBot::drawDebugInformation()\n{\n    BWAPI::Broodwar->drawTextScreen(BWAPI::Position(10, 10), \"Hello, World!\\n\");\n    Tools::DrawUnitCommands();\n    Tools::DrawUnitBoundingBoxes();\n}\n\n// Called whenever a unit is destroyed, with a pointer to the unit\nvoid StarterBot::onUnitDestroy(BWAPI::Unit unit)\n{\n\t\n}\n\n// Called whenever a unit is morphed, with a pointer to the unit\n// Zerg units morph when they turn into other units\nvoid StarterBot::onUnitMorph(BWAPI::Unit unit)\n{\n\t\n}\n\n// Called whenever a text is sent to the game by a user\nvoid StarterBot::onSendText(std::string text) \n{ \n    if (text == \"/map\")\n    {\n        m_mapTools.toggleDraw();\n    }\n}\n\n// Called whenever a unit is created, with a pointer to the destroyed unit\n// Units are created in buildings like barracks before they are visible, \n// so this will trigger when you issue the build command for most units\nvoid StarterBot::onUnitCreate(BWAPI::Unit unit)\n{ \n\t\n}\n\n// Called whenever a unit finished construction, with a pointer to the unit\nvoid StarterBot::onUnitComplete(BWAPI::Unit unit)\n{\n\t\n}\n\n// Called whenever a unit appears, with a pointer to the destroyed unit\n// This is usually triggered when units appear from fog of war and become visible\nvoid StarterBot::onUnitShow(BWAPI::Unit unit)\n{ \n\t\n}\n\n// Called whenever a unit gets hidden, with a pointer to the destroyed unit\n// This is usually triggered when units enter the fog of war and are no longer visible\nvoid StarterBot::onUnitHide(BWAPI::Unit unit)\n{ \n\t\n}\n\n// Called whenever a unit switches player control\n// This usually happens when a dark archon takes control of a unit\nvoid StarterBot::onUnitRenegade(BWAPI::Unit unit)\n{ \n\t\n}"
  },
  {
    "path": "UAlbertaBot/starterbot/StarterBot.h",
    "content": "#pragma once\n\n#include \"MapTools.h\"\n\n#include <BWAPI.h>\n\nclass StarterBot\n{\n    MapTools m_mapTools;\n\npublic:\n\n    StarterBot();\n\n    // helper functions to get you started with bot programming and learn the API\n    void sendIdleWorkersToMinerals();\n    void trainAdditionalWorkers();\n    void buildAdditionalSupply();\n    void drawDebugInformation();\n\n    // functions that are triggered by various BWAPI events from main.cpp\n\tvoid onStart();\n\tvoid onFrame();\n\tvoid onEnd(bool isWinner);\n\tvoid onUnitDestroy(BWAPI::Unit unit);\n\tvoid onUnitMorph(BWAPI::Unit unit);\n\tvoid onSendText(std::string text);\n\tvoid onUnitCreate(BWAPI::Unit unit);\n\tvoid onUnitComplete(BWAPI::Unit unit);\n\tvoid onUnitShow(BWAPI::Unit unit);\n\tvoid onUnitHide(BWAPI::Unit unit);\n\tvoid onUnitRenegade(BWAPI::Unit unit);\n};"
  },
  {
    "path": "UAlbertaBot/starterbot/Tools.cpp",
    "content": "#include \"Tools.h\"\n\nBWAPI::Unit Tools::GetClosestUnitTo(BWAPI::Position p, const BWAPI::Unitset& units)\n{\n    BWAPI::Unit closestUnit = nullptr;\n\n    for (auto& u : units)\n    {\n        if (!closestUnit || u->getDistance(p) < u->getDistance(closestUnit))\n        {\n            closestUnit = u;\n        }\n    }\n\n    return closestUnit;\n}\n\nBWAPI::Unit Tools::GetClosestUnitTo(BWAPI::Unit unit, const BWAPI::Unitset& units)\n{\n    if (!unit) { return nullptr; }\n    return GetClosestUnitTo(unit->getPosition(), units);\n}\n\nint Tools::CountUnitsOfType(BWAPI::UnitType type, const BWAPI::Unitset& units)\n{\n    int sum = 0;\n    for (auto& unit : units)\n    {\n        if (unit->getType() == type)\n        {\n            sum++;\n        }\n    }\n\n    return sum;\n}\n\nBWAPI::Unit Tools::GetUnitOfType(BWAPI::UnitType type)\n{\n    // For each unit that we own\n    for (auto& unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        // if the unit is of the correct type, and it actually has been constructed, return it\n        if (unit->getType() == type && unit->isCompleted())\n        {\n            return unit;\n        }\n    }\n\n    // If we didn't find a valid unit to return, make sure we return nullptr\n    return nullptr;\n}\n\nBWAPI::Unit Tools::GetDepot()\n{\n    const BWAPI::UnitType depot = BWAPI::Broodwar->self()->getRace().getResourceDepot();\n    return GetUnitOfType(depot);\n}\n\n// Attempt tp construct a building of a given type \nbool Tools::BuildBuilding(BWAPI::UnitType type)\n{\n    // Get the type of unit that is required to build the desired building\n    BWAPI::UnitType builderType = type.whatBuilds().first;\n\n    // Get a unit that we own that is of the given type so it can build\n    // If we can't find a valid builder unit, then we have to cancel the building\n    BWAPI::Unit builder = Tools::GetUnitOfType(builderType);\n    if (!builder) { return false; }\n\n    // Get a location that we want to build the building next to\n    BWAPI::TilePosition desiredPos = BWAPI::Broodwar->self()->getStartLocation();\n\n    // Ask BWAPI for a building location near the desired position for the type\n    int maxBuildRange = 64;\n    bool buildingOnCreep = type.requiresCreep();\n    BWAPI::TilePosition buildPos = BWAPI::Broodwar->getBuildLocation(type, desiredPos, maxBuildRange, buildingOnCreep);\n    return builder->build(type, buildPos);\n}\n\nvoid Tools::DrawUnitCommands()\n{\n    for (auto& unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        const BWAPI::UnitCommand & command = unit->getLastCommand();\n\n        // If the previous command had a ground position target, draw it in red\n        // Example: move to location on the map\n        if (command.getTargetPosition() != BWAPI::Positions::None)\n        {\n            BWAPI::Broodwar->drawLineMap(unit->getPosition(), command.getTargetPosition(), BWAPI::Colors::Red);\n        }\n\n        // If the previous command had a tile position target, draw it in red\n        // Example: build at given tile position location\n        if (command.getTargetTilePosition() != BWAPI::TilePositions::None)\n        {\n            BWAPI::Broodwar->drawLineMap(unit->getPosition(), BWAPI::Position(command.getTargetTilePosition()), BWAPI::Colors::Green);\n        }\n\n        // If the previous command had a unit target, draw it in red\n        // Example: attack unit, mine mineral, etc\n        if (command.getTarget() != nullptr)\n        {\n            BWAPI::Broodwar->drawLineMap(unit->getPosition(), command.getTarget()->getPosition(), BWAPI::Colors::White);\n        }\n    }\n}\n\nvoid Tools::DrawUnitBoundingBoxes()\n{\n    for (auto& unit : BWAPI::Broodwar->getAllUnits())\n    {\n        BWAPI::Position topLeft(unit->getLeft(), unit->getTop());\n        BWAPI::Position bottomRight(unit->getRight(), unit->getBottom());\n        BWAPI::Broodwar->drawBoxMap(topLeft, bottomRight, BWAPI::Colors::White);\n    }\n}\n\nvoid Tools::SmartRightClick(BWAPI::Unit unit, BWAPI::Unit target)\n{\n    // if there's no valid unit, ignore the command\n    if (!unit || !target) { return; }\n\n    // Don't issue a 2nd command to the unit on the same frame\n    if (unit->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount()) { return; }\n\n    // If we are issuing the same type of command with the same arguments, we can ignore it\n    // Issuing multiple identical commands on successive frames can lead to bugs\n    if (unit->getLastCommand().getTarget() == target) { return; }\n    \n    // If there's nothing left to stop us, right click!\n    unit->rightClick(target);\n}\n\nint Tools::GetTotalSupply(bool inProgress)\n{\n    // start the calculation by looking at our current completed supplyt\n    int totalSupply = BWAPI::Broodwar->self()->supplyTotal();\n\n    // if we don't want to calculate the supply in progress, just return that value\n    if (!inProgress) { return totalSupply; }\n\n    // if we do care about supply in progress, check all the currently constructing units if they will add supply\n    for (auto& unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        // ignore units that are fully completed\n        if (unit->isCompleted()) { continue; }\n\n        // if they are not completed, then add their supply provided to the total supply\n        totalSupply += unit->getType().supplyProvided();\n    }\n\n    // one last tricky case: if a unit is currently on its way to build a supply provider, add it\n    for (auto& unit : BWAPI::Broodwar->self()->getUnits())\n    {\n        // get the last command given to the unit\n        const BWAPI::UnitCommand& command = unit->getLastCommand();\n\n        // if it's not a build command we can ignore it\n        if (command.getType() != BWAPI::UnitCommandTypes::Build) { continue; }\n\n        // add the supply amount of the unit that it's trying to build\n        totalSupply += command.getUnitType().supplyProvided();\n    }\n\n    return totalSupply;\n}\n\nvoid Tools::DrawUnitHealthBars()\n{\n    // how far up from the unit to draw the health bar\n    int verticalOffset = -10;\n\n    // draw a health bar for each unit on the map\n    for (auto& unit : BWAPI::Broodwar->getAllUnits())\n    {\n        // determine the position and dimensions of the unit\n        const BWAPI::Position& pos = unit->getPosition();\n        int left = pos.x - unit->getType().dimensionLeft();\n        int right = pos.x + unit->getType().dimensionRight();\n        int top = pos.y - unit->getType().dimensionUp();\n        int bottom = pos.y + unit->getType().dimensionDown();\n\n        // if it's a resource, draw the resources remaining\n        if (unit->getType().isResourceContainer() && unit->getInitialResources() > 0)\n        {\n            double mineralRatio = (double)unit->getResources() / (double)unit->getInitialResources();\n            DrawHealthBar(unit, mineralRatio, BWAPI::Colors::Cyan, 0);\n        }\n        // otherwise if it's a unit, draw the hp \n        else if (unit->getType().maxHitPoints() > 0)\n        {\n            double hpRatio = (double)unit->getHitPoints() / (double)unit->getType().maxHitPoints();\n            BWAPI::Color hpColor = BWAPI::Colors::Green;\n            if (hpRatio < 0.66) hpColor = BWAPI::Colors::Orange;\n            if (hpRatio < 0.33) hpColor = BWAPI::Colors::Red;\n            DrawHealthBar(unit, hpRatio, hpColor, 0);\n            \n            // if it has shields, draw those too\n            if (unit->getType().maxShields() > 0)\n            {\n                double shieldRatio = (double)unit->getShields() / (double)unit->getType().maxShields();\n                DrawHealthBar(unit, shieldRatio, BWAPI::Colors::Blue, -3);\n            }\n        }\n    }\n}\n\nvoid Tools::DrawHealthBar(BWAPI::Unit unit, double ratio, BWAPI::Color color, int yOffset)\n{\n    int verticalOffset = -10;\n    const BWAPI::Position& pos = unit->getPosition();\n\n    int left = pos.x - unit->getType().dimensionLeft();\n    int right = pos.x + unit->getType().dimensionRight();\n    int top = pos.y - unit->getType().dimensionUp();\n    int bottom = pos.y + unit->getType().dimensionDown();\n\n    int ratioRight = left + (int)((right - left) * ratio);\n    int hpTop = top + yOffset + verticalOffset;\n    int hpBottom = top + 4 + yOffset + verticalOffset;\n\n    BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);\n    BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), color, true);\n    BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);\n\n    int ticWidth = 3;\n\n    for (int i(left); i < right - 1; i += ticWidth)\n    {\n        BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);\n    }\n}"
  },
  {
    "path": "UAlbertaBot/starterbot/Tools.h",
    "content": "#pragma once\n\n#include <BWAPI.h>\n\nnamespace Tools\n{\n    BWAPI::Unit GetClosestUnitTo(BWAPI::Position p, const BWAPI::Unitset& units);\n    BWAPI::Unit GetClosestUnitTo(BWAPI::Unit unit, const BWAPI::Unitset& units);\n\n    int CountUnitsOfType(BWAPI::UnitType type, const BWAPI::Unitset& units);\n\n    BWAPI::Unit GetUnitOfType(BWAPI::UnitType type);\n    BWAPI::Unit GetDepot();\n\n    bool BuildBuilding(BWAPI::UnitType type);\n\n    void DrawUnitBoundingBoxes();\n    void DrawUnitCommands();\n\n    void SmartRightClick(BWAPI::Unit unit, BWAPI::Unit target);\n\n    int GetTotalSupply(bool inProgress = false);\n\n    void DrawUnitHealthBars();\n    void DrawHealthBar(BWAPI::Unit unit, double ratio, BWAPI::Color color, int yOffset);\n}"
  },
  {
    "path": "UAlbertaBot/starterbot/main.cpp",
    "content": "#include <BWAPI.h>\n#include <BWAPI/Client.h>\n#include \"StarterBot.h\"\n#include <iostream>\n#include <thread>\n#include <chrono>\n\nvoid PlayGame();\n\nint main(int argc, char * argv[])\n{\n    size_t gameCount = 0;\n\n    // if we are not currently connected to BWAPI, try to reconnect\n    while (!BWAPI::BWAPIClient.connect())\n    {\n        std::this_thread::sleep_for(std::chrono::milliseconds{ 1000 });\n    }\n\n    // if we have connected to BWAPI\n    while (BWAPI::BWAPIClient.isConnected())\n    {\n        // the starcraft exe has connected but we need to wait for the game to start\n        std::cout << \"Waiting for game start\\n\";\n        while (BWAPI::BWAPIClient.isConnected() && !BWAPI::Broodwar->isInGame())\n        {\n            BWAPI::BWAPIClient.update();\n        }\n\n        // Check to see if Starcraft shut down somehow\n        if (BWAPI::BroodwarPtr == nullptr) { break; }\n\n        // If we are successfully in a game, call the module to play the game\n        if (BWAPI::Broodwar->isInGame())\n        {\n            std::cout << \"Playing game \" << gameCount++ << \" on map \" << BWAPI::Broodwar->mapFileName() << \"\\n\";\n\n            PlayGame();\n        }\n    }\n\n\n\n\treturn 0;\n}\n\nvoid PlayGame()\n{\n    StarterBot bot;\n\n    // The main game loop, which continues while we are connected to BWAPI and in a game\n    while (BWAPI::BWAPIClient.isConnected() && BWAPI::Broodwar->isInGame())\n    {\n        // Handle each of the events that happened on this frame of the game\n        for (const BWAPI::Event& e : BWAPI::Broodwar->getEvents())\n        {\n            switch (e.getType())\n            {\n                case BWAPI::EventType::MatchStart:   { bot.onStart();                       break; }\n                case BWAPI::EventType::MatchFrame:   { bot.onFrame();                       break; }\n                case BWAPI::EventType::MatchEnd:     { bot.onEnd(e.isWinner());             break; }\n                case BWAPI::EventType::UnitShow:     { bot.onUnitShow(e.getUnit());         break; }\n                case BWAPI::EventType::UnitHide:     { bot.onUnitHide(e.getUnit());         break; }\n                case BWAPI::EventType::UnitCreate:   { bot.onUnitCreate(e.getUnit());       break; }\n                case BWAPI::EventType::UnitMorph:    { bot.onUnitMorph(e.getUnit());        break; }\n                case BWAPI::EventType::UnitDestroy:  { bot.onUnitDestroy(e.getUnit());      break; }\n                case BWAPI::EventType::UnitRenegade: { bot.onUnitRenegade(e.getUnit());     break; }\n                case BWAPI::EventType::UnitComplete: { bot.onUnitComplete(e.getUnit());     break; }\n                case BWAPI::EventType::SendText:     { bot.onSendText(e.getText());         break; }\n            }\n        }\n\n        BWAPI::BWAPIClient.update();\n        if (!BWAPI::BWAPIClient.isConnected())\n        {\n            std::cout << \"Disconnected\\n\";\n            break;\n        }\n    }\n\n    std::cout << \"Game Over\\n\";\n}\n"
  }
]