您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
轻量级全局顶置画中画功能,支持大多数视频网站和直播平台
// ==UserScript== // @name 轻量级画中画扩展 // @version 2.0.2 // @description 轻量级全局顶置画中画功能,支持大多数视频网站和直播平台 // @author 嘉友友 // @match *://*/* // @license GPL-3.0 // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @icon data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE5IDdINVYxN0gxM1YxNUg3VjlIMTdWMTFIMTlWN1oiIGZpbGw9IiMwMDAwMDAiLz4KPHBhdGggZD0iTTE1IDEzVjE3SDE5VjEzSDE1WiIgZmlsbD0iIzAwMDAwMCIvPgo8L3N2Zz4K // @namespace https://greasyfork.org/users/1336389 // ==/UserScript== (function() { 'use strict'; // 检查浏览器支持 if (!document.pictureInPictureEnabled) { console.warn('画中画功能不被当前浏览器支持'); return; } // 全局状态管理 const State = { isProcessed: false, observer: null, currentPipVideo: null, floatingButton: null, isDragging: false, hideTimeout: null, animationFrame: null, isVisible: false, documentVisible: true, styleElement: null, currentNotification: null, cleanupTasks: new Set() }; // 常量配置 const CONFIG = { STORAGE_KEY: 'pip_button_global_position', DEFAULT_POSITION: { right: -30, top: 20, side: 'right' }, VIDEO_CACHE_SIZE: 50, POSITION_CACHE_SIZE: 30, DEBOUNCE_DELAY: 300, THROTTLE_DELAY: 200, CHECK_INTERVAL: 2000, CACHE_TIMEOUT: 1000, DRAG_THRESHOLD: 5, MIN_VIDEO_SIZE: 100, HIDE_DELAY: 2000, NOTIFICATION_DURATION: 3000 }; // 工具函数库 const Utils = { debounce(func, wait) { let timeout; const debounced = function executedFunction(...args) { if (timeout) clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), wait); }; debounced.cancel = () => timeout && clearTimeout(timeout); return debounced; }, throttle(func, wait) { let lastTime = 0; return function executedFunction(...args) { const now = performance.now(); if (now - lastTime >= wait) { lastTime = now; return func.apply(this, args); } }; }, rafThrottle(func) { let ticking = false; return function(...args) { if (!ticking) { ticking = true; requestAnimationFrame(() => { func.apply(this, args); ticking = false; }); } }; }, createLRUCache(maxSize) { const cache = new Map(); return { get(key) { if (cache.has(key)) { const value = cache.get(key); cache.delete(key); cache.set(key, value); return value; } return null; }, set(key, value) { if (cache.has(key)) { cache.delete(key); } else if (cache.size >= maxSize) { const firstKey = cache.keys().next().value; cache.delete(firstKey); } cache.set(key, value); }, has(key) { return cache.has(key); }, clear() { cache.clear(); } }; }, scheduleIdleTask(task, timeout = CONFIG.CHECK_INTERVAL) { if (typeof requestIdleCallback === 'function') { return requestIdleCallback(task, { timeout }); } else { return setTimeout(task, Math.min(timeout, 100)); } } }; // 缓存管理器 const CacheManager = { _videoCache: new WeakMap(), _positionCache: Utils.createLRUCache(CONFIG.POSITION_CACHE_SIZE), _lastCleanup: 0, _cleanupInterval: 30000, cacheVideoResult(video, isValid) { this._videoCache.set(video, { isValid, timestamp: performance.now() }); }, getCachedVideoResult(video) { const cached = this._videoCache.get(video); if (cached && (performance.now() - cached.timestamp) < CONFIG.CACHE_TIMEOUT) { return cached.isValid; } return null; }, cachePosition(key, position) { this._positionCache.set(key, position); }, getCachedPosition(key) { return this._positionCache.get(key); }, cleanup() { const now = performance.now(); if (now - this._lastCleanup > this._cleanupInterval) { this._positionCache.clear(); this._lastCleanup = now; } } }; // 视频检测器 const VideoDetector = { _lastQueryTime: 0, _cachedVideos: null, _visibleVideos: new Set(), isValidVideo(video) { if (!video || video.tagName !== 'VIDEO' || !video.isConnected) { return false; } // 检查缓存 const cached = CacheManager.getCachedVideoResult(video); if (cached !== null) { return cached; } // 执行检查 const isValid = this._checkVideoValidity(video); CacheManager.cacheVideoResult(video, isValid); return isValid; }, _checkVideoValidity(video) { // 检查视频源 if (!video.src && !video.srcObject && !video.currentSrc && !video.querySelector('source')) { return false; } // 检查样式 const style = getComputedStyle(video); if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') { return false; } // 检查尺寸 const rect = video.getBoundingClientRect(); return rect.width >= CONFIG.MIN_VIDEO_SIZE && rect.height >= CONFIG.MIN_VIDEO_SIZE; }, getAllVideos() { const now = performance.now(); // 使用缓存结果 if (this._cachedVideos && (now - this._lastQueryTime) < CONFIG.CACHE_TIMEOUT) { return this._cachedVideos.filter(v => v.isConnected); } // 查找所有视频元素 const allVideos = Array.from(document.querySelectorAll('video')); const videos = allVideos.filter(video => this.isValidVideo(video)); this._cachedVideos = videos; this._lastQueryTime = now; console.log('找到视频数量:', videos.length); return videos; }, getCurrentVideo() { if (State.currentPipVideo && this.isValidVideo(State.currentPipVideo)) { return State.currentPipVideo; } const videos = this.getAllVideos(); if (videos.length === 0) return null; // 优先返回正在播放的视频 for (const video of videos) { if (!video.paused && !video.ended) { return video; } } // 其次返回有时长的视频 for (const video of videos) { if (video.duration && video.duration !== Infinity) { return video; } } return videos[0] || null; }, cleanup() { this._visibleVideos.clear(); } }; // 全局位置管理器 const PositionManager = { _cache: null, _lastViewport: { width: 0, height: 0 }, save(position) { this._cache = position; try { const data = JSON.stringify(position); if (typeof GM_setValue !== 'undefined') { GM_setValue(CONFIG.STORAGE_KEY, data); } else { localStorage.setItem(CONFIG.STORAGE_KEY, data); } } catch (e) { console.warn('位置保存失败:', e); } }, load() { if (this._cache) return this._cache; try { let stored = null; if (typeof GM_getValue !== 'undefined') { stored = GM_getValue(CONFIG.STORAGE_KEY, null); } if (!stored && typeof localStorage !== 'undefined') { stored = localStorage.getItem(CONFIG.STORAGE_KEY); if (stored && typeof GM_setValue !== 'undefined') { this.save(JSON.parse(stored)); localStorage.removeItem(CONFIG.STORAGE_KEY); } } if (stored) { const position = typeof stored === 'string' ? JSON.parse(stored) : stored; this._cache = this.validatePosition(position); return this._cache; } } catch (e) { console.warn('位置加载失败:', e); } this._cache = CONFIG.DEFAULT_POSITION; return this._cache; }, validatePosition(position) { const viewport = { width: window.innerWidth, height: window.innerHeight }; const cacheKey = `${position.top}-${position.side}-${position.left || position.right}-${viewport.width}-${viewport.height}`; // 检查缓存 if (this._viewportUnchanged(viewport)) { const cached = CacheManager.getCachedPosition(cacheKey); if (cached) return cached; } // 计算有效位置 const maxX = viewport.width - 50; const maxY = viewport.height - 50; const validatedPosition = { top: Math.max(10, Math.min(position.top || 20, maxY)), side: position.side || 'right' }; if (position.side === 'right') { validatedPosition.right = Math.max(-30, Math.min(position.right || -30, maxX)); } else { validatedPosition.left = Math.max(-30, Math.min(position.left || -30, maxX)); } // 缓存结果 CacheManager.cachePosition(cacheKey, validatedPosition); this._lastViewport = viewport; return validatedPosition; }, _viewportUnchanged(viewport) { return viewport.width === this._lastViewport.width && viewport.height === this._lastViewport.height; }, reset() { this._cache = null; try { if (typeof GM_deleteValue !== 'undefined') { GM_deleteValue(CONFIG.STORAGE_KEY); } if (typeof localStorage !== 'undefined') { localStorage.removeItem(CONFIG.STORAGE_KEY); } } catch (e) { console.warn('位置重置失败:', e); } } }; // 样式管理器 const StyleManager = { create() { if (State.styleElement) return; State.styleElement = document.createElement('style'); State.styleElement.textContent = ` #floating-pip-button { position: fixed; z-index: 99999; background: rgba(0,0,0,0.8); color: white; border: none; border-radius: 50%; width: 50px; height: 50px; font-size: 20px; cursor: move; display: block; font-family: monospace; box-shadow: 0 2px 10px rgba(0,0,0,0.3); user-select: none; -webkit-user-select: none; backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px); transition: opacity 0.3s ease, transform 0.3s ease, right 0.3s ease, left 0.3s ease; will-change: transform, opacity, right, left; opacity: 0.6; transform: scale(0.8); touch-action: none; contain: layout style paint; } #floating-pip-button:hover { opacity: 1; transform: scale(1); } #pip-notification { position: fixed; top: 80px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.9); color: white; padding: 12px 20px; border-radius: 6px; z-index: 100000; font-size: 14px; pointer-events: none; box-shadow: 0 4px 12px rgba(0,0,0,0.3); backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px); animation: slideDown 0.3s ease; contain: layout style paint; } @keyframes slideDown { from { opacity: 0; transform: translateX(-50%) translateY(-20px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } } `; document.head.appendChild(State.styleElement); }, cleanup() { if (State.styleElement?.parentNode) { State.styleElement.remove(); State.styleElement = null; } } }; // 事件管理器 const EventManager = { _handlers: new Map(), init() { // 统一的事件委托 this.addHandler(document, 'mouseenter', this._handleDelegatedEvent, { passive: true, capture: true }); this.addHandler(document, 'mouseleave', this._handleDelegatedEvent, { passive: true, capture: true }); this.addHandler(document, 'contextmenu', this._handleDelegatedEvent, { passive: false, capture: true }); this.addHandler(document, 'keydown', this._handleKeyPress, { passive: false }); this.addHandler(document, 'enterpictureinpicture', this._handlePipChange, { passive: true }); this.addHandler(document, 'leavepictureinpicture', this._handlePipChange, { passive: true }); this.addHandler(document, 'visibilitychange', this._handleVisibilityChange, { passive: true }); this.addHandler(window, 'resize', Utils.throttle(this._handleResize, CONFIG.THROTTLE_DELAY), { passive: true }); this.addHandler(window, 'beforeunload', this._handleBeforeUnload, { passive: true, once: true }); }, addHandler(target, event, handler, options = {}) { target.addEventListener(event, handler, options); if (!this._handlers.has(target)) { this._handlers.set(target, []); } this._handlers.get(target).push({ event, handler, options }); }, _handleDelegatedEvent(e) { if (e.target.id === 'floating-pip-button') { switch(e.type) { case 'mouseenter': ButtonController.show(); break; case 'mouseleave': ButtonController.scheduleHide(); break; case 'contextmenu': e.preventDefault(); ButtonController.resetPosition(); break; } } }, _handleKeyPress(e) { if (e.key.toLowerCase() === 'p' && (e.ctrlKey || e.altKey)) { e.preventDefault(); const video = VideoDetector.getCurrentVideo(); if (video) { PipController.toggle(video); } else { NotificationManager.show('未找到可用的视频元素'); } } if (e.key.toLowerCase() === 'r' && e.ctrlKey && e.altKey && e.shiftKey) { e.preventDefault(); ButtonController.resetPosition(); } }, _handlePipChange() { ButtonController.updatePipState(); }, _handleVisibilityChange() { State.documentVisible = !document.hidden; if (State.documentVisible) { VideoManager.startDetection(); } else { VideoManager.stopDetection(); } }, _handleResize() { if (State.floatingButton) { ButtonController.adjustPosition(); } }, _handleBeforeUnload() { cleanup(); }, cleanup() { for (const [target, handlers] of this._handlers) { for (const { event, handler } of handlers) { target.removeEventListener(event, handler); } } this._handlers.clear(); } }; // 按钮控制器 const ButtonController = { create() { const button = document.createElement('button'); button.innerHTML = '⧉'; button.title = '画中画模式 (快捷键: Ctrl/Alt + P)\n右键重置位置'; button.id = 'floating-pip-button'; this.applyStoredPosition(button); this.setupDrag(button); return button; }, applyStoredPosition(button) { const position = PositionManager.load(); const styles = { top: position.top + 'px' }; if (position.side === 'right') { styles.right = position.right + 'px'; styles.left = 'auto'; } else { styles.left = position.left + 'px'; styles.right = 'auto'; } Object.assign(button.style, styles); const isAttached = (position.side === 'right' && position.right <= 0) || (position.side === 'left' && position.left <= 0); if (!isAttached) { button.style.opacity = '1'; button.style.transform = 'scale(1)'; State.isVisible = true; this.scheduleHide(); } }, setupDrag(button) { let startX, startY, initialX, initialY; button.addEventListener('mousedown', handleMouseDown, { passive: false }); function handleMouseDown(e) { if (e.button !== 0) return; startX = e.clientX; startY = e.clientY; const rect = button.getBoundingClientRect(); initialX = rect.left; initialY = rect.top; const handleMouseMove = Utils.rafThrottle(handleDrag); function handleDrag(e) { const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; if (!State.isDragging && (Math.abs(deltaX) > CONFIG.DRAG_THRESHOLD || Math.abs(deltaY) > CONFIG.DRAG_THRESHOLD)) { State.isDragging = true; button.style.cursor = 'grabbing'; button.style.transition = 'opacity 0.3s ease, transform 0.3s ease'; ButtonController.show(); } if (State.isDragging) { const newX = Math.max(0, Math.min(initialX + deltaX, window.innerWidth - 50)); const newY = Math.max(0, Math.min(initialY + deltaY, window.innerHeight - 50)); Object.assign(button.style, { left: newX + 'px', top: newY + 'px', right: 'auto' }); } } function handleMouseUp() { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); if (State.isDragging) { ButtonController.snapToEdgeAndSave(); State.isDragging = false; button.style.cursor = 'move'; button.style.transition = 'opacity 0.3s ease, transform 0.3s ease, right 0.3s ease, left 0.3s ease'; ButtonController.scheduleHide(); } else { PipController.toggle(VideoDetector.getCurrentVideo()); } } document.addEventListener('mousemove', handleMouseMove, { passive: false }); document.addEventListener('mouseup', handleMouseUp, { passive: true }); e.preventDefault(); } }, show() { if (!State.floatingButton || State.isVisible) return; clearTimeout(State.hideTimeout); if (State.animationFrame) { cancelAnimationFrame(State.animationFrame); } State.animationFrame = requestAnimationFrame(() => { const rect = State.floatingButton.getBoundingClientRect(); const isAtRightEdge = rect.right >= window.innerWidth - 5; const isAtLeftEdge = rect.left <= 5; const styles = { opacity: '1', transform: 'scale(1)' }; if (isAtRightEdge || State.floatingButton.style.right.includes('-')) { styles.right = '10px'; styles.left = 'auto'; } else if (isAtLeftEdge || State.floatingButton.style.left.includes('-')) { styles.left = '10px'; styles.right = 'auto'; } Object.assign(State.floatingButton.style, styles); State.isVisible = true; }); }, hide() { if (!State.floatingButton || State.isDragging || !State.isVisible) return; if (State.animationFrame) { cancelAnimationFrame(State.animationFrame); } State.animationFrame = requestAnimationFrame(() => { const rect = State.floatingButton.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const isCloserToRight = centerX > window.innerWidth / 2; const styles = { opacity: '0.6', transform: 'scale(0.8)' }; if (isCloserToRight) { styles.right = '-30px'; styles.left = 'auto'; } else { styles.left = '-30px'; styles.right = 'auto'; } Object.assign(State.floatingButton.style, styles); State.isVisible = false; }); }, scheduleHide: Utils.debounce(() => ButtonController.hide(), CONFIG.HIDE_DELAY), snapToEdgeAndSave() { if (!State.floatingButton) return; const rect = State.floatingButton.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const isCloserToRight = centerX > window.innerWidth / 2; const maxTop = window.innerHeight - 60; const newTop = Math.max(10, Math.min(rect.top, maxTop)); let position; const styles = { top: newTop + 'px', opacity: '0.6', transform: 'scale(0.8)' }; if (isCloserToRight) { styles.right = '-30px'; styles.left = 'auto'; position = { right: -30, top: newTop, side: 'right' }; } else { styles.left = '-30px'; styles.right = 'auto'; position = { left: -30, top: newTop, side: 'left' }; } Object.assign(State.floatingButton.style, styles); State.isVisible = false; PositionManager.save(position); }, adjustPosition() { PositionManager._cache = null; const position = PositionManager.load(); const validatedPosition = PositionManager.validatePosition(position); const styles = { top: validatedPosition.top + 'px' }; if (validatedPosition.side === 'right') { styles.right = validatedPosition.right + 'px'; styles.left = 'auto'; } else { styles.left = validatedPosition.left + 'px'; styles.right = 'auto'; } Object.assign(State.floatingButton.style, styles); PositionManager.save(validatedPosition); }, resetPosition() { if (!State.floatingButton) return; PositionManager.reset(); this.applyStoredPosition(State.floatingButton); NotificationManager.show('按钮位置已重置到吸附状态'); this.show(); setTimeout(() => this.scheduleHide(), CONFIG.HIDE_DELAY); }, updatePipState() { const pipElement = document.pictureInPictureElement; if (!pipElement) { State.currentPipVideo = null; } if (State.floatingButton) { State.floatingButton.style.background = pipElement ? 'rgba(33,150,243,0.8)' : 'rgba(0,0,0,0.8)'; State.floatingButton.title = pipElement ? '退出画中画模式 (快捷键: Ctrl/Alt + P)\n右键重置位置' : '画中画模式 (快捷键: Ctrl/Alt + P)\n右键重置位置'; } } }; // 画中画控制器 const PipController = { async toggle(video) { try { if (document.pictureInPictureElement) { await document.exitPictureInPicture(); NotificationManager.show('已退出画中画模式'); } else if (video && !video.disablePictureInPicture) { if (video.readyState === 0) { NotificationManager.show('视频正在加载中,请稍后再试'); return; } await video.requestPictureInPicture(); State.currentPipVideo = video; NotificationManager.show('已开启画中画模式'); } else { NotificationManager.show('未找到可用的视频'); } } catch (error) { const errorMessages = { 'InvalidStateError': '视频暂时无法使用画中画功能', 'NotSupportedError': '该视频不支持画中画功能', 'NotAllowedError': '画中画功能被禁用,请检查浏览器设置' }; NotificationManager.show(errorMessages[error.name] || '画中画功能暂不可用'); } } }; // 通知管理器 const NotificationManager = { show(message) { if (State.currentNotification) { State.currentNotification.textContent = message; State.currentNotification.style.animation = 'none'; State.currentNotification.offsetHeight; State.currentNotification.style.animation = 'slideDown 0.3s ease'; } else { State.currentNotification = document.createElement('div'); State.currentNotification.id = 'pip-notification'; State.currentNotification.textContent = message; document.body.appendChild(State.currentNotification); } setTimeout(() => { if (State.currentNotification?.parentNode) { State.currentNotification.style.opacity = '0'; State.currentNotification.style.transition = 'opacity 0.3s ease'; setTimeout(() => { if (State.currentNotification?.parentNode) { State.currentNotification.remove(); State.currentNotification = null; } }, 300); } }, CONFIG.NOTIFICATION_DURATION); } }; // 视频管理器 const VideoManager = { _checkTask: null, startDetection() { this.detectVideos(); this._scheduleNextCheck(); }, stopDetection() { if (this._checkTask) { if (typeof this._checkTask === 'number') { clearTimeout(this._checkTask); } else { if (typeof cancelIdleCallback === 'function') { cancelIdleCallback(this._checkTask); } } this._checkTask = null; } }, _scheduleNextCheck() { if (!State.documentVisible) return; this._checkTask = Utils.scheduleIdleTask(() => { if (State.documentVisible) { this.detectVideos(); this._scheduleNextCheck(); } }, CONFIG.CHECK_INTERVAL); }, detectVideos: Utils.debounce(() => { if (!State.documentVisible) return; const videos = VideoDetector.getAllVideos(); const hasVideo = videos.length > 0; console.log('检测到视频:', hasVideo, '按钮存在:', !!State.floatingButton); if (hasVideo !== !!State.floatingButton) { if (hasVideo && !State.floatingButton) { console.log('创建按钮'); StyleManager.create(); State.floatingButton = ButtonController.create(); document.body.appendChild(State.floatingButton); } else if (!hasVideo && State.floatingButton) { console.log('移除按钮'); State.floatingButton.remove(); State.floatingButton = null; State.isVisible = false; } } // 清理缓存 CacheManager.cleanup(); }, CONFIG.DEBOUNCE_DELAY) }; // DOM观察器 const DOMObserver = { init() { const callback = Utils.debounce((mutations) => { if (!State.documentVisible) return; let shouldCheck = false; for (const mutation of mutations) { if (mutation.type === 'childList') { for (const node of mutation.addedNodes) { if (node.nodeType === 1) { if (node.tagName === 'VIDEO') { shouldCheck = true; break; } else if (node.tagName === 'IFRAME' || (node.querySelector && node.querySelector('video'))) { shouldCheck = true; break; } } } } if (shouldCheck) break; } if (shouldCheck) { console.log('DOM变化触发视频检测'); VideoManager.detectVideos(); } }, 500); State.observer = new MutationObserver(callback); State.observer.observe(document.documentElement, { childList: true, subtree: true, attributes: false, attributeOldValue: false }); }, cleanup() { if (State.observer) { State.observer.disconnect(); State.observer = null; } } }; // 清理函数 function cleanup() { clearTimeout(State.hideTimeout); if (State.animationFrame) { cancelAnimationFrame(State.animationFrame); } VideoDetector.cleanup(); VideoManager.stopDetection(); DOMObserver.cleanup(); EventManager.cleanup(); StyleManager.cleanup(); if (State.floatingButton?.parentNode) { State.floatingButton.remove(); } if (State.currentNotification?.parentNode) { State.currentNotification.remove(); } for (const task of State.cleanupTasks) { try { task(); } catch (e) { console.warn('清理任务失败:', e); } } State.cleanupTasks.clear(); Object.assign(State, { isProcessed: false, observer: null, currentPipVideo: null, floatingButton: null, isDragging: false, hideTimeout: null, animationFrame: null, isVisible: false, documentVisible: true, styleElement: null, currentNotification: null }); } // 初始化函数 function initialize() { if (State.isProcessed) return; State.isProcessed = true; try { console.log('初始化画中画扩展'); EventManager.init(); DOMObserver.init(); // 延迟开始检测,确保页面加载完成 setTimeout(() => { VideoManager.startDetection(); }, 1000); console.log('画中画扩展初始化完成'); } catch (error) { console.error('画中画扩展初始化失败:', error); cleanup(); } } // 启动脚本 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialize, { once: true }); } else { // 确保 DOM 完全准备好 setTimeout(initialize, 100); } })();