```
<!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;
        }

        /* 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 {
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
            max-height: 400px;
            overflow: auto;
            border: 1px solid #ccc;
            padding: 10px;
        }

        /* 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;
        }
    </style>
</head>
<body>

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

    <div class="buttons">
        <button id="generate-btn">Generate Elements</button>
        <button id="search-btn" disabled>Start Search</button>
    </div>

    <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>

    <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) {
                const { left, top, width: rectWidth, height: rectHeight } = rect;
                const { x, y, width: targetWidth, height: targetHeight } = target;
                const { abs } = Math;

                return (
                    abs(left - x) <= targetWidth * z &&
                    abs(top - y) <= targetHeight * z &&
                    abs(rectWidth - targetWidth) <= targetWidth * z &&
                    abs(rectHeight - targetHeight) <= targetHeight * z
                );
            }

            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) {
                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();

                            if (isMatch(rect, target, z)) {
                                results.add(elem);
                                // Skip enqueuing children to maintain ancestry
                            } else if (exhaustive || isOverlap(rect, 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 viewport).
             * @param {number} y - The Y-coordinate of the target rectangle (relative to the viewport).
             * @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));

                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
                    );

                    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();

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

                        if (exhaustive || isOverlap(rect, 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)}%`;
        }

        // Function to generate many nested empty elements
        function generateElements(count = 10000, maxDepth = 5) {
            const container = document.getElementById('elements-container');
            container.innerHTML = ''; // Clear previous elements if any

            function createNestedElements(parent, currentDepth) {
                if (currentDepth > maxDepth) return;

                for (let i = 0; i < count / Math.pow(10, currentDepth); i++) {
                    const div = document.createElement('div');
                    div.classList.add('generated-element');
                    // Optional: Set styles or attributes to make elements identifiable
                    parent.appendChild(div);

                    // Randomly decide to nest further
                    if (Math.random() > 0.8) { // 20% chance to nest
                        createNestedElements(div, currentDepth + 1);
                    }
                }
            }

            // Start generating from the root container
            createNestedElements(container, 1);
        }

        // 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);
                console.log(elem);
            });
            window.results = Array.from(elements);
        }

        // Event listeners for buttons
        document.getElementById('generate-btn').addEventListener('click', () => {
            const generateBtn = document.getElementById('generate-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');

            // Disable buttons during generation
            generateBtn.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(10000, 3); // Generate 10,000 elements with max depth 3
                generateBtn.disabled = false;
                searchBtn.disabled = false;
                alert('Element generation complete!');
            }, 100); // Slight delay to ensure buttons get disabled first
        });

        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');
            generateBtn.disabled = true;
            searchBtn.disabled = true;

            // Define target rectangle (e.g., part of the viewport)
            const targetRect = {
                x: Math.random() * window.innerWidth / 2, // Random x
                y: Math.random() * window.innerHeight / 2, // Random y
                width: 50, // Fixed width
                height: 50 // Fixed height
            };
            const errorRatio = 0.5; // 20% error tolerance

            // Log or visually indicate target rectangle (optional)
            console.log('Target Rectangle:', targetRect);

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

</body>
</html>
```
update this such that the target rect is drawn (red border) on the page first when performing search. also we dont draw another target rect for next search, instead modify the existing drawn target rect