@realvare/baileys 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.MD CHANGED
@@ -53,7 +53,6 @@
53
53
  - [Text with Formatting](#text-with-formatting)
54
54
  - [Basic Media](#basic-media)
55
55
  - [Advanced Media](#advanced-media)
56
- - [Stickers](#stickers)
57
56
  - [Sticker Packs](#sticker-packs)
58
57
  - [Stickers on Status (2025 Feature)](#stickers-on-status-2025-feature)
59
58
  - [Interactive Messages](#interactive-messages)
@@ -76,7 +75,6 @@
76
75
  - [Status Quoted Messages](#status-quoted-messages)
77
76
  - [Status Sticker Interaction Messages](#status-sticker-interaction-messages)
78
77
  - [AI Rich Response Messages](#ai-rich-response-messages)
79
- - [New Interactive Features (2025)](#new-interactive-features-2025)
80
78
  - [Other Messages](#other-messages)
81
79
  - [Business Call Messages (BCall)](#business-call-messages-bcall)
82
80
  - [Call Log Messages](#call-log-messages)
@@ -100,12 +98,14 @@
100
98
  - [Secret Encrypted Messages](#secret-encrypted-messages)
101
99
  - [Status Notification Messages](#status-notification-messages)
102
100
  - [Sticker Sync RMR Messages](#sticker-sync-rmr-messages)
101
+ - [Request Payment](#request-payment)
103
102
  - [Send Payment](#send-payment)
104
103
  - [Decline Payment Request](#decline-payment-request)
105
104
  - [Cancel Payment Request](#cancel-payment-request)
106
105
  - [Scheduled Call Creation](#scheduled-call-creation)
107
106
  - [Scheduled Call Edit](#scheduled-call-edit)
108
107
  - [Pin/Unpin Messages](#pinunpin-messages)
108
+ - [Response Management](#response-management)
109
109
  - [🎭 Group Features](#-group-features)
110
110
  - [Basic Group Management](#basic-group-management)
111
111
  - [Participant Management](#participant-management)
@@ -113,15 +113,12 @@
113
113
  - [Advanced Group Messages](#advanced-group-messages)
114
114
  - [🔧 Fix LID/JID in Your Own Main and Handler](#-fix-lidjid-in-your-own-main-and-handler)
115
115
  - [Best Practices for LID/JID](#best-practices-for-lidjid)
116
- - [Integrated Example in Main](#integrated-example-in-main)
117
- - [Custom Handler Example](#custom-handler-example)
116
+ - [Integrated Example](#integrated-example)
118
117
  - [🚀 Smart LID/JID Cache](#-smart-lidjid-cache)
119
118
  - [🛡️ Advanced JID Validation](#️-advanced-jid-validation)
120
119
  - [📊 Conditional Logging](#-conditional-logging)
121
120
  - [🔧 Performance Configuration](#-performance-configuration)
122
- - [🧩 Events: LID and JID always available (new)](#-events-lid-and-jid-always-available-new)
123
- - [Gestione dei Messaggi (`messages.upsert`)](#gestione-dei-messaggi-messagesupsert)
124
- - [Gestione dei Partecipanti di Gruppo (`group-participants.update`)](#gestione-dei-partecipanti-di-gruppo-group-participantsupdate)
121
+ - [🧩 Events: LID and JID Management](#-events-lid-and-jid-management)
125
122
  - [⚙️ Advanced Configuration](#️-advanced-configuration)
126
123
  - [🔧 Complete Options for makeWASocket](#-complete-options-for-makewasocket)
127
124
  - [🛡️ Security and Encryption](#️-security-and-encryption)
@@ -225,26 +222,11 @@ const isValid = isValidJid('1234567890@s.whatsapp.net');
225
222
  ### 🎛️ Usage Example
226
223
 
227
224
  ```javascript
228
- const { makeWASocket, useMultiFileAuthState, setPerformanceConfig, PerformanceConfig } = require('@realvare/baileys');
225
+ const { makeWASocket, useMultiFileAuthState } = require('@realvare/baileys');
229
226
 
230
227
  // Set up authentication
231
228
  const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys');
232
229
 
233
- // Configure performance settings
234
- const performanceConfig = new PerformanceConfig();
235
-
236
- // Customize settings (optional)
237
- performanceConfig.updatePerformanceConfig({
238
- batchSize: 50,
239
- maxRetries: 5,
240
- retryDelay: 5000,
241
- retryBackoffMultiplier: 1.5,
242
- syncFullHistory: false
243
- });
244
-
245
- // Apply configuration
246
- setPerformanceConfig(performanceConfig);
247
-
248
230
  // Create socket
249
231
  const sock = makeWASocket({
250
232
  auth: state,
@@ -302,19 +284,7 @@ This library, based on Baileys with specific improvements, offers an intuitive A
302
284
  ### Basic Example - Starting Bot
303
285
 
304
286
  ```typescript
305
- import makeWASocket, { DisconnectReason, useMultiFileAuthState, getPerformanceConfig, setPerformanceConfig } from '@realvare/baileys';
306
-
307
- // Configure performance and cache
308
- setPerformanceConfig({
309
- performance: {
310
- enableCache: true,
311
- enableMetrics: true
312
- },
313
- debug: {
314
- enableLidLogging: true,
315
- logLevel: 'info'
316
- }
317
- });
287
+ import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@realvare/baileys';
318
288
 
319
289
  async function startBot() {
320
290
  // 🔐 Multi-file authentication setup for persistent sessions
@@ -330,7 +300,10 @@ async function startBot() {
330
300
 
331
301
  // Improved reconnection system
332
302
  let reconnectAttempts = 0;
333
- const config = getPerformanceConfig();
303
+ const maxRetries = 5;
304
+ const retryDelay = 5000;
305
+ const retryBackoffMultiplier = 1.5;
306
+ const maxRetryDelay = 60000;
334
307
 
335
308
  sock.ev.on('connection.update', (update) => {
336
309
  const { connection, lastDisconnect } = update;
@@ -341,16 +314,16 @@ async function startBot() {
341
314
  if (shouldReconnect) {
342
315
  reconnectAttempts++;
343
316
  const delay = Math.min(
344
- config.performance.retryDelay * Math.pow(
345
- config.performance.retryBackoffMultiplier,
317
+ retryDelay * Math.pow(
318
+ retryBackoffMultiplier,
346
319
  reconnectAttempts - 1
347
320
  ),
348
- config.performance.maxRetryDelay
321
+ maxRetryDelay
349
322
  );
350
323
 
351
- console.log(`🔄 Reconnection attempt ${reconnectAttempts}/${config.performance.maxRetries} in ${delay}ms`);
324
+ console.log(`🔄 Reconnection attempt ${reconnectAttempts}/${maxRetries} in ${delay}ms`);
352
325
 
353
- if (reconnectAttempts <= config.performance.maxRetries) {
326
+ if (reconnectAttempts <= maxRetries) {
354
327
  setTimeout(startBot, delay);
355
328
  } else {
356
329
  console.log('❌ Maximum number of reconnection attempts reached');
@@ -369,21 +342,7 @@ async function startBot() {
369
342
  ### Anti-Ban Example - Recommended Configuration to Avoid Bans
370
343
 
371
344
  ```typescript
372
- import makeWASocket, { DisconnectReason, useMultiFileAuthState, getPerformanceConfig, setPerformanceConfig, getSenderLid, validateJid } from '@realvare/baileys';
373
-
374
- // Anti-ban configuration to reduce ban risks from improper acks
375
- setPerformanceConfig({
376
- performance: {
377
- enableCache: true, // Enable TTL cache to reduce API calls
378
- enableMetrics: true, // Monitor performance to avoid overload
379
- batchSize: 50, // Process messages in smaller batches to simulate human speed
380
- maxRetries: 5, // Limit retry attempts to avoid aggressive behavior
381
- retryDelay: 5000, // Base delay in ms for reconnections
382
- retryBackoffMultiplier: 1.5,// Exponential backoff to space retries
383
- maxRetryDelay: 60000, // Maximum delay to avoid rapid reconnections
384
- maxMsgRetryCount: 3 // Limit message resend attempts
385
- }
386
- });
345
+ import makeWASocket, { DisconnectReason, useMultiFileAuthState, getSenderLid, validateJid } from '@realvare/baileys';
387
346
 
388
347
  async function startBot() {
389
348
  const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys');
@@ -398,7 +357,10 @@ async function startBot() {
398
357
  });
399
358
 
400
359
  let reconnectAttempts = 0;
401
- const config = getPerformanceConfig();
360
+ const maxRetries = 5;
361
+ const retryDelay = 5000;
362
+ const retryBackoffMultiplier = 1.5;
363
+ const maxRetryDelay = 60000;
402
364
 
403
365
  sock.ev.on('connection.update', (update) => {
404
366
  const { connection, lastDisconnect } = update;
@@ -409,14 +371,14 @@ async function startBot() {
409
371
  if (shouldReconnect) {
410
372
  reconnectAttempts++;
411
373
  const delay = Math.min(
412
- config.performance.retryDelay * Math.pow(
413
- config.performance.retryBackoffMultiplier,
374
+ retryDelay * Math.pow(
375
+ retryBackoffMultiplier,
414
376
  reconnectAttempts - 1
415
377
  ),
416
- config.performance.maxRetryDelay
378
+ maxRetryDelay
417
379
  );
418
380
 
419
- console.log(`Reconnecting attempt ${reconnectAttempts}/${config.performance.maxRetries} in ${delay}ms`);
381
+ console.log(`Reconnecting attempt ${reconnectAttempts}/${maxRetries} in ${delay}ms`);
420
382
 
421
383
  if (reconnectAttempts <= config.performance.maxRetries) {
422
384
  setTimeout(startBot, delay);
@@ -483,21 +445,19 @@ console.log('Cache statistics:', stats);
483
445
 
484
446
  ### Advanced Cache Configuration
485
447
 
486
- The cache can be configured with various options to optimize performance:
448
+ The cache is pre-configured with optimal settings for production use:
487
449
 
488
450
  ```typescript
489
- setPerformanceConfig({
490
- cache: {
491
- lidCache: {
492
- ttl: 5 * 60 * 1000, // Entry lifetime
493
- maxSize: 10000, // Maximum number of entries
494
- cleanupInterval: 2 * 60 * 1000 // Cleanup interval
495
- }
496
- },
497
- performance: {
498
- memoryThreshold: 0.85 // Threshold for automatic cleanup
499
- }
500
- });
451
+ import { CacheManager } from '@realvare/baileys';
452
+
453
+ // Cache is automatically configured with:
454
+ // - lidCache: 5 minutes TTL, 10000 max entries
455
+ // - jidCache: 5 minutes TTL, 10000 max entries
456
+ // - Automatic cleanup and memory management
457
+
458
+ // Monitor cache performance
459
+ const stats = CacheManager.getStats('lidCache');
460
+ console.log('Cache statistics:', stats);
501
461
  ```
502
462
  ## 🔍 Troubleshooting
503
463
 
@@ -513,13 +473,12 @@ setPerformanceConfig({
513
473
 
514
474
  ### Advanced Logging
515
475
  ```typescript
516
- setPerformanceConfig({
517
- debug: {
518
- enableLidLogging: true,
519
- enablePerformanceLogging: true,
520
- logLevel: 'debug'
521
- }
522
- });
476
+ import { Logger } from '@realvare/baileys';
477
+
478
+ // Use the built-in Logger for conditional logging
479
+ Logger.debug('Debug info');
480
+ Logger.performance('Performance metrics');
481
+ Logger.error('Error occurred');
523
482
  ```
524
483
 
525
484
  ### Basic Message Management with LID/JID
@@ -575,7 +534,6 @@ This section expands on the main methods, with detailed examples and parameters.
575
534
  | `validateJid(jid)` | **Validation**: Verifies JID | ✅ Included |
576
535
  | `getCacheStats()` | **Performance**: Cache statistics | ✅ Included |
577
536
  | `clearCache()` | **Cleanup**: Clears cache | ✅ Included |
578
- | `setPerformanceConfig(config)` | **Config**: Customizes performance | ✅ Included |
579
537
 
580
538
  **🔥 Note**: All the above methods are **ready to use** and shown in the Quick Guide. Go directly to the advanced sections for specific features!
581
539
 
@@ -1996,18 +1954,9 @@ conn.ev.on('messages.upsert', async ({ messages }) => {
1996
1954
  The library now includes an advanced cache system to optimize LID/JID conversions:
1997
1955
 
1998
1956
  ```typescript
1999
- import { getCacheStats, clearCache, setPerformanceConfig } from '@realvare/baileys';
2000
-
2001
- // Configure custom cache
2002
- setPerformanceConfig({
2003
- cache: {
2004
- lidCache: {
2005
- ttl: 10 * 60 * 1000, // 10 minutes
2006
- maxSize: 15000
2007
- }
2008
- }
2009
- });
1957
+ import { getCacheStats, clearCache, CacheManager } from '@realvare/baileys';
2010
1958
 
1959
+ // Cache is pre-configured with optimal settings
2011
1960
  // Monitor performance
2012
1961
  const stats = getCacheStats();
2013
1962
  console.log('LID Cache:', stats.lidCache.size, '/', stats.lidCache.maxSize);
@@ -2034,18 +1983,9 @@ if (validation.isValid) {
2034
1983
  ### 📊 Conditional Logging
2035
1984
 
2036
1985
  ```typescript
2037
- import { Logger, setPerformanceConfig } from '@realvare/baileys';
1986
+ import { Logger } from '@realvare/baileys';
2038
1987
 
2039
- // Configure logging
2040
- setPerformanceConfig({
2041
- debug: {
2042
- enableLidLogging: true,
2043
- enablePerformanceLogging: true,
2044
- logLevel: 'debug' // 'error', 'warn', 'info', 'debug'
2045
- }
2046
- });
2047
-
2048
- // Use conditional logger
1988
+ // Use the built-in Logger for conditional logging
2049
1989
  Logger.debug('Debug info');
2050
1990
  Logger.performance('Performance metrics');
2051
1991
  Logger.error('Error occurred');
@@ -2053,30 +1993,20 @@ Logger.error('Error occurred');
2053
1993
 
2054
1994
  ### 🔧 Performance Configuration
2055
1995
 
1996
+ The library comes pre-configured with optimal settings. Cache and logging are automatically managed:
1997
+
2056
1998
  ```typescript
2057
- import { setPerformanceConfig, getPerformanceConfig } from '@realvare/baileys';
1999
+ import { CacheManager, Logger, getCacheStats } from '@realvare/baileys';
2058
2000
 
2059
- // Complete configuration
2060
- setPerformanceConfig({
2061
- performance: {
2062
- enableCache: true,
2063
- enableMetrics: true,
2064
- batchSize: 100,
2065
- maxRetries: 3
2066
- },
2067
- cache: {
2068
- lidCache: { ttl: 5 * 60 * 1000, maxSize: 10000 },
2069
- jidCache: { ttl: 5 * 60 * 1000, maxSize: 10000 }
2070
- },
2071
- debug: {
2072
- enableLidLogging: false,
2073
- logLevel: 'warn'
2074
- }
2075
- });
2001
+ // Cache is automatically configured and managed
2002
+ // Monitor cache performance
2003
+ const stats = getCacheStats();
2004
+ console.log('Cache enabled: true');
2005
+ console.log('LID Cache:', stats.lidCache.size, '/', stats.lidCache.maxSize);
2076
2006
 
2077
- // Get current configuration
2078
- const config = getPerformanceConfig();
2079
- console.log('Cache enabled:', config.performance.enableCache);
2007
+ // Use Logger for conditional logging
2008
+ Logger.debug('Debug info');
2009
+ Logger.error('Error occurred');
2080
2010
  ```
2081
2011
 
2082
2012
  ---
@@ -6,7 +6,6 @@ const Types_1 = require("../Types");
6
6
  const Utils_1 = require("../Utils");
7
7
  const WABinary_1 = require("../WABinary");
8
8
  const chats_1 = require("./chats");
9
- const { getPerformanceConfig } = require('../Utils/performance-config');
10
9
  const { CacheManager } = require('../Utils/cache-manager');
11
10
  const makeGroupsSocket = (config) => {
12
11
  const sock = (0, chats_1.makeChatsSocket)(config);
@@ -24,8 +23,6 @@ const makeGroupsSocket = (config) => {
24
23
  content
25
24
  }));
26
25
  const groupMetadata = async (jid) => {
27
- const config = getPerformanceConfig();
28
-
29
26
  const forbiddenUntil = forbiddenGroupMetadataUntil.get(jid);
30
27
  if (forbiddenUntil && forbiddenUntil > Date.now()) {
31
28
  const err = new Error('forbidden');
@@ -54,30 +51,29 @@ const makeGroupsSocket = (config) => {
54
51
  let retryCount = 0;
55
52
  const maxRetries = 3;
56
53
  const baseDelay = 1000; // 1 second
57
-
54
+
58
55
  while (retryCount <= maxRetries) {
59
56
  try {
60
57
  const result = await groupQuery(jid, 'get', [{ tag: 'query', attrs: { request: 'interactive' } }]);
61
58
  const metadata = (0, exports.extractGroupMetadata)(result);
62
59
 
63
- // Cache the result
64
- CacheManager.set('groupMetadataCache', jid, metadata, config.cache.groupMetadataCache.ttl);
60
+ // Cache the result (default TTL: 5 minutes)
61
+ CacheManager.set('groupMetadataCache', jid, metadata, 5 * 60 * 1000);
65
62
 
66
63
  return metadata;
67
64
  } catch (error) {
68
65
  const statusCode = error?.output?.statusCode || error?.data;
69
66
  if (statusCode === 403 || error?.message === 'forbidden') {
70
- const cooldownMs = 5 * 60 * 1000;
67
+ const cooldownMs = 30 * 1000;
71
68
  forbiddenGroupMetadataUntil.set(jid, Date.now() + cooldownMs);
72
69
  throw error;
73
70
  }
74
71
  if (error.message === 'rate-overlimit' && retryCount < maxRetries) {
75
- const delay = baseDelay * Math.pow(2, retryCount); // Exponential backoff
72
+ const delay = baseDelay * Math.pow(2, retryCount);
76
73
  config.logger?.warn({ jid, retryCount, delay }, 'Rate limit hit, retrying group metadata fetch');
77
74
  await new Promise(resolve => setTimeout(resolve, delay));
78
75
  retryCount++;
79
76
  } else {
80
- // Re-throw non-rate-limit errors or if max retries exceeded
81
77
  throw error;
82
78
  }
83
79
  }
@@ -144,11 +140,15 @@ const makeGroupsSocket = (config) => {
144
140
 
145
141
  ev.on('group-participants.update', async (update) => {
146
142
  CacheManager.del('groupMetadataCache', update.id);
143
+ // Clear forbidden cooldown when participant update occurs (e.g. bot was added)
144
+ forbiddenGroupMetadataUntil.delete(update.id);
147
145
  });
148
146
 
149
147
  ev.on('groups.upsert', async (groups) => {
150
148
  for (const group of groups) {
151
149
  CacheManager.del('groupMetadataCache', group.id);
150
+ // Clear forbidden cooldown when a group is created/joined
151
+ forbiddenGroupMetadataUntil.delete(group.id);
152
152
  }
153
153
  });
154
154
  return {
@@ -202,24 +202,32 @@ const makeGroupsSocket = (config) => {
202
202
  ]);
203
203
  const node = (0, WABinary_1.getBinaryNodeChild)(result, 'membership_approval_requests');
204
204
  const participants = (0, WABinary_1.getBinaryNodeChildren)(node, 'membership_approval_request');
205
- return participants.map(v => v.attrs);
205
+ return participants.map(v => {
206
+ const rawJid = v.attrs.jid || '';
207
+ const resolvedJid = rawJid.endsWith('@lid')
208
+ ? (v.attrs.phone_number
209
+ ? (v.attrs.phone_number.includes('@') ? v.attrs.phone_number : `${v.attrs.phone_number}@s.whatsapp.net`)
210
+ : rawJid)
211
+ : rawJid;
212
+ return { ...v.attrs, jid: resolvedJid };
213
+ });
206
214
  },
207
215
  groupRequestParticipantsUpdate: async (jid, participants, action) => {
208
216
  participants = participants.map(resolveJid);
209
217
  const result = await groupQuery(jid, 'set', [{
210
- tag: 'membership_requests_action',
211
- attrs: {},
212
- content: [
213
- {
214
- tag: action,
215
- attrs: {},
216
- content: participants.map(jid => ({
217
- tag: 'participant',
218
- attrs: { jid }
219
- }))
220
- }
221
- ]
222
- }]);
218
+ tag: 'membership_requests_action',
219
+ attrs: {},
220
+ content: [
221
+ {
222
+ tag: action,
223
+ attrs: {},
224
+ content: participants.map(jid => ({
225
+ tag: 'participant',
226
+ attrs: { jid }
227
+ }))
228
+ }
229
+ ]
230
+ }]);
223
231
  const node = (0, WABinary_1.getBinaryNodeChild)(result, 'membership_requests_action');
224
232
  const nodeAction = (0, WABinary_1.getBinaryNodeChild)(node, action);
225
233
  const participantsAffected = (0, WABinary_1.getBinaryNodeChildren)(nodeAction, 'participant');
@@ -298,13 +306,13 @@ const makeGroupsSocket = (config) => {
298
306
  key = typeof key === 'string' ? { remoteJid: key } : key;
299
307
  key.remoteJid = resolveJid(key.remoteJid);
300
308
  const results = await groupQuery(inviteMessage.groupJid, 'set', [{
301
- tag: 'accept',
302
- attrs: {
303
- code: inviteMessage.inviteCode,
304
- expiration: inviteMessage.inviteExpiration.toString(),
305
- admin: key.remoteJid
306
- }
307
- }]);
309
+ tag: 'accept',
310
+ attrs: {
311
+ code: inviteMessage.inviteCode,
312
+ expiration: inviteMessage.inviteExpiration.toString(),
313
+ admin: key.remoteJid
314
+ }
315
+ }]);
308
316
  // if we have the full message key
309
317
  // update the invite message to be expired
310
318
  if (key.id) {
@@ -420,4 +428,4 @@ const extractGroupMetadata = (result) => {
420
428
  };
421
429
  return metadata;
422
430
  };
423
- exports.extractGroupMetadata = extractGroupMetadata;
431
+ exports.extractGroupMetadata = extractGroupMetadata;
@@ -11,7 +11,6 @@ const WAProto_1 = require("../../WAProto");
11
11
  const Defaults_1 = require("../Defaults");
12
12
  const Types_1 = require("../Types");
13
13
  const Utils_1 = require("../Utils");
14
- const performance_config_1 = require("../Utils/performance-config");
15
14
  const make_mutex_1 = require("../Utils/make-mutex");
16
15
  const WABinary_1 = require("../WABinary");
17
16
  const groups_1 = require("./groups");
@@ -450,7 +449,14 @@ const makeMessagesRecvSocket = (config) => {
450
449
  switch (child === null || child === void 0 ? void 0 : child.tag) {
451
450
  case 'create':
452
451
  let metadata = (0, groups_1.extractGroupMetadata)(child);
453
- const fullMetadata = await groupMetadata(groupJid);
452
+ let fullMetadata;
453
+ try {
454
+ fullMetadata = await groupMetadata(groupJid);
455
+ } catch (_err) {
456
+ // groupMetadata may fail with 403 right after group creation
457
+ // Use the partial metadata from the notification itself
458
+ fullMetadata = metadata;
459
+ }
454
460
  if (metadata.owner && metadata.owner.endsWith('@lid')) {
455
461
  const found = fullMetadata.participants.find(p => p.id === metadata.owner);
456
462
  metadata.owner = (found === null || found === void 0 ? void 0 : found.jid) || (0, WABinary_1.lidToJid)(metadata.owner);
@@ -1486,7 +1492,6 @@ const makeMessagesRecvSocket = (config) => {
1486
1492
  }
1487
1493
  });
1488
1494
  ev.on('messages.update', (updates) => {
1489
- const config = (0, performance_config_1.getPerformanceConfig)();
1490
1495
  updates.forEach(update => {
1491
1496
  if (update.update.status === WAProto_1.proto.WebMessageInfo.Status.PENDING &&
1492
1497
  Date.now() - (update.update.timestamp || 0) > 30000) {
@@ -1500,7 +1505,7 @@ const makeMessagesRecvSocket = (config) => {
1500
1505
  } catch (err) {
1501
1506
  logger.error({ err, key: update.key }, 'failed to retry stuck message');
1502
1507
  }
1503
- }, config.security?.messageDelay?.min || 1000);
1508
+ }, 1000);
1504
1509
  }
1505
1510
  });
1506
1511
  });