complete the v2 code, here is the v1 code for reference and send the fully working full v2 code.
---
v2: [ javascript:(function(){
    // Configuration with advanced options
    const CONFIG = {
        MAX_IMAGES: 500,
        CHUNK_SIZE: 50,
        CORS_PROXIES: [
            'https://corsproxy.io/?',
            'https://api.allorigins.win/raw?url=',
            'https://api.codetabs.com/v1/proxy?quest='
        ],
        VIEWER: {
            MIN_WIDTH: 800,
            MIN_HEIGHT: 600,
            PREFERRED_WIDTH: 1200,
            PREFERRED_HEIGHT: 800
        },
        SLIDESHOW: {
            MIN_INTERVAL: 1,
            MAX_INTERVAL: 10,
            DEFAULT_INTERVAL: 3
        },
        PRELOAD: {
            ADJACENT: 3,
            BATCH_SIZE: 5,
            TIMEOUT: 5000
        },
        ANIMATION: {
            DURATION: 300,
            EASING: 'cubic-bezier(0.4, 0, 0.2, 1)'
        },
        ZOOM: {
            MIN: 1,
            MAX: 5,
            STEP: 0.1
        },
        GESTURE: {
            SWIPE_THRESHOLD: 50,
            PINCH_THRESHOLD: 0.1
        },
        CACHE: {
            MAX_SIZE: 100,
            EXPIRE_TIME: 3600000 // 1 hour
        }
    };

    // Prevent multiple instances and handle cleanup
    if (window.ultimateImageViewerInstance) {
        try {
            window.ultimateImageViewerInstance.focus();
            return;
        } catch (e) {
            window.ultimateImageViewerInstance = null;
        }
    }

    // Enhanced URL sanitization with additional security checks
    function sanitizeURL(url) {
        try {
            const sanitized = new URL(url, window.location.href);
            
            // Strict protocol check
            if (!['http:', 'https:'].includes(sanitized.protocol)) {
                return null;
            }

            // Exclude potentially dangerous file types
            const dangerous = /\.(svg|svgz|html|htm|php|asp|aspx|jsp|cgi)$/i;
            if (dangerous.test(sanitized.pathname)) {
                return null;
            }

            // Check for common image extensions
            const validExtension = /\.(jpe?g|png|gif|webp|avif|bmp|ico)$/i;
            if (!validExtension.test(sanitized.pathname)) {
                // Additional check for images without extensions
                const contentType = url.match(/^data:image\/(jpeg|png|gif|webp|avif|bmp|ico)/i);
                if (!contentType) {
                    return null;
                }
            }

            // Remove hash and search parameters for cache consistency
            sanitized.hash = '';
            sanitized.search = '';
            
            return sanitized.href;
        } catch (e) {
            return null;
        }
    }

    // Advanced image source gathering with lazy-loading support
    async function gatherImageSources() {
        const sources = new Set();
        const seenUrls = new Set();
        let processedCount = 0;

        // Process elements in chunks to avoid blocking
        async function processElements(elements, attributeGetter) {
            for (let i = 0; i < elements.length; i += CONFIG.CHUNK_SIZE) {
                const chunk = Array.from(elements).slice(i, i + CONFIG.CHUNK_SIZE);
                await new Promise(resolve => {
                    setTimeout(() => {
                        chunk.forEach(element => {
                            const urls = attributeGetter(element);
                            urls.forEach(url => {
                                if (!seenUrls.has(url)) {
                                    seenUrls.add(url);
                                    const sanitized = sanitizeURL(url);
                                    if (sanitized) {
                                        sources.add(sanitized);
                                        processedCount++;
                                        if (processedCount >= CONFIG.MAX_IMAGES) {
                                            return Array.from(sources);
                                        }
                                    }
                                }
                            });
                        });
                        resolve();
                    }, 0);
                });
                if (processedCount >= CONFIG.MAX_IMAGES) break;
            }
        }

        // Image tag sources
        await processElements(
            document.querySelectorAll('img'),
            img => {
                const urls = [];
                ['src', 'data-src', 'data-original', 'data-lazy', 'data-lazy-src'].forEach(attr => {
                    const value = img.getAttribute(attr);
                    if (value) urls.push(value);
                });
                const srcset = img.srcset;
                if (srcset) {
                    srcset.split(',').forEach(src => {
                        const url = src.trim().split(' ')[0];
                        if (url) urls.push(url);
                    });
                }
                return urls;
            }
        );

        // Background images
        const styleObserver = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
                    const element = mutation.target;
                    const computed = window.getComputedStyle(element);
                    const background = computed.backgroundImage;
                    if (background && background !== 'none') {
                        const matches = background.match(/url\(['"]?([^'"]+)['"]?\)/g);
                        if (matches) {
                            matches.forEach(match => {
                                const url = match.slice(4, -1).replace(/['"]/g, '');
                                if (!seenUrls.has(url)) {
                                    seenUrls.add(url);
                                    const sanitized = sanitizeURL(url);
                                    if (sanitized) sources.add(sanitized);
                                }
                            });
                        }
                    }
                }
            });
        });

        // Observe dynamic style changes
        document.querySelectorAll('*').forEach(element => {
            styleObserver.observe(element, {
                attributes: true,
                attributeFilter: ['style']
            });
        });

        // Process link tags that might contain images
        await processElements(
            document.querySelectorAll('a[href]'),
            link => {
                const href = link.getAttribute('href');
                return href ? [href] : [];
            }
        );

        // Cleanup
        styleObserver.disconnect();

        return Array.from(sources).slice(0, CONFIG.MAX_IMAGES);
    }

    // Initialize viewer with advanced error handling
    async function initializeViewer() {
        try {
            const imageUrls = await gatherImageSources();

            if (imageUrls.length === 0) {
                throw new Error('No valid images found on this page.');
            }

            // Calculate optimal window size
            const screenWidth = window.screen.availWidth;
            const screenHeight = window.screen.availHeight;
            const width = Math.min(CONFIG.VIEWER.PREFERRED_WIDTH, screenWidth * 0.9);
            const height = Math.min(CONFIG.VIEWER.PREFERRED_HEIGHT, screenHeight * 0.9);

            // Open viewer window with position calculation
            const left = (screenWidth - width) / 2;
            const top = (screenHeight - height) / 2;
            const viewer = window.open(
                '',
                '_blank',
                `width=${width},height=${height},left=${left},top=${top},scrollbars=no,resizable=yes`
            );

            if (!viewer) {
                throw new Error('Unable to open image viewer. Please allow popups for this website.');
            }

            window.ultimateImageViewerInstance = viewer;

            // Generate viewer HTML (continued in next section...)
            const viewerHTML = generateViewerHTML(imageUrls);
            
            // Write content safely
            viewer.document.open();
            viewer.document.write(viewerHTML);
            viewer.document.close();

            // Add unload handler
            viewer.addEventListener('unload', () => {
                window.ultimateImageViewerInstance = null;
            });

        } catch (error) {
            console.error('Image Viewer Initialization Error:', error);
            alert(error.message || 'An error occurred while initializing the image viewer.');
        }
    }

    // Generate viewer HTML with modern UI
    function generateViewerHTML(imageUrls) {
        return `
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <meta name="color-scheme" content="dark">
                <title>Enhanced Image Viewer</title>
                <style>
                    /* Modern CSS Reset */
                    *, *::before, *::after {
                        box-sizing: border-box;
                        margin: 0;
                        padding: 0;
                    }

                    /* Custom Properties */
                    :root {
                        --primary-bg: #1a1a1a;
                        --secondary-bg: #2a2a2a;
                        --primary-text: #ffffff;
                        --secondary-text: #cccccc;
                        --accent-color: #3498db;
                        --danger-color: #e74c3c;
                        --success-color: #2ecc71;
                        --border-radius: 8px;
                        --transition-duration: ${CONFIG.ANIMATION.DURATION}ms;
                        --transition-timing: ${CONFIG.ANIMATION.EASING};
                    }

                    /* Base Styles */
                    html {
                        font-size: 16px;
                        line-height: 1.5;
                        -webkit-text-size-adjust: 100%;
                    }

                    body {
                        font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
                        background-color: var(--primary-bg);
                        color: var(--primary-text);
                        overflow: hidden;
                        height: 100vh;
                        width: 100vw;
                    }

                    /* Container Layout */
                    .viewer-container {
                        position: relative;
                        width: 100%;
                        height: 100%;
                        display: grid;
                        grid-template-rows: auto 1fr auto;
                        gap: 1rem;
                        padding: 1rem;
                    }

                    /* Header Styles */
                    .viewer-header {
                        display: flex;
                        justify-content: space-between;
                        align-items: center;
                        padding: 0.5rem 1rem;
                        background-color: var(--secondary-bg);
                        border-radius: var(--border-radius);
                        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
                    }

                    /* Main Content Area */
                    .viewer-main {
                        position: relative;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        overflow: hidden;
                        border-radius: var(--border-radius);
                        background-color: var(--secondary-bg);
                    }

                    /* Image Styles */
                    .main-image {
                        max-width: 100%;
                        max-height: 100%;
                        object-fit: contain;
                        transition: transform var(--transition-duration) var(--transition-timing),
                                  opacity var(--transition-duration) var(--transition-timing);
                        opacity: 0;
                        cursor: grab;
                        touch-action: none;
                        will-change: transform, opacity;
                    }

                    .main-image.visible {
                        opacity: 1;
                    }

                    .main-image.panning {
                        cursor: grabbing;
                    }

                    /* Controls */
                    .controls {
                        display: flex;
                        gap: 0.5rem;
                        flex-wrap: wrap;
                    }

                    .controls button {
                        background-color: var(--secondary-bg);
                        color: var(--primary-text);
                        border: none;
                        padding: 0.5rem 1rem;
                        border-radius: var(--border-radius);
                        cursor: pointer;
                        transition: background-color var(--transition-duration) var(--transition-timing);
                        display: flex;
                        align-items: center;
                        gap: 0.5rem;
                        font-size: 0.875rem;
                        white-space: nowrap;
                    }

                    .controls button:hover {
                        background-color: var(--accent-color);
                    }

                    .controls button:active {
                        transform: translateY(1px);
                    }

                    /* Navigation Buttons */
                    .nav-button {
                        position: absolute;
                        top: 50%;
                        transform: translateY(-50%);
                        background-color: rgba(0, 0, 0, 0.5);
                        color: var(--primary-text);
                        border: none;
                        width: 48px;
                        height: 48px;
                        border-radius: 50%;
                        cursor: pointer;
                        opacity: 0;
                        transition: opacity var(--transition-duration) var(--transition-timing),
                                  background-color var(--transition-duration) var(--transition-timing);
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        font-size: 1.5rem;
                    }

                    .viewer-main:hover .nav-button {
                        opacity: 1;
                    }

                    .nav-button:hover {
                        background-color: rgba(0, 0, 0, 0.8);
                    }

                    .prev-button { left: 1rem; }
                    .next-button { right: 1rem; }

                    /* Thumbnails */
                    .thumbnails {
                        display: flex;
                        gap: 0.5rem;
                        padding: 0.5rem;
                        overflow-x: auto;
                        scrollbar-width: thin;
                        scrollbar-color: var(--accent-color) var(--secondary-bg);
                        background-color: var(--secondary-bg);
                        border-radius: var(--border-radius);
                        scroll-behavior: smooth;
                    }

                    .thumbnails::-webkit-scrollbar {
                        height: 6px;
                    }

                    .thumbnails::-webkit-scrollbar-track {
                        background: var(--secondary-bg);
                        border-radius: var(--border-radius);
                    }

                    .thumbnails::-webkit-scrollbar-thumb {
                        background-color: var(--accent-color);
                        border-radius: var(--border-radius);
                    }

                    .thumbnail {
                        width: 60px;
                        height: 60px;
                        object-fit: cover;
                        border-radius: 4px;
                        cursor: pointer;
                        transition: transform var(--transition-duration) var(--transition-timing),
                                  box-shadow var(--transition-duration) var(--transition-timing);
                        flex-shrink: 0;
                    }

                    .thumbnail:hover {
                        transform: translateY(-2px);
                        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
                    }

                    .thumbnail.active {
                        border: 2px solid var(--accent-color);
                        transform: scale(1.1);
                    }

                    /* Loading Indicator */
                    .loader {
                        position: absolute;
                        top: 50%;
                        left: 50%;
                        transform: translate(-50%, -50%);
                        width: 40px;
                        height: 40px;
                        display: none;
                    }

                    .loader::after {
                        content: '';
                        width: 100%;
                        height: 100%;
                        border: 4px solid var(--secondary-bg);
                        border-top-color: var(--accent-color);
                        border-radius: 50%;
                        animation: spin 1s linear infinite;
                        display: block;
                    }

                    @keyframes spin {
                        to { transform: rotate(360deg); }
                    }

                    /* Error Message */
                    .error-message {
                        position: absolute;
                        top: 50%;
                        left: 50%;
                        transform: translate(-50%, -50%);
                        background-color: var(--danger-color);
                        color: white;
                        padding: 1rem;
                        border-radius: var(--border-radius);
                        text-align: center;
                        max-width: 80%;
                        display: none;
                    }

                    /* Responsive Design */
                    @media (max-width: 768px) {
                        .viewer-container {
                            padding: 0.5rem;
                            gap: 0.5rem;
                        }

                        .viewer-header {
                            padding: 0.25rem 0.5rem;
                        }

                        .controls button {
                            padding: 0.35rem 0.7rem;
                            font-size: 0.75rem;
                        }

                        .nav-button {
                            width: 36px;
                            height: 36px;
                            font-size: 1.25rem;
                        }

                        .thumbnail {
                            width: 48px;
                            height: 48px;
                        }
                    }

                    /* Touch Device Optimizations */
                    @media (hover: none) {
                        .nav-button {
                            opacity: 1;
                            background-color: rgba(0, 0, 0, 0.3);
                        }
                    }
                </style>
            </head>
            <body>
                <div class="viewer-container">
                    <div class="viewer-header">
                        <div class="controls">
                            <button id="playPauseBtn">
                                <span class="icon">▶</span>
                                <span class="text">Slideshow</span>
                            </button>
                            <button id="downloadBtn">
                                <span class="icon">⬇</span>
                                <span class="text">Download</span>
                            </button>
                            <button id="zoomInBtn">
                                <span class="icon">+</span>
                                <span class="text">Zoom In</span>
                            </button>
                            <button id="zoomOutBtn">
                                <span class="icon">-</span>
                                <span class="text">Zoom Out</span>
                            </button>
                            <button id="resetBtn">
                                <span class="icon">↺</span>
                                <span class="text">Reset</span>
                            </button>
                        </div>
                        <button id="fullscreenBtn" class="fullscreen-btn">⛶</button>
                    </div>

                    <div class="viewer-main">
                        <img src="" alt="Main Image" class="main-image" id="mainImage">
                        <div class="loader" id="loader"></div>
                        <div class="error-message" id="errorMessage"></div>
                        <button class="nav-button prev-button" id="prevBtn">❮</button>
                        <button class="nav-button next-button" id="nextBtn">❯</button>
                    </div>

                    <div class="thumbnails" id="thumbnails"></div>
                </div>

                <script>
                    (function() {
                        // Configuration
                        const CONFIG = ${JSON.stringify(CONFIG)};
                        const imageUrls = ${JSON.stringify(imageUrls)};

                        // State Management using Proxy for reactivity
                        const state = new Proxy({
                            currentIndex: 0,
                            proxyIndex: 0,
                            isFullscreen: false,
                            isSlideshow: false,
                            slideshowInterval: null,
                            zoom: 1,
                            translateX: 0,
                            translateY: 0,
                            isPanning: false,
                            startX: 0,
                            startY: 0,
                            initialX: 0,
                            initialY: 0,
                            loadedImages: new Set(),
                            errorRetries: new Map(),
                            touchStartTime: 0,
                            touchStartX: 0,
                            lastTapTime: 0
                        }, {
                            set(target, property, value) {
                                const oldValue = target[property];
                                target[property] = value;
                                
                                // React to state changes
                                switch(property) {
                                    case 'currentIndex':
                                        handleIndexChange(oldValue, value);
                                        break;
                                    case 'zoom':
                                        handleZoomChange(value);
                                        break;
                                    case 'isSlideshow':
                                        updateSlideshowUI(value);
                                        break;
                                }
                                
                                return true;
                            }
                        });

                        // Cache Management
                        const imageCache = {
                            cache: new Map(),
                            maxSize: CONFIG.CACHE.MAX_SIZE,
                            expireTime: CONFIG.CACHE.EXPIRE_TIME,

                            set(key, value) {
                                if (this.cache.size >= this.maxSize) {
                                    const oldestKey = this.cache.keys().next().value;
                                    this.cache.delete(oldestKey);
                                }
                                this.cache.set(key, {
                                    value,
                                    timestamp: Date.now()
                                });
                            },

                            get(key) {
                                const entry = this.cache.get(key);
                                if (!entry) return null;
                                
                                if (Date.now() - entry.timestamp > this.expireTime) {
                                    this.cache.delete(key);
                                    return null;
                                }
                                
                                return entry.value;
                            },

                            clear() {
                                this.cache.clear();
                            }
                        };

                        // Element References
                        const elements = {
                            mainImage: document.getElementById('mainImage'),
                            loader: document.getElementById('loader'),
                            errorMessage: document.getElementById('errorMessage'),
                            playPauseBtn: document.getElementById('playPauseBtn'),
                            downloadBtn: document.getElementById('downloadBtn'),
                            zoomInBtn: document.getElementById('zoomInBtn'),
                            zoomOutBtn: document.getElementById('zoomOutBtn'),
                            resetBtn: document.getElementById('resetBtn'),
                            fullscreenBtn: document.getElementById('fullscreenBtn'),
                            prevBtn: document.getElementById('prevBtn'),
                            nextBtn: document.getElementById('nextBtn'),
                            thumbnails: document.getElementById('thumbnails'),
                            container: document.querySelector('.viewer-container')
                        };

                        // Utility Functions
                        const utils = {
                            debounce(func, wait) {
                                let timeout;
                                return function executedFunction(...args) {
                                    const later = () => {
                                        clearTimeout(timeout);
                                        func(...args);
                                    };
                                    clearTimeout(timeout);
                                    timeout = setTimeout(later, wait);
                                };
                            },

                            throttle(func, limit) {
                                let inThrottle;
                                return function executedFunction(...args) {
                                    if (!inThrottle) {
                                        func(...args);
                                        inThrottle = true;
                                        setTimeout(() => inThrottle = false, limit);
                                    }
                                };
                            },

                            clamp(value, min, max) {
                                return Math.min(Math.max(value, min), max);
                            },

                            getDistance(touch1, touch2) {
                                return Math.hypot(
                                    touch2.clientX - touch1.clientX,
                                    touch2.clientY - touch1.clientY
                                );
                            },

                            getMidpoint(touch1, touch2) {
                                return {
                                    x: (touch1.clientX + touch2.clientX) / 2,
                                    y: (touch1.clientY + touch2.clientY) / 2
                                };
                            }
                        };

                        // Image Loading and Management
                        async function loadImage(url, retryCount = 0) {
                            const cachedUrl = imageCache.get(url);
                            if (cachedUrl) return cachedUrl;

                            const maxRetries = 3;
                            try {
                                if (retryCount >= maxRetries) {
                                    throw new Error('Max retries exceeded');
                                }

                                // Try different CORS proxies
                                for (const proxy of CONFIG.CORS_PROXIES) {
                                    try {
                                        const proxiedUrl = proxy + encodeURIComponent(url);
                                        const response = await fetch(proxiedUrl, {
                                            method: 'HEAD',
                                            timeout: CONFIG.PRELOAD.TIMEOUT
                                        });
                                        
                                        if (response.ok) {
                                            imageCache.set(url, proxiedUrl);
                                            return proxiedUrl;
                                        }
                                    } catch (e) {
                                        continue;
                                    }
                                }

                                // If all proxies fail, retry with exponential backoff
                                const backoffDelay = Math.pow(2, retryCount) * 1000;
                                await new Promise(resolve => setTimeout(resolve, backoffDelay));
                                return loadImage(url, retryCount + 1);

                            } catch (error) {
                                console.error(`Failed to load image: ${url}`, error);
                                throw error;
                            }
                        }

                        // Image Display and Navigation
                        async function showImage(index, useTransition = true) {
                            if (index < 0 || index >= imageUrls.length) return;
                            
                            state.currentIndex = index;
                            updateThumbnails();
                            resetZoomAndPan();

                            elements.loader.style.display = 'block';
                            elements.errorMessage.style.display = 'none';
                            elements.mainImage.classList.remove('visible');

                            try {
                                const url = imageUrls[index];
                                const imgUrl = await loadImage(url);
                                
                                await new Promise((resolve, reject) => {
                                    const img = new Image();
                                    img.onload = resolve;
                                    img.onerror = reject;
                                    img.src = imgUrl;
                                });

                                elements.mainImage.src = imgUrl;
                                if (useTransition) {
                                    requestAnimationFrame(() => {
                                        elements.mainImage.classList.add('visible');
                                    });
                                } else {
                                    elements.mainImage.classList.add('visible');
                                }

                                preloadAdjacentImages();
                                updateNavButtons();

                            } catch (error) {
                                showError('Failed to load image. Please try again.');
                            } finally {
                                elements.loader.style.display = 'none';
                            }
                        }

                        // Error Handling
                        function showError(message) {
                            elements.errorMessage.textContent = message;
                            elements.errorMessage.style.display = 'block';
                            elements.loader.style.display = 'none';
                        }

                        // Navigation and Controls
                        function updateNavButtons() {
                            elements.prevBtn.style.display = state.currentIndex > 0 ? 'flex' : 'none';
                            elements.nextBtn.style.display = state.currentIndex < imageUrls.length - 1 ? 'flex' : 'none';
                        }

                        // Zoom and Pan Controls
                        function setZoom(newZoom, centerX = null, centerY = null) {
                            const oldZoom = state.zoom;
                            state.zoom = utils.clamp(newZoom, CONFIG.ZOOM.MIN, CONFIG.ZOOM.MAX);

                            if (centerX !== null && centerY !== null) {
                                // Adjust pan to keep the zoom centered on the mouse position
                                const rect = elements.mainImage.getBoundingClientRect();
                                const offsetX = (centerX - rect.left) / rect.width;
                                const offsetY = (centerY - rect.top) / rect.height;

                                state.translateX = (state.translateX * state.zoom / oldZoom) +
                                    (1 - state.zoom / oldZoom) * offsetX * rect.width;
                                state.translateY = (state.translateY * state.zoom / oldZoom) +
                                    (1 - state.zoom / oldZoom) * offsetY * rect.height;
                            }

                            updateTransform();
                        }

                        function updateTransform() {
                            elements.mainImage.style.transform = 
                                `scale(${state.zoom}) translate(${state.translateX}px, ${state.translateY}px)`;
                        }

                        function resetZoomAndPan() {
                            state.zoom = 1;
                            state.translateX = 0;
                            state.translateY = 0;
                            updateTransform();
                        }

                        // Event Handlers
                        function handleKeyboardEvents(e) {
                            switch(e.key) {
                                case 'ArrowLeft':
                                    if (state.currentIndex > 0) {
                                        showImage(state.currentIndex - 1);
                                    }
                                    break;
                                case 'ArrowRight':
                                    if (state.currentIndex < imageUrls.length - 1) {
                                        showImage(state.currentIndex + 1);
                                    }
                                    break;
                                case '+':
                                case '=':
                                    setZoom(state.zoom + CONFIG.ZOOM.STEP);
                                    break;
                                case '-':
                                    setZoom(state.zoom - CONFIG.ZOOM.STEP);
                                    break;
                                case '0':
                                    resetZoomAndPan();
                                    break;
                                case 'Escape':
                                    if (state.isFullscreen) {
                                        toggleFullscreen();
                                    }
                                    break;
                            }
                        }

                        // Touch Event Handlers
                        let initialTouchDistance = 0;
                        let initialZoom = 1;

                        function handleTouchStart(e) {
                            if (e.touches.length === 2) {
                                initialTouchDistance = utils.getDistance(e.touches[
]
v1: [ javascript:(function(){
    try {
        // Configuration Object
        const CONFIG = {
            MAX_IMAGES: 200, // Maximum number of images to extract
            CORS_PROXIES: [
                'https://corsproxy.io/?',
                'https://api.allorigins.win/raw?url=',
                'https://api.codetabs.com/v1/proxy?quest='
            ],
            SLIDESHOW: {
                DEFAULT_INTERVAL: 3 // seconds
            },
            PRELOAD: {
                ADJACENT: 2
            },
            ANIMATION: {
                DURATION: 300, // ms
                EASING: 'ease'
            }
        };

        // Prevent multiple instances
        if (window.ultimateImageViewerInstance) {
            window.ultimateImageViewerInstance.focus();
            return;
        }

        // Function to sanitize URLs and exclude SVGs
        function sanitizeURL(url) {
            try {
                const sanitized = new URL(url, window.location.href);
                // Allow only HTTP and HTTPS protocols
                if (!['http:', 'https:'].includes(sanitized.protocol)) {
                    return null;
                }
                // Exclude SVG images
                if (sanitized.pathname.endsWith('.svg') || sanitized.pathname.endsWith('.svgz')) {
                    return null;
                }
                return sanitized.href;
            } catch (e) {
                return null;
            }
        }

        // Function to gather image sources excluding SVGs
        function gatherImageSources() {
            const sources = new Set();

            // Extract from <img> tags
            const imgTags = document.querySelectorAll('img');
            imgTags.forEach(img => {
                ['src', 'data-src', 'data-large', 'data-original'].forEach(attr => {
                    const src = img.getAttribute(attr);
                    if (src) {
                        const sanitized = sanitizeURL(src);
                        if (sanitized) sources.add(sanitized);
                    }
                });
                // Also check if image is wrapped in a link
                const parentLink = img.closest('a[href]');
                if (parentLink) {
                    const href = parentLink.getAttribute('href');
                    if (href) {
                        const sanitizedLink = sanitizeURL(href);
                        if (sanitizedLink) sources.add(sanitizedLink);
                    }
                }
            });

            // Extract from CSS background images
            const elements = document.querySelectorAll('*');
            elements.forEach(el => {
                const bg = window.getComputedStyle(el).backgroundImage;
                if (bg && bg !== 'none') {
                    const matches = bg.match(/url\(["']?(.+?)["']?\)/);
                    if (matches && matches[1]) {
                        const url = matches[1];
                        const sanitized = sanitizeURL(url);
                        if (sanitized) sources.add(sanitized);
                    }
                }
            });

            // Extract from <source> tags (e.g., within <picture> elements)
            const sourceTags = document.querySelectorAll('source');
            sourceTags.forEach(source => {
                ['srcset', 'data-srcset'].forEach(attr => {
                    const srcset = source.getAttribute(attr);
                    if (srcset) {
                        srcset.split(',').forEach(part => {
                            const [url] = part.trim().split(' ');
                            const sanitized = sanitizeURL(url);
                            if (sanitized) sources.add(sanitized);
                        });
                    }
                });
            });

            // Convert to array and limit
            return Array.from(sources).slice(0, CONFIG.MAX_IMAGES);
        }

        const imageUrls = gatherImageSources();

        if (imageUrls.length === 0) {
            alert('No images found on this page.');
            return;
        }

        // Open viewer window
        const viewer = window.open('', '_blank', 'width=1200,height=800,scrollbars=no,resizable=yes');
        if (!viewer) {
            alert('Unable to open image viewer. Please allow popups for this website.');
            return;
        }

        window.ultimateImageViewerInstance = viewer;

        // HTML Content for viewer
        const viewerHTML = `
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>Image Viewer</title>
                <style>
                    /* Reset and Base Styles */
                    * {
                        margin: 0;
                        padding: 0;
                        box-sizing: border-box;
                    }
                    body, html {
                        width: 100%;
                        height: 100%;
                        overflow: hidden;
                        font-family: Arial, sans-serif;
                        background-color: #000;
                        color: #fff;
                    }
                    .viewer-container {
                        position: relative;
                        width: 100%;
                        height: 100%;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        background-color: #000;
                    }
                    .main-image {
                        max-width: 100%;
                        max-height: 100%;
                        object-fit: contain;
                        transition: transform ${CONFIG.ANIMATION.DURATION}ms ${CONFIG.ANIMATION.EASING}, opacity ${CONFIG.ANIMATION.DURATION}ms ${CONFIG.ANIMATION.EASING};
                        opacity: 0;
                        cursor: grab;
                    }
                    .main-image.visible {
                        opacity: 1;
                    }
                    .controls {
                        position: absolute;
                        top: 10px;
                        left: 50%;
                        transform: translateX(-50%);
                        display: flex;
                        gap: 10px;
                        background: rgba(0, 0, 0, 0.5);
                        padding: 10px;
                        border-radius: 5px;
                        z-index: 1000;
                    }
                    .controls button {
                        background: #333;
                        border: none;
                        color: #fff;
                        padding: 10px;
                        cursor: pointer;
                        border-radius: 3px;
                        transition: background 0.3s;
                        font-size: 14px;
                    }
                    .controls button:hover {
                        background: #555;
                    }
                    .thumbnails {
                        position: absolute;
                        bottom: 10px;
                        left: 50%;
                        transform: translateX(-50%);
                        display: flex;
                        gap: 5px;
                        overflow-x: auto;
                        max-width: 90%;
                        padding: 5px;
                        background: rgba(0, 0, 0, 0.5);
                        border-radius: 5px;
                        z-index: 1000;
                    }
                    .thumbnails img {
                        width: 60px;
                        height: 60px;
                        object-fit: cover;
                        cursor: pointer;
                        border: 2px solid transparent;
                        border-radius: 3px;
                        transition: border 0.3s;
                    }
                    .thumbnails img.active {
                        border: 2px solid #fff;
                    }
                    .nav-button {
                        position: absolute;
                        top: 50%;
                        transform: translateY(-50%);
                        background: rgba(0, 0, 0, 0.5);
                        border: none;
                        color: #fff;
                        padding: 15px;
                        cursor: pointer;
                        border-radius: 50%;
                        font-size: 18px;
                        transition: background 0.3s;
                        z-index: 1000;
                        display: none; /* Hidden by default */
                    }
                    .nav-button:hover {
                        background: rgba(0, 0, 0, 0.8);
                    }
                    .prev-button {
                        left: 20px;
                    }
                    .next-button {
                        right: 20px;
                    }
                    .loader {
                        position: absolute;
                        top: 50%;
                        left: 50%;
                        transform: translate(-50%, -50%);
                        border: 8px solid #f3f3f3;
                        border-top: 8px solid #555;
                        border-radius: 50%;
                        width: 60px;
                        height: 60px;
                        animation: spin 1s linear infinite;
                        z-index: 1000;
                        display: none;
                    }
                    @keyframes spin {
                        0% { transform: translate(-50%, -50%) rotate(0deg); }
                        100% { transform: translate(-50%, -50%) rotate(360deg); }
                    }
                    .fullscreen {
                        position: absolute;
                        top: 10px;
                        right: 10px;
                        background: rgba(0, 0, 0, 0.5);
                        border: none;
                        color: #fff;
                        padding: 10px;
                        cursor: pointer;
                        border-radius: 3px;
                        transition: background 0.3s;
                        z-index: 1000;
                        font-size: 14px;
                    }
                    .fullscreen:hover {
                        background: rgba(0, 0, 0, 0.8);
                    }
                    @media (max-width: 768px) {
                        .controls {
                            flex-direction: column;
                            top: auto;
                            bottom: 60px;
                        }
                        .nav-button {
                            padding: 10px;
                        }
                        .thumbnails img {
                            width: 40px;
                            height: 40px;
                        }
                        .controls button {
                            font-size: 12px;
                            padding: 8px;
                        }
                        .fullscreen {
                            padding: 8px;
                            font-size: 12px;
                        }
                    }
                </style>
            </head>
            <body>
                <div class="viewer-container">
                    <img src="" alt="Main Image" class="main-image" id="mainImage">
                    <div class="loader" id="loader"></div>
                    <button class="fullscreen" id="fullscreenBtn">⛶</button>
                    <div class="controls">
                        <button id="playPauseBtn">▶️ Slideshow</button>
                        <button id="downloadBtn">⬇️ Download</button>
                    </div>
                    <button class="nav-button prev-button" id="navPrev">❮</button>
                    <button class="nav-button next-button" id="navNext">❯</button>
                    <div class="thumbnails" id="thumbnails"></div>
                </div>
                <script>
                    (function() {
                        // Configuration inside viewer
                        const CONFIG = ${JSON.stringify(CONFIG)};
                        const imageUrls = ${JSON.stringify(imageUrls)};
                        
                        // State Management
                        const state = {
                            currentIndex: 0,
                            proxyIndex: 0,
                            isFullscreen: false,
                            isSlideshow: false,
                            slideshowInterval: null,
                            zoom: 1,
                            translateX: 0,
                            translateY: 0,
                            isPanning: false,
                            startX: 0,
                            startY: 0,
                            initialX: 0,
                            initialY: 0
                        };
    
                        // Element References
                        const mainImage = document.getElementById('mainImage');
                        const loader = document.getElementById('loader');
                        const playPauseBtn = document.getElementById('playPauseBtn');
                        const downloadBtn = document.getElementById('downloadBtn');
                        const navPrev = document.getElementById('navPrev');
                        const navNext = document.getElementById('navNext');
                        const thumbnailsContainer = document.getElementById('thumbnails');
                        const fullscreenBtn = document.getElementById('fullscreenBtn');
                        const viewerContainer = document.querySelector('.viewer-container');
    
                        // Image URL Cache
                        const imageCache = new Set();
    
                        // Initialize Viewer
                        function init() {
                            generateThumbnails();
                            showImage(state.currentIndex, false);
                            bindEvents();
                        }
    
                        // Generate Thumbnails
                        function generateThumbnails() {
                            imageUrls.forEach((url, index) => {
                                const img = document.createElement('img');
                                img.src = url;
                                img.alt = \`Image \${index + 1}\`;
                                img.addEventListener('click', () => {
                                    showImage(index);
                                });
                                thumbnailsContainer.appendChild(img);
                            });
                        }
    
                        // Show Image
                        async function showImage(index, useTransition = true) {
                            if (index < 0 || index >= imageUrls.length) return;
                            state.currentIndex = index;
                            updateActiveThumbnail();
    
                            const url = imageUrls[index];
                            loader.style.display = 'block';
                            mainImage.classList.remove('visible');
                            
                            try {
                                const imgUrl = await getImageUrl(url);
                                mainImage.src = imgUrl;
                                if (useTransition) {
                                    setTimeout(() => {
                                        mainImage.classList.add('visible');
                                    }, 50); // Slight delay for transition
                                } else {
                                    mainImage.classList.add('visible');
                                }
                                preloadAdjacentImages();
                            } catch (e) {
                                console.error('Image Load Error:', e);
                                alert('Failed to load image.');
                            } finally {
                                loader.style.display = 'none';
                            }
                        }
    
                        // Get Image URL using CORS Proxy
                        async function getImageUrl(url) {
                            // If already cached, return it directly
                            if (imageCache.has(url)) {
                                return url;
                            }
    
                            for (let i = 0; i < CONFIG.CORS_PROXIES.length; i++) {
                                const proxy = CONFIG.CORS_PROXIES[i];
                                const proxiedURL = proxy + encodeURIComponent(url);
                                try {
                                    // Check if the image can be fetched via proxy
                                    const response = await fetch(proxiedURL, { method: 'HEAD' });
                                    if (response.ok) {
                                        imageCache.add(url); // Cache the URL after successful proxy
                                        return proxiedURL;
                                    }
                                } catch (e) {
                                    // Continue to next proxy
                                    console.warn(\`Proxy \${proxy} failed for URL: \${url}\`);
                                }
                            }
    
                            throw new Error('All proxies failed to load the image.');
                        }
    
                        // Preload Adjacent Images (URLs only)
                        function preloadAdjacentImages() {
                            for (let i = 1; i <= CONFIG.PRELOAD.ADJACENT; i++) {
                                const nextIndex = (state.currentIndex + i) % imageUrls.length;
                                const prevIndex = (state.currentIndex - i + imageUrls.length) % imageUrls.length;
                                [nextIndex, prevIndex].forEach(index => {
                                    const url = imageUrls[index];
                                    getImageUrl(url).catch(() => {});
                                });
                            }
                        }
    
                        // Update Active Thumbnail
                        function updateActiveThumbnail() {
                            const thumbnails = thumbnailsContainer.querySelectorAll('img');
                            thumbnails.forEach((thumb, index) => {
                                thumb.classList.toggle('active', index === state.currentIndex);
                            });
                        }
    
                        // Bind Event Listeners
                        function bindEvents() {
                            // Slideshow Toggle
                            playPauseBtn.addEventListener('click', toggleSlideshow);
    
                            // Download Button
                            downloadBtn.addEventListener('click', downloadCurrentImage);
    
                            // Navigation Buttons (Hidden)
                            navPrev.style.display = 'none';
                            navNext.style.display = 'none';
    
                            // Click on Sides for Navigation
                            viewerContainer.addEventListener('click', function(e) {
                                const rect = mainImage.getBoundingClientRect();
                                const x = e.clientX - rect.left;
                                const midpoint = rect.width / 2;
                                const margin = 50; // Pixels from center to register navigation
                                if (x < midpoint - margin) { // Left side click
                                    showImage((state.currentIndex - 1 + imageUrls.length) % imageUrls.length);
                                } else if (x > midpoint + margin) { // Right side click
                                    showImage((state.currentIndex + 1) % imageUrls.length);
                                }
                                // Clicks near the center (within margin) do nothing to avoid conflict with panning
                            });
    
                            // Keyboard Navigation
                            document.addEventListener('keydown', (e) => {
                                switch(e.key) {
                                    case 'ArrowLeft':
                                        showImage((state.currentIndex - 1 + imageUrls.length) % imageUrls.length);
                                        break;
                                    case 'ArrowRight':
                                        showImage((state.currentIndex + 1) % imageUrls.length);
                                        break;
                                    case 'Escape':
                                        if (state.isFullscreen) toggleFullscreen();
                                        break;
                                }
                            });
    
                            // Mouse Wheel Zoom
                            mainImage.addEventListener('wheel', (e) => {
                                e.preventDefault();
                                const delta = e.deltaY > 0 ? -0.1 : 0.1;
                                setZoom(state.zoom + delta, e.clientX, e.clientY);
                            });
    
                            // Touch Gestures for Mobile
                            let touchStartDist = 0;
                            let initialZoom = 1;
    
                            viewer.document.addEventListener('touchstart', (e) => {
                                if (e.touches.length === 2) {
                                    touchStartDist = getDistance(e.touches[0], e.touches[1]);
                                    initialZoom = state.zoom;
                                }
                            });
    
                            viewer.document.addEventListener('touchmove', (e) => {
                                if (e.touches.length === 2) {
                                    const currentDist = getDistance(e.touches[0], e.touches[1]);
                                    const scale = currentDist / touchStartDist;
                                    setZoom(initialZoom * scale);
                                    e.preventDefault();
                                }
                            }, { passive: false });
    
                            // Panning
                            mainImage.addEventListener('mousedown', startPan);
                            document.addEventListener('mousemove', pan);
                            document.addEventListener('mouseup', endPan);
    
                            // Prevent image dragging
                            mainImage.addEventListener('dragstart', (e) => e.preventDefault());
                        }
    
                        // Calculate Distance Between Two Touches
                        function getDistance(touch1, touch2) {
                            const dx = touch1.clientX - touch2.clientX;
                            const dy = touch1.clientY - touch2.clientY;
                            return Math.hypot(dx, dy);
                        }
    
                        // Zoom Function
                        function setZoom(newZoom, centerX, centerY) {
                            state.zoom = Math.max(1, Math.min(CONFIG.ZOOM.MAX, newZoom)); // Prevent zooming out below 1
                            mainImage.style.transform = \`scale(\${state.zoom}) translate(\${state.translateX}px, \${state.translateY}px)\`;
                        }
    
                        // Panning Functions
                        function startPan(e) {
                            if (state.zoom <= 1) return;
                            state.isPanning = true;
                            state.startX = e.clientX;
                            state.startY = e.clientY;
                            state.initialX = state.translateX;
                            state.initialY = state.translateY;
                            mainImage.style.cursor = 'grabbing';
                        }
    
                        function pan(e) {
                            if (!state.isPanning) return;
                            const dx = e.clientX - state.startX;
                            const dy = e.clientY - state.startY;
                            state.translateX = state.initialX + dx;
                            state.translateY = state.initialY + dy;
                            mainImage.style.transform = \`scale(\${state.zoom}) translate(\${state.translateX}px, \${state.translateY}px)\`;
                        }
    
                        function endPan() {
                            state.isPanning = false;
                            mainImage.style.cursor = 'grab';
                        }
    
                        // Toggle Fullscreen
                        function toggleFullscreen() {
                            if (!state.isFullscreen) {
                                if (viewer.document.documentElement.requestFullscreen) {
                                    viewer.document.documentElement.requestFullscreen().catch(() => {});
                                } else if (viewer.document.documentElement.webkitRequestFullscreen) { /* Safari */
                                    viewer.document.documentElement.webkitRequestFullscreen();
                                } else if (viewer.document.documentElement.msRequestFullscreen) { /* IE11 */
                                    viewer.document.documentElement.msRequestFullscreen();
                                }
                                state.isFullscreen = true;
                                fullscreenBtn.textContent = '🡽';
                            } else {
                                if (viewer.document.fullscreenElement || viewer.document.webkitFullscreenElement || viewer.document.msFullscreenElement) {
                                    if (viewer.document.exitFullscreen) {
                                        viewer.document.exitFullscreen().catch(() => {});
                                    } else if (viewer.document.webkitExitFullscreen) { /* Safari */
                                        viewer.document.webkitExitFullscreen();
                                    } else if (viewer.document.msExitFullscreen) { /* IE11 */
                                        viewer.document.msExitFullscreen();
                                    }
                                }
                                state.isFullscreen = false;
                                fullscreenBtn.textContent = '⛶';
                            }
                        }
    
                        // Toggle Slideshow
                        function toggleSlideshow() {
                            if (state.isSlideshow) {
                                clearInterval(state.slideshowInterval);
                                state.slideshowInterval = null;
                                state.isSlideshow = false;
                                playPauseBtn.textContent = '▶️ Slideshow';
                            } else {
                                state.slideshowInterval = setInterval(() => {
                                    showImage((state.currentIndex + 1) % imageUrls.length);
                                }, CONFIG.SLIDESHOW.DEFAULT_INTERVAL * 1000);
                                state.isSlideshow = true;
                                playPauseBtn.textContent = '⏸️ Slideshow';
                            }
                        }
    
                        // Download Current Image
                        function downloadCurrentImage() {
                            const url = mainImage.src;
                            if (!url) {
                                alert('No image to download.');
                                return;
                            }
                            const link = document.createElement('a');
                            link.href = url;
                            link.download = \`image_\${state.currentIndex + 1}.jpg\`;
                            document.body.appendChild(link);
                            link.click();
                            document.body.removeChild(link);
                        }
    
                        // Initialize the viewer
                        init();
    
                        // Cleanup on Close
                        window.addEventListener('beforeunload', () => {
                            window.ultimateImageViewerInstance = null;
                        });
                    })();
                </script>
            </body>
            </html>
        `;

        // Write content to viewer
        viewer.document.open();
        viewer.document.write(viewerHTML);
        viewer.document.close();

    } catch (error) {
        console.error('Image Viewer Error:', error);
        alert('An error occurred while launching the image viewer.');
    }
})(); ]