code:
#include "opengl.h"
#include "../../../../app/browser/Browser.h"

#include <iostream>
#include <cmath>
#include <cstring> // for memset

// for creating new windows
extern std::unique_ptr<Browser> browser;

inline void checkGLState(std::string whereWhat) {
    GLenum glErr=glGetError();
    if(glErr != GL_NO_ERROR) {
        std::cout << whereWhat << " - not ok: " << glErr << std::endl;
    }
}

// maybe change to return std::pair<GLuint, GLuint>
// with the renderer and version?
bool initGL() {
    const GLubyte *brenderer = glGetString(GL_RENDERER);
    const GLubyte *version = glGetString(GL_VERSION);
    std::cout << "Renderer: " << brenderer << std::endl;
    std::cout << "Version: " << version << std::endl;

    checkGLState("opengl::initGL - start");

    glEnable(GL_BLEND); checkGLState("opengl::initGL - glEnable blend");
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); checkGLState("opengl::initGL - glBlendFunc");

    unsigned int clearColor = 0xCCCCCCCC;
    float r = (static_cast<float>((clearColor >> 24) & 0xFF)) / 255;
    float g = (static_cast<float>((clearColor >> 16) & 0xFF)) / 255;
    float b = (static_cast<float>((clearColor >>  8) & 0xFF)) / 255;
    float a = (static_cast<float>((clearColor >>  0) & 0xFF)) / 255;

    //glClearColor(0.8f, 0.8f, 0.8f, 0.8f);
    glClearColor(r, g, b, a); checkGLState("opengl::initGL - glClearColor");
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); checkGLState("opengl::initGL - glTexParameteri min");
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); checkGLState("opengl::initGL - glTexParameteri mag");

    //std::cout << "OpenGL is set up" << std::endl;

    return true;
}

bool initGLEW() {
    glewExperimental = GL_TRUE;
    const GLenum err = glewInit();
    if (err != GLEW_OK) {
        std::cout << "Could not initialize GLEW: " << glewGetErrorString(err) << std::endl;
        return false;
    }
    return true;
}

// only called once
bool OpenGL::initialize() {
    if (!glfwInit()) {
        std::cout << "Could not initialize GLFW" << std::endl;
        return false;
    }

    cursorHand = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
    cursorArrow = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
    cursorIbeam = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
    glfwSetErrorCallback([](int error, const char* description) {
        std::cout << "glfw error [" << error << "]:" << description << std::endl;
    });

    // I don't think you can init GLEW without a window
    return true;
}

OpenGLWindowHandle * OpenGL::createWindow(std::string title, Rect *position, unsigned int flags) {
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    int windowWidth = position->w;
    int windowHeight = position->h;
    OpenGLWindowHandle *twin = new OpenGLWindowHandle();
    twin->width = position->w;
    twin->height = position->h;
    GLFWwindow *window = glfwCreateWindow(windowWidth, windowHeight, title.c_str(), nullptr, nullptr);
    twin->window = window;

    // replace first parameter of all these callbacks with our window object instead of a GLFWwindow
    glfwSetWindowUserPointer(window, this);
    // probably should set up all the hooks here
    glfwMakeContextCurrent(window);

    // init GLEW
    if (!initGLEW()) {
        // FIXME: un do glfw create window
	// can't delete without a non-virtual deconstrcutor
        //delete win;
        return nullptr;
    }
    // init shaders?
    // we only want the box (texture shader)
    // I don't think you can init GLEW without a window
    initGL();

    // load the shaders
    twin->textureShader = twin->shaderLoader.getShader(VertexShader("TextureShader.vert"),
                                                       FragmentShader("TextureShader.frag"));
    twin->fontShader = twin->shaderLoader.getShader(VertexShader("FontShader.vert"),
                                                    FragmentShader("FontShader.frag"));

    // configure opengl coordinates
    //std::cout << "position: " << position->w << "x" << position->h << std::endl;
    glViewport(0, 0, static_cast<GLsizei>(position->w), static_cast<GLsizei>(position->h)); checkGLState("OpenGL::createWindow - glViewport");

    // replace first parameter of all these callbacks with our window object instead of a GLFWwindow
    glfwSetWindowUserPointer(twin->window, twin);

    // set up event callbacks

    // window events
    glfwSetFramebufferSizeCallback(window, [](GLFWwindow *glfwwin, int width, int height) {
        glViewport(0, 0, width, height);
    });
    glfwSetWindowSizeCallback(window, [](GLFWwindow *glfwwin, int width, int height) {
        OpenGLWindowHandle *thiz = reinterpret_cast<OpenGLWindowHandle*>(glfwGetWindowUserPointer(glfwwin));
        if (thiz->onResize) {
            thiz->onResize(width, height);
        }
    });

    // mouse events
    glfwSetCursorPosCallback(window, [](GLFWwindow *glfwwin, double xPos, double yPos) {
        OpenGLWindowHandle *thiz = reinterpret_cast<OpenGLWindowHandle*>(glfwGetWindowUserPointer(glfwwin));
        //std::cout << "Window::Window:onMousemove - at " << static_cast<int>(xPos) << "," << static_cast<int>(yPos) << std::endl;
        thiz->cursorX = xPos;
        thiz->cursorY = yPos;
        if (xPos < 0 || yPos < 0) return;
        if (xPos > thiz->width || yPos > thiz->height) return;
        // p. much worthless on double
        /*
         static double lx = 0;
         static double ly = 0;
         if (lx == xPos && ly == yPos) {
         return;
         }
         lx = xPos;
         ly = yPos;
         std::cout << "Window::Window:onMousemove - noCache" << std::endl;
         */
        //std::cout << "Window::Window:onMousemove - onWheel" << std::endl;
        if (thiz->onMouseMove) {
            thiz->onMouseMove(xPos, yPos);
        }
    });
    glfwSetScrollCallback(window, [](GLFWwindow *glfwwin, double xOffset, double yOffset) {
        OpenGLWindowHandle *thiz = reinterpret_cast<OpenGLWindowHandle*>(glfwGetWindowUserPointer(glfwwin));
        //std::cout << "glfwSetScrollCallback " << yOffset << " int" << (int)(yOffset * 10) << std::endl;
        if (thiz->onWheel) {
            thiz->onWheel(xOffset * 10, yOffset * 10);
        }
    });
    glfwSetMouseButtonCallback(window, [](GLFWwindow *glfwwin, int button, int action, int mods) {
        OpenGLWindowHandle *thiz = reinterpret_cast<OpenGLWindowHandle*>(glfwGetWindowUserPointer(glfwwin));
        if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
            //std::cout << "left press" << std::endl;
            if (thiz->onMouseUp) {
                thiz->onMouseDown(thiz->cursorX, thiz->cursorY);
            }
        }
        if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) {
            //std::cout << "left release" << std::endl;
            if (thiz->onMouseUp) {
                thiz->onMouseUp(thiz->cursorX, thiz->cursorY);
            }
        }
    });

    // keyboard events

    // works with utf-32 and os keyboard layout but we'll lkeep the low level for now
    glfwSetCharCallback(window, [](GLFWwindow* glfwwin, unsigned int codepoint) {
        OpenGLWindowHandle *thiz = reinterpret_cast<OpenGLWindowHandle*>(glfwGetWindowUserPointer(glfwwin));
        //std::cout << "OpenGL::glfwSetCharCallback - codepoint: " << codepoint << std::endl;

        // should be used for inputComponent
        if (thiz->onKeyPress) {
            thiz->onKeyPress(codepoint);
        }
    });

    glfwSetKeyCallback(window, [](GLFWwindow *glfwwin, int key, int scancode, int action, int mods) {
        OpenGLWindowHandle *thiz = reinterpret_cast<OpenGLWindowHandle*>(glfwGetWindowUserPointer(glfwwin));
        std::cout << "opengl::glfwSetKeyCallback - Key " << key << " action: " << action << " mods: " << mods << std::endl;
        switch(action) {
            case GLFW_RELEASE:
                if (thiz->onKeyUp) {
                    std::cout << "hasKeyUp" << std::endl;
                    thiz->onKeyUp(key, scancode, mods);
                }
            break;
            case GLFW_PRESS:
                //thiz->ui->onKeyDown(key, scancode, mods);
                //thiz->ui->onKeyPress(key, scancode, action, mods);
                if (thiz->onKeyDown) {
                    std::cout << "hasKeyDown" << std::endl;
                    thiz->onKeyDown(key, scancode, mods);
                }
            break;
            case GLFW_REPEAT:
                //thiz->ui->onKeyRepeat(key, scancode, mods);
                //thiz->ui->onKeyPress(key, scancode, action, mods);
                if (thiz->onKeyRepeat) {
                    std::cout << "hasKeyRepeat" << std::endl;
                    thiz->onKeyRepeat(key, scancode, mods);
                }
            break;
        }
    });

    /*
    // Change to the projection matrix, reset the matrix and set up orthagonal projection (i.e. 2D)
    glMatrixMode(GL_PROJECTION);
    glErr=glGetError();
    if(glErr != GL_NO_ERROR) {
        std::cout << "OpenGL::createWindow - glMatrixMode - not ok: " << gluErrorString(glErr) << std::endl;
    }
    glLoadIdentity();
    glErr=glGetError();
    if(glErr != GL_NO_ERROR) {
        std::cout << "OpenGL::createWindow - glLoadIdentity - not ok: " << gluErrorString(glErr) << std::endl;
    }
    glOrtho(0, position->w, position->h, 0, 0, 1); // Paramters: left, right, bottom, top, near, far
    glErr=glGetError();
    if(glErr != GL_NO_ERROR) {
        std::cout << "OpenGL::createWindow - glOrtho - not ok: " << gluErrorString(glErr) << std::endl;
    }
    */

    // set up box shader
    GLuint elementBufferObject = 0;

    glGenVertexArrays(1, &twin->vertexArrayObjectBox); checkGLState("OpenGL::createWindow - genVAOBox");
    glBindVertexArray(twin->vertexArrayObjectBox); checkGLState("OpenGL::createWindow - bindVAOBox");
    glGenBuffers(1, &elementBufferObject); checkGLState("OpenGL::createWindow - genEBO");

    // we may need the VBO here...
    glGenBuffers(1, &twin->vertexBufferObjectBox); checkGLState("OpenGL::createWindow - genVBOBox");
    float vertices[20] = {
        0.0f, 0.0f, 0.0f,    0.0f, 1.0f,
        0.0f, 0.0f, 0.0f,    1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,    1.0f, 0.0f,
        0.0f, 0.0f, 0.0f,    0.0f, 0.0f
    };

    // select buffer
    glBindBuffer(GL_ARRAY_BUFFER, twin->vertexBufferObjectBox); checkGLState("OpenGL::createWindow - bindVBO");
    // write buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); checkGLState("OpenGL::createWindow - bufVBO");
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject); checkGLState("OpenGL::createWindow - bindEBO");
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(this->indices), this->indices, GL_STATIC_DRAW); checkGLState("OpenGL::createWindow - buffEBO");

    // attribute 0 = 3 floats
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr); checkGLState("OpenGL::createWindow - glVertexAttribPointer0");
    glEnableVertexAttribArray(0); checkGLState("OpenGL::createWindow - glEnableVertexAttribArray0");

    // attribute 1 = 2 floats, at 3
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), reinterpret_cast<void*>(3 * sizeof(float))); checkGLState("OpenGL::createWindow - glVertexAttribPointer1");
    glEnableVertexAttribArray(1); checkGLState("OpenGL::createWindow - glEnableVertexAttribArray1");

    //glBindVertexArray(0);

    // set up text shader
    glGenVertexArrays(1, &twin->vertexArrayObjectText); checkGLState("OpenGL::createWindow - genVAOText");
    glBindVertexArray(twin->vertexArrayObjectText); checkGLState("OpenGL::createWindow - bindVBOText");

    // vBO
    glGenBuffers(1, &twin->vertexBufferObjectText); checkGLState("OpenGL::createWindow - genVBOText");
    glBindBuffer(GL_ARRAY_BUFFER, twin->vertexBufferObjectText); checkGLState("OpenGL::createWindow - bindVBOText");
    std::unique_ptr<float[]> vertices2 = std::make_unique<float[]>(36); // upload garbage for now
    glBufferData(GL_ARRAY_BUFFER, ((3 + 4 + 2) * 4) * sizeof(float), vertices2.get(), GL_STATIC_DRAW); checkGLState("OpenGL::createWindow - buffVBOText");

    // eBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject); checkGLState("OpenGL::createWindow - bindVBOText");
    //glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, (3 + 4 + 2) * sizeof(float), nullptr); checkGLState("OpenGL::createWindow - glVertexAttribPointerText0");
    glEnableVertexAttribArray(0); checkGLState("OpenGL::createWindow - glEnableVertexAttribArrayText0");

    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, (3 + 4 + 2) * sizeof(float), reinterpret_cast<void*>(3 * sizeof(float))); checkGLState("opengl::createWindow - glVertexAttribPointerText1");
    glEnableVertexAttribArray(1); checkGLState("OpenGL::createWindow - glEnableVertexAttribArrayText1");

    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, (3 + 4 + 2) * sizeof(float), reinterpret_cast<void*>(7 * sizeof(float))); checkGLState("opengl::createWindow - glVertexAttribPointerText2");
    glEnableVertexAttribArray(2); checkGLState("OpenGL::createWindow - glEnableVertexAttribArrayText2");

    glBindVertexArray(0);

    return twin;
}

void OpenGLWindowHandle::clear() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); checkGLState("OpenGLWindowHandle::clear");
}

void OpenGLWindowHandle::swapBuffers() {
    glfwSwapBuffers(this->window); checkGLState("OpenGLWindowHandle::swapBuffers");
}

OpenGLTexture* OpenGLWindowHandle::createSprite(unsigned char* texture, GLsizei w, GLsizei h) {
    OpenGLTexture *handle = new OpenGLTexture;
    glGenTextures(1, &handle->number);

    // make sure texture size is a power of two
    size_t potw = pow(2, ceil(log(w) / log(2)));
    size_t poth = pow(2, ceil(log(h) / log(2)));
    // FIXME: need to dynamically allocate for c++
    //unsigned char data[16384][16384][4];
    //unsigned char ***image = allocate_dynamic_bitmap(poth, potw, 4);
    unsigned char *data = reinterpret_cast<unsigned char *>(tlsf_malloc(sizeof(unsigned char) * poth * potw * 4));
    //memset(data, 0, poth * potw * 4);
    //memset(image, 0, poth * potw * 4);
    // unflip texture
    unsigned int loadWidth = static_cast<unsigned int>(w);
    unsigned int loadHeight = static_cast<unsigned int>(h);
    for (unsigned int py = 0; py < loadHeight; py++) {
        for (unsigned int px = 0; px < loadWidth; px++) {
            for (unsigned int i = 0; i < 4; i++) {
                //data[1023 - py][px][i] = anime.pixel_data[((px * 4) + (py * 4 * 1024)) + i];
                size_t read = ((px * 4) + (py * 4 * loadWidth)) + i;
                unsigned char val = texture[read];
                size_t ypos = potw - 1 - py; // flip y
                size_t write = ((px * 4) + (ypos * 4 * potw)) + i;
                data[write] = val;
                //data[ypos][px][i] = val;
            }
        }
    }

    // upload to video card
    // select
    glBindTexture(GL_TEXTURE_2D, handle->number); checkGLState("OpenGLWindowHandle::createSprite - bind");
    // upload
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<int>(potw), static_cast<int>(poth), 0, GL_RGBA, GL_UNSIGNED_BYTE, data); checkGLState("OpenGLWindowHandle::createSprite - upload");
    // process
    glGenerateMipmap(GL_TEXTURE_2D); checkGLState("OpenGLWindowHandle::createSprite - process");
    // unselect
    glBindTexture(GL_TEXTURE_2D, 0); checkGLState("OpenGLWindowHandle::createSprite - unselect");

    return handle;
}

OpenGLTexture* OpenGLWindowHandle::createTextSprite(unsigned char *texture, GLsizei w, GLsizei h, textureMap &textureMap) {
    OpenGLTexture *handle = new OpenGLTexture;
    glGenTextures(1, &handle->number); checkGLState("OpenGLWindowHandle::createTextureFromColor - glGenTextures");

    // upload
    glBindTexture(GL_TEXTURE_2D, handle->number); checkGLState("OpenGLWindowHandle::createTextureFromColor - bindTexture");
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, texture); checkGLState("OpenGLWindowHandle::createTextureFromColor - glTexImage2D");
    glGenerateMipmap(GL_TEXTURE_2D); checkGLState("OpenGLWindowHandle::createTextureFromColor - glGenerateMipmap");
    glBindTexture(GL_TEXTURE_2D, 0); checkGLState("OpenGLWindowHandle::createTextureFromColor - unBindTex");

    // I flipped this maybe due to coords...
    handle->s0 = textureMap.map[0];
    handle->t0 = textureMap.map[1];
    handle->s1 = textureMap.map[2];
    handle->t1 = textureMap.map[3];

    return handle;
}

OpenGLTexture* OpenGLWindowHandle::createSpriteFromColor(const unsigned int hexColor) {
    //std::cout << "createTextureFromColor: " << hexColor << std::endl;
    unsigned char texture[1][1][4];
    texture[0][0][0]=(hexColor >> 24) & 0xFF;
    texture[0][0][1]=(hexColor >> 16) & 0xFF;
    texture[0][0][2]=(hexColor >>  8) & 0xFF;
    texture[0][0][3]=(hexColor >>  0) & 0xFF;
    //std::cout << "opengl::createTextureFromColor R: " << (int)texture[0][0][0] << " G: " << (int)texture[0][0][1] << " B: " << (int)texture[0][0][2] << " A: " << (int)texture[0][0][3] << std::endl;
    // I can't figure out how to pass data to opengl::createTexture
    // so we'll just do this for now
    OpenGLTexture *handle=new OpenGLTexture;

    glGenTextures(1, &handle->number); checkGLState("OpenGLWindowHandle::createTextureFromColor - glGenTextures");
    glBindTexture(GL_TEXTURE_2D, handle->number); checkGLState("OpenGLWindowHandle::createTextureFromColor - glBindTexture");
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture); checkGLState("OpenGLWindowHandle::createTextureFromColor - glTexImage2D");
    glGenerateMipmap(GL_TEXTURE_2D); checkGLState("OpenGLWindowHandle::createTextureFromColor - glGenerateMipmap");
    glBindTexture(GL_TEXTURE_2D, 0); checkGLState("OpenGLWindowHandle::createTextureFromColor - unselect");

    return handle;
}

#include <cmath>

// converts 0-1 to screen
// but centered
void pointToViewport(float &rawX, float &rawY, size_t windowWidth, size_t windowHeight) {
    //std::cout << "Component::pointToViewport - notBoundToPage converting from " << static_cast<int>(rawX) << "," << static_cast<int>(rawY) << std::endl;
    //std::cout << "BoundToPage using " << screenWidth << "x" << screenHeight << std::endl;
    rawX = ((rawX / windowWidth) * 2) - 1;
    rawY = ((rawY / windowHeight) * 2) - 1;
    //std::cout << "Component::pointToViewport - BoundToPage using " << static_cast<int>(rawX) << "x" << static_cast<int>(rawY) << std::endl;
    //std::cout << "Component::pointToViewport - BoundToPage converted to " << rawX << "," << rawY << std::endl;
}

void pointToViewportText(float &rawX, float &rawY, size_t windowWidth, size_t windowHeight);
void pointToViewportText(float &rawX, float &rawY, size_t windowWidth, size_t windowHeight) {
    //std::cout << "notBoundToPage using " << screenWidth << "x" << screenHeight << std::endl;
    //std::cout << "Component::pointToViewport - notBoundToPage converting from " << static_cast<int>(rawX) << "," << static_cast<int>(rawY) << std::endl;
    if (rawX < 0) {
        rawX += windowWidth;
    }
    if (rawY < 0) {
        rawY += windowHeight;
    }
    if (rawX > 1) {
        rawX /= windowWidth;
    }
    if (rawY > 1) {
        rawY /= windowHeight;
    }
    rawX = (rawX * 2) - 1;
    rawY = (rawY * 2) - 1;
    //std::cout << "Component::pointToViewport - notBoundToPage converted to " << rawX << "," << rawY << std::endl;
}

// keeps 0-1 (and *2 to convert to screen)
// but also takes pixels (and converts to screen)
// anchors to upperleft
void distanceToViewport(float &rawX, float &rawY, size_t windowWidth, size_t windowHeight) {
    if (std::abs(rawX) > 1) {
        rawX /= windowWidth;
    }
    if (std::abs(rawY) > 1) {
        rawY /= windowHeight;
    }
    rawX *= 2;
    rawY *= 2;
}

void OpenGLWindowHandle::drawSpriteBox(OpenGLTexture *texture, Rect *position) {
    std::cout << "Window size: " << this->width << "," << this->height << std::endl;
    // figure out new vertices
    float vx = position->x;
    // 320, 320 is mid to top
    // 0, 320 to bottom to top
    //float vy = (int)position->h - (int)position->y - (int)this->height;
    float vy = static_cast<int>(position->h) - position->y;
    float vWidth = position->w;
    float vHeight = position->h;
    //std::cout << "placing box at " << (int)vx << "x" << (int)vy << " size: " << (int)vWidth << "x" << (int)vHeight << std::endl;
    pointToViewport(vx, vy, this->width, this->height);

    //std::cout << "vWidth before: " << (int)vWidth << std::endl;
    distanceToViewport(vWidth, vHeight, this->width, this->height);
    //std::cout << "vWidth after: " << (int)vWidth << std::endl;

    //std::cout << "placing box at GL " << (int)vx << "x" << (int)vy << " size: " << (int)(vWidth*10000) << "x" << (int)(vHeight*10000) << std::endl;
    float vertices[20] = {
        0.0f, 0.0f, 0.0f,    0.0f, 1.0f,
        0.0f, 0.0f, 0.0f,    1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,    1.0f, 0.0f,
        0.0f, 0.0f, 0.0f,    0.0f, 0.0f
    };
    vertices[(0 * 5) + 0] = vx;
    vertices[(0 * 5) + 1] = vy + vHeight;
    vertices[(1 * 5) + 0] = vx + vWidth;
    vertices[(1 * 5) + 1] = vy + vHeight;
    vertices[(2 * 5) + 0] = vx + vWidth;
    vertices[(2 * 5) + 1] = vy;
    vertices[(3 * 5) + 0] = vx;
    vertices[(3 * 5) + 1] = vy;

    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectBox); checkGLState("OpenGLWindowHandle::drawSpriteBox - unselect");
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); checkGLState("OpenGLWindowHandle::drawSpriteBox - glBufferData");
    float textureTransformMatrix[16] = {
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1
    };
    textureShader->bind();
    GLint transformLocation = textureShader->uniform("transform");
    glUniformMatrix4fv(transformLocation, 1, GL_FALSE, textureTransformMatrix); checkGLState("OpenGLWindowHandle::drawSpriteBox - glUniformMatrix4fv");

    glBindVertexArray(vertexArrayObjectBox); checkGLState("OpenGLWindowHandle::drawSpriteBox - glBindVertexArray");
    glBindTexture(GL_TEXTURE_2D, texture->number); checkGLState("OpenGLWindowHandle::drawSpriteBox - glBindTexture");
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); checkGLState("OpenGLWindowHandle::drawSpriteBox - glDrawElements");
}

inline void setVerticesColor(std::unique_ptr<float[]> &vertices, int p, unsigned int color);

#define posMac(p) (p * (3 + 4 + 2)) // 3 positions + 4 color channels + 2 S&T (texture mapping)

inline void setVerticesColor(std::unique_ptr<float[]> &vertices, int p, unsigned int color) {
    vertices[static_cast<size_t>(posMac(p) + 2)] = 0.0f;
    vertices[static_cast<size_t>(posMac(p) + 3)] = (static_cast<float>((color >> 24) & 0xFF)) / 255;
    vertices[static_cast<size_t>(posMac(p) + 4)] = (static_cast<float>((color >> 16) & 0xFF)) / 255;
    vertices[static_cast<size_t>(posMac(p) + 5)] = (static_cast<float>((color >>  8) & 0xFF)) / 255;
    vertices[static_cast<size_t>(posMac(p) + 6)] = (static_cast<float>((color >>  0) & 0xFF)) / 255;
}

void OpenGLWindowHandle::drawSpriteText(OpenGLTexture *texture, unsigned int hexColor, Rect *position) {
    float vx0 = position->x;
    float vy0 = static_cast<int>(this->height) - position->y + position->h;
    float vx1 = position->x + position->w;
    float vy1 = static_cast<int>(this->height) - position->y;
    pointToViewportText(vx0, vy0, this->width, this->height);
    pointToViewportText(vx1, vy1, this->width, this->height);

    std::unique_ptr<float[]> vertices = std::make_unique<float[]>(36);
    vertices[posMac(0) + 0] = vx0;
    vertices[posMac(0) + 1] = vy0;
    setVerticesColor(vertices, 0, hexColor);
    vertices[posMac(0) + 7] = texture->s0;
    vertices[posMac(0) + 8] = texture->t0;

    vertices[posMac(1) + 0] = vx0;
    vertices[posMac(1) + 1] = vy1;
    setVerticesColor(vertices, 1, hexColor);
    vertices[posMac(1) + 7] = texture->s0;
    vertices[posMac(1) + 8] = texture->t1;

    vertices[posMac(2) + 0] = vx1;
    vertices[posMac(2) + 1] = vy1;
    setVerticesColor(vertices, 2, hexColor);
    vertices[posMac(2) + 7] = texture->s1;
    vertices[posMac(2) + 8] = texture->t1;

    vertices[posMac(3) + 0] = vx1;
    vertices[posMac(3) + 1] = vy0;
    setVerticesColor(vertices, 3, hexColor);
    vertices[posMac(3) + 7] = texture->s1;
    vertices[posMac(3) + 8] = texture->t0;

    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectText); checkGLState("OpenGLWindowHandle::drawSpriteText - glBindBuffer");
    glBufferData(GL_ARRAY_BUFFER, ((3 + 4 + 2) * 4) * sizeof(float), vertices.get(), GL_STATIC_DRAW); checkGLState("OpenGLWindowHandle::drawSpriteText - glBufferData");

    float transformMatrix[16] = {
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1
    };
    fontShader->bind();
    GLint transformLocation = fontShader->uniform("transform");
    glUniformMatrix4fv(transformLocation, 1, GL_FALSE, transformMatrix); checkGLState("OpenGLWindowHandle::drawSpriteText - glUniformMatrix4fv");

    // load vertices
    glBindVertexArray(vertexArrayObjectText); checkGLState("OpenGLWindowHandle::drawSpriteText - glBindVertexArray");
    // load texture
    glBindTexture(GL_TEXTURE_2D, texture->number); checkGLState("OpenGLWindowHandle::drawSpriteText - glBindTexture");
    // draw primitives using vertices and texture
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); checkGLState("OpenGLWindowHandle::drawSpriteText - glDrawElements");

}


code:
#ifndef OPENGL_H
#define OPENGL_H

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <memory> // for unique_ptr
#include <vector>
#include <string>
#include "ShaderLoader.h"
#include "../renderer.h"

struct quadVector {
    GLfloat vector[4][3];
};

class TextureAtlas {
public:
    GLuint texture;
    sizes w, h; // texture width/height
    sizes mx, my; // max x,y currently available
    std::vector<Rect*> used; // small struct to loop on vs. unused
    std::vector<Rect*> available; // have to generate it, might as well cache it
    bool smooth;
    unsigned char bpp; // 0-4

    ~TextureAtlas();
    void updateMaxAvailArea();
    void markAreaUsed(Rect *it);
    void rebuildAvailable();
};

class OpenGLTexture : public Sprite {
public:
    // future
    TextureAtlas *mp_atlas;
    quadVector m_texureVector;
    // temp for now
    GLuint number;
    GLfloat s0;
    GLfloat t0;
    GLfloat s1;
    GLfloat t1;
};

// unlike a texture more like a sprite
class OpenGLTexturedQuad {
public:
    bool fontShader;
    sizes width;
    sizes height;
    // vertices
    coordinates x0;
    coordinates y0;
    coordinates x1;
    coordinates y1;
    // texture map
    float s0;
    float t0;
    float s1;
    float t1;
    sizes textureWidth;
    sizes textureHeight;
    std::unique_ptr<unsigned char[]> textureData;
};

class opengl; // few declr

bool initGL();
bool initGLEW();

class OpenGLWindowHandle : public WindowHandle {
public:
    void clear();
    void swapBuffers();
    OpenGLTexture* createSprite(unsigned char* texture, GLsizei w, GLsizei h);
    OpenGLTexture* createTextSprite(unsigned char *texture, GLsizei w, GLsizei h, textureMap &textureMap);
    OpenGLTexture* createSpriteFromColor(const unsigned int hexColor);
    using WindowHandle::drawSpriteBox;
    void drawSpriteBox(OpenGLTexture *texture, Rect *position);
    using WindowHandle::drawSpriteText;
    void drawSpriteText(OpenGLTexture *texture, unsigned int hexColor, Rect *position);
    // property
    GLFWwindow *window;
    opengl *renderer;
    // our singular vao
    GLuint vertexArrayObjectBox = 0;
    GLuint vertexArrayObjectText = 0;
    // our singular vbo
    GLuint vertexBufferObjectBox = 0;
    GLuint vertexBufferObjectText = 0;
    ShaderLoader shaderLoader;
    Shader *textureShader;
    Shader *fontShader;
    // needed for mouse down/up events
    double cursorX = 0;
    double cursorY = 0;
};

// singleton, there should only be one of these in the system
class OpenGL : public BaseRenderer {
public:
    bool initialize();
    OpenGLWindowHandle *createWindow(std::string title, Rect *position, unsigned int flags);
    // need texture/sprite functions (for elements that are going to be used across windows)
    // maybe take in opengl_window_handle*, nullptr meaning all
    // properties
    const unsigned int indices[6] = {
        0, 1, 2,
        0, 2, 3
    };
    GLFWcursor* cursorHand;
    GLFWcursor* cursorArrow;
    GLFWcursor* cursorIbeam;
};

void pointToViewport(float&, float&, size_t, size_t);
void distanceToViewport(float&, float&, size_t, size_t);

#endif

repo_name: despair/netrunner

license: mit


code: #include "renderer.h"


code:
#ifndef RENDERER_H
#define RENDERER_H

#include <memory> // for unique_ptr
#include <vector>
#include <string>
#include <functional>

#ifdef FLOATCOORDS
typedef double coordinates;
typedef double sizes;
#else
typedef short coordinates;
typedef unsigned short sizes;
#endif

struct textureMap {
    // was GLfloat
    float map[4];
};

typedef struct{
    coordinates x, y;
    sizes w, h;
} Rect;

class Sprite {
};

class WindowHandle {
public:
    virtual void clear() { }
    virtual void swapBuffers() { }
    // can we const texture?
    virtual Sprite* createSprite(unsigned char *texture, int w, int h) { return nullptr; }
    virtual Sprite* createTextSprite(unsigned char *texture, int w, int h, textureMap &textureMap) { return nullptr; }
    virtual Sprite* createSpriteFromColor(const unsigned int hexColor) { return nullptr; }
    virtual void drawSpriteBox(Sprite *texture, Rect *position) {}
    virtual void drawSpriteText(Sprite *texture, unsigned int hexColor, Rect *position) {}
    //
    size_t width;
    size_t height;
    // window functions
    std::function<void(int w, int h)> onResize = nullptr;
    // mouse functions
    std::function<void(int x, int y)> onMouseDown = nullptr;
    std::function<void(int x, int y)> onMouseUp = nullptr;
    std::function<void(int x, int y)> onMouseMove = nullptr;
    std::function<void(int x, int y)> onWheel = nullptr;
    // keyboard functions
    std::function<void(int key, int scancode, int mods)> onKeyUp = nullptr;
    std::function<void(int key, int scancode, int mods)> onKeyRepeat = nullptr;
    std::function<void(int key, int scancode, int mods)> onKeyDown = nullptr;
    std::function<void(unsigned int codepoint)> onKeyPress = nullptr;
};

// maybe convert to interface?
class BaseRenderer {
public:
    virtual bool initialize() { return true; }
    virtual WindowHandle *createWindow(std::string title, Rect *position, unsigned int flags) { return nullptr; }
};

#endif


code:
#include <ctime>
#include <iostream>
#include <sys/stat.h>
#include <string.h>

#include "app/browser/Browser.h"
#include "environment/Environment.h"
#include "interfaces/components/TabbedComponent.h"
#include "interfaces/components/InputComponent.h"
#include "interfaces/graphical/renderers/glfw/opengl.h"
#include "parsers/images/netpbm/pnm.h"
#include "platform/tlsf.h"
#include "tools/CFGFileParser.h"
#include "tools/CommandLineParams.h"
#include "tools/Log.h"
#include "tools/URL.h"
#include "tools/WebResource.h"

#if defined(_WIN32) && !defined(_WIN64)
#define PLATFORM "i686-pc-winnt"
#endif
#ifdef _WIN64
#define PLATFORM "amd64-pc-winnt"
#endif

// global
// to remove this
// window uses this to make windows and get window count (can be just be passed in when creating a window)
// AElement uses it to getActiveDocumentComponent and navTo on that
//
std::unique_ptr<Browser> browser = nullptr;
std::unique_ptr<BaseRenderer> renderer = nullptr;

// forward declaration
bool isAbsolutePath(const std::string s);
bool fileExists(const std::string s);

bool isAbsolutePath(const std::string s) {
    return (s.length() > 0 && s[0] == '/');
}

bool fileExists(const std::string s) {
    struct stat buf;
    return stat(s.c_str(), &buf) != -1;
}

extern TextRasterizerCache *rasterizerCache;

#include <iostream>
#include <fstream>

std::ofstream assignfile;
std::ofstream execfile;

int main(int argc, char *argv[]) {
    // show help msg when "--help" appears
    if (argc > 1) {
        // has to be set up for logging before first logging call
        initCLParams(argc, argv);
        if (strcmp(argv[1], "--help")==0) {
            std::cout << "./netrunner [http://host.tld/|/path/to/file.html] [-log <error|warning|notice|info|debug>]" << std::endl;
            return 1;
        }
    }

    std::ofstream myfile;
    assignfile.open ("js_assignments.txt");
    execfile.open ("js_execution.txt");

    std::cout \
    << "#     #                 ######" << std::endl \
    << "##    #  ######   ##### #     #  #    #  #    #  #    #  ######  #####" << std::endl \
    << "# #   #  #          #   #     #  #    #  ##   #  ##   #  #       #    #" << std::endl \
    << "#  #  #  #####      #   ######   #    #  # #  #  # #  #  #####   #    #" << std::endl \
    << "#   # #  #          #   #   #    #    #  #  # #  #  # #  #       #####" << std::endl \
    << "#    ##  #          #   #    #   #    #  #   ##  #   ##  #       #   #" << std::endl \
    << "#     #  ######     #   #     #   ####   #    #  #    #  ######  #    #" << std::endl;

#if defined(VERSION) && defined(PLATFORM)
    std::cout << "/g/ntr - NetRunner build " << __DATE__ << ": rev-" << VERSION << " for " << PLATFORM << std::endl;
#else
    std::cout << "/g/ntr - NetRunner build " << __DATE__ << ": internal-dev non-Makefile build" << std::endl;
#endif

    Environment::init();
    CFGFileParser *parser = new CFGFileParser("res/netrunner.cfg");
    BrowserConfiguration *config = new BrowserConfiguration();
    if (!parser) {
        std::cout << "no parser!" << std::endl;
    }
    if (parser->ParseText()){
        parser->WriteConfig(*config);
    }
    delete parser;

    bool jsConsole = false;
    std::cout << "Global Settings contains, in no particular order:\n";
    for ( auto it = config->Settings.begin(); it != config->Settings.end(); ++it ){
        std::cout << it->first << ":" << it->second << std::endl;
        if (it->first == "CONSOLE" && it->second == "TRUE") {
            jsConsole = true;
        }
    }
    std::cout << std::endl;

    renderer = std::make_unique<OpenGL>();

	//Environment::init();

    renderer->initialize();

    /*
    Rect pos;
    pos.x=0;
    pos.y=0;
    pos.w=1024;
    pos.h=640;
    OpenGLWindowHandle *win = renderer.createWindow("NTR", &pos, 0);
    if (!win) {
        std::cout << "Couldn't create window" << std::endl;
        return 0;
    }

    OpenGLTexture *blue = win->createSpriteFromColor(0x0000FFFF);
    if (!blue) {
        std::cout << "Couldn't create blue" << std::endl;
        return 0;
    }
    Rect dPos = { 0, 0, 512, 320 };
     */

    /*
    const std::shared_ptr<TextRasterizer> textRasterizer = rasterizerCache->loadFont(12, false);
    rasterizationRequest request;
    request.text = "Hello World";
    request.startX = 512;
    request.availableWidth = 1024;
    request.maxTextureSize = 16384;
    request.noWrap = true;
    //std::cout << "rasterizing [" << text << "] @" << rawX << " availableWidth: " << availableWidth << " sourceStartX: " << rasterStartX << " noWrap: " << noWrap << std::endl;
    std::shared_ptr<rasterizationResponse> response = textRasterizer->rasterize(request);

    textureMap textureMap;
    textureMap.map[0] = response->s0;
    textureMap.map[1] = response->t0;
    textureMap.map[2] = response->s1;
    textureMap.map[3] = response->t1;

    OpenGLTexture *text = win->createTextSprite(response->textureData.get(), response->textureWidth, response->textureHeight, textureMap);
    Rect dPos3 = { 512, 320, 512, 320};
     */

    /*
    RGBAPNMObject *anime = readPPM("kon32_661.pam");
    if (!anime) {
        std::cout << "Couldn't load image" << std::endl;
        return 0;
    }
     opengl_texture_handle *red = win->createSprite(anime->m_Ptr, anime->width, anime->height);
     Rect dPos2 = { 512, 320, 512, 320};
    */

    /*
    win->clear();
    win->drawSpriteBox(blue, &dPos);
    win->drawSpriteText(text, 0x000000FF, &dPos3);
    //win->drawSpriteBox(red, &dPos2);
    win->swapBuffers();

    while(1) {
        glfwWaitEvents(); // block until something changes
    }

    return 0;
    */

    // we need to set up OGL before we can setDOM (because component can't be constructed (currently) without OGL)
    // but should be after CommandLineParams incase we need to change some type of window config
    browser = std::make_unique<Browser>();
    browser->addWindow();
    if (!browser->windows.front().get()->window) {
        std::cout << "main() - unable to add a window" << std::endl;
        return 1;
    }
    if (jsConsole) {
        std::cout << "turning on JS console" << std::endl;
        browser->addJSDebuggerWindow();
    }

    //std::cout << "argc " << argc << std::endl;
    if (argc > 1) {
        // this isn't going to work
        std::string rawUrl = getCLParamByIndex(1);
        if (rawUrl != "-log") {
            // if we do this here, shouldn't we do this in parseUri too?
            if (rawUrl.find("://") == rawUrl.npos) {
                // Path should always be absolute for file://
                if (isAbsolutePath(rawUrl)) {
                    rawUrl = "file://" + rawUrl;
                } else {
                    auto absolutePath = std::string(getenv("PWD")) + '/' + rawUrl;
                    if (fileExists(absolutePath)) {
                        rawUrl = "file://" + absolutePath;
                    } else {
                        // Default to http if the file wasn't found
                        rawUrl = "http://" + rawUrl;
                    }
                }
            }
            //logDebug() << "pre URL parse [" << url << "]" << std::endl;
            //window->currentURL = URL(rawUrl);
            logDebug() << "loading [" << rawUrl << "]" << std::endl;
            TabbedComponent *tabComponent = dynamic_cast<TabbedComponent*>(browser->windows.front().get()->tabComponent.get());
            if (tabComponent) {
                tabComponent->addTab("Start Tab, Loading...");
                tabComponent->selectTab(tabComponent->tabs.front());
                // render the loading label, before we block for loading
                browser->render();
            }
            /*
            if (!setWindowContent(window->currentURL)) {
                return 1;
            }
            */
            std::shared_ptr<DocumentComponent> docComponent = browser->getActiveDocumentComponent();
            if (docComponent) {
                // now tell it to navigate somewhere
                docComponent->navTo(rawUrl);
            }
        } else {
            // be nice if we could put http:// in the address bar
        }
    }

    browser->loop();
    return 0;
}


code:
#ifndef HTTPCOMMON_H
#define HTTPCOMMON_H
enum class Version {
    HTTP10,
    HTTP11
};

enum class Method {
    GET,
    POST
};
#endif


code:
#include "HTTPRequest.h"
#include <errno.h>
#include <iostream>
#include <string.h>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <winsock2.h>
#include <windows.h>
#include <WS2tcpip.h>
#include <wspiapi.h> // Windows 2000, and a IPv4 only fallback if Trumpet Winsock isn't installed on NT 4.0
#define ssize_t intptr_t
#else
// unix includes here
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif

#ifdef WIN32
// Initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif

HTTPRequest::HTTPRequest(const std::shared_ptr<URL> u) {
#ifdef WIN32
	if (iResult != 0) {
		std::cout << "WSAStartup failed: " << iResult << std::endl;
		return;
	}
#endif
    uri = u;
    version = Version::HTTP10;
    method = Method::GET;
    userAgent = "NetRunner";
}

bool HTTPRequest::sendRequest(std::function<void(const HTTPResponse&)> responseCallback, std::unique_ptr<std::string> ptrPostBody) const {
    struct addrinfo hints;
    struct addrinfo *serverInfo = nullptr;
    std::string host = uri->host;
    std::string document = uri->path;
    if (uri->query != "") {
        document += "?" + uri->query;
    }
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    const int res = getaddrinfo(uri->host.c_str(), std::to_string(uri->port).c_str(), &hints, &serverInfo);
    if (res != 0) {
        std::cout << "Could not lookup " << host << ": " << res << std::endl;
        freeaddrinfo(serverInfo);
        return false;
    }

    const int sock = socket(serverInfo->ai_family, serverInfo->ai_socktype, serverInfo->ai_protocol);
    if (sock == -1) {
        std::cout << "Could not create socket: " << errno << std::endl;
        freeaddrinfo(serverInfo);
        return false;
    }

    if (connect(sock, serverInfo->ai_addr, serverInfo->ai_addrlen) == -1) {
        std::cout << "Could not connect to: " << host << ":" << errno << std::endl;
        freeaddrinfo(serverInfo);
        return false;
    }
    std::string postBody = "";
    if (ptrPostBody) {
        // The moral of the story is, if you have binary (non-alphanumeric) data (or a significantly sized payload) to transmit, use multipart/form-data
        std::string fixedPostBody(*ptrPostBody);
        auto search = fixedPostBody.find(" ");
        if (search != std::string::npos) {
            fixedPostBody.replace(search, 1, "+");
        }
        // close userAgent
        postBody = "\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " + std::to_string(fixedPostBody.size())+ "\r\n\r\n" + fixedPostBody;
    }

    const std::string request = methodToString(method) + std::string(" ") + document + std::string(" ") + versionToString(version) + std::string("\r\nHost: ") + host + std::string("\r\nUser-Agent: ") + userAgent + postBody + std::string("\r\n\r\n");
    std::cout << "HTTP Request: " << request << std::endl;
    const ssize_t sent = send(sock, request.c_str(), request.length(), 0);
    if (sent == -1) {
        std::cout << "Could not send \"" << request << "\": " << errno << std::endl;
        freeaddrinfo(serverInfo);
        return false;
    }

    std::string response;
    char buffer[512];
    ssize_t received;
    while ((received = recv(sock, buffer, sizeof(buffer), 0)) != 0) {
        response += std::string(buffer, static_cast<unsigned int>(received));
    }

    responseCallback(HTTPResponse(response));

    freeaddrinfo(serverInfo);
    return true;
}

const std::string HTTPRequest::versionToString(const Version ver) const {
    switch (ver) {
        case Version::HTTP10:
            return "HTTP/1.0";
        case Version::HTTP11:
            return "HTTP/1.1";
        default:
            return "ERROR";
    }
}

const std::string HTTPRequest::methodToString(const Method meth) const {
    switch (meth) {
        case Method::GET:
            return "GET";
        case Method::POST:
            return "POST";
        default:
            return "ERROR";
    }
}


code:
#ifndef HTTPREQUEST_H
#define HTTPREQUEST_H

#include "HTTPCommon.h"
#include "HTTPResponse.h"
#include "../tools/URL.h"
#include <functional>
#include <string>

class HTTPRequest {
public:
    HTTPRequest(const std::shared_ptr<URL> u);
    bool sendRequest(std::function<void(const HTTPResponse&)> responseCallback, std::unique_ptr<std::string> ptrPostBody) const;
    const std::string versionToString(const Version version) const;
    const std::string methodToString(const Method method) const;
    Method method;
    Version version;
private:
    std::string userAgent;
    std::shared_ptr<URL> uri;
};

#endif


code:
#include "HTTPResponse.h"
#include <iostream>

HTTPResponse::HTTPResponse(const std::string &rawResponse) {
    int state = 0;
    unsigned int cursor = 0;
    unsigned int start = 0;
    std::string propertyKey;
    for (cursor = 0; cursor < rawResponse.length(); cursor++) {
        if (state % 2 == 0 && rawResponse[cursor] == ' ') {
            if (state == 0) {
                version = rawResponse.substr(0, cursor - start);
            }
            else {
                propertyKey = rawResponse.substr(start, cursor - start - 1);
            }
            start = cursor + 1;
            state++;
        }
        else if (state % 2 == 1 && rawResponse[cursor] == '\r') {
            if (state == 1) {
                status = rawResponse.substr(start, cursor - start);
            }
            else {
                properties.insert(std::pair<std::string, std::string>(propertyKey, rawResponse.substr(start, cursor - start)));
            }
            start = cursor + 2; // start after new line
            state++;
        }
        else if (state % 2 == 0 && rawResponse[cursor] == '\r') {
            cursor += 2; // skip over the rest of the new lines
            break;
        }
    }
    body = rawResponse.substr(cursor, rawResponse.length() - cursor - 1);
    //std::cout << "Body is [" << body << "]" << std::endl;
    statusCode = 0;
    if (status != "") { // if timeout?
        statusCode = stoi(status);
    }
    std::cout << "HTTPResponse::HTTPResponse - Status is " << status << std::endl;
}


code:
#ifndef HTTPRESPONSE_H
#define HTTPRESPONSE_H

#include <map>
#include <string>

class HTTPResponse {
public:
    HTTPResponse(const std::string &rawRequest);
    std::string version;
    std::string status;
    std::map<std::string, std::string> properties;
    std::string body;
    int statusCode;
private:
};

#endif


code:
// ©2008-2017 despair <despair@netrunner.cc>
#include "HTTPSRequest.h"
#include <errno.h>
#include <iostream>
#include <string.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <wincrypt.h>
#else
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#endif

// PolarSSL internal state
mbedtls_net_context server_fd;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;

HTTPSRequest::HTTPSRequest(const std::shared_ptr<URL> u) {
    if (!initTLS()){
        printf("failed to start TLS!");
        return;
    }
    uri = u;
    version = Version::HTTP10;
    method = Method::GET;
    userAgent = "NetRunner/0.1 PolarSSL/2.5.1";
}

bool HTTPSRequest::sendRequest(std::function<void(const HTTPResponse&)> responseCallback, std::unique_ptr<std::string> ptrPostBody) const {
    std::string response;
    std::string document = uri->path;
    if (uri->query != "") {
        document += "?" + uri->query;
    }
    std::string host = uri->host;
    std::string port = std::to_string(uri->port);

    char buffer[512];
    int ret;
    unsigned flags;

    if(mbedtls_net_connect(&server_fd, host.c_str(),port.c_str(), MBEDTLS_NET_PROTO_TCP) != 0 ) {
        std::cout << "HTTPS Request: cant connect to " << host << ":" << port << std::endl;
        return false;
    }

    if (mbedtls_ssl_config_defaults(&conf,MBEDTLS_SSL_IS_CLIENT,MBEDTLS_SSL_TRANSPORT_STREAM,MBEDTLS_SSL_PRESET_DEFAULT) != 0) {
        std::cout << "HTTPS Request: cant config" << std::endl;
        return false;
    }

    mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
    mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
    mbedtls_ssl_conf_ca_chain( &conf, &cacert, nullptr );

    if( mbedtls_ssl_setup( &ssl, &conf ) != 0 ) {
        std::cout << "HTTPS Request: cant setup" << std::endl;
        return false;
    }
    if(mbedtls_ssl_set_hostname( &ssl, uri->host.c_str() ) != 0 ) {
        std::cout << "HTTPS Request: cant hostname" << std::endl;
        return false;
    }

    mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, nullptr );

    int state = mbedtls_ssl_handshake( &ssl );

    while(state != 0){
        if( state != MBEDTLS_ERR_SSL_WANT_READ && state != MBEDTLS_ERR_SSL_WANT_WRITE ) {
            printf( " failed\n  ! mbedtls_ssl_handshake returned -0x%x\n\n", -state );
            return false;
        }
    }

    if( ( flags = mbedtls_ssl_get_verify_result( &ssl ) ) != 0 ) {
        printf("Invalid server cert!");
        return false;
    }
    std::string postBody = "";
    if (ptrPostBody) {
        // The moral of the story is, if you have binary (non-alphanumeric) data (or a significantly sized payload) to transmit, use multipart/form-data
        std::string fixedPostBody(*ptrPostBody);
        auto search = fixedPostBody.find(" ");
        if (search != std::string::npos) {
            fixedPostBody.replace(search, 1, "+");
        }
        // close userAgent
        postBody = "\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " + std::to_string(fixedPostBody.size())+ "\r\n\r\n" + fixedPostBody;
    }

    const std::string request = methodToString(method) + std::string(" ") + document + std::string(" ") + versionToString(version) + std::string("\r\nHost: ") + host + std::string("\r\nUser-Agent: ") + userAgent + postBody + std::string("\r\n\r\n");
    std::cout << "HTTPS Request: " << request << std::endl;

    while( ( state = mbedtls_ssl_write( &ssl, reinterpret_cast<const unsigned char*>(request.c_str()), request.length() ) ) <= 0 ){
        if( state != MBEDTLS_ERR_SSL_WANT_READ && state != MBEDTLS_ERR_SSL_WANT_WRITE ){
            printf( " failed\n  ! mbedtls_ssl_write returned %d\n\n", state );
            return false;
        }
    }

    do{
        ret = mbedtls_ssl_read( &ssl, reinterpret_cast<unsigned char *>(buffer), 512 );
        if (ret <= 0){
            break;
        }
        else{
            response += std::string(buffer, static_cast<unsigned int>(ret));
        }
    }
    while( ret != 0 );

    // clean up after the request
    mbedtls_ssl_close_notify( &ssl );
    responseCallback(HTTPResponse(response));
    mbedtls_net_free( &server_fd );
    mbedtls_x509_crt_free( &cacert );
    mbedtls_ssl_free( &ssl );
    mbedtls_ssl_config_free( &conf );
    mbedtls_ctr_drbg_free( &ctr_drbg );
    mbedtls_entropy_free( &entropy );
    return true;
}

const std::string HTTPSRequest::versionToString(const Version ver) const {
    switch (ver) {
        case Version::HTTP10:
            return "HTTP/1.0";
        case Version::HTTP11:
            return "HTTP/1.1";
        default:
            return "ERROR";
    }
}

const std::string HTTPSRequest::methodToString(const Method meth) const {
    switch (meth) {
        case Method::GET:
            return "GET";
        case Method::POST:
            return "POST";
        default:
            return "ERROR";
    }
}

bool HTTPSRequest::initTLS(){
    mbedtls_net_init( &server_fd );
    mbedtls_ssl_init( &ssl );
    mbedtls_ssl_config_init( &conf );
    mbedtls_x509_crt_init( &cacert );
    mbedtls_ctr_drbg_init( &ctr_drbg );

#ifndef FIXED_SEED
    char seed[64];
#endif

#if defined(_WIN32) && !defined(FIXED_SEED)
    /* On Windows NT 4.0 or later, use CryptoAPI to grab 64 bytes of random data */
    HCRYPTPROV hprovider = 0;
    CryptAcquireContext(&hprovider, NULL, NULL, PROV_RSA_FULL,CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
    CryptGenRandom(hprovider, 64, (BYTE*)&seed);
    CryptReleaseContext(hprovider, 0);
#else
#if !defined(_WIN32) && !defined(FIXED_SEED)
    int fd;
    fd = open("/dev/urandom", O_RDONLY);
    if (fd == -1)
        return false;
    if (try_read(fd, seed, 64) != 0) {
        if (try_close(fd) != 0)
            return false;
        return false;
    }

    if (try_close(fd) != 0)
        return false;

    seed[63] = 0;
#endif
#endif
    // only define FIXED_SEED if yer platform does NOT provide a source of (extra) randomness!!!
#ifdef FIXED_SEED
    const char *seed = "!@netrunner_ssl_seed$%?rvx86_despair##^^%$#@";
#endif
	mbedtls_entropy_init( &entropy );
    if(mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, reinterpret_cast<const unsigned char*>(seed), strlen(seed) ) != 0 ){
        return false;
    }

    int ret = mbedtls_x509_crt_parse_file( &cacert, "ca-bundle.crt");
    if( ret < 0 ){
        printf( " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", -ret );
        return false;
    }
    return true;
}

/* Random seed generation, non-Windows */
#if !defined(_WIN32) && !defined(FIXED_SEED)
static int try_close(int fd){
    int ret;
    for (;;) {
        errno = 0;
        ret = close(fd);
        if (ret == -1 && errno == EINTR)
            continue;
        break;
    }
    return ret;
}

static int try_read(int fd, char *out, size_t count){
    size_t total;
    ssize_t partial;

    total = 0;
    while (total < count){
        for (;;) {
            errno = 0;
            partial = read(fd, out + total, count - total);
            if (partial == -1 && errno == EINTR)
                continue;
            break;
        }

        if (partial < 1)
            return -1;

        total += partial;
    }

    return 0;
}
#endif


code:
#ifndef HTTPSREQUEST_H
#define HTTPSREQUEST_H

#include "HTTPCommon.h"
#include "HTTPResponse.h"
#include "../tools/URL.h"
#include <functional>
#include <string>
#ifdef NULL
#undef NULL
#define NULL nullptr
#endif

// PolarSSL
#include <mbedtls/ssl.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/error.h>
#include <mbedtls/certs.h>

#ifndef _WIN32
static int try_close(int fd);
static int try_read(int fd, char *out, size_t count);
#endif

// FIXME: needs to extend HTTPRequest
class HTTPSRequest {
public:
    HTTPSRequest(const std::shared_ptr<URL> u);
    bool sendRequest(std::function<void(const HTTPResponse&)> responseCallback, std::unique_ptr<std::string> ptrPostBody) const;
    const std::string versionToString(const Version version) const;
    const std::string methodToString(const Method method) const;
    bool initTLS();
    // has to be public, otherwise how are we going to change it
    Method method;
    Version version;
private:
    std::string userAgent;
    std::shared_ptr<URL> uri;
};

#endif


code:
#include "pnm.h"
#include <string>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <map>
#ifdef _WIN32
#include <io.h>
#include <windows.h>
#include <fcntl.h>
#endif

#include "../../../environment/Environment.h"

// pnm
// The PNM format is just an abstraction of the PBM, PGM, and PPM formats. I.e. the name "PNM" refers collectively to PBM, PGM, and PPM.
// pam has the advanced header

RGBAPNMObject * readPPM(const char* fileName) {
    RGBAPNMObject *data=new RGBAPNMObject;
    // open the file to read just the header reading
    FILE* fr = fopen((Environment::getResourceDir() + "/" + fileName).c_str(), "rb");
    if (!fr) {
        std::cout << "Can't open " << fileName << std::endl;
        return nullptr;
    }

    // formatted read of header
    char fileType[11];
    int res=0;
    res = fscanf(fr, "%9s", fileType);
    data->magicNum=fileType;

    //std::cout << "fileType:" << fileType << std::endl;

    unsigned char bits = 0;
    bool pamType = false;
    std::map<std::string, std::string> pamHeader;

    // check to see if it's a PPM image file
    if (strncmp(fileType, "P4" , 2) == 0) {
        bits = 1; // PBM
    } else if (strncmp(fileType, "P5" , 2) == 0) {
        bits = 8; // PGM
    } else if (strncmp(fileType, "P6" , 2) == 0) {
        bits = 24; // PPM
    } else if (strncmp(fileType, "P7" , 2) == 0) {
        pamType = true;
        bool headerDone = false;
        char cLine[80];
        char *read;
        while(!headerDone) {
            //read = getline(&cLine, &len, fr);
            read = fgets(cLine, 80, fr);
            //res = fscanf(fr, "%s\n", cLine);
            std::string line(cLine);
            line.erase(line.find_last_not_of(" \t\n\r\f\v") + 1);
            //std::cout << "read " << line << std::endl;
            size_t spacePos = line.find(" ");
            std::string key(line.substr(0, spacePos));
            std::string val(line.substr(spacePos + 1));
            //std::cout << "read [" << key << "]=[" << val << "]" << std::endl;
            pamHeader[key]=val;
            if (read == NULL) headerDone = true;
            if (line == "ENDHDR") headerDone = true;
        }
        bits = std::stoi(pamHeader["DEPTH"]) * 8; // 4 * 8 = 32
        if (pamHeader["TUPLTYPE"] != "RGB_ALPHA") {
            std::cout << "Unsupported TUPLTYPE: " << pamHeader["TUPLTYPE"] << std::endl;
            return nullptr;
        }
        //
    } else if (strncmp(fileType, "P8" , 2) == 0) {
        bits = 32; // PPM
    }
    //std::cout << "bits:" << bits << std::endl;

    // read the rest of header
    unsigned int width, height;
    if (pamType) {
        width = static_cast<unsigned int>(std::stoi(pamHeader["WIDTH"]));
        height = static_cast<unsigned int>(std::stoi(pamHeader["HEIGHT"]));
    } else {
        res = fscanf(fr, "%u\n %u\n", &width, &height);
    }
    data->width = width;
    data->height = height;

    // read maximum
    data->maxColVal = 255; // just set a default
    if (bits != 1) {
        unsigned int maximum;
        if (pamType) {
            maximum = static_cast<unsigned int>(std::stoi(pamHeader["MAXVAL"]));
        } else {
            res = fscanf(fr, "%u\n", &maximum);
        }
        data->maxColVal = maximum;
    }
    unsigned int size = width * height;
    if (bits != 1) {
        size *= bits/8;
    }
    std::cout << "read " << fileName << " pnm/pam " << width << "," << height << "@" << static_cast<int>(bits) << "(" << bits/8 << ")" << "/" << data->maxColVal << std::endl;

    // allocate array for pixels
    unsigned char* pixels = static_cast<unsigned char*>(tlsf_malloc(size)); // used to be: new char[size];
    //unsigned char* pixels = reinterpret_cast<unsigned char*>(tlsf_calloc(size, sizeof(unsigned char))); // used to be: new char[size];

    // unformatted read of binary pixel data
    res = fread(pixels, 1, size,fr);
    data->m_Ptr = pixels;

    // close file
    fclose(fr);

    // return the array
    return data;
} // end of readPPM

void writePBM4(const char *filename, const RGBAPNMObject &data) {
  FILE *fp = fopen(filename, "wb"); /* b - binary mode */
  fprintf(fp, "P6\n%d %d\n255\n", data.width, data.height);
  for (unsigned int j = 0; j < data.height; ++j) {
    for (unsigned int i = 0; i < data.width; ++i) {
      static unsigned char color[1];
      unsigned int pos = ((i * 4) + (j * 4 * 1024));
      //color[0] = data.m_Ptr[pos + 0];  /* red */
      //color[1] = data.m_Ptr[pos + 1];  /* green */
      //color[2] = data.m_Ptr[pos + 2];  /* blue */
      color[0] = data.m_Ptr[pos + 3];  /* alpha */
      fwrite(color, 1, 1, fp);
    }
  }
  fclose(fp);
}

void writePGM5(const char *filename, const RGBAPNMObject &data) {
  FILE *fp = fopen(filename, "wb"); /* b - binary mode */
  fprintf(fp, "P5\n%d %d\n255\n", data.width, data.height);
  for (unsigned int j = 0; j < data.height; ++j) {
    for (unsigned int i = 0; i < data.width; ++i) {
      static unsigned char color[1];
      unsigned int pos = ((i * 4) + (j * 4 * 1024));
      color[0] = data.m_Ptr[pos + 0];  /* red */
      //color[1] = data.m_Ptr[pos + 1];  /* green */
      //color[2] = data.m_Ptr[pos + 2];  /* blue */
      //color[3] = data.m_Ptr[pos + 3];  /* alpha */
      fwrite(color, 1, 1, fp);
    }
  }
  fclose(fp);
}

void writePPM6(const char *filename, const RGBAPNMObject &data) {
  FILE *fp = fopen(filename, "wb"); /* b - binary mode */
  fprintf(fp, "P6\n%d %d\n255\n", data.width, data.height);
  for (unsigned int j = 0; j < data.height; ++j) {
    for (unsigned int i = 0; i < data.width; ++i) {
      static unsigned char color[3];
      unsigned int pos = ((i * 4) + (j * 4 * 1024));
      color[0] = data.m_Ptr[pos + 0];  /* red */
      color[1] = data.m_Ptr[pos + 1];  /* green */
      color[2] = data.m_Ptr[pos + 2];  /* blue */
      //color[3] = data.m_Ptr[pos + 3];  /* alpha */
      fwrite(color, 1, 3, fp);
    }
  }
  fclose(fp);
}

void writePPM8(const char *filename, const RGBAPNMObject &data) {
  FILE *fp = fopen(filename, "wb"); /* b - binary mode */
  fprintf(fp, "P8\n%d %d\n255\n", data.width, data.height);
  for (unsigned int j = 0; j < data.height; ++j) {
    for (unsigned int i = 0; i < data.width; ++i) {
      static unsigned char color[4];
      unsigned int pos = ((i * 4) + (j * 4 * 1024));
      color[0] = data.m_Ptr[pos + 0];  /* red */
      color[1] = data.m_Ptr[pos + 1];  /* green */
      color[2] = data.m_Ptr[pos + 2];  /* blue */
      color[3] = data.m_Ptr[pos + 3];  /* alpha */
      fwrite(color, 1, 4, fp);
    }
  }
  fclose(fp);
}


code:
#ifndef PNMPARSER_H
#define PNMPARSER_H

#include <string>
#include "../../../platform/tlsf.h"

// this structure expects RGBA
struct RGBAPNMObject {
  std::string magicNum;
  unsigned int width, height, maxColVal;
  unsigned char * m_Ptr;

  // fast allocation!
  static void* operator new(size_t n){
    void *mem = tlsf_malloc(n);
    if (mem){
        return mem;
    }
    throw std::bad_alloc {};
  }
  static void operator delete(void *p){
    tlsf_free(p);
  }
};

RGBAPNMObject * readPPM(const char* fileName);
void writePBM4(const char *filename, const RGBAPNMObject &data);
void writePGM5(const char *filename, const RGBAPNMObject &data);
void writePPM6(const char *filename, const RGBAPNMObject &data);
void writePPM8(const char *filename, const RGBAPNMObject &data);

#endif


code:
#include "tga.h"
#include <string>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <map>

#include "../../../environment/Environment.h"
#include "../../../platform/tlsf.h"

// tga

BitMapObject *LoadTGAFile(const char *filename) {
    BitMapObject *tgaFile = new BitMapObject;
    FILE *filePtr;
    unsigned char ucharBad;
    short int sintBad;
    long imageSize;
    int colorMode;
    unsigned char colorSwap;
    size_t res;

    // Open the TGA file.
    filePtr = fopen(filename, "rb");
    if (filePtr == NULL) {
        return nullptr;
    }

    // Read the two first bytes we don't need.
    res = fread(&ucharBad, sizeof(unsigned char), 1, filePtr);
    res = fread(&ucharBad, sizeof(unsigned char), 1, filePtr);

    // Which type of image gets stored in imageTypeCode.
    unsigned char imageTypeCode;
    res = fread(&imageTypeCode, sizeof(unsigned char), 1, filePtr);

    // For our purposes, the type code should be 2 (uncompressed RGBA image)
    // or 3 (uncompressed black-and-white images).
    if (imageTypeCode != 2 && imageTypeCode != 3) {
        fclose(filePtr);
        return nullptr;
    }

    // Read 13 bytes of data we don't need.
    res = fread(&sintBad, sizeof(short int), 1, filePtr);
    res = fread(&sintBad, sizeof(short int), 1, filePtr);
    res = fread(&ucharBad, sizeof(unsigned char), 1, filePtr);
    res = fread(&sintBad, sizeof(short int), 1, filePtr);
    res = fread(&sintBad, sizeof(short int), 1, filePtr);

    // Read the image's width and height.
    short int imageWidth;
    short int imageHeight;
    res = fread(&imageWidth, sizeof(short int), 1, filePtr);
    res = fread(&imageHeight, sizeof(short int), 1, filePtr);
    tgaFile->width = static_cast<size_t>(imageWidth);
    tgaFile->height = static_cast<size_t>(imageHeight);

    // Read the bit depth.
    unsigned char bitCount;
    res = fread(&bitCount, sizeof(unsigned char), 1, filePtr);

    // Read one byte of data we don't need.
    res = fread(&ucharBad, sizeof(unsigned char), 1, filePtr);

    // Color mode -> 3 = BGR, 4 = BGRA.
    colorMode = bitCount / 8;
    imageSize = static_cast<long int>(tgaFile->width * tgaFile->height * static_cast<long unsigned int>(colorMode & 32));

    // Allocate memory for the image data.
    tgaFile->imageData = static_cast<unsigned char*>(tlsf_malloc(sizeof(unsigned char) * static_cast<long unsigned int>(imageSize)));

    // Read the image data.
    res = fread(tgaFile->imageData, sizeof(unsigned char), static_cast<long unsigned int>(imageSize), filePtr);

    // Change from BGR to RGB so OpenGL can read the image data.
    for (int imageIdx = 0; imageIdx < imageSize; imageIdx += colorMode) {
        colorSwap = tgaFile->imageData[imageIdx];
        tgaFile->imageData[imageIdx] = tgaFile->imageData[imageIdx + 2];
        tgaFile->imageData[imageIdx + 2] = colorSwap;
    }

    fclose(filePtr);
    return tgaFile;
}


code:
#ifndef TGAPARSER_H
#define TGAPARSER_H

#include <string>
#include "../../../platform/tlsf.h"

struct TGAObject {
    unsigned char imageTypeCode;
    short int imageWidth;
    short int imageHeight;
    unsigned char bitCount;
    unsigned char *imageData;
};

// we'll force RGBA for now
struct BitMapObject {
    std::string filename;
    size_t width, height;
    unsigned char *imageData;

    // fast allocation!
    static void* operator new(size_t n){
        void *mem = tlsf_malloc(n);
        if (mem){
            return mem;
        }
        throw std::bad_alloc {};
    }
    static void operator delete(void *p){
        tlsf_free(p);
    }
};

BitMapObject *LoadTGAFile(const char *filename);

#endif


code:
#include "Node.h"
#include "TagNode.h"

Node::Node(NodeType type) {
    nodeType = type;
}

Node::~Node() {
}

std::vector<std::string> Node::getSourceList() {
    std::vector<std::string> returnVec;

    for (std::shared_ptr<Node>& child : children) {
        auto childSrcs = child->getSourceList();
        returnVec.insert(returnVec.end(),
                         childSrcs.begin(),
                         childSrcs.end());
    }

    return returnVec;
}

std::shared_ptr<Node> Node::findTagNodeParent(std::string tag, std::shared_ptr<Node> node) {
    if (!node.get()) {
        // found root?
        return nullptr;
    }
    TagNode *tagNode = dynamic_cast<TagNode*>(node.get());
    if (tagNode) {
        if (tagNode->tag == tag) {
            return node;
        }
    }
    return Node::findTagNodeParent(tag, node->parent);
}


code:
#ifndef NODE_H
#define NODE_H

#include "../../interfaces/components/Component.h"
#include <memory>
#include <vector>
#include <functional>
#include <string>
#include <sstream>
#include <iostream>

enum class NodeType {
    ROOT,
    TAG,
    TEXT
};

class Node {
public:
    Node(NodeType type);
    virtual ~Node();
    NodeType nodeType;
    std::shared_ptr<Node> parent;
    std::vector<std::shared_ptr<Node>> children;
    std::shared_ptr<Component> component;

    static std::shared_ptr<Node> findTagNodeParent(std::string tag, std::shared_ptr<Node> node);
    virtual std::vector<std::string> getSourceList();
};

#endif


code:
#include "TagNode.h"

TagNode::TagNode() : Node(NodeType::TAG) {
}

// iterator down and extract any src attributes
std::vector<std::string> TagNode::getSourceList() {
    std::vector<std::string> returnVec;

    auto propIter = properties.find("src");
    if (propIter != properties.end()) {
        returnVec.push_back(propIter->second);
    }

    for (std::shared_ptr<Node>& child : children) {
        auto childSrcs = child->getSourceList();
        returnVec.insert(returnVec.end(),
                         childSrcs.begin(),
                         childSrcs.end());
    }

    return returnVec;
}

std::unique_ptr<std::pair<std::string, std::string>> TagNode::getTagNodeNameValue() {
    auto namePropIter = this->properties.find("name");
    if (namePropIter == this->properties.end()) {
        return nullptr;
    }
    auto valuePropIter = this->properties.find("value");
    if (valuePropIter == this->properties.end()) {
        return nullptr;
    }
    return std::make_unique<std::pair<std::string, std::string>>(namePropIter->second, valuePropIter->second);
}


code:
#ifndef TAGNODE_H
#define TAGNODE_H

#include "Node.h"
#include <map>

class TagNode : public Node {
public:
    TagNode();
    std::string tag;
    std::map<std::string, std::string> properties;

    std::vector<std::string> getSourceList() override;
    std::unique_ptr<std::pair<std::string, std::string>> getTagNodeNameValue();
};

#endif


code:
#include "TextNode.h"

TextNode::TextNode() : Node(NodeType::TEXT) {
}


code:
#ifndef TEXTNODE_H
#define TEXTNODE_H

#include "Node.h"

class TextNode : public Node {
public:
    TextNode();
    std::string text;

    std::vector<std::string> getSourceList() override { return {}; };
};

#endif


code:
#include "HTMLParser.h"
#include "../TextNode.h"
#include <algorithm>
#include <iostream>
#include <memory>

// ok=ul, not ok=li
void autoCloseTag(std::shared_ptr<Node> currentNode, std::shared_ptr<Node> rootNode, std::string ok, std::string notok) {
    // are we inside an ul? li?
    // recurse up to parent
    std::shared_ptr<Node> it = currentNode;
    //std::cout << "scanning li for unclosed lis" << std::endl;
    while(it != rootNode) {
        if (it->nodeType == NodeType::TAG) {
            TagNode *pTagNode = dynamic_cast<TagNode*>(it.get());
            if (pTagNode) {
                // tag node
                //std::cout << "scanning: " << pTagNode->tag << std::endl;
                if (pTagNode->tag == ok) {
                    // we're ok, we found UL first
                    it = rootNode; // mark done
                    break;
                }
                if (pTagNode->tag == notok) {
                    // we're not ok, we found UL first
                    //std::cout << "need to close previous LI tag" << std::endl;

                    // set our parent to be our sibling LI's parent

                    // well currentNode is us
                    if (currentNode && pTagNode->parent) {
                        // we need to remove from children
                        for(std::vector<std::shared_ptr<Node>>::iterator it2 = currentNode->parent->children.begin(); it2!=currentNode->parent->children.end(); ++it2) {
                            if (it2->get() == currentNode.get()) {
                                //std::cout << "found us in children" << std::endl;
                                it2 = currentNode->parent->children.erase(it2);
                                break;
                            }
                        }
                        // move node under new parent
                        currentNode->parent = pTagNode->parent;
                        pTagNode->parent->children.push_back(currentNode);
                    } else {
                        std::cout << "HTMLParser::Parse - currentNode or pTagNode->parent - close previous " << notok << " tag" << std::endl;
                    }

                    it = rootNode; // mark done
                    break;
                }
            }
        }
        // recurse up
        it = it->parent;
    }
    //std::cout << "scanned li for unclosed lis" << std::endl;
}

void printNode(const std::shared_ptr<Node> node, const int indent) {
    for (int i = 0; i < indent; i++) {
        std::cout << '\t';
    }

    if (node->nodeType == NodeType::ROOT) {
        std::cout << "ROOT\n" << std::endl;
    }
    else if (node->nodeType == NodeType::TAG) {
        std::cout << "TAG: " << dynamic_cast<TagNode*>(node.get())->tag << std::endl;
        for (const std::pair<std::string, std::string> property : dynamic_cast<TagNode*>(node.get())->properties) {
            for (int i = 0; i < indent; i++) {
                std::cout << '\t';
            }
            std::cout << "  " << property.first << ": " << property.second << std::endl;
        }
    }
    else if (node->nodeType == NodeType::TEXT) {
        std::cout << "TEXT: " << dynamic_cast<TextNode*>(node.get())->text << std::endl;
    }

    for (std::shared_ptr<Node> child : node->children) {
        printNode(child, indent + 1);
    }
}

std::shared_ptr<Node> HTMLParser::parse(const std::string &html) const {
    std::shared_ptr<Node> rootNode = std::make_shared<Node>(NodeType::ROOT);
    std::shared_ptr<Node> currentNode = rootNode;
    std::shared_ptr<Node> startTagLevel = rootNode;
    std::vector<unsigned int> starts;
    unsigned int cursor;
    int state = 0;
    int prependWhiteSpace = false;
    for (cursor = 0; cursor < html.length(); cursor++) { // TODO handle trying to look ahead past string length
        if (state == 0) { // Outside tag
            if (html[cursor] == ' ' || html[cursor] == '\t' || html[cursor] == '\r' || html[cursor] == '\n') {
                prependWhiteSpace = true;
                continue;
            }
            else if (html[cursor] == '<') {
                // HTML comments
                if (html[cursor + 1] == '!' && html[cursor + 2] == '-'  && html[cursor + 3] == '-' ) {
                    //std::cout << "HTMLParser::Parse - starting HTML comment at " << cursor << std::endl;
                    cursor += 2; // advance cursor to end of comment start
                    state = 4;
                }
                // close tag
                else if (html[cursor + 1] == '/') {
                    // start closing tag
                    //std::cout << "HTMLParser::Parse - starting closing tag at " << html.substr(cursor, 7)  << std::endl;
                    if (currentNode && currentNode->parent) {
                      // we should snap to the level we started at (as we maybe a couple levels deep

                      // but it's the matching part of this tag
                      currentNode = currentNode->parent;
                    } else {
                      std::cout << "HTMLParser::Parse - currentNode/parent is null - close tag" << std::endl;
                    }
                    state = 1; // ignore closing tags
                }
                // these have never have a closing tag
                else if (
                    (html[cursor + 1] == 'h' && html[cursor + 2] == 'r') ||
                    (html[cursor + 1] == 'b' && html[cursor + 2] == 'r') ||
                    (html[cursor + 1] == 'w' && html[cursor + 2] == 'b' && html[cursor + 3] == 'r') ||
                    (html[cursor + 1] == 'i' && html[cursor + 2] == 'm' && html[cursor + 3] == 'g') ||
                    (html[cursor + 1] == 'l' && html[cursor + 2] == 'i' && html[cursor + 3] == 'n' && html[cursor + 4] == 'k') ||
                    (html[cursor + 1] == 'm' && html[cursor + 2] == 'e' && html[cursor + 3] == 't' && html[cursor + 4] == 'a') ||
                    (html[cursor + 1] == 'i' && html[cursor + 2] == 'n' && html[cursor + 3] == 'p' && html[cursor + 4] == 'u' && html[cursor + 5] == 't')
                    ) {
                    //std::cout << "HTMLParser::Parse - Starting single tag " << html.substr(cursor, 6)  << std::endl;
                    std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
                    if (currentNode) {
                        currentNode->children.push_back(tagNode);
                        tagNode->parent = currentNode;
                    } else {
                        std::cout << "HTMLParser::Parse - currentNode is null - tagNode" << std::endl;
                    }
                    currentNode = tagNode;
                    size_t closeTagPos = html.substr(cursor + 1).find(">");
                    //std::cout << "found closeTagPos at " << closeTagPos << std::endl;
                    if (closeTagPos == std::string::npos) {
                        std::cout << "HTMLParser::Parse - can't find closing tag for single tag" << std::endl;
                        cursor ++;
                    } else {
                        std::string element = html.substr(cursor, closeTagPos + 2);
                        //std::cout << "HTMLParser::Parse - creating element, tag: " << element << std::endl;
                        parseTag(element, *dynamic_cast<TagNode*>(currentNode.get()));
                        cursor += 2 + closeTagPos;
                    }

                    // drop back
                    if (currentNode && currentNode->parent) {
                        currentNode = currentNode->parent;
                    } else {
                        std::cout << "HTMLParser::Parse - currentNode/parent is null - textNode state3" << std::endl;
                    }

                    prependWhiteSpace = false;
                    state = 0;
                }
                // start tag (<bob> <bob part)
                else {
                    //std::cout << "HTMLParser::Parse - start oc tag " << html.substr(cursor, 6) << std::endl;
                    std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
                    if (currentNode) {
                      currentNode->children.push_back(tagNode);
                      tagNode->parent = currentNode;
                    } else {
                      std::cout << "HTMLParser::Parse - currentNode is null - tagNode" << std::endl;
                    }
                    currentNode = tagNode;
                    starts.push_back(cursor);
                    state = 2;
                }
            }
            else { // start text node
                //std::cout << "HTMLParser::Parse - start text node " << html.substr(cursor, 6) << std::endl;
                std::shared_ptr<TextNode> textNode = std::make_shared<TextNode>();
                // not sure why currentNode is null but it is
                if (currentNode) {
                  currentNode->children.push_back(textNode);
                  textNode->parent = currentNode;
                } else {
                  std::cout << "HTMLParser::Parse - currentNode is null - textNode" << std::endl;
                }
                currentNode = textNode;
                starts.push_back(cursor);
                state = 3;
            }
            cursor--;
        }
        else if (state == 1) { // Skip Over Element (used by closing tag)
            if (html[cursor] == '>') {
                //std::cout << "HTMLParser::parse - close tag: " << html.substr(starts.back(), cursor - starts.back() + 1) << std::endl;
                state = 0;
                prependWhiteSpace = false;
            }
        }
        else if (state == 4) { // HTML Comment
            if (html[cursor] == '-' && html[cursor + 1] == '-' && html[cursor + 2] == '>') {
                //std::cout << "HTMLParser::Parse - Found end HTML comment at " << html.substr(cursor, 6) << std::endl;
                state = 0;
                cursor += 2; // advance cursor to end of comment
                prependWhiteSpace = false;
            }
        }
        else if (state == 2) { // Search for end tag node
            if (html[cursor] == '>') { // end tag node
                std::string element = html.substr(starts.back(), cursor - starts.back() + 1);
                //std::cout << "HTMLParser::parse - end open tag: " << element << std::endl;
                if (element == "
") {
                    // this will close previous li before starting a new one
                    autoCloseTag(currentNode, rootNode, "ul", "li");
                    //std::cout << "scanned parents for unclosed lis" << std::endl;
                } else
                if (element == "<option>") { // FIXME: options have attributes
                    // this will close previous option before starting a new one
                    autoCloseTag(currentNode, rootNode, "select", "option");
                    //std::cout << "scanned parents for unclosed options" << std::endl;
                }
                starts.pop_back();
                parseTag(element, *dynamic_cast<TagNode*>(currentNode.get()));
                state = 0;
                prependWhiteSpace = false;
            }
        }
        else if (state == 3) { // End text node
            if (html[cursor + 1] == '<') {
                // find next space
                std::string left = html.substr(cursor);
                size_t end = std::min(left.find(" "), left.find(">"));
                if (end != std::string::npos) {
                    if (end > 14) {
                        //std::cout << "Tag Distance [" << end << "] [" << html.substr(cursor, end) << "]\n";
                        continue;
                    }
                }
                dynamic_cast<TextNode*>(currentNode.get())->text = (prependWhiteSpace?" ":"") + html.substr(starts.back(), cursor - starts.back() + 1);
                //std::cout << "HTMLParser::parse - end text node: " << html.substr(starts.back(), cursor - starts.back() + 1) << std::endl;
                starts.pop_back();
                if (currentNode && currentNode->parent) {
                  currentNode = currentNode->parent;
                } else {
                  std::cout << "HTMLParser::Parse - currentNode/parent is null - textNode state3" << std::endl;
                }
                state = 0;
                prependWhiteSpace = false;
            }
        }
    }

    //printNode(rootNode, 0);
    return rootNode;
}

void HTMLParser::parseTag(const std::string &element, TagNode &tagNode) const {
    //std::cout << "HTMLParser::parseTag - element [" << element << "]" << std::endl;
    unsigned int cursor;
    unsigned int start = 1; // skip first <
    int state = 0;
    std::string propertyKey;
    for (cursor = 0; cursor < element.length();  cursor++) {
        if (state == 0) {
            // space or end
            if (element[cursor] == ' ' || element[cursor] == '>') {
                // set our tag (type / name, i.e. h1)
                tagNode.tag = element.substr(start, cursor - start);
                // make sure our tag is lowercase
                std::transform(tagNode.tag.begin(), tagNode.tag.end(), tagNode.tag.begin(), tolower);
                start = cursor + 1;
                state = 1;
            }
        }
        else if (state == 1) { // attribute search
            if (element[cursor] == ' ') {
                start = cursor + 1;
            }
            else if (element[cursor] == '=') {
                propertyKey = element.substr(start, cursor - start);
                start = cursor + 1; // start for non quotes
                state = 2;
            }
        }
        else if (state == 2) { // after = of attribute
            if (element[cursor] == '"') {
                start = cursor + 1;
                state = 3;
            }
            else if (element[cursor] == '\'') {
                start = cursor + 1;
                state = 4;
            } else if (element[cursor] == ' ') {
                // we just probably found an end of attribute without quotes
                tagNode.properties.insert(std::pair<std::string, std::string>(propertyKey, element.substr(start, cursor - start)));
                start = cursor + 1;
                state = 1;
            }
        }
        else if (state == 3) {
            if (element[cursor] == '"') {
                // was suggested to use tagNode.properties[propertyKey] = element.substr(start, cursor - start);
                // for better readabiilty
                tagNode.properties.insert(std::pair<std::string, std::string>(propertyKey, element.substr(start, cursor - start)));
                start = cursor + 1;
                state = 1;
            }
        }
        else if (state == 4) {
            if (element[cursor] == '\'') {
                tagNode.properties.insert(std::pair<std::string, std::string>(propertyKey, element.substr(start, cursor - start)));
                start = cursor + 1;
                state = 1;
            }
        }
    }
    // 2 is attribute without quotes, 3/4 is unclosed quote
    if (state == 2 || state == 3 || state ==4) {
        // we were in an atrr=
        tagNode.properties.insert(std::pair<std::string, std::string>(propertyKey, element.substr(start, cursor - start - 1)));
    } else {
        if (state != 1) {
            // so what's ending on state 0 about (somethin about no atttributes and maybe no tag name/type)
            std::cout << "HTMLParser::parseTag ending on state " << state << std::endl;
        }
    }
}


code:
#ifndef HTMLPARSER_H
#define HTMLPARSER_H

#include "../Node.h"
#include "../TagNode.h"
#include <string>

void autoCloseTag(std::shared_ptr<Node> currentNode, std::shared_ptr<Node> rootNode, std::string ok, std::string notok);
void printNode(const std::shared_ptr<Node> node, const int indent);

class HTMLParser {
public:
    std::shared_ptr<Node> parse(const std::string &html) const;
    void parseTag(const std::string &element, TagNode &tagNode) const;
};

#endif


code:
#include "NTRMLParser.h"
#include "../TextNode.h"
#include <algorithm>
#include <iostream>
#include <memory>

std::shared_ptr<Node> NTRMLParser::parse(const std::string &ntrml) const {
    std::shared_ptr<Node> rootNode = std::make_shared<Node>(NodeType::ROOT);
    std::shared_ptr<Node> currentNode = rootNode;
    std::shared_ptr<Node> startTagLevel = rootNode;
    std::vector<unsigned int> starts;
    unsigned int cursor;
    int state = 0;
    int prependWhiteSpace = false;
    for (cursor = 0; cursor < ntrml.length(); cursor++) { // TODO handle trying to look ahead past string
        if (state == 0) { // Outside tag
            if (ntrml[cursor] == ' ' || ntrml[cursor] == '\t' || ntrml[cursor] == '\r' || ntrml[cursor] == '\n') {
                prependWhiteSpace = true;
                continue;
            }
            else if (ntrml[cursor] == '<') {
                // HTML style comments
                if (ntrml[cursor + 1] == '!' && ntrml[cursor + 2] == '-'  && ntrml[cursor + 3] == '-' ) {
                    //std::cout << "NTRMLParser::Parse - starting HTML comment at " << cursor << std::endl;
                    cursor += 3; // advance cursor to end of comment start
                    state = 4;
                }
                // close tag
                else if (ntrml[cursor + 1] == '/') {
                    // start closing tag
                    //std::cout << "NTRMLParser::Parse - starting closing tag at " << ntrml.substr(cursor, 7)  << std::endl;
                    if (currentNode && currentNode->parent) {
                      // we should snap to the level we started at (as we maybe a couple levels deep

                      // but it's the matching part of this tag
                      currentNode = currentNode->parent;
                    } else {
                      std::cout << "NTRMLParser::Parse - currentNode/parent is null - close tag" << std::endl;
                    }
                    state = 1; // ignore closing tags
                }
                // these have never have a closing tag
                else if (
                    /*(ntrml[cursor + 1] == 'h' && ntrml[cursor + 2] == 'r') ||
                    (ntrml[cursor + 1] == 'b' && ntrml[cursor + 2] == 'r') ||
                    (ntrml[cu rsor + 1] == 'w' && ntrml[cursor + 2] == 'b' && ntrml[cursor + 3] == 'r') || */
                    (ntrml[cursor + 1] == 'i' && ntrml[cursor + 2] == 'm' && ntrml[cursor + 3] == 'g') ||
                    /* (ntrml[cursor + 1] == 'l' && ntrml[cursor + 2] == 'i' && ntrml[cursor + 3] == 'n' && ntrml[cursor + 4] == 'k') ||
                    (ntrml[cursor + 1] == 'm' && ntrml[cursor + 2] == 'e' && ntrml[cursor + 3] == 't' && ntrml[cursor + 4] == 'a') || */
                    (ntrml[cursor + 1] == 'i' && ntrml[cursor + 2] == 'n' && ntrml[cursor + 3] == 'p' && ntrml[cursor + 4] == 'u' && ntrml[cursor + 5] == 't')
                    ) {
                    //std::cout << "NTRMLParser::Parse - Starting single tag " << ntrml.substr(cursor, 6)  << std::endl;
                    std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
                    if (currentNode) {
                        currentNode->children.push_back(tagNode);
                        tagNode->parent = currentNode;
                    } else {
                        std::cout << "NTRMLParser::Parse - currentNode is null - tagNode" << std::endl;
                    }
                    currentNode = tagNode;
                    size_t closeTagPos = ntrml.substr(cursor + 1).find(">");
                    //std::cout << "found closeTagPos at " << closeTagPos << std::endl;
                    if (closeTagPos == std::string::npos) {
                        std::cout << "NTRMLParser::Parse - can't find closing tag for single tag" << std::endl;
                        cursor ++;
                    } else {
                        std::string element = ntrml.substr(cursor, closeTagPos + 2);
                        //std::cout << "NTRMLParser::Parse - creating element, tag: " << element << std::endl;
                        parseTag(element, *dynamic_cast<TagNode*>(currentNode.get()));
                        cursor += 2 + closeTagPos;
                    }

                    // drop back
                    if (currentNode && currentNode->parent) {
                        currentNode = currentNode->parent;
                    } else {
                        std::cout << "NTRMLParser::Parse - currentNode/parent is null - textNode state3" << std::endl;
                    }

                    prependWhiteSpace = false;
                    state = 0;
                }
                // start tag (<bob> <bob part)
                else {
                    //std::cout << "NTRMLParser::Parse - start oc tag " << ntrml.substr(cursor, 6) << std::endl;
                    std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
                    if (currentNode) {
                      currentNode->children.push_back(tagNode);
                      tagNode->parent = currentNode;
                    } else {
                      std::cout << "NTRMLParser::Parse - currentNode is null - tagNode" << std::endl;
                    }
                    currentNode = tagNode;
                    starts.push_back(cursor);
                    state = 2;
                }
            }
            else { // start text node
                //std::cout << "NTRMLParser::Parse - start text node " << ntrml.substr(cursor, 6) << std::endl;
                std::shared_ptr<TextNode> textNode = std::make_shared<TextNode>();
                // not sure why currentNode is null but it is
                if (currentNode) {
                  currentNode->children.push_back(textNode);
                  textNode->parent = currentNode;
                } else {
                  std::cout << "NTRMLParser::Parse - currentNode is null - textNode" << std::endl;
                }
                currentNode = textNode;
                starts.push_back(cursor);
                state = 3;
            }
            cursor--;
        }
        else if (state == 1) { // Skip Over Element (used by closing tag)
            if (ntrml[cursor] == '>') {
                //std::cout << "NTRMLParser::parse - close tag: " << ntrml.substr(starts.back(), cursor - starts.back() + 1) << std::endl;
                state = 0;
                prependWhiteSpace = false;
            }
        }
        else if (state == 4) { // HTML style Comment
            if (ntrml[cursor] == '-' && ntrml[cursor + 1] == '-' && ntrml[cursor + 2] == '>') {
                //std::cout << "NTRMLParser::Parse - Found end NTRML comment at " << ntrml.substr(cursor, 6) << std::endl;
                state = 0;
                cursor += 2; // advance cursor to end of comment
                prependWhiteSpace = false;
            }
        }
        else if (state == 2) { // Search for end tag node
            if (ntrml[cursor] == '>') { // end tag node
                std::string element = ntrml.substr(starts.back(), cursor - starts.back() + 1);
                //std::cout << "NTRMLParser::parse - end open tag: " << element << std::endl;
                /*
                if (element == "
") {
                    // this will close previous li before starting a new one
                    autoCloseTag(currentNode, rootNode, "ul", "li");
                    //std::cout << "scanned parents for unclosed lis" << std::endl;
                } else
                if (element == "<option>") { // FIXME: options have attributes
                    // this will close previous option before starting a new one
                    autoCloseTag(currentNode, rootNode, "select", "option");
                    //std::cout << "scanned parents for unclosed options" << std::endl;
                }
                */
                starts.pop_back();
                parseTag(element, *dynamic_cast<TagNode*>(currentNode.get()));
                state = 0;
                prependWhiteSpace = false;
            }
        }
        else if (state == 3) { // End text node
            if (ntrml[cursor + 1] == '<') {
                dynamic_cast<TextNode*>(currentNode.get())->text = (prependWhiteSpace?" ":"") + ntrml.substr(starts.back(), cursor - starts.back() + 1);
                //std::cout << "NTRMLParser::parse - end text node: " << ntrml.substr(starts.back(), cursor - starts.back() + 1) << std::endl;
                starts.pop_back();
                if (currentNode && currentNode->parent) {
                  currentNode = currentNode->parent;
                } else {
                  std::cout << "NTRMLParser::Parse - currentNode/parent is null - textNode state3" << std::endl;
                }
                state = 0;
                prependWhiteSpace = false;
            }
        }
    }

    //printNode(rootNode, 0);
    return rootNode;
}


code:
#ifndef NTRMLPARSER_H
#define NTRMLPARSER_H

#include "../html/HTMLParser.h"

// our parseTag function is similar enough
class NTRMLParser : public HTMLParser {
public:
    std::shared_ptr<Node> parse(const std::string &ntrml) const;
};

#endif


code:
#include "BrowserJS.h"

std::vector<std::string> getConstructs() {
    std::vector<std::string> constructs;
    constructs.push_back("document.addEventListener");
    constructs.push_back("document.querySelector");
    return constructs;
}

bool isConstruct(std::string construct) {
    std::vector<std::string> constructs = getConstructs();
    std::vector<std::string>::iterator it = std::find(constructs.begin(), constructs.end(), construct);
    std::cout << "isConstruct [" << construct << "](" << ((it != constructs.end())?"true":"false") << ")\n";
    return it != constructs.end();
}

js_internal_storage *executeConstruct(std::string functionName, std::string params, js_function &scope) {
    std::vector<std::string> constructs = getConstructs();
    std::vector<std::string>::iterator it = std::find(constructs.begin(), constructs.end(), functionName);
    if (it == constructs.end()) {
      return nullptr;
    }
    std::cout << "executeConstruct [" << functionName << "](" << params << ")\n";
    if (functionName == "document.querySelector") {
        return jsConstruct_querySelector(params, scope);
    }
    return nullptr;
}

js_internal_storage *jsConstruct_querySelector(std::string params, js_function &scope) {
    js_bool *jb = new js_bool;
    jb->value = false;
    return jb;
}


code:
#ifndef BROWSERJS_H
#define BROWSERJS_H

#include "JSParser.h"
#include "../../../interfaces/components/DocumentComponent.h"
#include "../../../interfaces/graphical/renderers/glfw/Window.h"

#include <vector>

std::vector<std::string> getConstructs();
bool isConstruct(std::string construct);
js_internal_storage *executeConstruct(std::string functionName, std::string params, js_function &scope);
js_internal_storage *jsConstruct_querySelector(std::string params, js_function &scope);

class BrowserJavaScript : public JavaScript {
public:
    BrowserJavaScript() {
        this->setUpRoot();
        // we can modify rootScope...
    }
    DocumentComponent *document;
    Window *window;
};

#endif