```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Find Most Ancestral Elements with Progress Feedback</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            position: relative; /* Positioned ancestor for absolute positioning */
        }

        /* Button Styles */
        .buttons {
            margin-bottom: 20px;
        }

        button {
            padding: 10px 20px;
            margin-right: 10px;
            font-size: 16px;
            cursor: pointer;
        }

        /* Progress Bar Styles */
        #progress-container {
            width: 100%;
            background-color: #f3f3f3;
            border: 1px solid #ccc;
            border-radius: 5px;
            overflow: hidden;
            margin-bottom: 10px;
            height: 25px;
        }

        #progress-bar {
            width: 0%;
            height: 100%;
            background-color: #4caf50;
            transition: width 0.2s ease;
        }

        #progress-text {
            display: block;
            text-align: right;
            margin-top: -25px;
            margin-bottom: 20px;
            font-weight: bold;
        }

        /* Elements Container */
        #elements-container {
            width: 1200px; /* Define width */
            height: 2400px; /* Define height */
            display: block; /* Change from flex to block for absolute positioning */
            overflow: auto;
            border: 1px solid #ccc;
            padding: 10px;
            position: relative; /* To position nested elements if needed */
        }

        /* Generated Elements */
        .generated-element {
            width: 50px;
            height: 50px;
            background-color: #add8e6;
            border: 1px solid #000;
            box-sizing: border-box;
        }

        /* Results */
        #results {
            margin-top: 20px;
        }

        #results ul {
            list-style-type: none;
            padding-left: 0;
        }

        #results li {
            padding: 5px 0;
        }

        /* Target Rectangle Styles */
        #target-rect {
            position: absolute; /* Changed from fixed to absolute */
            border: 2px solid red;
            pointer-events: none; /* Allows clicks to pass through the rectangle */
            z-index: 1000; /* Ensure it's on top of other elements */
            display: none; /* Hidden by default */
        }

        /* Input Sections */
        .input-section {
            margin-bottom: 20px;
        }

        .input-section label {
            display: inline-block;
            width: 120px;
            font-weight: bold;
        }

        .input-section input {
            padding: 5px;
            width: 100px;
            margin-right: 10px;
            box-sizing: border-box;
        }

        .error-message {
            color: red;
            margin-top: 5px;
            display: block;
        }
    </style>
</head>
<body>

    <h1>Find Most Ancestral Elements with Progress Feedback</h1>

    <!-- Generation Parameters Section -->
    <div class="input-section">
        <h2>Generation Parameters</h2>
        <label for="generate-count">Number of Elements:</label>
        <input type="number" id="generate-count" value="200" min="1">
        <label for="generate-max-depth">Maximum Depth:</label>
        <input type="number" id="generate-max-depth" value="2" min="0">
        <button id="generate-btn">Generate Elements</button>
        <span id="generate-errors" class="error-message"></span>
    </div>

    <!-- Target Rectangle Definition Section -->
    <div class="input-section">
        <h2>Define Target Rectangle</h2>
        <label for="rect-x">X-coordinate:</label>
        <input type="number" id="rect-x" value="0" min="0">
        <label for="rect-y">Y-coordinate:</label>
        <input type="number" id="rect-y" value="0" min="0">
        <label for="rect-width">Width:</label>
        <input type="number" id="rect-width" value="100" min="1">
        <label for="rect-height">Height:</label>
        <input type="number" id="rect-height" value="100" min="1">
        <button id="update-rect-btn">Update Rect</button>
        <button id="create-target-btn">Create Random Rect</button>
        <span id="rect-errors" class="error-message"></span>
    </div>

    <!-- Search Button -->
    <div class="buttons">
        <button id="search-btn" disabled>Start Search</button>
    </div>

    <!-- Progress Bar -->
    <div id="progress-container">
        <div id="progress-bar"></div>
    </div>
    <span id="progress-text">0%</span>

    <h2>Generated Elements</h2>
    <div id="elements-container"></div>

    <!-- Target Rectangle -->
    <div id="target-rect"></div>

    <h2>Search Results</h2>
    <div id="results">
        <ul id="results-list"></ul>
    </div>

    <script>
        // Optimized findMostAncestralElements function using closure for caching
        const findMostAncestralElements = (function () {
            // Cached helper functions
            function isMatch(rect, target, z) {
                // Calculate the coordinates of the intersection rectangle
                const xLeft = Math.max(rect.left, target.x);
                const yTop = Math.max(rect.top, target.y);
                const xRight = Math.min(rect.left + rect.width, target.x + target.width);
                const yBottom = Math.min(rect.top + rect.height, target.y + target.height);

                // Compute the width and height of the overlapping area
                const overlapWidth = xRight - xLeft;
                const overlapHeight = yBottom - yTop;

                // If there is no overlap, the overlapping area is 0
                if (overlapWidth <= 0 || overlapHeight <= 0) {
                    return false; // No part of rect is inside target
                }

                // Calculate areas
                const overlapArea = overlapWidth * overlapHeight;
                const rectArea = rect.width * rect.height;

                // Determine if the overlapping area meets the required ratio
                return overlapArea >= (1 - z) * rectArea;
            }

            function isOverlap(rect, target) {
                const { left, top, width: rectWidth, height: rectHeight } = rect;
                const { x, y, width: targetWidth, height: targetHeight } = target;

                return (
                    left < x + targetWidth &&
                    left + rectWidth > x &&
                    top < y + targetHeight &&
                    top + rectHeight > y
                );
            }

            function createProcessBatchAsync(queue, target, z, exhaustive, iterationBatch, onProgress, head, results, marginLeft, marginTop) {
                return function processBatchAsync() {
                    return new Promise((resolve) => {
                        let processed = 0;

                        while (head.value < queue.length && processed < iterationBatch) {
                            const elem = queue[head.value++];
                            const rect = elem.getBoundingClientRect();

                            // Adjust rect coordinates based on page scroll and margin offsets
                            const adjustedRect = {
                                left: rect.left + window.pageXOffset + marginLeft,
                                top: rect.top + window.pageYOffset + marginTop,
                                width: rect.width,
                                height: rect.height
                            };

                            if (isMatch(adjustedRect, target, z)) {
                                results.add(elem);
                                console.log(elem);
                            } else if (exhaustive || isOverlap(adjustedRect, target)) {
                                const children = elem.children;
                                for (let i = 0, len = children.length; i < len; i++) {
                                    queue.push(children[i]);
                                }
                            }

                            processed++;
                        }

                        if (onProgress) {
                            onProgress({
                                processedElements: head.value,
                                totalQueued: queue.length,
                                uniqueResults: results.size,
                            });
                        }

                        resolve();
                    });
                };
            }

            /**
             * The optimized findMostAncestralElements function.
             *
             * @param {number} x - The X-coordinate of the target rectangle (relative to the page).
             * @param {number} y - The Y-coordinate of the target rectangle (relative to the page).
             * @param {number} width - The width of the target rectangle.
             * @param {number} height - The height of the target rectangle.
             * @param {number} errorRatio - The allowed error ratio (0 to 1) for matching.
             * @param {Object} [options] - Optional settings.
             * @param {boolean} [options.exhaustive=true] - If true, performs an exhaustive search.
             * @param {number} [options.asyncIterations] - Number of iterations per asynchronous batch.
             *                                             If null, undefined, or <= 0, executes synchronously.
             * @param {Function} [options.onProgress] - Callback function to receive progress updates.
             * @returns {Promise<Element[]>|Element[]} A promise that resolves to an array of the most ancestral DOM elements matching the criteria, or the array directly if not asynchronous.
             */
            return function findMostAncestralElements(
                x,
                y,
                width,
                height,
                errorRatio,
                options = {}
            ) {
                const {
                    exhaustive = true,
                    asyncIterations, // Renamed from 'async' to 'asyncIterations'
                    onProgress,
                } = options;

                // Determine if the function should execute asynchronously
                const isAsync = typeof asyncIterations === 'number' && asyncIterations > 0;
                const iterationBatch = isAsync ? asyncIterations : null;

                // Clamp errorRatio between 0 and 1
                const z = Math.max(0, Math.min(errorRatio, 1));

                // Get body margins
                const bodyStyles = getComputedStyle(document.body);
                const marginLeft = parseFloat(bodyStyles.marginLeft);
                const marginTop = parseFloat(bodyStyles.marginTop);

                // Adjust target coordinates by subtracting body margins to align with absolute positioning
                const target = { x, y, width, height };
                const results = new Set();
                const queue = [document.body];
                const head = { value: 0 }; // Using an object to allow mutation inside closure

                if (isAsync) {
                    const processBatch = createProcessBatchAsync(
                        queue,
                        target,
                        z,
                        exhaustive,
                        iterationBatch,
                        onProgress,
                        head,
                        results,
                        marginLeft,
                        marginTop
                    );

                    return new Promise((resolve) => {
                        function iterate() {
                            processBatch().then(() => {
                                if (head.value < queue.length) {
                                    setTimeout(iterate, 0);
                                } else {
                                    resolve(Array.from(results));
                                }
                            });
                        }
                        iterate();
                    });
                } else {
                    // Synchronous Processing
                    while (head.value < queue.length) {
                        const elem = queue[head.value++];
                        const rect = elem.getBoundingClientRect();

                        // Adjust rect coordinates based on page scroll and margin offsets
                        const adjustedRect = {
                            left: rect.left + window.pageXOffset + marginLeft,
                            top: rect.top + window.pageYOffset + marginTop,
                            width: rect.width,
                            height: rect.height
                        };

                        if (isMatch(adjustedRect, target, z)) {
                            results.add(elem);
                            continue; // Skip enqueuing children to maintain ancestry
                        }

                        if (exhaustive || isOverlap(adjustedRect, target)) {
                            const children = elem.children;
                            for (let i = 0, len = children.length; i < len; i++) {
                                queue.push(children[i]);
                            }
                        }

                        if (onProgress) {
                            onProgress({
                                processedElements: head.value,
                                totalQueued: queue.length,
                                uniqueResults: results.size,
                            });
                        }
                    }
                    return Array.from(results);
                }
            };
        })();

        // Function to update the progress bar and percentage text
        function updateProgressBar(progress) {
            const { processedElements, totalQueued } = progress;
            const progressBar = document.getElementById('progress-bar');
            const progressText = document.getElementById('progress-text');

            // Estimate percentage based on processed vs total queued
            const percentage = totalQueued > 0 ? Math.min((processedElements / (processedElements + totalQueued)) * 100, 100) : 100;

            progressBar.style.width = `${percentage}%`;
            progressText.textContent = `${percentage.toFixed(2)}%`;
        }

        // Corrected Function to Generate Elements in a Grid Without Overlapping
        function generateElements(count = 200, maxDepth = 2) {
            const container = document.getElementById('elements-container');
            container.innerHTML = ''; // Clear previous elements if any

            const ELEMENT_SIZE = 50; // px
            const GAP = 10; // px

            // Get container dimensions
            const containerRect = container.getBoundingClientRect();
            const containerWidth = containerRect.width - GAP; // Adjust for padding and gaps
            const containerHeight = containerRect.height - GAP;

            const columns = Math.floor((containerWidth) / (ELEMENT_SIZE + GAP));
            const rows = Math.floor((containerHeight) / (ELEMENT_SIZE + GAP));

            let currentColumn = 0;
            let currentRow = 0;

            // Function to get position based on row and column
            function getPosition(row, column) {
                const left = column * (ELEMENT_SIZE + GAP);
                const top = row * (ELEMENT_SIZE + GAP);
                return { left, top };
            }

            // Function to create nested elements with controlled branching
            function createNestedElements(parent, currentDepth) {
                if (currentDepth > maxDepth) return;

                // Define a fixed number of child elements per parent to prevent exponential growth
                const CHILDREN_PER_PARENT = 2; // Fixed branching factor

                for (let i = 0; i < CHILDREN_PER_PARENT; i++) {
                    const div = document.createElement('div');
                    div.classList.add('generated-element');

                    // Position children within the parent with a smaller gap
                    const childGap = 5; // px
                    const childLeft = (i % 2) * (ELEMENT_SIZE + childGap);
                    const childTop = Math.floor(i / 2) * (ELEMENT_SIZE + childGap);

                    // Apply inline styles for absolute positioning
                    div.style.position = 'absolute';
                    div.style.left = `${childLeft}px`;
                    div.style.top = `${childTop}px`;

                    parent.appendChild(div);

                    // Randomly decide to nest further with controlled depth
                    if (Math.random() > 0.5) { // 50% chance to nest for demonstration
                        createNestedElements(div, currentDepth + 1);
                    }
                }
            }

            // Generate top-level elements in grid
            for (let i = 0; i < count; i++) {
                if (currentRow >= rows) {
                    console.warn('Reached maximum rows. Some elements may not be visible.');
                    break;
                }

                const div = document.createElement('div');
                div.classList.add('generated-element');

                const row = currentRow;
                const column = currentColumn;
                const { left, top } = getPosition(row, column);

                // Apply inline styles for absolute positioning
                div.style.position = 'absolute';
                div.style.left = `${left}px`;
                div.style.top = `${top}px`;

                container.appendChild(div);

                // Randomly decide to nest further with controlled branching
                if (Math.random() > 0.7) { // 30% chance to nest
                    createNestedElements(div, 1);
                }

                // Update row and column
                currentColumn++;
                if (currentColumn >= columns) {
                    currentColumn = 0;
                    currentRow++;
                }
            }
        }

        // Function to display search results
        function displayResults(elements) {
            const resultsList = document.getElementById('results-list');
            resultsList.innerHTML = ''; // Clear previous results

            if (elements.length === 0) {
                resultsList.innerHTML = '<li>No matching elements found.</li>';
                return;
            }

            elements.forEach((elem, index) => {
                const li = document.createElement('li');
                li.textContent = `Element ${index + 1}: ${elem.tagName}${elem.id ? `#${elem.id}` : ''}${elem.className ? `.${elem.className}` : ''}`;
                resultsList.appendChild(li);
            });
            window.results = Array.from(elements);
        }

        // Function to draw or update the target rectangle
        function drawTargetRect(targetRect) {
            const targetDiv = document.getElementById('target-rect');

            // Get body margins
            const bodyStyles = getComputedStyle(document.body);
            const marginLeft = parseFloat(bodyStyles.marginLeft);
            const marginTop = parseFloat(bodyStyles.marginTop);

            // Set the position and size based on targetRect, accounting for body margins
            targetDiv.style.left = `${targetRect.x + marginLeft}px`;
            targetDiv.style.top = `${targetRect.y + marginTop}px`;
            targetDiv.style.width = `${targetRect.width}px`;
            targetDiv.style.height = `${targetRect.height}px`;
            // Display the rectangle
            targetDiv.style.display = 'block';
        }

        // Function to create a random target rectangle
        function createRandomTargetRect() {
            const targetDiv = document.getElementById('target-rect');

            // Define target rectangle dimensions
            const width = 100; // px
            const height = 100; // px

            // Get body dimensions to ensure the rectangle stays within the page
            const bodyStyles = getComputedStyle(document.body);
            const marginLeft = parseFloat(bodyStyles.marginLeft);
            const marginTop = parseFloat(bodyStyles.marginTop);

            const maxX = document.documentElement.scrollWidth - width; // Ensure within horizontal bounds
            const maxY = document.documentElement.scrollHeight - height; // Ensure within vertical bounds

            const x = Math.random() * maxX;
            const y = Math.random() * maxY;

            const targetRect = { x: Math.round(x), y: Math.round(y), width, height };

            drawTargetRect(targetRect);
            updateRectInputFields(targetRect); // Update input fields with new values
            return targetRect;
        }

        // Function to update the rectangle input fields with given values
        function updateRectInputFields(rect) {
            document.getElementById('rect-x').value = rect.x;
            document.getElementById('rect-y').value = rect.y;
            document.getElementById('rect-width').value = rect.width;
            document.getElementById('rect-height').value = rect.height;
        }

        // Event listeners for buttons
        document.getElementById('generate-btn').addEventListener('click', () => {
            const generateBtn = document.getElementById('generate-btn');
            const createTargetBtn = document.getElementById('create-target-btn');
            const searchBtn = document.getElementById('search-btn');
            const progressBar = document.getElementById('progress-bar');
            const progressText = document.getElementById('progress-text');
            const resultsList = document.getElementById('results-list');
            const generateErrors = document.getElementById('generate-errors');

            // Clear previous error messages
            generateErrors.textContent = '';

            // Get input values
            const countInput = document.getElementById('generate-count').value;
            const maxDepthInput = document.getElementById('generate-max-depth').value;

            let hasError = false;
            let count = parseInt(countInput, 10);
            let maxDepth = parseInt(maxDepthInput, 10);
            let errorMessage = '';

            // Validate count
            if (isNaN(count) || count <= 0) {
                errorMessage += 'Number of Elements must be a positive integer. ';
                hasError = true;
            }

            // Validate maxDepth
            if (isNaN(maxDepth) || maxDepth < 0) {
                errorMessage += 'Maximum Depth must be a non-negative integer.';
                hasError = true;
            }

            if (hasError) {
                generateErrors.textContent = errorMessage;
                return;
            }

            // Disable buttons during generation
            generateBtn.disabled = true;
            createTargetBtn.disabled = true;
            searchBtn.disabled = true;
            resultsList.innerHTML = '';
            progressBar.style.width = '0%';
            progressText.textContent = '0%';

            // Generate elements
            setTimeout(() => { // Use setTimeout to allow UI to update
                generateElements(count, maxDepth); // Generate elements with user-specified count and maxDepth
                generateBtn.disabled = false;
                createTargetBtn.disabled = false;
                searchBtn.disabled = false;
            }, 100); // Slight delay to ensure buttons get disabled first
        });

        document.getElementById('create-target-btn').addEventListener('click', () => {
            const targetRect = createRandomTargetRect();
            // Optionally, you can notify the user
            // alert('Random Target Rectangle Created!');
        });

        document.getElementById('update-rect-btn').addEventListener('click', () => {
            const rectErrors = document.getElementById('rect-errors');
            rectErrors.textContent = ''; // Clear previous error messages

            // Get input values
            const xInput = document.getElementById('rect-x').value;
            const yInput = document.getElementById('rect-y').value;
            const widthInput = document.getElementById('rect-width').value;
            const heightInput = document.getElementById('rect-height').value;

            let hasError = false;
            let x = parseFloat(xInput);
            let y = parseFloat(yInput);
            let width = parseFloat(widthInput);
            let height = parseFloat(heightInput);
            let errorMessage = '';

            // Validate x
            if (isNaN(x) || x < 0) {
                errorMessage += 'X-coordinate must be a non-negative number. ';
                hasError = true;
            }

            // Validate y
            if (isNaN(y) || y < 0) {
                errorMessage += 'Y-coordinate must be a non-negative number. ';
                hasError = true;
            }

            // Validate width
            if (isNaN(width) || width <= 0) {
                errorMessage += 'Width must be a positive number. ';
                hasError = true;
            }

            // Validate height
            if (isNaN(height) || height <= 0) {
                errorMessage += 'Height must be a positive number.';
                hasError = true;
            }

            if (hasError) {
                rectErrors.textContent = errorMessage;
                return;
            }

            const targetRect = { x, y, width, height };
            drawTargetRect(targetRect);
            console.log('User Defined Target Rectangle:', targetRect);
            // Optionally, notify the user
        });

        document.getElementById('search-btn').addEventListener('click', () => {
            const searchBtn = document.getElementById('search-btn');
            const resultsList = document.getElementById('results-list');

            // Clear previous results
            resultsList.innerHTML = '';
            // Reset progress bar
            const progressBar = document.getElementById('progress-bar');
            const progressText = document.getElementById('progress-text');
            progressBar.style.width = '0%';
            progressText.textContent = '0%';

            // Disable buttons during search
            const generateBtn = document.getElementById('generate-btn');
            const createTargetBtn = document.getElementById('create-target-btn');
            const updateRectBtn = document.getElementById('update-rect-btn');
            generateBtn.disabled = true;
            createTargetBtn.disabled = true;
            updateRectBtn.disabled = true;
            searchBtn.disabled = true;

            let targetRect = getCurrentTargetRect();

            // If no target rect exists, create one
            if (!targetRect) {
                targetRect = createRandomTargetRect();
            }

            // Log the target rectangle
            console.log('Using Target Rectangle:', targetRect);

            // Start search
            findMostAncestralElements(
                targetRect.x,
                targetRect.y,
                targetRect.width,
                targetRect.height,
                0.5, // errorRatio
                {
                    asyncIterations: 100, // Process 100 elements per batch
                    onProgress: (progress) => {
                        updateProgressBar(progress);
                    }
                }
            ).then((matchingElements) => {
                displayResults(matchingElements);
                alert(`Search complete! Found ${matchingElements.length} matching elements.`);
                generateBtn.disabled = false;
                createTargetBtn.disabled = false;
                updateRectBtn.disabled = false;
                searchBtn.disabled = false;
            }).catch((error) => {
                console.error('Error during search:', error);
                alert('An error occurred during the search.');
                generateBtn.disabled = false;
                createTargetBtn.disabled = false;
                updateRectBtn.disabled = false;
                searchBtn.disabled = false;
            });
        });

        // Helper function to get the current target rectangle
        function getCurrentTargetRect() {
            const targetDiv = document.getElementById('target-rect');
            if (targetDiv.style.display === 'none') return null;

            // Get body margins
            const bodyStyles = getComputedStyle(document.body);
            const marginLeft = parseFloat(bodyStyles.marginLeft);
            const marginTop = parseFloat(bodyStyles.marginTop);

            const left = parseFloat(targetDiv.style.left) - marginLeft;
            const top = parseFloat(targetDiv.style.top) - marginTop;
            const width = parseFloat(targetDiv.style.width);
            const height = parseFloat(targetDiv.style.height);

            if (isNaN(left) || isNaN(top) || isNaN(width) || isNaN(height)) {
                return null;
            }

            return { x: left, y: top, width, height };
        }
    </script>

</body>
</html>
```
currently, rect isMatched  against targetRect using getBoundingClientRect which is relative to viewport, this is not what we want. we want a page rect instead of a client rect