<commit_before>/*
 * Copyright 2010-2012 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "WindowImp.h"

#include <new>
#include <iostream>
#include <boost/version.hpp>
#include <boost/bind.hpp>

#include "BeforeUnloadEventImp.h"
#include "DOMImplementationImp.h"
#include "DocumentImp.h"
#include "KeyboardEventImp.h"
#include "MouseEventImp.h"
#include "NodeImp.h"
#include "css/BoxImage.h"
#include "css/Ico.h"
#include "css/ViewCSSImp.h"
#include "html/HTMLIFrameElementImp.h"
#include "html/HTMLLinkElementImp.h"
#include "html/HTMLScriptElementImp.h"
#include "http/HTTPConnection.h"

#include "Test.util.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

WindowImp::Parser::Parser(DocumentImp* document, int fd, const std::string& optionalEncoding) :
    stream(fd, boost::iostreams::never_close_handle),   // TODO: never_close_handle?
    htmlInputStream(stream, optionalEncoding),
    tokenizer(&htmlInputStream),
    parser(document, &tokenizer)
{
    stream.seekg(0, std::ios::beg);
}

WindowImp::WindowImp(WindowImp* parent, ElementImp* frameElement) :
    request(parent ? parent->getLocation().getHref() : u""),
    history(this),
    backgroundTask(this),
    thread(std::ref(backgroundTask)),
    window(0),
    view(0),
    viewFlags(0),
    parent(parent),
    frameElement(frameElement),
    parser(0),
    clickTarget(0),
    detail(0),
    buttons(0),
    scrollWidth(0),
    scrollHeight(0),
    width(816),     // US letter size, 96 DPI
    height(1056),
    redisplay(false),
    zoomable(true),
    zoom(1.0f),
    faviconOverridable(false),
    windowDepth(0)
{
    if (parent) {
        parent->childWindows.push_back(this);
        windowDepth = parent->windowDepth + 1;
    }
}

WindowImp::~WindowImp()
{
    if (parent) {
        for (auto i = parent->childWindows.begin(); i != parent->childWindows.end(); ++i) {
            if (*i == this) {
                parent->childWindows.erase(i);
                break;
            }
        }
    }
    backgroundTask.abort();
    thread.join();
}

void WindowImp::setSize(unsigned w, unsigned h)
{
    if (width != w || height != h) {
        width = w;
        height = h;
        setFlags(Box::NEED_REFLOW);
    }
}

void WindowImp::setFlags(unsigned f)
{
    if (view) {
        view->setFlags(f | viewFlags);
        viewFlags = 0;
    } else
        viewFlags |= f;
}

DocumentWindowPtr WindowImp::activate()
{
    if (window) {
        window->activate(this);
        return window;
    }
    return 0;
}

void WindowImp::enableZoom(bool value)
{
    zoomable = value;
}

float WindowImp::getZoom() const
{
    return zoom;
}

void WindowImp::setZoom(float value)
{
    if (zoomable) {
        zoom = value;
        if (view) {
            view->setZoom(zoom);
            redisplay = true;
        }
    }
}

void WindowImp::updateView(ViewCSSImp* next)
{
    if (!next || view == next || !window || !window->getDocument())
        return;

    unsigned flags = 0;
    if (view) {
        flags |= view->gatherFlags();
        delete view;
    }
    view = next;
    if (viewFlags)
        setFlags(flags | viewFlags);
    view->setZoom(zoom);
    detail = 0;
    redisplay = true;

    if (!view->getTree()) {
        // cf. http://test.csswg.org/suites/css2.1/20110323/html4/root-box-003.htm
        canvas.shutdown();
        canvas.setup(width, height);
        canvas.beginRender(view->getBackgroundColor());
        canvas.endRender();
    }

    if (!parent) {
        std::u16string title = view->getDocument().getTitle();
        setWindowTitle(utfconv(title).c_str());
    }
}

void WindowImp::setDocumentWindow(const DocumentWindowPtr& window)
{
    this->window = window;
    delete view;
    view = 0;
    viewFlags = 0;
    if (window)
        backgroundTask.restart(BackgroundTask::Cascade);
    detail = 0;
    redisplay = true;
    setFavicon();
}

bool WindowImp::isBindingDocumentWindow() const
{
    if (!parent)
        return false;
    DocumentImp* document = dynamic_cast<DocumentImp*>(parent->getDocument().self());
    return document->isBindingDocumentWindow(this);
}

bool WindowImp::poll()
{
    if (!window)
        return false;
    DocumentImp* document = dynamic_cast<DocumentImp*>(window->getDocument().self());

    // Update the canvas before processing events.
    if (request.getReadyState() == HttpRequest::DONE && document && backgroundTask.getState() == BackgroundTask::Done) {
        ViewCSSImp* next = backgroundTask.getView();
        updateView(next);
        if (view && (view->gatherFlags() & Box::NEED_REPAINT)) {
            redisplay = true;
            render(0);
        }
    }

    while (backgroundTask.getState() == BackgroundTask::Done && !eventQueue.empty()) {
        const EventTask task = eventQueue.front();
        switch (task.type) {
        case EventTask::MouseDown:
        case EventTask::MouseUp:
            mouse(task);
            break;
        case EventTask::MouseMove:
            mouseMove(task);
            break;
        case EventTask::KeyDown:
            keydown(task);
            break;
        case EventTask::KeyUp:
            keyup(task);
            break;
        default:
            break;
        }
        eventQueue.pop_front();
    }

    for (auto i = childWindows.begin(); i != childWindows.end(); ++i) {
        WindowImp* child = *i;
        if (child->poll()) {
            redisplay |= true;
            if (view) {
                if (document && document->isBindingDocumentWindow(child))
                    view->setFlags(Box::NEED_SELECTOR_REMATCHING);
                else
                    view->setFlags(Box::NEED_REPAINT);
            }
        }
    }

    switch (request.getReadyState())
    {
    case HttpRequest::UNSENT:
        break;
    case HttpRequest::OPENED:
    case HttpRequest::HEADERS_RECEIVED:
    case HttpRequest::LOADING:
        break;
    case HttpRequest::DONE:
        if (!document) {
            recordTime("%*shttp request done", windowDepth * 2, "");
            // TODO: Check header
            Document newDocument = getDOMImplementation()->createDocument(u"", u"", 0);
            if (document = dynamic_cast<DocumentImp*>(newDocument.self())) {
                // TODO: Fire a simple unload event.
                window->setDocument(newDocument);
                document->setDefaultView(this);
                document->setURL(request.getRequestMessage().getURL());
                if (!request.getError())
                    history.update(window);
                else
                    document->setError(request.getError());
                parser = new(std::nothrow) Parser(document, request.getContentDescriptor(), request.getResponseMessage().getContentCharset());
                if (!parser)
                    break;  // TODO: error handling
            } else
                break;  // TODO: error handling
        }
        if (document->getReadyState() == u"loading") {
            // TODO: Note white it would be nice to parse the HTML docucment in
            // the background task, firstly we need to check if we can run JS
            // in the background.
            activate();

            HTMLScriptElementImp* script = document->getPendingParsingBlockingScript();
            if (script) {
                if (!script->isReadyToBeParserExecuted())
                    break;
                script->execute();
                document->setPendingParsingBlockingScript(0);
            }

            // TODO: run this in the background
            Token token;
            do {
                token = parser->getToken();
                parser->processToken(token);
            } while (token.getType() != Token::Type::EndOfFile && !document->getPendingParsingBlockingScript());
            if (document->getPendingParsingBlockingScript())
                break;
            document->setCharset(utfconv(parser->getEncoding()));

            // TODO: Check if the parser has been aborted.
            NodeImp::evalTree(document);
            document->resetStyleSheets();
            recordTime("%*shtml parsed", windowDepth * 2, "");
            if (4 <= getLogLevel())
                dumpTree(std::cerr, document);
        }
        switch (backgroundTask.getState()) {
        case BackgroundTask::Cascaded:
            HTMLElementImp::xblEnteredDocument(document);
            backgroundTask.wakeUp(BackgroundTask::Layout);
            break;
        case BackgroundTask::Init:
        case BackgroundTask::Done: {
            ViewCSSImp* next = backgroundTask.getView();
            updateView(next);
            if (document->getReadyState() == u"interactive") {
                // TODO: Check if the parser has been aborted.

                // Run from the step 3. of 'stops parsing'.
                // cf. http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-end

                // Process scripts that will execute when the document has finished parsing (i.e., defer).
                // TODO: Check there's no style sheet that is blocking scripts.
                if (document->processDeferScripts()) {
                    if (!document->hasContentLoaded()) {
                        if (events::Event event = new(std::nothrow) EventImp) {
                            event.initEvent(u"DOMContentLoaded", true, false);
                            document->dispatchEvent(event);
                        }
                        document->decrementLoadEventDelayCount();
                        document->setContentLoaded();

                        backgroundTask.restart(BackgroundTask::Cascade);
                    }
                }
            }
            if (document->getReadyState() == u"complete") {
            }
            if (view) {
                if (unsigned flags = view->gatherFlags()) {
                    if (flags & Box::NEED_SELECTOR_REMATCHING) {
                        recordTime("%*strigger selector rematching", windowDepth * 2, "");
                        backgroundTask.restart(BackgroundTask::Cascade);
                        view = 0;
                    } else if (flags & Box::NEED_SELECTOR_MATCHING) {
                        recordTime("%*strigger restyling", windowDepth * 2, "");
                        backgroundTask.wakeUp(BackgroundTask::Cascade);
                        view = 0;
                    } else if (flags & (Box::NEED_STYLE_RECALCULATION | Box::NEED_EXPANSION | Box::NEED_CHILD_REFLOW | Box::NEED_REFLOW)) {
                        recordTime("%*strigger reflow", windowDepth * 2, "");
                        backgroundTask.wakeUp(BackgroundTask::Layout);
                        view = 0;
                    } else if (flags & Box::NEED_REPAINT)
                        redisplay = true;
                }
            }
            break;
        }
        default:
            break;
        }
        break;
    default:
        break;
    }
    bool result = redisplay;
    redisplay = false;
    if (!result && view && view->hasExpired(getTick())) {
        view->setFlags(Box::NEED_REPAINT);
        result = true;
    }
    if (result)
        recordTime("%*strigger repaint", windowDepth * 2, "");
    return result;
}

void WindowImp::render(ViewCSSImp* parentView)
{
    recordTime("%*srepaint begin: %s (%s)", windowDepth * 2, "", utfconv(window->getDocument().getReadyState()).c_str(), view ? "render" : "canvas");
    if (view) {
        if (view->gatherFlags() & Box::NEED_REPAINT) {
            view->clearFlags(Box::NEED_REPAINT);
            canvas.shutdown();
            canvas.setup(width, height);
            canvas.beginRender(view->getBackgroundColor());
            view->render(parentView ? parentView->getClipCount() : 0);
            scrollWidth = view->getScrollWidth();
            scrollHeight = view->getScrollHeight();
            canvas.endRender();
        }
        if (2 <= getLogLevel() && backgroundTask.getState() == BackgroundTask::Done && !view->gatherFlags()) {
            std::cout << "\n## " << window->getDocument().getReadyState() << '\n';
            view->dump();
            std::cout << "##\n";
            std::cout.flush();
        }
    }
    canvas.render(width, height);
    recordTime("%*srepaint end", windowDepth * 2, "");
}

void WindowImp::mouse(int button, int up, int x, int y, int modifiers)
{
    eventQueue.emplace_back(up ? EventTask::MouseUp : EventTask::MouseDown, modifiers, x, y, button);
}

void WindowImp::mouseMove(int x, int y, int modifiers)
{
    if (!eventQueue.empty()) {
        EventTask& back = eventQueue.back();
        if (back.type == EventTask::MouseMove) {
            back.x = x;
            back.y = y;<commit_msg>(WindowImp::render) : Dump window depth at log level 2; note this is for harness to always check the top level window<commit_after>/*
 * Copyright 2010-2012 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "WindowImp.h"

#include <new>
#include <iostream>
#include <boost/version.hpp>
#include <boost/bind.hpp>

#include "BeforeUnloadEventImp.h"
#include "DOMImplementationImp.h"
#include "DocumentImp.h"
#include "KeyboardEventImp.h"
#include "MouseEventImp.h"
#include "NodeImp.h"
#include "css/BoxImage.h"
#include "css/Ico.h"
#include "css/ViewCSSImp.h"
#include "html/HTMLIFrameElementImp.h"
#include "html/HTMLLinkElementImp.h"
#include "html/HTMLScriptElementImp.h"
#include "http/HTTPConnection.h"

#include "Test.util.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

WindowImp::Parser::Parser(DocumentImp* document, int fd, const std::string& optionalEncoding) :
    stream(fd, boost::iostreams::never_close_handle),   // TODO: never_close_handle?
    htmlInputStream(stream, optionalEncoding),
    tokenizer(&htmlInputStream),
    parser(document, &tokenizer)
{
    stream.seekg(0, std::ios::beg);
}

WindowImp::WindowImp(WindowImp* parent, ElementImp* frameElement) :
    request(parent ? parent->getLocation().getHref() : u""),
    history(this),
    backgroundTask(this),
    thread(std::ref(backgroundTask)),
    window(0),
    view(0),
    viewFlags(0),
    parent(parent),
    frameElement(frameElement),
    parser(0),
    clickTarget(0),
    detail(0),
    buttons(0),
    scrollWidth(0),
    scrollHeight(0),
    width(816),     // US letter size, 96 DPI
    height(1056),
    redisplay(false),
    zoomable(true),
    zoom(1.0f),
    faviconOverridable(false),
    windowDepth(0)
{
    if (parent) {
        parent->childWindows.push_back(this);
        windowDepth = parent->windowDepth + 1;
    }
}

WindowImp::~WindowImp()
{
    if (parent) {
        for (auto i = parent->childWindows.begin(); i != parent->childWindows.end(); ++i) {
            if (*i == this) {
                parent->childWindows.erase(i);
                break;
            }
        }
    }
    backgroundTask.abort();
    thread.join();
}

void WindowImp::setSize(unsigned w, unsigned h)
{
    if (width != w || height != h) {
        width = w;
        height = h;
        setFlags(Box::NEED_REFLOW);
    }
}

void WindowImp::setFlags(unsigned f)
{
    if (view) {
        view->setFlags(f | viewFlags);
        viewFlags = 0;
    } else
        viewFlags |= f;
}

DocumentWindowPtr WindowImp::activate()
{
    if (window) {
        window->activate(this);
        return window;
    }
    return 0;
}

void WindowImp::enableZoom(bool value)
{
    zoomable = value;
}

float WindowImp::getZoom() const
{
    return zoom;
}

void WindowImp::setZoom(float value)
{
    if (zoomable) {
        zoom = value;
        if (view) {
            view->setZoom(zoom);
            redisplay = true;
        }
    }
}

void WindowImp::updateView(ViewCSSImp* next)
{
    if (!next || view == next || !window || !window->getDocument())
        return;

    unsigned flags = 0;
    if (view) {
        flags |= view->gatherFlags();
        delete view;
    }
    view = next;
    if (viewFlags)
        setFlags(flags | viewFlags);
    view->setZoom(zoom);
    detail = 0;
    redisplay = true;

    if (!view->getTree()) {
        // cf. http://test.csswg.org/suites/css2.1/20110323/html4/root-box-003.htm
        canvas.shutdown();
        canvas.setup(width, height);
        canvas.beginRender(view->getBackgroundColor());
        canvas.endRender();
    }

    if (!parent) {
        std::u16string title = view->getDocument().getTitle();
        setWindowTitle(utfconv(title).c_str());
    }
}

void WindowImp::setDocumentWindow(const DocumentWindowPtr& window)
{
    this->window = window;
    delete view;
    view = 0;
    viewFlags = 0;
    if (window)
        backgroundTask.restart(BackgroundTask::Cascade);
    detail = 0;
    redisplay = true;
    setFavicon();
}

bool WindowImp::isBindingDocumentWindow() const
{
    if (!parent)
        return false;
    DocumentImp* document = dynamic_cast<DocumentImp*>(parent->getDocument().self());
    return document->isBindingDocumentWindow(this);
}

bool WindowImp::poll()
{
    if (!window)
        return false;
    DocumentImp* document = dynamic_cast<DocumentImp*>(window->getDocument().self());

    // Update the canvas before processing events.
    if (request.getReadyState() == HttpRequest::DONE && document && backgroundTask.getState() == BackgroundTask::Done) {
        ViewCSSImp* next = backgroundTask.getView();
        updateView(next);
        if (view && (view->gatherFlags() & Box::NEED_REPAINT)) {
            redisplay = true;
            render(0);
        }
    }

    while (backgroundTask.getState() == BackgroundTask::Done && !eventQueue.empty()) {
        const EventTask task = eventQueue.front();
        switch (task.type) {
        case EventTask::MouseDown:
        case EventTask::MouseUp:
            mouse(task);
            break;
        case EventTask::MouseMove:
            mouseMove(task);
            break;
        case EventTask::KeyDown:
            keydown(task);
            break;
        case EventTask::KeyUp:
            keyup(task);
            break;
        default:
            break;
        }
        eventQueue.pop_front();
    }

    for (auto i = childWindows.begin(); i != childWindows.end(); ++i) {
        WindowImp* child = *i;
        if (child->poll()) {
            redisplay |= true;
            if (view) {
                if (document && document->isBindingDocumentWindow(child))
                    view->setFlags(Box::NEED_SELECTOR_REMATCHING);
                else
                    view->setFlags(Box::NEED_REPAINT);
            }
        }
    }

    switch (request.getReadyState())
    {
    case HttpRequest::UNSENT:
        break;
    case HttpRequest::OPENED:
    case HttpRequest::HEADERS_RECEIVED:
    case HttpRequest::LOADING:
        break;
    case HttpRequest::DONE:
        if (!document) {
            recordTime("%*shttp request done", windowDepth * 2, "");
            // TODO: Check header
            Document newDocument = getDOMImplementation()->createDocument(u"", u"", 0);
            if (document = dynamic_cast<DocumentImp*>(newDocument.self())) {
                // TODO: Fire a simple unload event.
                window->setDocument(newDocument);
                document->setDefaultView(this);
                document->setURL(request.getRequestMessage().getURL());
                if (!request.getError())
                    history.update(window);
                else
                    document->setError(request.getError());
                parser = new(std::nothrow) Parser(document, request.getContentDescriptor(), request.getResponseMessage().getContentCharset());
                if (!parser)
                    break;  // TODO: error handling
            } else
                break;  // TODO: error handling
        }
        if (document->getReadyState() == u"loading") {
            // TODO: Note white it would be nice to parse the HTML docucment in
            // the background task, firstly we need to check if we can run JS
            // in the background.
            activate();

            HTMLScriptElementImp* script = document->getPendingParsingBlockingScript();
            if (script) {
                if (!script->isReadyToBeParserExecuted())
                    break;
                script->execute();
                document->setPendingParsingBlockingScript(0);
            }

            // TODO: run this in the background
            Token token;
            do {
                token = parser->getToken();
                parser->processToken(token);
            } while (token.getType() != Token::Type::EndOfFile && !document->getPendingParsingBlockingScript());
            if (document->getPendingParsingBlockingScript())
                break;
            document->setCharset(utfconv(parser->getEncoding()));

            // TODO: Check if the parser has been aborted.
            NodeImp::evalTree(document);
            document->resetStyleSheets();
            recordTime("%*shtml parsed", windowDepth * 2, "");
            if (4 <= getLogLevel())
                dumpTree(std::cerr, document);
        }
        switch (backgroundTask.getState()) {
        case BackgroundTask::Cascaded:
            HTMLElementImp::xblEnteredDocument(document);
            backgroundTask.wakeUp(BackgroundTask::Layout);
            break;
        case BackgroundTask::Init:
        case BackgroundTask::Done: {
            ViewCSSImp* next = backgroundTask.getView();
            updateView(next);
            if (document->getReadyState() == u"interactive") {
                // TODO: Check if the parser has been aborted.

                // Run from the step 3. of 'stops parsing'.
                // cf. http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-end

                // Process scripts that will execute when the document has finished parsing (i.e., defer).
                // TODO: Check there's no style sheet that is blocking scripts.
                if (document->processDeferScripts()) {
                    if (!document->hasContentLoaded()) {
                        if (events::Event event = new(std::nothrow) EventImp) {
                            event.initEvent(u"DOMContentLoaded", true, false);
                            document->dispatchEvent(event);
                        }
                        document->decrementLoadEventDelayCount();
                        document->setContentLoaded();

                        backgroundTask.restart(BackgroundTask::Cascade);
                    }
                }
            }
            if (document->getReadyState() == u"complete") {
            }
            if (view) {
                if (unsigned flags = view->gatherFlags()) {
                    if (flags & Box::NEED_SELECTOR_REMATCHING) {
                        recordTime("%*strigger selector rematching", windowDepth * 2, "");
                        backgroundTask.restart(BackgroundTask::Cascade);
                        view = 0;
                    } else if (flags & Box::NEED_SELECTOR_MATCHING) {
                        recordTime("%*strigger restyling", windowDepth * 2, "");
                        backgroundTask.wakeUp(BackgroundTask::Cascade);
                        view = 0;
                    } else if (flags & (Box::NEED_STYLE_RECALCULATION | Box::NEED_EXPANSION | Box::NEED_CHILD_REFLOW | Box::NEED_REFLOW)) {
                        recordTime("%*strigger reflow", windowDepth * 2, "");
                        backgroundTask.wakeUp(BackgroundTask::Layout);
                        view = 0;
                    } else if (flags & Box::NEED_REPAINT)
                        redisplay = true;
                }
            }
            break;
        }
        default:
            break;
        }
        break;
    default:
        break;
    }
    bool result = redisplay;
    redisplay = false;
    if (!result && view && view->hasExpired(getTick())) {
        view->setFlags(Box::NEED_REPAINT);
        result = true;
    }
    if (result)
        recordTime("%*strigger repaint", windowDepth * 2, "");
    return result;
}

void WindowImp::render(ViewCSSImp* parentView)
{
    recordTime("%*srepaint begin: %s (%s)", windowDepth * 2, "", utfconv(window->getDocument().getReadyState()).c_str(), view ? "render" : "canvas");
    if (view) {
        if (view->gatherFlags() & Box::NEED_REPAINT) {
            view->clearFlags(Box::NEED_REPAINT);
            canvas.shutdown();
            canvas.setup(width, height);
            canvas.beginRender(view->getBackgroundColor());
            view->render(parentView ? parentView->getClipCount() : 0);
            scrollWidth = view->getScrollWidth();
            scrollHeight = view->getScrollHeight();
            canvas.endRender();
        }
        if (2 <= getLogLevel() && backgroundTask.getState() == BackgroundTask::Done && !view->gatherFlags()) {
            unsigned depth = 1;
            for (WindowImp* w = this; w->parent; w = w->parent)
                ++depth;
            std::cout << "\n## " << window->getDocument().getReadyState();
            if (1 < depth)
                std::cout << " (" << depth << ')';
            std::cout << '\n';
            view->dump();
            std::cout << "##\n";
            std::cout.flush();
        }
    }
    canvas.render(width, height);
    recordTime("%*srepaint end", windowDepth * 2, "");
}

void WindowImp::mouse(int button, int up, int x, int y, int modifiers)
{
    eventQueue.emplace_back(up ? EventTask::MouseUp : EventTask::MouseDown, modifiers, x, y, button);
}

void WindowImp::mouseMove(int x, int y, int modifiers)
{
    if (!eventQueue.empty()) {
        EventTask& back = eventQueue.back();
        if (back.type == EventTask::MouseMove) {
            back.x = x;
            back.y = y;
{'fraction_non_alphanumeric': 0.12867701956099747, 'fraction_numerical': 0.005860833208899507, 'mean_word_length': 2.0841584158415842, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 143, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4477907', 'n_tokens_mistral': 7593, 'n_tokens_neox': 7406, 'n_words': 1649}