Binance Red Packet Auto Claimer

Automatically extracts red packet codes from Telegram and claims them on Binance

Size

27.7 KB

Version

1.1.6

Created

Mar 20, 2026

Updated

25 days ago

1// ==UserScript==
2// @name		Binance Red Packet Auto Claimer
3// @description		Automatically extracts red packet codes from Telegram and claims them on Binance
4// @version		1.1.6
5// @match		https://*.web.telegram.org/*
6// @match		https://www.binance.com/*/my/wallet/account/payment/cryptobox
7// @icon		https://web.telegram.org/a/favicon.ico
8// @grant		GM.getValue
9// @grant		GM.setValue
10// @grant		GM.deleteValue
11// ==/UserScript==
12(function() {
13    'use strict';
14
15    console.log('Binance Red Packet Auto Claimer - Extension loaded');
16
17    // Utility function to wait for element
18    function waitForElement(selector, timeout = 10000) {
19        return new Promise((resolve, reject) => {
20            const element = document.querySelector(selector);
21            if (element) {
22                return resolve(element);
23            }
24
25            const observer = new MutationObserver((mutations, obs) => {
26                const element = document.querySelector(selector);
27                if (element) {
28                    obs.disconnect();
29                    resolve(element);
30                }
31            });
32
33            observer.observe(document.body, {
34                childList: true,
35                subtree: true
36            });
37
38            setTimeout(() => {
39                observer.disconnect();
40                reject(new Error(`Element ${selector} not found within ${timeout}ms`));
41            }, timeout);
42        });
43    }
44
45    // Utility function to delay
46    function delay(ms) {
47        return new Promise(resolve => setTimeout(resolve, ms));
48    }
49
50    // ==================== TELEGRAM FUNCTIONALITY ====================
51    async function extractCodesFromTelegram() {
52        console.log('Starting code extraction from Telegram...');
53        
54        // Find all code elements in messages - updated selector
55        const codeElements = document.querySelectorAll('code.monospace-text, code.text-entity-code[data-entity-type="MessageEntityCode"]');
56        console.log(`Found ${codeElements.length} code elements`);
57        
58        const codes = [];
59        const seen = new Set();
60        codeElements.forEach(codeEl => {
61            const code = codeEl.textContent.trim();
62            if (code && code.length > 0 && !seen.has(code)) {
63                seen.add(code);
64                codes.push(code);
65            }
66        });
67
68        console.log(`Extracted ${codes.length} red packet codes:`, codes);
69        
70        // Store codes in GM storage
71        if (codes.length > 0) {
72            await GM.setValue('redPacketCodes', JSON.stringify(codes));
73            console.log('Codes saved to storage');
74        }
75        
76        return codes;
77    }
78
79    async function scrollAndExtractAllCodes() {
80        console.log('Starting full extraction with scrolling...');
81        
82        const scrollableContainer = document.querySelector('.scrollable.scrollable-y');
83        if (!scrollableContainer) {
84            console.error('Scrollable container not found');
85            return await extractCodesFromTelegram();
86        }
87        
88        let previousCodeCount = 0;
89        let noNewCodesCount = 0;
90        const maxScrollAttempts = 50; // Maximum scroll attempts
91        let scrollAttempts = 0;
92        
93        while (scrollAttempts < maxScrollAttempts && noNewCodesCount < 3) {
94            // Scroll to top
95            scrollableContainer.scrollTop = 0;
96            await delay(1000); // Wait for messages to load
97            
98            // Extract current codes
99            const codeElements = document.querySelectorAll('code.monospace-text, code.text-entity-code[data-entity-type="MessageEntityCode"]');
100            const currentCodeCount = codeElements.length;
101            
102            console.log(`Scroll attempt ${scrollAttempts + 1}: Found ${currentCodeCount} code elements`);
103            
104            // Check if we found new codes
105            if (currentCodeCount === previousCodeCount) {
106                noNewCodesCount++;
107                console.log(`No new codes found (${noNewCodesCount}/3)`);
108            } else {
109                noNewCodesCount = 0;
110                previousCodeCount = currentCodeCount;
111            }
112            
113            scrollAttempts++;
114        }
115        
116        console.log(`Finished scrolling after ${scrollAttempts} attempts`);
117        
118        // Final extraction
119        return await extractCodesFromTelegram();
120    }
121
122    async function setupTelegramExtractor() {
123        console.log('Setting up Telegram code extractor...');
124        
125        // Create control panel
126        const controlPanel = document.createElement('div');
127        controlPanel.id = 'telegram-extractor-panel';
128        controlPanel.style.cssText = `
129            position: fixed;
130            top: 80px;
131            right: 20px;
132            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
133            color: white;
134            padding: 20px;
135            border-radius: 12px;
136            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
137            z-index: 10000;
138            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
139            min-width: 280px;
140            backdrop-filter: blur(10px);
141        `;
142        
143        controlPanel.innerHTML = `
144            <div style="font-size: 16px; font-weight: bold; margin-bottom: 15px; display: flex; align-items: center; gap: 8px;">
145                <span style="font-size: 20px;">🎁</span>
146                Red Packet Extractor
147            </div>
148            <div style="font-size: 13px; margin-bottom: 15px; opacity: 0.9; line-height: 1.4;">
149                Extract codes from all your groups
150            </div>
151            <div id="codes-count" style="font-size: 14px; margin-bottom: 15px; padding: 10px; background: rgba(255,255,255,0.2); border-radius: 8px; text-align: center;">
152                <span style="font-size: 24px; font-weight: bold;" id="count-number">0</span>
153                <div style="font-size: 12px; margin-top: 4px; opacity: 0.9;">codes found</div>
154            </div>
155            <div id="group-progress" style="font-size: 12px; margin-bottom: 15px; padding: 8px; background: rgba(255,255,255,0.15); border-radius: 6px; text-align: center; display: none;">
156                <div id="group-progress-text">Processing groups...</div>
157            </div>
158            <button id="extract-all-btn" style="
159                width: 100%;
160                padding: 12px;
161                background: white;
162                color: #667eea;
163                border: none;
164                border-radius: 8px;
165                font-weight: bold;
166                cursor: pointer;
167                font-size: 14px;
168                transition: all 0.3s;
169                margin-bottom: 10px;
170            ">Extract From All Groups</button>
171            <button id="extract-btn" style="
172                width: 100%;
173                padding: 12px;
174                background: rgba(255,255,255,0.2);
175                color: white;
176                border: 1px solid rgba(255,255,255,0.3);
177                border-radius: 8px;
178                font-weight: 500;
179                cursor: pointer;
180                font-size: 13px;
181                transition: all 0.3s;
182                margin-bottom: 10px;
183            ">Extract Current Group Only</button>
184            <button id="clear-codes-btn" style="
185                width: 100%;
186                padding: 10px;
187                background: rgba(255,255,255,0.2);
188                color: white;
189                border: 1px solid rgba(255,255,255,0.3);
190                border-radius: 8px;
191                font-weight: 500;
192                cursor: pointer;
193                font-size: 13px;
194                transition: all 0.3s;
195            ">Clear Stored Codes</button>
196            <div id="status-message" style="font-size: 12px; margin-top: 12px; padding: 8px; background: rgba(255,255,255,0.15); border-radius: 6px; text-align: center; display: none;"></div>
197        `;
198        
199        document.body.appendChild(controlPanel);
200        
201        // Add hover effects
202        const extractAllBtn = document.getElementById('extract-all-btn');
203        const extractBtn = document.getElementById('extract-btn');
204        const clearBtn = document.getElementById('clear-codes-btn');
205        
206        extractAllBtn.addEventListener('mouseenter', () => {
207            extractAllBtn.style.transform = 'translateY(-2px)';
208            extractAllBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.2)';
209        });
210        extractAllBtn.addEventListener('mouseleave', () => {
211            extractAllBtn.style.transform = 'translateY(0)';
212            extractAllBtn.style.boxShadow = 'none';
213        });
214        
215        extractBtn.addEventListener('mouseenter', () => {
216            extractBtn.style.transform = 'translateY(-2px)';
217            extractBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.2)';
218        });
219        extractBtn.addEventListener('mouseleave', () => {
220            extractBtn.style.transform = 'translateY(0)';
221            extractBtn.style.boxShadow = 'none';
222        });
223        
224        clearBtn.addEventListener('mouseenter', () => {
225            clearBtn.style.background = 'rgba(255,255,255,0.3)';
226        });
227        clearBtn.addEventListener('mouseleave', () => {
228            clearBtn.style.background = 'rgba(255,255,255,0.2)';
229        });
230        
231        // Update count on load
232        const storedCodes = await GM.getValue('redPacketCodes', '[]');
233        const codes = JSON.parse(storedCodes);
234        document.getElementById('count-number').textContent = codes.length;
235        
236        // Extract from all groups button handler
237        extractAllBtn.addEventListener('click', async () => {
238            extractAllBtn.disabled = true;
239            extractAllBtn.textContent = 'Extracting...';
240            
241            const groupProgress = document.getElementById('group-progress');
242            const groupProgressText = document.getElementById('group-progress-text');
243            groupProgress.style.display = 'block';
244            
245            try {
246                // Get all chat items from sidebar
247                const chatItems = document.querySelectorAll('.chatlist-chat');
248                console.log(`Found ${chatItems.length} chats in sidebar`);
249                
250                groupProgressText.textContent = `Found ${chatItems.length} groups. Starting extraction...`;
251                await delay(1000);
252                
253                // Store all codes from all groups
254                let allCodes = new Set();
255                
256                // Get existing codes
257                const existingCodes = await GM.getValue('redPacketCodes', '[]');
258                const existingCodesArray = JSON.parse(existingCodes);
259                existingCodesArray.forEach(code => allCodes.add(code));
260                
261                for (let i = 0; i < chatItems.length; i++) {
262                    const chatItem = chatItems[i];
263                    groupProgressText.textContent = `Processing group ${i + 1}/${chatItems.length}...`;
264                    
265                    // Click on the chat to open it
266                    chatItem.click();
267                    await delay(2000); // Wait for chat to load
268                    
269                    // Extract codes from this group
270                    const codes = await scrollAndExtractAllCodes();
271                    codes.forEach(code => allCodes.add(code));
272                    
273                    // Update count
274                    document.getElementById('count-number').textContent = allCodes.size;
275                    groupProgressText.textContent = `Group ${i + 1}/${chatItems.length}: Found ${codes.length} codes (Total: ${allCodes.size})`;
276                    
277                    console.log(`Extracted ${codes.length} codes from group ${i + 1}. Total unique codes: ${allCodes.size}`);
278                }
279                
280                // Save all codes
281                await GM.setValue('redPacketCodes', JSON.stringify(Array.from(allCodes)));
282                
283                const statusMsg = document.getElementById('status-message');
284                statusMsg.style.display = 'block';
285                statusMsg.style.background = 'rgba(76, 175, 80, 0.3)';
286                statusMsg.textContent = `✓ Extracted ${allCodes.size} total codes from ${chatItems.length} groups!`;
287                
288                groupProgress.style.display = 'none';
289                
290                setTimeout(() => {
291                    statusMsg.style.display = 'none';
292                }, 5000);
293            } catch (error) {
294                console.error('Error extracting codes from all groups:', error);
295                const statusMsg = document.getElementById('status-message');
296                statusMsg.style.display = 'block';
297                statusMsg.style.background = 'rgba(244, 67, 54, 0.3)';
298                statusMsg.textContent = '✗ Error extracting codes';
299                groupProgress.style.display = 'none';
300            } finally {
301                extractAllBtn.disabled = false;
302                extractAllBtn.textContent = 'Extract From All Groups';
303            }
304        });
305        
306        // Extract button handler (current group only)
307        extractBtn.addEventListener('click', async () => {
308            extractBtn.disabled = true;
309            extractBtn.textContent = 'Extracting...';
310            
311            try {
312                const codes = await scrollAndExtractAllCodes();
313                document.getElementById('count-number').textContent = codes.length;
314                
315                const statusMsg = document.getElementById('status-message');
316                statusMsg.style.display = 'block';
317                statusMsg.style.background = 'rgba(76, 175, 80, 0.3)';
318                statusMsg.textContent = `✓ Extracted ${codes.length} codes successfully!`;
319                
320                setTimeout(() => {
321                    statusMsg.style.display = 'none';
322                }, 3000);
323            } catch (error) {
324                console.error('Error extracting codes:', error);
325                const statusMsg = document.getElementById('status-message');
326                statusMsg.style.display = 'block';
327                statusMsg.style.background = 'rgba(244, 67, 54, 0.3)';
328                statusMsg.textContent = '✗ Error extracting codes';
329            } finally {
330                extractBtn.disabled = false;
331                extractBtn.textContent = 'Extract Current Group Only';
332            }
333        });
334        
335        // Clear button handler
336        clearBtn.addEventListener('click', async () => {
337            await GM.setValue('redPacketCodes', '[]');
338            await GM.deleteValue('currentCodeIndex');
339            document.getElementById('count-number').textContent = '0';
340            
341            const statusMsg = document.getElementById('status-message');
342            statusMsg.style.display = 'block';
343            statusMsg.style.background = 'rgba(255, 152, 0, 0.3)';
344            statusMsg.textContent = '✓ All codes cleared';
345            
346            setTimeout(() => {
347                statusMsg.style.display = 'none';
348            }, 2000);
349        });
350        
351        // Auto-extract on page load
352        await delay(2000);
353        console.log('Auto-extracting codes on page load...');
354        const extractedCodes = await scrollAndExtractAllCodes();
355        document.getElementById('count-number').textContent = extractedCodes.length;
356    }
357
358    // ==================== BINANCE FUNCTIONALITY ====================
359    async function claimRedPacketOnBinance() {
360        console.log('Starting Binance red packet claiming process...');
361        
362        // Get stored codes
363        const storedCodes = await GM.getValue('redPacketCodes', '[]');
364        const codes = JSON.parse(storedCodes);
365        
366        if (codes.length === 0) {
367            console.log('No codes available to claim');
368            return { success: false, message: 'No codes available' };
369        }
370        
371        // Get current index
372        let currentIndex = await GM.getValue('currentCodeIndex', 0);
373        
374        if (currentIndex >= codes.length) {
375            console.log('All codes have been processed');
376            return { success: false, message: 'All codes claimed' };
377        }
378        
379        const currentCode = codes[currentIndex];
380        console.log(`Claiming code ${currentIndex + 1}/${codes.length}: ${currentCode}`);
381        
382        try {
383            // Find input field
384            const input = document.querySelector('input[placeholder="Enter red packet code"]');
385            if (!input) {
386                throw new Error('Input field not found');
387            }
388            
389            // Clear and enter code
390            input.value = '';
391            input.focus();
392            input.value = currentCode;
393            
394            // Trigger input event to enable the button
395            input.dispatchEvent(new Event('input', { bubbles: true }));
396            input.dispatchEvent(new Event('change', { bubbles: true }));
397            
398            console.log('Code entered into input field');
399            await delay(500);
400            
401            // Find and click Claim button
402            const claimButton = Array.from(document.querySelectorAll('button')).find(btn => 
403                btn.textContent.trim() === 'Claim' && 
404                !btn.classList.contains('inactive') &&
405                btn.getAttribute('aria-disabled') !== 'true'
406            );
407            
408            if (!claimButton) {
409                throw new Error('Claim button not found or not enabled');
410            }
411            
412            console.log('Clicking Claim button...');
413            claimButton.click();
414            
415            // Wait for popup to appear
416            await delay(2000);
417            
418            // Look for "Open" button in popup
419            const openButton = Array.from(document.querySelectorAll('button')).find(btn => 
420                btn.textContent.trim() === 'Open'
421            );
422            
423            if (openButton) {
424                console.log('Found Open button, clicking...');
425                openButton.click();
426                await delay(2000);
427                
428                // Look for close button (X button)
429                const closeButton = document.querySelector('button[aria-label="Close"], button.bn-modal-close, button[class*="close"]');
430                if (closeButton) {
431                    console.log('Found close button, clicking...');
432                    closeButton.click();
433                    await delay(1000);
434                }
435            }
436            
437            // Move to next code
438            currentIndex++;
439            await GM.setValue('currentCodeIndex', currentIndex);
440            
441            console.log(`Successfully processed code. Moving to next (${currentIndex}/${codes.length})`);
442            return { success: true, message: `Claimed ${currentIndex}/${codes.length}`, currentIndex, total: codes.length };
443            
444        } catch (error) {
445            console.error('Error claiming red packet:', error);
446            // Still move to next code even if there's an error
447            currentIndex++;
448            await GM.setValue('currentCodeIndex', currentIndex);
449            return { success: false, message: error.message, currentIndex, total: codes.length };
450        }
451    }
452
453    async function setupBinanceClaimer() {
454        console.log('Setting up Binance auto claimer...');
455        
456        // Create control panel
457        const controlPanel = document.createElement('div');
458        controlPanel.id = 'binance-claimer-panel';
459        controlPanel.style.cssText = `
460            position: fixed;
461            top: 80px;
462            right: 20px;
463            background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
464            color: white;
465            padding: 20px;
466            border-radius: 12px;
467            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
468            z-index: 10000;
469            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
470            min-width: 300px;
471            backdrop-filter: blur(10px);
472        `;
473        
474        controlPanel.innerHTML = `
475            <div style="font-size: 16px; font-weight: bold; margin-bottom: 15px; display: flex; align-items: center; gap: 8px;">
476                <span style="font-size: 20px;">🎁</span>
477                Auto Claimer
478            </div>
479            <div style="font-size: 13px; margin-bottom: 15px; opacity: 0.9; line-height: 1.4;">
480                Automatically claim red packets one by one
481            </div>
482            <div id="progress-info" style="font-size: 14px; margin-bottom: 15px; padding: 12px; background: rgba(255,255,255,0.2); border-radius: 8px;">
483                <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
484                    <span>Progress:</span>
485                    <span id="progress-text" style="font-weight: bold;">0/0</span>
486                </div>
487                <div style="width: 100%; height: 8px; background: rgba(255,255,255,0.3); border-radius: 4px; overflow: hidden;">
488                    <div id="progress-bar" style="width: 0%; height: 100%; background: white; transition: width 0.3s;"></div>
489                </div>
490            </div>
491            <button id="start-claiming-btn" style="
492                width: 100%;
493                padding: 12px;
494                background: white;
495                color: #f5576c;
496                border: none;
497                border-radius: 8px;
498                font-weight: bold;
499                cursor: pointer;
500                font-size: 14px;
501                transition: all 0.3s;
502                margin-bottom: 10px;
503            ">Start Auto Claiming</button>
504            <button id="stop-claiming-btn" style="
505                width: 100%;
506                padding: 10px;
507                background: rgba(255,255,255,0.2);
508                color: white;
509                border: 1px solid rgba(255,255,255,0.3);
510                border-radius: 8px;
511                font-weight: 500;
512                cursor: pointer;
513                font-size: 13px;
514                transition: all 0.3s;
515                display: none;
516            ">Stop Claiming</button>
517            <button id="reset-progress-btn" style="
518                width: 100%;
519                padding: 10px;
520                background: rgba(255,255,255,0.2);
521                color: white;
522                border: 1px solid rgba(255,255,255,0.3);
523                border-radius: 8px;
524                font-weight: 500;
525                cursor: pointer;
526                font-size: 13px;
527                transition: all 0.3s;
528            ">Reset Progress</button>
529            <div id="claim-status" style="font-size: 12px; margin-top: 12px; padding: 8px; background: rgba(255,255,255,0.15); border-radius: 6px; text-align: center; display: none;"></div>
530        `;
531        
532        document.body.appendChild(controlPanel);
533        
534        let isClaimingActive = false;
535        let claimingInterval = null;
536        
537        const startBtn = document.getElementById('start-claiming-btn');
538        const stopBtn = document.getElementById('stop-claiming-btn');
539        const resetBtn = document.getElementById('reset-progress-btn');
540        const progressText = document.getElementById('progress-text');
541        const progressBar = document.getElementById('progress-bar');
542        const statusDiv = document.getElementById('claim-status');
543        
544        // Add hover effects
545        startBtn.addEventListener('mouseenter', () => {
546            startBtn.style.transform = 'translateY(-2px)';
547            startBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.2)';
548        });
549        startBtn.addEventListener('mouseleave', () => {
550            startBtn.style.transform = 'translateY(0)';
551            startBtn.style.boxShadow = 'none';
552        });
553        
554        // Update progress display
555        async function updateProgress() {
556            const storedCodes = await GM.getValue('redPacketCodes', '[]');
557            const codes = JSON.parse(storedCodes);
558            const currentIndex = await GM.getValue('currentCodeIndex', 0);
559            
560            progressText.textContent = `${currentIndex}/${codes.length}`;
561            const percentage = codes.length > 0 ? (currentIndex / codes.length) * 100 : 0;
562            progressBar.style.width = `${percentage}%`;
563        }
564        
565        // Initial progress update
566        await updateProgress();
567        
568        // Start claiming
569        startBtn.addEventListener('click', async () => {
570            isClaimingActive = true;
571            startBtn.style.display = 'none';
572            stopBtn.style.display = 'block';
573            resetBtn.disabled = true;
574            resetBtn.style.opacity = '0.5';
575            
576            statusDiv.style.display = 'block';
577            statusDiv.style.background = 'rgba(33, 150, 243, 0.3)';
578            statusDiv.textContent = '⏳ Auto claiming started...';
579            
580            // Claim immediately, then set interval
581            async function claimNext() {
582                if (!isClaimingActive) return;
583                
584                const result = await claimRedPacketOnBinance();
585                await updateProgress();
586                
587                if (result.success) {
588                    statusDiv.style.background = 'rgba(76, 175, 80, 0.3)';
589                    statusDiv.textContent = `${result.message}`;
590                } else {
591                    if (result.message === 'All codes claimed') {
592                        statusDiv.style.background = 'rgba(255, 152, 0, 0.3)';
593                        statusDiv.textContent = '✓ All codes have been claimed!';
594                        isClaimingActive = false;
595                        startBtn.style.display = 'block';
596                        stopBtn.style.display = 'none';
597                        resetBtn.disabled = false;
598                        resetBtn.style.opacity = '1';
599                        if (claimingInterval) clearInterval(claimingInterval);
600                    } else {
601                        statusDiv.style.background = 'rgba(244, 67, 54, 0.3)';
602                        statusDiv.textContent = `⚠ Error: ${result.message}`;
603                    }
604                }
605            }
606            
607            await claimNext();
608            claimingInterval = setInterval(claimNext, 5000); // Claim every 5 seconds
609        });
610        
611        // Stop claiming
612        stopBtn.addEventListener('click', () => {
613            isClaimingActive = false;
614            if (claimingInterval) {
615                clearInterval(claimingInterval);
616                claimingInterval = null;
617            }
618            startBtn.style.display = 'block';
619            stopBtn.style.display = 'none';
620            resetBtn.disabled = false;
621            resetBtn.style.opacity = '1';
622            
623            statusDiv.style.background = 'rgba(255, 152, 0, 0.3)';
624            statusDiv.textContent = '⏸ Claiming stopped';
625        });
626        
627        // Reset progress
628        resetBtn.addEventListener('click', async () => {
629            await GM.deleteValue('currentCodeIndex');
630            await updateProgress();
631            
632            statusDiv.style.display = 'block';
633            statusDiv.style.background = 'rgba(255, 152, 0, 0.3)';
634            statusDiv.textContent = '✓ Progress reset';
635            
636            setTimeout(() => {
637                statusDiv.style.display = 'none';
638            }, 2000);
639        });
640    }
641
642    // ==================== INITIALIZATION ====================
643    async function init() {
644        console.log('Initializing extension...');
645        console.log('Current URL:', window.location.href);
646        
647        // Wait for page to be ready
648        await delay(1500);
649        
650        if (window.location.href.includes('web.telegram.org')) {
651            console.log('Running on Telegram');
652            await setupTelegramExtractor();
653        } else if (window.location.href.includes('binance.com') && window.location.href.includes('/my/wallet/account/payment/cryptobox')) {
654            console.log('Running on Binance');
655            await setupBinanceClaimer();
656        }
657    }
658
659    // Start the extension
660    if (document.readyState === 'loading') {
661        document.addEventListener('DOMContentLoaded', init);
662    } else {
663        init();
664    }
665})();