tiny-essentials 1.10.2 → 1.11.0
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 +1 -1
- package/dist/{TinyEssentials.js → v1/TinyEssentials.js} +804 -0
- package/dist/v1/TinyEssentials.min.js +2 -0
- package/dist/v1/TinyNotifyCenter.js +461 -0
- package/dist/v1/TinyNotifyCenter.min.js +1 -0
- package/dist/v1/TinyToastNotify.js +417 -0
- package/dist/v1/TinyToastNotify.min.js +1 -0
- package/dist/v1/build/TinyNotifyCenter.cjs +7 -0
- package/dist/v1/build/TinyNotifyCenter.d.mts +3 -0
- package/dist/v1/build/TinyNotifyCenter.mjs +2 -0
- package/dist/v1/build/TinyToastNotify.cjs +7 -0
- package/dist/v1/build/TinyToastNotify.d.mts +3 -0
- package/dist/v1/build/TinyToastNotify.mjs +2 -0
- package/dist/v1/css/TinyNotify.css +350 -0
- package/dist/v1/css/TinyNotify.min.css +1 -0
- package/dist/v1/index.cjs +4 -0
- package/dist/v1/index.d.mts +3 -1
- package/dist/v1/index.mjs +3 -1
- package/dist/v1/libs/TinyNotifyCenter.cjs +422 -0
- package/dist/v1/libs/TinyNotifyCenter.d.mts +166 -0
- package/dist/v1/libs/TinyNotifyCenter.mjs +385 -0
- package/dist/v1/libs/TinyToastNotify.cjs +378 -0
- package/dist/v1/libs/TinyToastNotify.d.mts +157 -0
- package/dist/v1/libs/TinyToastNotify.mjs +332 -0
- package/docs/{README.md → v1/README.md} +2 -0
- package/docs/{basics → v1/basics}/text.md +2 -2
- package/docs/v1/libs/TinyNotifyCenter.md +291 -0
- package/docs/v1/libs/TinyToastNotify.md +290 -0
- package/package.json +4 -2
- package/dist/TinyEssentials.min.js +0 -2
- package/dist/v1/libs/TinyRateLimit.cjs +0 -196
- package/dist/v1/libs/TinyRateLimit.d.mts +0 -86
- package/dist/v1/libs/TinyRateLimit.mjs +0 -171
- /package/dist/{ColorSafeStringify.js → v1/ColorSafeStringify.js} +0 -0
- /package/dist/{ColorSafeStringify.min.js → v1/ColorSafeStringify.min.js} +0 -0
- /package/dist/{TinyBasicsEs.js → v1/TinyBasicsEs.js} +0 -0
- /package/dist/{TinyBasicsEs.min.js → v1/TinyBasicsEs.min.js} +0 -0
- /package/dist/{TinyBasicsEs.min.js.LICENSE.txt → v1/TinyBasicsEs.min.js.LICENSE.txt} +0 -0
- /package/dist/{TinyEssentials.min.js.LICENSE.txt → v1/TinyEssentials.min.js.LICENSE.txt} +0 -0
- /package/dist/{TinyLevelUp.js → v1/TinyLevelUp.js} +0 -0
- /package/dist/{TinyLevelUp.min.js → v1/TinyLevelUp.min.js} +0 -0
- /package/dist/{TinyPromiseQueue.js → v1/TinyPromiseQueue.js} +0 -0
- /package/dist/{TinyPromiseQueue.min.js → v1/TinyPromiseQueue.min.js} +0 -0
- /package/dist/{TinyRateLimiter.js → v1/TinyRateLimiter.js} +0 -0
- /package/dist/{TinyRateLimiter.min.js → v1/TinyRateLimiter.min.js} +0 -0
- /package/dist/{aiMarker.css → v1/css/aiMarker.css} +0 -0
- /package/dist/{aiMarker.min.css → v1/css/aiMarker.min.css} +0 -0
- /package/docs/{basics → v1/basics}/array.md +0 -0
- /package/docs/{basics → v1/basics}/asyncReplace.md +0 -0
- /package/docs/{basics → v1/basics}/clock.md +0 -0
- /package/docs/{basics → v1/basics}/objFilter.md +0 -0
- /package/docs/{basics → v1/basics}/simpleMath.md +0 -0
- /package/docs/{libs → v1/libs}/ColorSafeStringify.md +0 -0
- /package/docs/{libs → v1/libs}/TinyLevelUp.md +0 -0
- /package/docs/{libs → v1/libs}/TinyPromiseQueue.md +0 -0
- /package/docs/{libs → v1/libs}/TinyRateLimiter.md +0 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# 🍞✨ `TinyToastNotify` Class
|
|
2
|
+
|
|
3
|
+
A lightweight notification system designed to display timed messages inside a container. It supports positioning, duration customization, HTML rendering, click handling, and optional avatar display.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🔧 Features
|
|
8
|
+
|
|
9
|
+
* 📍 **Positioning**:
|
|
10
|
+
Customize horizontal (`x`: `left`, `center`, `right`) and vertical (`y`: `top`, `bottom`) alignment.
|
|
11
|
+
|
|
12
|
+
* ⏳ **Dynamic display time**:
|
|
13
|
+
Automatically adjusts based on message length.
|
|
14
|
+
|
|
15
|
+
* 📝 **Flexible content**:
|
|
16
|
+
|
|
17
|
+
* Optional `title` 🏷️
|
|
18
|
+
* Optional `avatar` 🖼️
|
|
19
|
+
* Optional `onClick` handler 🖱️
|
|
20
|
+
* Optional raw HTML rendering 💡
|
|
21
|
+
|
|
22
|
+
* 🌙 **Fade-out animation**:
|
|
23
|
+
With customizable duration.
|
|
24
|
+
|
|
25
|
+
* 🛡️ **Robust validation**:
|
|
26
|
+
Ensures safe and predictable behavior.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## ⚙️ Customization Setters
|
|
31
|
+
|
|
32
|
+
* `setX(position: 'left' | 'center' | 'right')` — Sets horizontal alignment.
|
|
33
|
+
* `setY(position: 'top' | 'bottom')` — Sets vertical alignment.
|
|
34
|
+
* `setBaseDuration(ms: number)` — Base visible time in milliseconds.
|
|
35
|
+
* `setExtraPerChar(ms: number)` — Additional duration per character.
|
|
36
|
+
* `setFadeOutDuration(ms: number)` — Duration of fade-out animation.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 🧩 Types
|
|
41
|
+
|
|
42
|
+
### 🔁 `CloseToastFunc`
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
type CloseToastFunc = () => void;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
A callback function used to manually close a notification.
|
|
49
|
+
It’s passed as the **second argument** to `onClick` handlers, allowing programmatic dismissal.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### 💬 `NotifyData`
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
type NotifyData =
|
|
57
|
+
| string
|
|
58
|
+
| {
|
|
59
|
+
message: string; // The main message to display
|
|
60
|
+
title?: string; // Optional title above the message
|
|
61
|
+
onClick?: (event: MouseEvent, close: CloseToastFunc) => void; // Optional click handler
|
|
62
|
+
html?: boolean; // If true, message will be rendered as raw HTML
|
|
63
|
+
avatar?: string; // Optional avatar image URL
|
|
64
|
+
};
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Represents the input used to display a notification.
|
|
68
|
+
It can either be a plain string (used as the message), or a detailed object for richer customization.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 🔧 Constructor: `new TinyToastNotify(...)`
|
|
73
|
+
|
|
74
|
+
Initializes a new `TinyToastNotify` instance with positioning and timing preferences.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
new TinyToastNotify(
|
|
78
|
+
y?: 'top' | 'bottom',
|
|
79
|
+
x?: 'left' | 'right' | 'center',
|
|
80
|
+
baseDuration?: number,
|
|
81
|
+
extraPerChar?: number,
|
|
82
|
+
fadeOutDuration?: number,
|
|
83
|
+
selector?: string
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 📝 Parameters
|
|
88
|
+
|
|
89
|
+
| Parameter | Type | Default | Description |
|
|
90
|
+
| ----------------- | ----------------------------------- | --------------------- | ----------------------------------------------------- |
|
|
91
|
+
| `y` | `'top'` \| `'bottom'` | `'top'` | Vertical alignment of the notification container |
|
|
92
|
+
| `x` | `'left'` \| `'center'` \| `'right'` | `'right'` | Horizontal alignment of the notification container |
|
|
93
|
+
| `baseDuration` | `number` | `3000` | Base display time in milliseconds |
|
|
94
|
+
| `extraPerChar` | `number` | `50` | Extra milliseconds added per character in the message |
|
|
95
|
+
| `fadeOutDuration` | `number` | `300` | Time (ms) for fade-out animation |
|
|
96
|
+
| `selector` | `string` | `'.notify-container'` | CSS selector used to find or create the container |
|
|
97
|
+
|
|
98
|
+
### 🧠 Behavior
|
|
99
|
+
|
|
100
|
+
* Validates all input values strictly to prevent misconfigurations.
|
|
101
|
+
* Attempts to locate an existing container via the selector and alignment classes.
|
|
102
|
+
* If not found, it creates a new container and appends it to `document.body`.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 📦 Method: `getContainer()`
|
|
107
|
+
|
|
108
|
+
Returns the `HTMLElement` used to host all notifications.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
getContainer(): HTMLElement
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 🔁 Returns
|
|
115
|
+
|
|
116
|
+
* The current notification container element.
|
|
117
|
+
|
|
118
|
+
### ⚠️ Throws
|
|
119
|
+
|
|
120
|
+
* Throws an error if the container is not a valid `HTMLElement`.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## ⚙️ Position and Timing Getters & Setters
|
|
125
|
+
|
|
126
|
+
### 🔝 `getY()`
|
|
127
|
+
|
|
128
|
+
Returns the current vertical position.
|
|
129
|
+
|
|
130
|
+
* **Returns:**
|
|
131
|
+
`'top' | 'bottom'` — The vertical alignment of the notification container.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### 🔄 `setY(value)`
|
|
136
|
+
|
|
137
|
+
Sets the vertical position of the notification container and updates its CSS classes.
|
|
138
|
+
|
|
139
|
+
* **Parameters:**
|
|
140
|
+
|
|
141
|
+
* `value: 'top' | 'bottom'` — The new vertical position to set.
|
|
142
|
+
|
|
143
|
+
* **Throws:**
|
|
144
|
+
|
|
145
|
+
* `Error` if the value is invalid.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### ↔️ `getX()`
|
|
150
|
+
|
|
151
|
+
Returns the current horizontal position.
|
|
152
|
+
|
|
153
|
+
* **Returns:**
|
|
154
|
+
`'left' | 'center' | 'right'` — The horizontal alignment of the notification container.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### 🔀 `setX(value)`
|
|
159
|
+
|
|
160
|
+
Sets the horizontal position of the notification container and updates its CSS classes.
|
|
161
|
+
|
|
162
|
+
* **Parameters:**
|
|
163
|
+
|
|
164
|
+
* `value: 'left' | 'center' | 'right'` — The new horizontal position to set.
|
|
165
|
+
|
|
166
|
+
* **Throws:**
|
|
167
|
+
|
|
168
|
+
* `Error` if the value is invalid.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### ⏲️ `getBaseDuration()`
|
|
173
|
+
|
|
174
|
+
Returns the base display duration for notifications.
|
|
175
|
+
|
|
176
|
+
* **Returns:**
|
|
177
|
+
`number` — Base time in milliseconds that a notification stays visible.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### ⏳ `setBaseDuration(value)`
|
|
182
|
+
|
|
183
|
+
Sets the base display duration for notifications.
|
|
184
|
+
|
|
185
|
+
* **Parameters:**
|
|
186
|
+
|
|
187
|
+
* `value: number` — Base display time in milliseconds.
|
|
188
|
+
|
|
189
|
+
* **Throws:**
|
|
190
|
+
|
|
191
|
+
* `Error` if `value` is not a valid non-negative finite number.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### ➕ `getExtraPerChar()`
|
|
196
|
+
|
|
197
|
+
Returns extra display time added per character.
|
|
198
|
+
|
|
199
|
+
* **Returns:**
|
|
200
|
+
`number` — Extra milliseconds added per character in the notification.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### ✏️ `setExtraPerChar(value)`
|
|
205
|
+
|
|
206
|
+
Sets the extra display time added per character.
|
|
207
|
+
|
|
208
|
+
* **Parameters:**
|
|
209
|
+
|
|
210
|
+
* `value: number` — Extra milliseconds per character.
|
|
211
|
+
|
|
212
|
+
* **Throws:**
|
|
213
|
+
|
|
214
|
+
* `Error` if `value` is not a valid non-negative finite number.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### 🌙 `getFadeOutDuration()`
|
|
219
|
+
|
|
220
|
+
Returns the fade-out animation duration.
|
|
221
|
+
|
|
222
|
+
* **Returns:**
|
|
223
|
+
`number` — Duration in milliseconds of the fade-out effect.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
### 🎞️ `setFadeOutDuration(value)`
|
|
228
|
+
|
|
229
|
+
Sets the fade-out animation duration.
|
|
230
|
+
|
|
231
|
+
* **Parameters:**
|
|
232
|
+
|
|
233
|
+
* `value: number` — Fade-out time in milliseconds.
|
|
234
|
+
|
|
235
|
+
* **Throws:**
|
|
236
|
+
|
|
237
|
+
* `Error` if `value` is not a valid non-negative finite number.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 🚀 `show(data)`
|
|
242
|
+
|
|
243
|
+
Displays a notification with customizable content and duration based on message length.
|
|
244
|
+
|
|
245
|
+
### 📝 Parameters
|
|
246
|
+
|
|
247
|
+
* `data: NotifyData` — The notification data, which can be either:
|
|
248
|
+
|
|
249
|
+
* A **string** — Used as the message text directly.
|
|
250
|
+
* An **object** with the following optional properties:
|
|
251
|
+
|
|
252
|
+
* `message: string` — The main message text (required in object form).
|
|
253
|
+
* `title?: string` — Optional title shown above the message.
|
|
254
|
+
* `onClick?: function(MouseEvent, CloseToastFunc): void` — Optional click handler, receives the click event and a function to programmatically close the toast.
|
|
255
|
+
* `html?: boolean` — Whether the message should be interpreted as raw HTML (default is plain text).
|
|
256
|
+
* `avatar?: string` — Optional URL for an avatar image shown to the left of the notification.
|
|
257
|
+
|
|
258
|
+
### 🛠️ Behavior
|
|
259
|
+
|
|
260
|
+
* Creates a notification `<div>` element with class `notify` and adds entrance animation.
|
|
261
|
+
* Supports optional avatar image, title, and click handler.
|
|
262
|
+
* Shows a close button (`×`) with hover effect.
|
|
263
|
+
* Calculates display duration as:
|
|
264
|
+
`baseDuration + (message length × extraPerChar) + fadeOutDuration` milliseconds.
|
|
265
|
+
* Automatically fades out and removes the notification after the calculated total time.
|
|
266
|
+
* Clicking the close button or calling the programmatic `close` function dismisses the notification.
|
|
267
|
+
* If an `onClick` handler is provided, clicking the notification (except on the close button) triggers it.
|
|
268
|
+
|
|
269
|
+
### ⚠️ Errors
|
|
270
|
+
|
|
271
|
+
* Throws an error if `data` is neither a string nor a valid object with a string `message` property.
|
|
272
|
+
* Throws an error if `onClick` is defined but is not a function.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## 🎨 CSS Files Location
|
|
277
|
+
|
|
278
|
+
The CSS files for the TinyNotify project build can be found in the following folder:
|
|
279
|
+
|
|
280
|
+
```
|
|
281
|
+
dist/v1/css
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Inside this folder, you'll find the main stylesheets:
|
|
285
|
+
|
|
286
|
+
- `TinyNotify.css` — the full, unminified CSS file
|
|
287
|
+
- `TinyNotify.min.css` — the minified, optimized CSS file for production 🚀
|
|
288
|
+
|
|
289
|
+
Use these files to style your notifications!
|
|
290
|
+
Happy coding! ✨
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-essentials",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "npm run test:mjs && npm run test:cjs && npm run test:js",
|
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
"build:js": "tsc -p tsconfig.json && rollup -c && webpack --mode production",
|
|
23
23
|
"build-clean": "npm run clean && npm run build",
|
|
24
24
|
"build-dist": "npm run build",
|
|
25
|
-
"build:css": "
|
|
25
|
+
"build:css": "npm run build:css:aimaker && npm run build:css:tinynotify",
|
|
26
|
+
"build:css:aimaker": "sass src/v1/scss/aiMarker.scss dist/v1/css/aiMarker.css --no-source-map && sass src/v1/scss/aiMarker.scss dist/v1/css/aiMarker.min.css --no-source-map --style=compressed",
|
|
27
|
+
"build:css:tinynotify": "sass src/v1/scss/TinyNotify.scss dist/v1/css/TinyNotify.css --no-source-map && sass src/v1/scss/TinyNotify.scss dist/v1/css/TinyNotify.min.css --no-source-map --style=compressed",
|
|
26
28
|
"clean": "rm -rf dist",
|
|
27
29
|
"prepublishOnly": "npm run build"
|
|
28
30
|
},
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! For license information please see TinyEssentials.min.js.LICENSE.txt */
|
|
2
|
-
(()=>{var e={251:(e,t)=>{t.read=function(e,t,r,n,i){var o,s,u=8*i-n-1,a=(1<<u)-1,f=a>>1,l=-7,h=r?i-1:0,p=r?-1:1,c=e[t+h];for(h+=p,o=c&(1<<-l)-1,c>>=-l,l+=u;l>0;o=256*o+e[t+h],h+=p,l-=8);for(s=o&(1<<-l)-1,o>>=-l,l+=n;l>0;s=256*s+e[t+h],h+=p,l-=8);if(0===o)o=1-f;else{if(o===a)return s?NaN:1/0*(c?-1:1);s+=Math.pow(2,n),o-=f}return(c?-1:1)*s*Math.pow(2,o-n)},t.write=function(e,t,r,n,i,o){var s,u,a,f=8*o-i-1,l=(1<<f)-1,h=l>>1,p=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,c=n?0:o-1,g=n?1:-1,y=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(u=isNaN(t)?1:0,s=l):(s=Math.floor(Math.log(t)/Math.LN2),t*(a=Math.pow(2,-s))<1&&(s--,a*=2),(t+=s+h>=1?p/a:p*Math.pow(2,1-h))*a>=2&&(s++,a/=2),s+h>=l?(u=0,s=l):s+h>=1?(u=(t*a-1)*Math.pow(2,i),s+=h):(u=t*Math.pow(2,h-1)*Math.pow(2,i),s=0));i>=8;e[r+c]=255&u,c+=g,u/=256,i-=8);for(s=s<<i|u,f+=i;f>0;e[r+c]=255&s,c+=g,s/=256,f-=8);e[r+c-g]|=128*y}},287:(e,t,r)=>{"use strict";var n=r(526),i=r(251),o="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;t.hp=a,t.IS=50;var s=2147483647;function u(e){if(e>s)throw new RangeError('The value "'+e+'" is invalid for option "size"');var t=new Uint8Array(e);return Object.setPrototypeOf(t,a.prototype),t}function a(e,t,r){if("number"==typeof e){if("string"==typeof t)throw new TypeError('The "string" argument must be of type string. Received type number');return h(e)}return f(e,t,r)}function f(e,t,r){if("string"==typeof e)return function(e,t){if("string"==typeof t&&""!==t||(t="utf8"),!a.isEncoding(t))throw new TypeError("Unknown encoding: "+t);var r=0|y(e,t),n=u(r),i=n.write(e,t);return i!==r&&(n=n.slice(0,i)),n}(e,t);if(ArrayBuffer.isView(e))return function(e){if(_(e,Uint8Array)){var t=new Uint8Array(e);return c(t.buffer,t.byteOffset,t.byteLength)}return p(e)}(e);if(null==e)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(_(e,ArrayBuffer)||e&&_(e.buffer,ArrayBuffer))return c(e,t,r);if("undefined"!=typeof SharedArrayBuffer&&(_(e,SharedArrayBuffer)||e&&_(e.buffer,SharedArrayBuffer)))return c(e,t,r);if("number"==typeof e)throw new TypeError('The "value" argument must not be of type number. Received type number');var n=e.valueOf&&e.valueOf();if(null!=n&&n!==e)return a.from(n,t,r);var i=function(e){if(a.isBuffer(e)){var t=0|g(e.length),r=u(t);return 0===r.length||e.copy(r,0,0,t),r}return void 0!==e.length?"number"!=typeof e.length||F(e.length)?u(0):p(e):"Buffer"===e.type&&Array.isArray(e.data)?p(e.data):void 0}(e);if(i)return i;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof e[Symbol.toPrimitive])return a.from(e[Symbol.toPrimitive]("string"),t,r);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}function l(e){if("number"!=typeof e)throw new TypeError('"size" argument must be of type number');if(e<0)throw new RangeError('The value "'+e+'" is invalid for option "size"')}function h(e){return l(e),u(e<0?0:0|g(e))}function p(e){for(var t=e.length<0?0:0|g(e.length),r=u(t),n=0;n<t;n+=1)r[n]=255&e[n];return r}function c(e,t,r){if(t<0||e.byteLength<t)throw new RangeError('"offset" is outside of buffer bounds');if(e.byteLength<t+(r||0))throw new RangeError('"length" is outside of buffer bounds');var n;return n=void 0===t&&void 0===r?new Uint8Array(e):void 0===r?new Uint8Array(e,t):new Uint8Array(e,t,r),Object.setPrototypeOf(n,a.prototype),n}function g(e){if(e>=s)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+s.toString(16)+" bytes");return 0|e}function y(e,t){if(a.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||_(e,ArrayBuffer))return e.byteLength;if("string"!=typeof e)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof e);var r=e.length,n=arguments.length>2&&!0===arguments[2];if(!n&&0===r)return 0;for(var i=!1;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":return j(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return $(e).length;default:if(i)return n?-1:j(e).length;t=(""+t).toLowerCase(),i=!0}}function m(e,t,r){var n=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return L(this,t,r);case"utf8":case"utf-8":return M(this,t,r);case"ascii":return S(this,t,r);case"latin1":case"binary":return I(this,t,r);case"base64":return N(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return U(this,t,r);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}function d(e,t,r){var n=e[t];e[t]=e[r],e[r]=n}function b(e,t,r,n,i){if(0===e.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),F(r=+r)&&(r=i?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(i)return-1;r=e.length-1}else if(r<0){if(!i)return-1;r=0}if("string"==typeof t&&(t=a.from(t,n)),a.isBuffer(t))return 0===t.length?-1:w(e,t,r,n,i);if("number"==typeof t)return t&=255,"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):w(e,[t],r,n,i);throw new TypeError("val must be string, number or Buffer")}function w(e,t,r,n,i){var o,s=1,u=e.length,a=t.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(e.length<2||t.length<2)return-1;s=2,u/=2,a/=2,r/=2}function f(e,t){return 1===s?e[t]:e.readUInt16BE(t*s)}if(i){var l=-1;for(o=r;o<u;o++)if(f(e,o)===f(t,-1===l?0:o-l)){if(-1===l&&(l=o),o-l+1===a)return l*s}else-1!==l&&(o-=o-l),l=-1}else for(r+a>u&&(r=u-a),o=r;o>=0;o--){for(var h=!0,p=0;p<a;p++)if(f(e,o+p)!==f(t,p)){h=!1;break}if(h)return o}return-1}function v(e,t,r,n){r=Number(r)||0;var i=e.length-r;n?(n=Number(n))>i&&(n=i):n=i;var o=t.length;n>o/2&&(n=o/2);for(var s=0;s<n;++s){var u=parseInt(t.substr(2*s,2),16);if(F(u))return s;e[r+s]=u}return s}function E(e,t,r,n){return G(j(t,e.length-r),e,r,n)}function x(e,t,r,n){return G(function(e){for(var t=[],r=0;r<e.length;++r)t.push(255&e.charCodeAt(r));return t}(t),e,r,n)}function T(e,t,r,n){return G($(t),e,r,n)}function A(e,t,r,n){return G(function(e,t){for(var r,n,i,o=[],s=0;s<e.length&&!((t-=2)<0);++s)n=(r=e.charCodeAt(s))>>8,i=r%256,o.push(i),o.push(n);return o}(t,e.length-r),e,r,n)}function N(e,t,r){return 0===t&&r===e.length?n.fromByteArray(e):n.fromByteArray(e.slice(t,r))}function M(e,t,r){r=Math.min(e.length,r);for(var n=[],i=t;i<r;){var o,s,u,a,f=e[i],l=null,h=f>239?4:f>223?3:f>191?2:1;if(i+h<=r)switch(h){case 1:f<128&&(l=f);break;case 2:128==(192&(o=e[i+1]))&&(a=(31&f)<<6|63&o)>127&&(l=a);break;case 3:o=e[i+1],s=e[i+2],128==(192&o)&&128==(192&s)&&(a=(15&f)<<12|(63&o)<<6|63&s)>2047&&(a<55296||a>57343)&&(l=a);break;case 4:o=e[i+1],s=e[i+2],u=e[i+3],128==(192&o)&&128==(192&s)&&128==(192&u)&&(a=(15&f)<<18|(63&o)<<12|(63&s)<<6|63&u)>65535&&a<1114112&&(l=a)}null===l?(l=65533,h=1):l>65535&&(l-=65536,n.push(l>>>10&1023|55296),l=56320|1023&l),n.push(l),i+=h}return function(e){var t=e.length;if(t<=B)return String.fromCharCode.apply(String,e);for(var r="",n=0;n<t;)r+=String.fromCharCode.apply(String,e.slice(n,n+=B));return r}(n)}a.TYPED_ARRAY_SUPPORT=function(){try{var e=new Uint8Array(1),t={foo:function(){return 42}};return Object.setPrototypeOf(t,Uint8Array.prototype),Object.setPrototypeOf(e,t),42===e.foo()}catch(e){return!1}}(),a.TYPED_ARRAY_SUPPORT||"undefined"==typeof console||"function"!=typeof console.error||console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support."),Object.defineProperty(a.prototype,"parent",{enumerable:!0,get:function(){if(a.isBuffer(this))return this.buffer}}),Object.defineProperty(a.prototype,"offset",{enumerable:!0,get:function(){if(a.isBuffer(this))return this.byteOffset}}),a.poolSize=8192,a.from=function(e,t,r){return f(e,t,r)},Object.setPrototypeOf(a.prototype,Uint8Array.prototype),Object.setPrototypeOf(a,Uint8Array),a.alloc=function(e,t,r){return function(e,t,r){return l(e),e<=0?u(e):void 0!==t?"string"==typeof r?u(e).fill(t,r):u(e).fill(t):u(e)}(e,t,r)},a.allocUnsafe=function(e){return h(e)},a.allocUnsafeSlow=function(e){return h(e)},a.isBuffer=function(e){return null!=e&&!0===e._isBuffer&&e!==a.prototype},a.compare=function(e,t){if(_(e,Uint8Array)&&(e=a.from(e,e.offset,e.byteLength)),_(t,Uint8Array)&&(t=a.from(t,t.offset,t.byteLength)),!a.isBuffer(e)||!a.isBuffer(t))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(e===t)return 0;for(var r=e.length,n=t.length,i=0,o=Math.min(r,n);i<o;++i)if(e[i]!==t[i]){r=e[i],n=t[i];break}return r<n?-1:n<r?1:0},a.isEncoding=function(e){switch(String(e).toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"latin1":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return!0;default:return!1}},a.concat=function(e,t){if(!Array.isArray(e))throw new TypeError('"list" argument must be an Array of Buffers');if(0===e.length)return a.alloc(0);var r;if(void 0===t)for(t=0,r=0;r<e.length;++r)t+=e[r].length;var n=a.allocUnsafe(t),i=0;for(r=0;r<e.length;++r){var o=e[r];if(_(o,Uint8Array))i+o.length>n.length?a.from(o).copy(n,i):Uint8Array.prototype.set.call(n,o,i);else{if(!a.isBuffer(o))throw new TypeError('"list" argument must be an Array of Buffers');o.copy(n,i)}i+=o.length}return n},a.byteLength=y,a.prototype._isBuffer=!0,a.prototype.swap16=function(){var e=this.length;if(e%2!=0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(var t=0;t<e;t+=2)d(this,t,t+1);return this},a.prototype.swap32=function(){var e=this.length;if(e%4!=0)throw new RangeError("Buffer size must be a multiple of 32-bits");for(var t=0;t<e;t+=4)d(this,t,t+3),d(this,t+1,t+2);return this},a.prototype.swap64=function(){var e=this.length;if(e%8!=0)throw new RangeError("Buffer size must be a multiple of 64-bits");for(var t=0;t<e;t+=8)d(this,t,t+7),d(this,t+1,t+6),d(this,t+2,t+5),d(this,t+3,t+4);return this},a.prototype.toString=function(){var e=this.length;return 0===e?"":0===arguments.length?M(this,0,e):m.apply(this,arguments)},a.prototype.toLocaleString=a.prototype.toString,a.prototype.equals=function(e){if(!a.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e||0===a.compare(this,e)},a.prototype.inspect=function(){var e="",r=t.IS;return e=this.toString("hex",0,r).replace(/(.{2})/g,"$1 ").trim(),this.length>r&&(e+=" ... "),"<Buffer "+e+">"},o&&(a.prototype[o]=a.prototype.inspect),a.prototype.compare=function(e,t,r,n,i){if(_(e,Uint8Array)&&(e=a.from(e,e.offset,e.byteLength)),!a.isBuffer(e))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(void 0===t&&(t=0),void 0===r&&(r=e?e.length:0),void 0===n&&(n=0),void 0===i&&(i=this.length),t<0||r>e.length||n<0||i>this.length)throw new RangeError("out of range index");if(n>=i&&t>=r)return 0;if(n>=i)return-1;if(t>=r)return 1;if(this===e)return 0;for(var o=(i>>>=0)-(n>>>=0),s=(r>>>=0)-(t>>>=0),u=Math.min(o,s),f=this.slice(n,i),l=e.slice(t,r),h=0;h<u;++h)if(f[h]!==l[h]){o=f[h],s=l[h];break}return o<s?-1:s<o?1:0},a.prototype.includes=function(e,t,r){return-1!==this.indexOf(e,t,r)},a.prototype.indexOf=function(e,t,r){return b(this,e,t,r,!0)},a.prototype.lastIndexOf=function(e,t,r){return b(this,e,t,r,!1)},a.prototype.write=function(e,t,r,n){if(void 0===t)n="utf8",r=this.length,t=0;else if(void 0===r&&"string"==typeof t)n=t,r=this.length,t=0;else{if(!isFinite(t))throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");t>>>=0,isFinite(r)?(r>>>=0,void 0===n&&(n="utf8")):(n=r,r=void 0)}var i=this.length-t;if((void 0===r||r>i)&&(r=i),e.length>0&&(r<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");for(var o=!1;;)switch(n){case"hex":return v(this,e,t,r);case"utf8":case"utf-8":return E(this,e,t,r);case"ascii":case"latin1":case"binary":return x(this,e,t,r);case"base64":return T(this,e,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return A(this,e,t,r);default:if(o)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),o=!0}},a.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var B=4096;function S(e,t,r){var n="";r=Math.min(e.length,r);for(var i=t;i<r;++i)n+=String.fromCharCode(127&e[i]);return n}function I(e,t,r){var n="";r=Math.min(e.length,r);for(var i=t;i<r;++i)n+=String.fromCharCode(e[i]);return n}function L(e,t,r){var n=e.length;(!t||t<0)&&(t=0),(!r||r<0||r>n)&&(r=n);for(var i="",o=t;o<r;++o)i+=H[e[o]];return i}function U(e,t,r){for(var n=e.slice(t,r),i="",o=0;o<n.length-1;o+=2)i+=String.fromCharCode(n[o]+256*n[o+1]);return i}function O(e,t,r){if(e%1!=0||e<0)throw new RangeError("offset is not uint");if(e+t>r)throw new RangeError("Trying to access beyond buffer length")}function D(e,t,r,n,i,o){if(!a.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||t<o)throw new RangeError('"value" argument is out of bounds');if(r+n>e.length)throw new RangeError("Index out of range")}function P(e,t,r,n,i,o){if(r+n>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function k(e,t,r,n,o){return t=+t,r>>>=0,o||P(e,0,r,4),i.write(e,t,r,n,23,4),r+4}function R(e,t,r,n,o){return t=+t,r>>>=0,o||P(e,0,r,8),i.write(e,t,r,n,52,8),r+8}a.prototype.slice=function(e,t){var r=this.length;(e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t<e&&(t=e);var n=this.subarray(e,t);return Object.setPrototypeOf(n,a.prototype),n},a.prototype.readUintLE=a.prototype.readUIntLE=function(e,t,r){e>>>=0,t>>>=0,r||O(e,t,this.length);for(var n=this[e],i=1,o=0;++o<t&&(i*=256);)n+=this[e+o]*i;return n},a.prototype.readUintBE=a.prototype.readUIntBE=function(e,t,r){e>>>=0,t>>>=0,r||O(e,t,this.length);for(var n=this[e+--t],i=1;t>0&&(i*=256);)n+=this[e+--t]*i;return n},a.prototype.readUint8=a.prototype.readUInt8=function(e,t){return e>>>=0,t||O(e,1,this.length),this[e]},a.prototype.readUint16LE=a.prototype.readUInt16LE=function(e,t){return e>>>=0,t||O(e,2,this.length),this[e]|this[e+1]<<8},a.prototype.readUint16BE=a.prototype.readUInt16BE=function(e,t){return e>>>=0,t||O(e,2,this.length),this[e]<<8|this[e+1]},a.prototype.readUint32LE=a.prototype.readUInt32LE=function(e,t){return e>>>=0,t||O(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},a.prototype.readUint32BE=a.prototype.readUInt32BE=function(e,t){return e>>>=0,t||O(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},a.prototype.readIntLE=function(e,t,r){e>>>=0,t>>>=0,r||O(e,t,this.length);for(var n=this[e],i=1,o=0;++o<t&&(i*=256);)n+=this[e+o]*i;return n>=(i*=128)&&(n-=Math.pow(2,8*t)),n},a.prototype.readIntBE=function(e,t,r){e>>>=0,t>>>=0,r||O(e,t,this.length);for(var n=t,i=1,o=this[e+--n];n>0&&(i*=256);)o+=this[e+--n]*i;return o>=(i*=128)&&(o-=Math.pow(2,8*t)),o},a.prototype.readInt8=function(e,t){return e>>>=0,t||O(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},a.prototype.readInt16LE=function(e,t){e>>>=0,t||O(e,2,this.length);var r=this[e]|this[e+1]<<8;return 32768&r?4294901760|r:r},a.prototype.readInt16BE=function(e,t){e>>>=0,t||O(e,2,this.length);var r=this[e+1]|this[e]<<8;return 32768&r?4294901760|r:r},a.prototype.readInt32LE=function(e,t){return e>>>=0,t||O(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},a.prototype.readInt32BE=function(e,t){return e>>>=0,t||O(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},a.prototype.readFloatLE=function(e,t){return e>>>=0,t||O(e,4,this.length),i.read(this,e,!0,23,4)},a.prototype.readFloatBE=function(e,t){return e>>>=0,t||O(e,4,this.length),i.read(this,e,!1,23,4)},a.prototype.readDoubleLE=function(e,t){return e>>>=0,t||O(e,8,this.length),i.read(this,e,!0,52,8)},a.prototype.readDoubleBE=function(e,t){return e>>>=0,t||O(e,8,this.length),i.read(this,e,!1,52,8)},a.prototype.writeUintLE=a.prototype.writeUIntLE=function(e,t,r,n){e=+e,t>>>=0,r>>>=0,n||D(this,e,t,r,Math.pow(2,8*r)-1,0);var i=1,o=0;for(this[t]=255&e;++o<r&&(i*=256);)this[t+o]=e/i&255;return t+r},a.prototype.writeUintBE=a.prototype.writeUIntBE=function(e,t,r,n){e=+e,t>>>=0,r>>>=0,n||D(this,e,t,r,Math.pow(2,8*r)-1,0);var i=r-1,o=1;for(this[t+i]=255&e;--i>=0&&(o*=256);)this[t+i]=e/o&255;return t+r},a.prototype.writeUint8=a.prototype.writeUInt8=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,1,255,0),this[t]=255&e,t+1},a.prototype.writeUint16LE=a.prototype.writeUInt16LE=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,2,65535,0),this[t]=255&e,this[t+1]=e>>>8,t+2},a.prototype.writeUint16BE=a.prototype.writeUInt16BE=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=255&e,t+2},a.prototype.writeUint32LE=a.prototype.writeUInt32LE=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e,t+4},a.prototype.writeUint32BE=a.prototype.writeUInt32BE=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},a.prototype.writeIntLE=function(e,t,r,n){if(e=+e,t>>>=0,!n){var i=Math.pow(2,8*r-1);D(this,e,t,r,i-1,-i)}var o=0,s=1,u=0;for(this[t]=255&e;++o<r&&(s*=256);)e<0&&0===u&&0!==this[t+o-1]&&(u=1),this[t+o]=(e/s|0)-u&255;return t+r},a.prototype.writeIntBE=function(e,t,r,n){if(e=+e,t>>>=0,!n){var i=Math.pow(2,8*r-1);D(this,e,t,r,i-1,-i)}var o=r-1,s=1,u=0;for(this[t+o]=255&e;--o>=0&&(s*=256);)e<0&&0===u&&0!==this[t+o+1]&&(u=1),this[t+o]=(e/s|0)-u&255;return t+r},a.prototype.writeInt8=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=255&e,t+1},a.prototype.writeInt16LE=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,2,32767,-32768),this[t]=255&e,this[t+1]=e>>>8,t+2},a.prototype.writeInt16BE=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=255&e,t+2},a.prototype.writeInt32LE=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,4,2147483647,-2147483648),this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},a.prototype.writeInt32BE=function(e,t,r){return e=+e,t>>>=0,r||D(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},a.prototype.writeFloatLE=function(e,t,r){return k(this,e,t,!0,r)},a.prototype.writeFloatBE=function(e,t,r){return k(this,e,t,!1,r)},a.prototype.writeDoubleLE=function(e,t,r){return R(this,e,t,!0,r)},a.prototype.writeDoubleBE=function(e,t,r){return R(this,e,t,!1,r)},a.prototype.copy=function(e,t,r,n){if(!a.isBuffer(e))throw new TypeError("argument should be a Buffer");if(r||(r=0),n||0===n||(n=this.length),t>=e.length&&(t=e.length),t||(t=0),n>0&&n<r&&(n=r),n===r)return 0;if(0===e.length||0===this.length)return 0;if(t<0)throw new RangeError("targetStart out of bounds");if(r<0||r>=this.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),e.length-t<n-r&&(n=e.length-t+r);var i=n-r;return this===e&&"function"==typeof Uint8Array.prototype.copyWithin?this.copyWithin(t,r,n):Uint8Array.prototype.set.call(e,this.subarray(r,n),t),i},a.prototype.fill=function(e,t,r,n){if("string"==typeof e){if("string"==typeof t?(n=t,t=0,r=this.length):"string"==typeof r&&(n=r,r=this.length),void 0!==n&&"string"!=typeof n)throw new TypeError("encoding must be a string");if("string"==typeof n&&!a.isEncoding(n))throw new TypeError("Unknown encoding: "+n);if(1===e.length){var i=e.charCodeAt(0);("utf8"===n&&i<128||"latin1"===n)&&(e=i)}}else"number"==typeof e?e&=255:"boolean"==typeof e&&(e=Number(e));if(t<0||this.length<t||this.length<r)throw new RangeError("Out of range index");if(r<=t)return this;var o;if(t>>>=0,r=void 0===r?this.length:r>>>0,e||(e=0),"number"==typeof e)for(o=t;o<r;++o)this[o]=e;else{var s=a.isBuffer(e)?e:a.from(e,n),u=s.length;if(0===u)throw new TypeError('The value "'+e+'" is invalid for argument "value"');for(o=0;o<r-t;++o)this[o+t]=s[o%u]}return this};var C=/[^+/0-9A-Za-z-_]/g;function j(e,t){var r;t=t||1/0;for(var n=e.length,i=null,o=[],s=0;s<n;++s){if((r=e.charCodeAt(s))>55295&&r<57344){if(!i){if(r>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(s+1===n){(t-=3)>-1&&o.push(239,191,189);continue}i=r;continue}if(r<56320){(t-=3)>-1&&o.push(239,191,189),i=r;continue}r=65536+(i-55296<<10|r-56320)}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,r<128){if((t-=1)<0)break;o.push(r)}else if(r<2048){if((t-=2)<0)break;o.push(r>>6|192,63&r|128)}else if(r<65536){if((t-=3)<0)break;o.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return o}function $(e){return n.toByteArray(function(e){if((e=(e=e.split("=")[0]).trim().replace(C,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function G(e,t,r,n){for(var i=0;i<n&&!(i+r>=t.length||i>=e.length);++i)t[i+r]=e[i];return i}function _(e,t){return e instanceof t||null!=e&&null!=e.constructor&&null!=e.constructor.name&&e.constructor.name===t.name}function F(e){return e!=e}var H=function(){for(var e="0123456789abcdef",t=new Array(256),r=0;r<16;++r)for(var n=16*r,i=0;i<16;++i)t[n+i]=e[r]+e[i];return t}()},526:(e,t)=>{"use strict";t.byteLength=function(e){var t=u(e),r=t[0],n=t[1];return 3*(r+n)/4-n},t.toByteArray=function(e){var t,r,o=u(e),s=o[0],a=o[1],f=new i(function(e,t,r){return 3*(t+r)/4-r}(0,s,a)),l=0,h=a>0?s-4:s;for(r=0;r<h;r+=4)t=n[e.charCodeAt(r)]<<18|n[e.charCodeAt(r+1)]<<12|n[e.charCodeAt(r+2)]<<6|n[e.charCodeAt(r+3)],f[l++]=t>>16&255,f[l++]=t>>8&255,f[l++]=255&t;return 2===a&&(t=n[e.charCodeAt(r)]<<2|n[e.charCodeAt(r+1)]>>4,f[l++]=255&t),1===a&&(t=n[e.charCodeAt(r)]<<10|n[e.charCodeAt(r+1)]<<4|n[e.charCodeAt(r+2)]>>2,f[l++]=t>>8&255,f[l++]=255&t),f},t.fromByteArray=function(e){for(var t,n=e.length,i=n%3,o=[],s=16383,u=0,f=n-i;u<f;u+=s)o.push(a(e,u,u+s>f?f:u+s));return 1===i?(t=e[n-1],o.push(r[t>>2]+r[t<<4&63]+"==")):2===i&&(t=(e[n-2]<<8)+e[n-1],o.push(r[t>>10]+r[t>>4&63]+r[t<<2&63]+"=")),o.join("")};for(var r=[],n=[],i="undefined"!=typeof Uint8Array?Uint8Array:Array,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s=0;s<64;++s)r[s]=o[s],n[o.charCodeAt(s)]=s;function u(e){var t=e.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}function a(e,t,n){for(var i,o,s=[],u=t;u<n;u+=3)i=(e[u]<<16&16711680)+(e[u+1]<<8&65280)+(255&e[u+2]),s.push(r[(o=i)>>18&63]+r[o>>12&63]+r[o>>6&63]+r[63&o]);return s.join("")}n["-".charCodeAt(0)]=62,n["_".charCodeAt(0)]=63}},t={};function r(n){var i=t[n];if(void 0!==i)return i.exports;var o=t[n]={exports:{}};return e[n](o,o.exports,r),o.exports}r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var n={};(()=>{"use strict";async function e(e,t,r){const n=[];e.replace(t,((e,...t)=>(n.push(r(e,...t)),e)));const i=await Promise.all(n);return e.replace(t,(()=>i.shift()))}r.r(n),r.d(n,{ColorSafeStringify:()=>I,TinyLevelUp:()=>t,TinyPromiseQueue:()=>L,TinyRateLimiter:()=>U,addAiMarkerShortcut:()=>B,arraySortPositions:()=>i,asyncReplace:()=>e,checkObj:()=>b,cloneObjTypeOrder:()=>y,countObj:()=>w,extendObjType:()=>c,formatBytes:()=>A,formatCustomTimer:()=>u,formatDayTimer:()=>f,formatTimer:()=>a,getAge:()=>T,getSimplePerc:()=>x,getTimeDuration:()=>s,isJsonObject:()=>v,objType:()=>d,reorderObjTypeOrder:()=>g,ruleOfThree:()=>E,shuffleArray:()=>o,toTitleCase:()=>N,toTitleCaseLowerFirst:()=>M});const t=class{constructor(e,t){if("number"!=typeof e||Number.isNaN(e))throw new Error("giveExp must be a valid number");if("number"!=typeof t||Number.isNaN(t))throw new Error("expLevel must be a valid number");this.giveExp=e,this.expLevel=t}createUser(){return{exp:0,level:1,totalExp:0}}validateUser(e){if("number"!=typeof e.exp||Number.isNaN(e.exp))throw new Error("exp must be a valid number");if("number"!=typeof e.level||Number.isNaN(e.level))throw new Error("level must be a valid number");if(e.level<1)throw new Error("level must be at least 1");if("number"!=typeof e.totalExp||Number.isNaN(e.totalExp))throw new Error("totalExp must be a valid number")}isValidUser(e){return!("number"!=typeof e.exp||Number.isNaN(e.exp)||"number"!=typeof e.level||Number.isNaN(e.level)||e.level<1||"number"!=typeof e.totalExp||Number.isNaN(e.totalExp))}getGiveExpBase(){if("number"!=typeof this.giveExp||Number.isNaN(this.giveExp))throw new Error("giveExp must be a valid number");return this.giveExp}getExpLevelBase(){if("number"!=typeof this.expLevel||Number.isNaN(this.expLevel))throw new Error("expLevel must be a valid number");return this.expLevel}expValidator(e){const t=this.getExpLevelBase();this.validateUser(e);let r=0;const n=t*e.level;return e.exp>=n&&(e.level++,r=e.exp-n,e.exp=0,r>0)?this.give(e,r,"extra"):e.exp<1&&e.level>1&&(e.level--,r=Math.abs(e.exp),e.exp=t*e.level,r>0)?this.remove(e,r,"extra"):e}getTotalExp(e){this.validateUser(e);let t=0;for(let r=1;r<=e.level;r++)t+=this.getExpLevelBase()*r;return t+=e.exp,t}expGenerator(e=1){if("number"!=typeof e||Number.isNaN(e))throw new Error("multi must be a valid number");return Math.floor(Math.random()*this.getGiveExpBase())*e}getMissingExp(e){return this.getProgress(e)-e.exp}progress(e){return this.getProgress(e)}getProgress(e){return this.validateUser(e),this.getExpLevelBase()*e.level}set(e,t){if("number"!=typeof t||Number.isNaN(t))throw new Error("value must be a valid number");return e.exp=t,this.expValidator(e),e.totalExp=this.getTotalExp(e),e}give(e,t=0,r="add",n=1){if("number"!=typeof n||Number.isNaN(n))throw new Error("multi must be a valid number");if("number"!=typeof t||Number.isNaN(t))throw new Error("extraExp must be a valid number");if("string"!=typeof r)throw new Error("type must be a valid string");return"add"===r?e.exp+=this.expGenerator(n)+t:"extra"===r&&(e.exp+=t),this.expValidator(e),e.totalExp=this.getTotalExp(e),e}remove(e,t=0,r="add",n=1){if("number"!=typeof n||Number.isNaN(n))throw new Error("multi must be a valid number");if("number"!=typeof t||Number.isNaN(t))throw new Error("extraExp must be a valid number");if("string"!=typeof r)throw new Error("type must be a valid string");return"add"===r?e.exp-=this.expGenerator(n)+t:"extra"===r&&(e.exp-=t),this.expValidator(e),e.totalExp=this.getTotalExp(e),e}};function i(e,t=!1){return t?function(t,r){return t[e]>r[e]?-1:t[e]<r[e]?1:0}:function(t,r){return t[e]<r[e]?-1:t[e]>r[e]?1:0}}function o(e){let t,r=e.length;for(;0!==r;)t=Math.floor(Math.random()*r),r--,[e[r],e[t]]=[e[t],e[r]];return e}function s(e=new Date,t="asSeconds",r=null){if(e instanceof Date){const n=r instanceof Date?r:new Date,i=e.getTime()-n.getTime();switch(t){case"asMilliseconds":return i;case"asSeconds":default:return i/1e3;case"asMinutes":return i/6e4;case"asHours":return i/36e5;case"asDays":return i/864e5}}return null}function u(e,t="seconds",r="{time}"){e=Math.max(0,Math.floor(e));const n=["seconds","minutes","hours","days","months","years"].indexOf(t),i=n>=5,o=n>=4,s=n>=3,u=n>=2,a=n>=1,f=n>=0,l={years:i?0:NaN,months:o?0:NaN,days:s?0:NaN,hours:u?0:NaN,minutes:a?0:NaN,seconds:f?0:NaN,total:NaN};let h=e;if(i||o||s){const e=new Date(1980,0,1),t=new Date(e.getTime()+1e3*h),r=new Date(e);if(i)for(;new Date(r.getFullYear()+1,r.getMonth(),r.getDate()).getTime()<=t.getTime();)r.setFullYear(r.getFullYear()+1),l.years++;if(o)for(;new Date(r.getFullYear(),r.getMonth()+1,r.getDate()).getTime()<=t.getTime();)r.setMonth(r.getMonth()+1),l.months++;if(s)for(;new Date(r.getFullYear(),r.getMonth(),r.getDate()+1).getTime()<=t.getTime();)r.setDate(r.getDate()+1),l.days++;h=Math.floor((t.getTime()-r.getTime())/1e3)}u&&(l.hours=Math.floor(h/3600),h%=3600),a&&(l.minutes=Math.floor(h/60),h%=60),f&&(l.seconds=h);const p={seconds:f?e:NaN,minutes:a?e/60:NaN,hours:u?e/3600:NaN,days:s?e/86400:NaN,months:o?12*l.years+l.months+(l.days||0)/30:NaN,years:i?l.years+(l.months||0)/12+(l.days||0)/365:NaN};l.total=+(p[t]||0).toFixed(2).replace(/\.00$/,"");const c=e=>{const t="string"==typeof e?parseInt(e):e;return Number.isNaN(t)?"NaN":String(t).padStart(2,"0")},g=[u?c(l.hours):null,a?c(l.minutes):null,f?c(l.seconds):null].filter((e=>null!==e)).join(":");return r.replace(/\{years\}/g,String(l.years)).replace(/\{months\}/g,String(l.months)).replace(/\{days\}/g,String(l.days)).replace(/\{hours\}/g,c(l.hours)).replace(/\{minutes\}/g,c(l.minutes)).replace(/\{seconds\}/g,c(l.seconds)).replace(/\{time\}/g,g).replace(/\{total\}/g,String(l.total)).trim()}function a(e){return u(e,"hours","{hours}:{minutes}:{seconds}")}function f(e){return u(e,"days","{days}d {hours}:{minutes}:{seconds}")}var l=r(287);const h="undefined"!=typeof window&&void 0!==window.document,p={items:{},order:[]};function c(e,t){const r=[],n=Array.isArray(e)?e:Object.entries(e);for(const[e,i]of n)if(!p.items.hasOwnProperty(e)){p.items[e]=i;let n="number"==typeof t?t:-1;if(-1===n){const e=p.order.indexOf("object");n=e>-1?e:p.order.length}n=Math.min(Math.max(0,n),p.order.length),p.order.splice(n,0,e),r.push(e)}return r}function g(e){const t=[...p.order];return!!e.every((e=>t.includes(e)))&&(p.order=e.slice(),!0)}function y(){return[...p.order]}const m=e=>{if(null===e)return"null";for(const t of p.order)if("function"!=typeof p.items[t]||p.items[t](e))return t;return"unknown"};function d(e,t){if(void 0===e)return null;const r=m(e);return"string"==typeof t?r===t.toLowerCase():r}function b(e){const t={valid:null,type:null};for(const r of p.order)if("function"==typeof p.items[r]){const n=p.items[r](e);if(n){t.valid=n,t.type=r;break}}return t}function w(e){return Array.isArray(e)?e.length:d(e,"object")?Object.keys(e).length:0}function v(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)&&"[object Object]"===Object.prototype.toString.call(e)}function E(e,t,r,n=!1){return n?Number(e*t)/r:Number(r*t)/e}function x(e,t){return e*(t/100)}function T(e=0,t=null){if(null!=e&&0!==e){const r=new Date(e);if(Number.isNaN(r.getTime()))return null;const n=t instanceof Date?t:new Date;let i=n.getFullYear()-r.getFullYear();const o=n.getMonth(),s=r.getMonth(),u=n.getDate(),a=r.getDate();return(o<s||o===s&&u<a)&&i--,Math.abs(i)}return null}function A(e,t=null,r=null){if("number"!=typeof e||e<0)return{unit:null,value:null};if(0===e)return{unit:"Bytes",value:0};const n=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],i=r&&n.includes(r)?n.indexOf(r):n.length-1,o=Math.min(Math.floor(Math.log(e)/Math.log(1024)),i);let s=e/Math.pow(1024,o);if(null!==t){const e=t<0?0:t;s=parseFloat(s.toFixed(e))}return{unit:n[o],value:s}}function N(e){return e.replace(/\w\S*/g,(e=>e.charAt(0).toUpperCase()+e.substr(1).toLowerCase()))}function M(e){const t=e.replace(/\w\S*/g,(e=>e.charAt(0).toUpperCase()+e.substr(1).toLowerCase()));return t.charAt(0).toLowerCase()+t.slice(1)}function B(e="a"){"undefined"!=typeof HTMLElement?document.addEventListener("keydown",(function(t){if(t.ctrlKey&&t.altKey&&t.key.toLowerCase()===e){if(t.preventDefault(),!document.body)return void console.warn("[AiMarkerShortcut] <body> element not found. Cannot toggle class. Ensure the DOM is fully loaded when using the shortcut.");document.body.classList.toggle("detect-made-by-ai")}})):console.error("[AiMarkerShortcut] Environment does not support the DOM. This function must be run in a browser.")}c([["undefined",e=>void 0===e],["null",e=>null===e],["boolean",e=>"boolean"==typeof e],["number",e=>"number"==typeof e&&!Number.isNaN(e)],["bigint",e=>"bigint"==typeof e],["string",e=>"string"==typeof e],["symbol",e=>"symbol"==typeof e],["function",e=>"function"==typeof e],["array",e=>Array.isArray(e)]]),h||c([["buffer",e=>void 0!==l.hp&&l.hp.isBuffer(e)]]),h&&c([["file",e=>"undefined"!=typeof File&&e instanceof File]]),c([["date",e=>e instanceof Date],["regexp",e=>e instanceof RegExp],["map",e=>e instanceof Map],["set",e=>e instanceof Set],["weakmap",e=>e instanceof WeakMap],["weakset",e=>e instanceof WeakSet],["promise",e=>e instanceof Promise]]),h&&c([["htmlelement",e=>"undefined"!=typeof HTMLElement&&e instanceof HTMLElement]]),c([["object",e=>v(e)]]);class S{#e;static#t={default:{reset:"[0m",key:"[36m",string:"[32m",string_url:"[34m",string_bool:"[35m",string_number:"[33m",number:"[33m",boolean:"[35m",null:"[1;30m",special:"[31m",func:"[90m"},solarized:{reset:"[0m",key:"[38;5;37m",string:"[38;5;136m",string_url:"[38;5;33m",string_bool:"[38;5;166m",string_number:"[38;5;136m",number:"[38;5;136m",boolean:"[38;5;166m",null:"[38;5;241m",special:"[38;5;160m",func:"[38;5;244m"},monokai:{reset:"[0m",key:"[38;5;81m",string:"[38;5;114m",string_url:"[38;5;75m",string_bool:"[38;5;204m",string_number:"[38;5;221m",number:"[38;5;221m",boolean:"[38;5;204m",null:"[38;5;241m",special:"[38;5;160m",func:"[38;5;102m"}};constructor(e={}){this.#e={...S.#t.default,...e}}#r(e,t){const r=[];e=(e=(e=e.replace(/(?<!")\b(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\b(?!")/g,`${t.number}$1${t.reset}`)).replace(/"([^"]+)":/g,((e,t)=>{const n=`___KEY${r.length}___`;return r.push({marker:n,key:t}),`${n}:`}))).replace(/"(?:\\.|[^"\\])*?"/g,(e=>{const r=e.slice(1,-1);return/^(https?|ftp):\/\/[^\s]+$/i.test(r)?`${t.string_url}${e}${t.reset}`:/^(true|false|null)$/.test(r)?`${t.string_bool}${e}${t.reset}`:/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(r)?`${t.string_number}${e}${t.reset}`:`${t.string}${e}${t.reset}`}));for(const{marker:n,key:i}of r){const r=new RegExp(n,"g");e=e.replace(r,`${t.key}"${i}"${t.reset}`)}return(e=(e=(e=(e=e.replace(/(?<!")\b(true|false)\b(?!")/g,`${t.boolean}$1${t.reset}`)).replace(/(?<!")\bnull\b(?!")/g,`${t.null}null${t.reset}`)).replace(/\[Circular\]/g,`${t.special}[Circular]${t.reset}`)).replace(/\[undefined\]/g,`${t.special}[undefined]${t.reset}`)).replace(/"function.*?[^\\]"/gs,`${t.func}$&${t.reset}`)}colorize(e,t={}){const r={...this.#e,...t};return this.#r(e,r)}getColors(){return{...this.#e}}updateColors(e){Object.assign(this.#e,e)}resetColors(){this.#e={...S.#t.default}}loadColorPreset(e){const t=S.#t[e];if(!t)throw new Error(`Preset "${e}" not found.`);this.#e={...t}}saveColorPreset(e,t){S.#t[e]={...t}}getAvailablePresets(){return Object.keys(S.#t)}}const I=S,L=class{#n=[];#i=!1;#o={};#s=new Set;isRunning(){return this.#i}async#u(e){if(e&&"function"==typeof e.task&&"function"==typeof e.resolve&&"function"==typeof e.reject){const{task:t,resolve:r,reject:n,delay:i,id:o}=e;try{if(o&&this.#s.has(o))return n(new Error("The function was canceled on TinyPromiseQueue.")),this.#s.delete(o),this.#i=!1,void this.#a();i&&o&&await new Promise((e=>{const t=setTimeout((()=>{delete this.#o[o],e(null)}),i);this.#o[o]=t})),r(await t())}catch(e){n(e)}finally{this.#i=!1,this.#a()}}}async#f(){const e=[];for(;this.#n.length&&"POINT_MARKER"===this.#n[0]?.marker;)e.push(this.#n.shift());if(0===e.length)return this.#i=!1,void this.#a();await Promise.all(e.map((({task:e,resolve:t,reject:r,id:n})=>new Promise((async i=>{if(n&&this.#s.has(n))return this.#s.delete(n),r(new Error("The function was canceled on TinyPromiseQueue.")),void i(!0);await e().then(t).catch(r),i(!0)}))))),this.#i=!1,this.#a()}async#a(){if(!this.#i&&0!==this.#n.length)if(this.#i=!0,"string"!=typeof this.#n[0]?.marker||"POINT_MARKER"!==this.#n[0]?.marker){const e=this.#n.shift();this.#u(e)}else this.#f()}getIndexById(e){return this.#n.findIndex((t=>t.id===e))}getQueuedIds(){return this.#n.map(((e,t)=>({index:t,id:e.id}))).filter((e=>"string"==typeof e.id))}reorderQueue(e,t){if("number"!=typeof e||"number"!=typeof t||e<0||t<0||e>=this.#n.length||t>=this.#n.length)return;const[r]=this.#n.splice(e,1);this.#n.splice(t,0,r)}async enqueuePoint(e,t){if("function"!=typeof e)return Promise.reject(new Error("Task must be a function returning a Promise."));if(void 0!==t&&"string"!=typeof t)throw new Error('The "id" parameter must be a string.');return this.#i?new Promise(((r,n)=>{this.#n.push({marker:"POINT_MARKER",task:e,resolve:r,reject:n,id:t}),this.#a()})):e()}enqueue(e,t,r){if("function"!=typeof e)return Promise.reject(new Error("Task must be a function returning a Promise."));if(void 0!==t&&("number"!=typeof t||t<0))return Promise.reject(new Error("Delay must be a positive number or undefined."));if(void 0!==r&&"string"!=typeof r)throw new Error('The "id" parameter must be a string.');return new Promise(((n,i)=>{this.#n.push({task:e,resolve:n,reject:i,id:r,delay:t}),this.#a()}))}cancelTask(e){if("string"!=typeof e)throw new Error('The "id" parameter must be a string.');let t=!1;e in this.#o&&(clearTimeout(this.#o[e]),delete this.#o[e],t=!0);const r=this.getIndexById(e);if(-1!==r){const[e]=this.#n.splice(r,1);e?.reject?.(new Error("The function was canceled on TinyPromiseQueue.")),t=!0}return t&&this.#s.add(e),t}},U=class{#l=null;#h=null;#p=null;#c=null;#g=null;#y=null;groupData=new Map;lastSeen=new Map;userToGroup=new Map;groupFlags=new Map;groupTTL=new Map;#m=null;setOnMemoryExceeded(e){if("function"!=typeof e)throw new Error("onMemoryExceeded must be a function");this.#m=e}clearOnMemoryExceeded(){this.#m=null}#d=null;setOnGroupExpired(e){if("function"!=typeof e)throw new Error("onGroupExpired must be a function");this.#d=e}clearOnGroupExpired(){this.#d=null}constructor({maxHits:e,interval:t,cleanupInterval:r,maxIdle:n=3e5,maxMemory:i=1e5}){const o=e=>"number"==typeof e&&Number.isFinite(e)&&e>=1&&Number.isInteger(e),s=o(e),u=o(t),a=o(r),f=o(n);if(!s&&!u)throw new Error("RateLimiter requires at least one valid option: 'maxHits' or 'interval'.");if(void 0!==e&&!s)throw new Error("'maxHits' must be a positive integer if defined.");if(void 0!==t&&!u)throw new Error("'interval' must be a positive integer in milliseconds if defined.");if(void 0!==r&&!a)throw new Error("'cleanupInterval' must be a positive integer in milliseconds if defined.");if(!f)throw new Error("'maxIdle' must be a positive integer in milliseconds.");if("number"==typeof i&&Number.isFinite(i)&&i>0)this.#l=Math.floor(i);else{if(null!=i)throw new Error("maxMemory must be a positive number or null");this.#l=null}this.#p=s?e:null,this.#c=u?t:null,this.#g=a?r:null,this.#y=n,null!==this.#g&&(this.#h=setInterval((()=>this._cleanup()),this.#g))}isGroupId(e){const t=this.groupFlags.get(e);return"boolean"==typeof t&&t}getUsersInGroup(e){const t=[];for(const[r,n]of this.userToGroup.entries())n===e&&t.push(r);return t}setGroupTTL(e,t){if("number"!=typeof t||!Number.isFinite(t)||t<=0)throw new Error("TTL must be a positive number in milliseconds");this.groupTTL.set(e,t)}getGroupTTL(e){return this.groupTTL.get(e)??null}deleteGroupTTL(e){this.groupTTL.delete(e)}assignToGroup(e,t){const r=this.userToGroup.get(e);if(r&&r!==t)throw new Error(`User ${e} is already assigned to group ${r}`);if(r===t)return;const n=this.groupData.get(e);if(this.isGroupId(e)){for(const[r,n]of this.userToGroup.entries())n===e&&this.userToGroup.set(r,t);this.userToGroup.delete(e)}else this.userToGroup.set(e,t);if(!n)return;const i=this.groupData.get(t);if(i)for(const e of n)i.push(e);else{const e=[];for(const t of n)e.push(t);this.groupData.set(t,e)}this.lastSeen.set(t,Date.now()),this.groupFlags.delete(e),this.groupData.delete(e),this.lastSeen.delete(e),this.groupTTL.delete(e),this.groupFlags.set(t,!0)}getGroupId(e){return this.userToGroup.get(e)||e}hit(e){const t=this.getGroupId(e),r=Date.now();this.groupData.has(t)||(this.groupData.set(t,[]),this.groupFlags.set(t,!1));const n=this.groupData.get(t);if(!n)throw new Error(`No data found for groupId: ${t}`);if(n.push(r),this.lastSeen.set(t,r),null!==this.#c){const e=r-this.getInterval();for(;n.length&&n[0]<e;)n.shift()}null!==this.#l&&"number"==typeof this.#l&&n.length>this.#l&&(n.splice(0,n.length-this.#l),"function"==typeof this.#m&&this.#m(t))}isRateLimited(e){const t=this.getGroupId(e);if(!this.groupData.has(t))return!1;const r=this.groupData.get(t);if(!r)throw new Error(`No data found for groupId: ${t}`);if(null!==this.#c){const e=Date.now()-this.getInterval();let t=0;for(let n=r.length-1;n>=0&&r[n]>e;n--)t++;return null!==this.#p?t>this.getMaxHits():t>0}return null!==this.#p&&r.length>this.getMaxHits()}resetGroup(e){this.groupFlags.delete(e),this.groupData.delete(e),this.lastSeen.delete(e),this.groupTTL.delete(e)}reset(e){return this.resetUserGroup(e)}resetUserGroup(e){this.userToGroup.delete(e)}setData(e,t){if(!Array.isArray(t))throw new Error("timestamps must be an array of numbers.");for(const e of t)if("number"!=typeof e||!Number.isFinite(e))throw new Error("All timestamps must be finite numbers.");this.groupData.has(e)||this.groupFlags.set(e,!1),this.groupData.set(e,t),this.lastSeen.set(e,Date.now())}hasData(e){return this.groupData.has(e)}getData(e){return this.groupData.get(e)||[]}getMaxIdle(){if("number"!=typeof this.#y||!Number.isFinite(this.#y)||this.#y<0)throw new Error("'maxIdle' must be a non-negative finite number.");return this.#y}setMaxIdle(e){if("number"!=typeof e||!Number.isFinite(e)||e<0)throw new Error("'maxIdle' must be a non-negative finite number.");this.#y=e}_cleanup(){const e=Date.now();for(const[t,r]of this.lastSeen.entries())e-r>(this.getGroupTTL(t)??this.getMaxIdle())&&(this.groupFlags.delete(t),this.groupData.delete(t),this.lastSeen.delete(t),this.groupTTL.delete(t),"function"==typeof this.#d&&this.#d(t))}getActiveGroups(){return Array.from(this.groupData.keys())}getAllUserMappings(){return Object.fromEntries(this.userToGroup)}getInterval(){if("number"!=typeof this.#c||!Number.isFinite(this.#c))throw new Error("'interval' is not a valid finite number.");return this.#c}getMaxHits(){if("number"!=typeof this.#p||!Number.isFinite(this.#p))throw new Error("'maxHits' is not a valid finite number.");return this.#p}getTotalHits(e){const t=this.groupData.get(e);return Array.isArray(t)?t.length:0}getLastHit(e){const t=this.groupData.get(e);return t?.length?t[t.length-1]:null}getTimeSinceLastHit(e){const t=this.getLastHit(e);return null!==t?Date.now()-t:null}_calculateAverageSpacing(e){if(!Array.isArray(e)||e.length<2)return null;let t=0;for(let r=1;r<e.length;r++)t+=e[r]-e[r-1];return t/(e.length-1)}getAverageHitSpacing(e){return this._calculateAverageSpacing(this.groupData.get(e))}getMetrics(e){const t=this.groupData.get(e);if(!Array.isArray(t)||0===t.length)return{totalHits:0,lastHit:null,timeSinceLastHit:null,averageHitSpacing:null};const r=t.length,n=t[r-1];return{totalHits:r,lastHit:n,timeSinceLastHit:Date.now()-n,averageHitSpacing:this._calculateAverageSpacing(t)}}destroy(){this.#h&&clearInterval(this.#h),this._cleanup(),this.groupData.clear(),this.lastSeen.clear(),this.userToGroup.clear(),this.groupTTL.clear(),this.groupFlags.clear()}}})(),window.TinyEssentials=n})();
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Class representing a flexible rate limiter per user.
|
|
5
|
-
*
|
|
6
|
-
* This rate limiter can be configured by maximum number of hits,
|
|
7
|
-
* time interval, or a combination of both. It supports automatic
|
|
8
|
-
* cleanup of inactive users to optimize memory usage.
|
|
9
|
-
*
|
|
10
|
-
* @class
|
|
11
|
-
*/
|
|
12
|
-
class TinyRateLimiter {
|
|
13
|
-
/**
|
|
14
|
-
* @param {Object} options
|
|
15
|
-
* @param {number} [options.maxHits] - Max interactions allowed
|
|
16
|
-
* @param {number} [options.interval] - Time window in milliseconds
|
|
17
|
-
* @param {number} [options.cleanupInterval=60000] - Interval for automatic cleanup (ms)
|
|
18
|
-
* @param {number} [options.maxIdle=300000] - Max idle time for a user before being cleaned (ms)
|
|
19
|
-
*/
|
|
20
|
-
constructor({ maxHits, interval, cleanupInterval = 60000, maxIdle = 300000 }) {
|
|
21
|
-
/** @param {number|undefined} val */
|
|
22
|
-
const isPositiveInteger = (val) =>
|
|
23
|
-
typeof val === 'number' && Number.isFinite(val) && val >= 1 && Number.isInteger(val);
|
|
24
|
-
|
|
25
|
-
const isMaxHitsValid = isPositiveInteger(maxHits);
|
|
26
|
-
const isIntervalValid = isPositiveInteger(interval);
|
|
27
|
-
const isCleanupValid = isPositiveInteger(cleanupInterval);
|
|
28
|
-
const isMaxIdleValid = isPositiveInteger(maxIdle);
|
|
29
|
-
|
|
30
|
-
if (!isMaxHitsValid && !isIntervalValid)
|
|
31
|
-
throw new Error("RateLimiter requires at least one valid option: 'maxHits' or 'interval'.");
|
|
32
|
-
if (maxHits !== undefined && !isMaxHitsValid)
|
|
33
|
-
throw new Error("'maxHits' must be a positive integer if defined.");
|
|
34
|
-
if (interval !== undefined && !isIntervalValid)
|
|
35
|
-
throw new Error("'interval' must be a positive integer in milliseconds if defined.");
|
|
36
|
-
if (!isCleanupValid)
|
|
37
|
-
throw new Error("'cleanupInterval' must be a positive integer in milliseconds.");
|
|
38
|
-
if (!isMaxIdleValid) throw new Error("'maxIdle' must be a positive integer in milliseconds.");
|
|
39
|
-
|
|
40
|
-
this.maxHits = isMaxHitsValid ? maxHits : null;
|
|
41
|
-
this.interval = isIntervalValid ? interval : null;
|
|
42
|
-
this.cleanupInterval = cleanupInterval;
|
|
43
|
-
this.maxIdle = maxIdle;
|
|
44
|
-
|
|
45
|
-
/** @type {Map<string, number[]>} */
|
|
46
|
-
this.userData = new Map();
|
|
47
|
-
|
|
48
|
-
/** @type {Map<string, number>} */
|
|
49
|
-
this.lastSeen = new Map();
|
|
50
|
-
|
|
51
|
-
// Start automatic cleanup
|
|
52
|
-
this._cleanupTimer = setInterval(() => this._cleanup(), this.cleanupInterval);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Get the interval window in milliseconds.
|
|
57
|
-
*
|
|
58
|
-
* @returns {number} The interval value.
|
|
59
|
-
* @throws {Error} If interval is not a valid finite number.
|
|
60
|
-
*/
|
|
61
|
-
getInterval() {
|
|
62
|
-
if (typeof this.interval !== 'number' || !Number.isFinite(this.interval))
|
|
63
|
-
throw new Error("'interval' is not a valid finite number.");
|
|
64
|
-
return this.interval;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Get the maximum number of allowed hits.
|
|
69
|
-
*
|
|
70
|
-
* @returns {number} The maxHits value.
|
|
71
|
-
* @throws {Error} If maxHits is not a valid finite number.
|
|
72
|
-
*/
|
|
73
|
-
getMaxHits() {
|
|
74
|
-
if (typeof this.maxHits !== 'number' || !Number.isFinite(this.maxHits)) {
|
|
75
|
-
throw new Error("'maxHits' is not a valid finite number.");
|
|
76
|
-
}
|
|
77
|
-
return this.maxHits;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Register a hit for a specific user
|
|
82
|
-
* @param {string} userId
|
|
83
|
-
*/
|
|
84
|
-
hit(userId) {
|
|
85
|
-
const now = Date.now();
|
|
86
|
-
|
|
87
|
-
if (!this.userData.has(userId)) {
|
|
88
|
-
this.userData.set(userId, []);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const history = this.userData.get(userId);
|
|
92
|
-
if (!history) throw new Error(`No data found for userId: ${userId}`);
|
|
93
|
-
|
|
94
|
-
history.push(now);
|
|
95
|
-
this.lastSeen.set(userId, now);
|
|
96
|
-
|
|
97
|
-
// Clean up old entries
|
|
98
|
-
if (this.interval !== null) {
|
|
99
|
-
const interval = this.getInterval();
|
|
100
|
-
const cutoff = now - interval;
|
|
101
|
-
while (history.length && history[0] < cutoff) {
|
|
102
|
-
history.shift();
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Optional: keep only the last N entries for memory optimization
|
|
107
|
-
if (this.maxHits !== null) {
|
|
108
|
-
const maxHits = this.getMaxHits();
|
|
109
|
-
if (history.length > maxHits) {
|
|
110
|
-
history.splice(0, history.length - maxHits);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Check if the user is currently rate limited
|
|
117
|
-
* @param {string} userId
|
|
118
|
-
* @returns {boolean}
|
|
119
|
-
*/
|
|
120
|
-
isRateLimited(userId) {
|
|
121
|
-
const now = Date.now();
|
|
122
|
-
|
|
123
|
-
if (!this.userData.has(userId)) return false;
|
|
124
|
-
|
|
125
|
-
const history = this.userData.get(userId);
|
|
126
|
-
if (!history) throw new Error(`No data found for userId: ${userId}`);
|
|
127
|
-
|
|
128
|
-
if (this.interval !== null) {
|
|
129
|
-
const interval = this.getInterval();
|
|
130
|
-
const recent = history.filter((t) => t > now - interval);
|
|
131
|
-
if (this.maxHits !== null) {
|
|
132
|
-
return recent.length >= this.getMaxHits();
|
|
133
|
-
}
|
|
134
|
-
return recent.length > 0;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (this.maxHits !== null) {
|
|
138
|
-
return history.length >= this.getMaxHits();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Manually reset user data
|
|
146
|
-
* @param {string} userId
|
|
147
|
-
*/
|
|
148
|
-
reset(userId) {
|
|
149
|
-
this.userData.delete(userId);
|
|
150
|
-
this.lastSeen.delete(userId);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Set hit timestamps for a user
|
|
155
|
-
* @param {string} userId
|
|
156
|
-
* @param {number[]} timestamps
|
|
157
|
-
*/
|
|
158
|
-
setData(userId, timestamps) {
|
|
159
|
-
this.userData.set(userId, timestamps);
|
|
160
|
-
this.lastSeen.set(userId, Date.now());
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Get timestamps from user
|
|
165
|
-
* @param {string} userId
|
|
166
|
-
* @returns {number[]}
|
|
167
|
-
*/
|
|
168
|
-
getData(userId) {
|
|
169
|
-
return this.userData.get(userId) || [];
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Cleanup old/inactive users
|
|
174
|
-
* @private
|
|
175
|
-
*/
|
|
176
|
-
_cleanup() {
|
|
177
|
-
const now = Date.now();
|
|
178
|
-
for (const [userId, last] of this.lastSeen.entries()) {
|
|
179
|
-
if (now - last > this.maxIdle) {
|
|
180
|
-
this.userData.delete(userId);
|
|
181
|
-
this.lastSeen.delete(userId);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Destroy the rate limiter, stopping all intervals
|
|
188
|
-
*/
|
|
189
|
-
destroy() {
|
|
190
|
-
clearInterval(this._cleanupTimer);
|
|
191
|
-
this.userData.clear();
|
|
192
|
-
this.lastSeen.clear();
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
module.exports = TinyRateLimiter;
|