├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── localDataStorage-3.0.0.js ├── localDataStorage-3.0.0.min.js ├── localDataStorage-3.0.0.trim.js └── wiki-extra └── Memory-Requirements2.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: ["https://su.pport.me/mac/"] 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, William McMeans 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 💼 localDataStorage
2 | [![Maintenance](https://img.shields.io/badge/Maintained%3F-Yes-green.svg)](https://github.com/macmcmeans/localDataStorage/graphs/commit-activity) 3 | [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) 4 | [![Minified](https://img.shields.io/github/size/macmcmeans/localdatastorage/localDataStorage-3.0.0.min.js?color=violet&label=Minified)](https://cdn.jsdelivr.net/gh/macmcmeans/localDataStorage@3.0.0/localDataStorage-3.0.0.min.js) 5 | [![Latest](https://img.shields.io/github/v/tag/macmcmeans/localdatastorage?sort=semver&style=flat)](https://github.com/macmcmeans/localDataStorage/releases/tag/v3.0.0) 6 | [![UTF8](https://img.shields.io/badge/UTF‑8%20%F0%9F%98%83-Yes-orange)](https://www.smashingmagazine.com/2012/06/all-about-unicode-utf8-character-sets/) 7 | [![SU.PPORT.ME](https://img.shields.io/badge/SU.PPORT.ME-Mac-brightgreen)](https://su.pport.me/mac/) 8 | 9 | ### TL;DR 10 | Directly use [![](https://img.shields.io/static/v1?label=&message=Array&color=gold)](https://github.com/macmcmeans/localDataStorage/blob/master/README.md) 11 | [![](https://img.shields.io/static/v1?label=&message=BigInt&color=gold)](https://github.com/macmcmeans/localDataStorage/blob/master/README.md) 12 | [![](https://img.shields.io/static/v1?label=&message=Boolean&color=gold)](https://github.com/macmcmeans/localDataStorage/blob/master/README.md) 13 | [![](https://img.shields.io/static/v1?label=&message=Date&color=gold)](https://github.com/macmcmeans/localDataStorage/blob/master/README.md) 14 | [![](https://img.shields.io/static/v1?label=&message=Float&color=gold)](https://github.com/macmcmeans/localDataStorage/blob/master/README.md) 15 | [![](https://img.shields.io/static/v1?label=&message=Integer&color=gold)](https://github.com/macmcmeans/localDataStorage/blob/master/README.md) 16 | [![](https://img.shields.io/static/v1?label=&message=Object&color=gold)](https://github.com/macmcmeans/localDataStorage/blob/master/README.md) 17 | [![](https://img.shields.io/static/v1?label=&message=String&color=gold)](https://github.com/macmcmeans/localDataStorage/blob/master/README.md) in localStorage with no conversion. 18 |
 
19 | 20 | ### Highlights 21 | This is a synchronous JavaScript interface for the HTML5 localStorage API that-- 22 | 1) __transparently sets/gets__ key values using data "types" such as Array, BigInt, Boolean, Date, Float, Integer, Object and String; 23 | 2) __provides__ lightweight __data obfuscation__; 24 | 3) intelligently __compresses strings__ (to save storage space); 25 | 4) __facilitates robust lookup__ including query by key (name), query by (key) value and query by existence (boolean check); 26 | 5) __enforces segmented shared storage__ within the same domain by prefixing keys; 27 | 6) lets you __respond to localStorage change events__ on the same page/tab that fired them; 28 | 7) __broadcasts__ change events across the origin for the benefit of other windows/tabs; 29 | 8) lets you __easily work with arrays__ using dedicated Array Keys; and 30 | 9) offers __Memory Keys__ (that can be backed up to disk) for the fastest read times possible. 31 | 32 |
 
33 | Version 3.0.0
34 | Author: W. “Mac” McMeans
35 | Date: 12 AUG 2022 36 |
 
37 | 38 | ## Trusted Installation 39 | 40 | ### Include via CDN 41 | 42 | ```js 43 | 48 | ``` 49 | Since the source file is delivered from a repository over which we have no control, best practices demand we do not trust it. Thus we use [Subresource Integrity](https://archive.ph/ll97b) (SRI) to prevent tampering. 50 | 51 | Unlike the [BrowseAloud story](https://archive.ph/vuKft), my library is a static, self-contained resource which can be fully protected by SRI. 52 |
 
53 | 54 | ## Application: 55 | Primary usage is the ability to seamlessly *set/get* keys for typical data types without having to perform conversion in your own logic. Toss out an integer and have it returned. Throw an array into storage and get it back, including the ability to add and remove elements. Are you also working with dates, booleans or objects? No problem. While it’s not rocket science to convert, track and restore your own data, letting the interface handle that chore for you is exceptionally convenient. It also saves you the hassle having to incorporate conversion logic in your application. To track a data type, storage management requires one additional byte of memory overhead per key value, so an eight-byte array, for example, will be stored using nine bytes. 56 | 57 | Data Protection
Since localStorage data resides in a client environment where the information is not protected from access or tampering, this data can be rendered unintelligible at the expense of a small amount of memory overhead. Depending on your application, this may be worth the tradeoff. To hide your data, key values may be obfuscated using *safeset/safeget*. A master scramble key may be set globally, or individual scramble keys may be used per each *safeset/safeget* call. Scramble keys can be any value and of any type (array, boolean, date, float, integer, etc.) Key values that have been *safeset* with an individual scramble key can always be retrieved, but cannot be reconstructed apart from the exact scramble key with which they were obfuscated. For convenience, the global scramble key is stored in the interface. For security, individual scramble keys are not. The global scramble key may be accessed using *setscramblekey/getscramblekey* methods. Individual scramble keys must be remembered. 58 | 59 | Scrambling is not encryption. For example, no attempt is made to conceal data lengths by artificially padding to a minimum length. This would be counterproductive to minimizing memory usage. 60 | 61 | Compression
Strings are intelligently compressed on‑the‑fly when storing. This means they are first analyzed to determine whether compression would lower the actual byte count (not string length) needed for storage, and if so, are silently compressed for you. This works well for common English texts (short‑length, 7‑bit ASCII), and not much else. If desired, you may manually *crunch/uncrunch* your own key values. 62 | 63 | Robust Access
One may query by key (the standard way) or query by existence (*haskey* checks if the key is in the store while *hasval* checks if the store contains the value). You can query for duplicate values with *listdupes* and *showdupes*. Convenience methods prevent writing over an existing key *(softset)* and permit deleting a key immediately upon retrieval *(chopget)*. You can easily query and update an array key using *push/pull* and *contains* without the need for external array logic. Key values can be checked for their data type, for example, using *isfloat*, and keys can be renamed (*rename*). Lastly, bypass methods *(forceset/forceget)* permit accessing localStorage directly. 64 | 65 | Storage Management
Since HTML5 localStorage is accessible to all processes running in the browser for the domain visited, it is advisable to have an interface that segments access. To that end, the use of prefixed keys is strongly encouraged, and localDataStorage will only read/write/delete its own values. Unlike the HTML5 API, there is no method in the interface to clear all storage keys, only all prefixed keys. At any time, memory usage can be tracked against key values and key names, for example, using *valbytes* or *keybytes*. 66 | 67 | The domain of operation for HTML5 localStorage is specific to the protocol, host & port; and multiple instances of localDataStorage can be run against the same domain at the same time. It is emoji‑friendly 🤪🤷‍♂️💖👍, which is to say that key names and their values, as well as scramble keys and storage prefixes, are multibyte Unicode‑safe. 68 | 69 | 70 | ## Events 71 | The native localStorage change event is... lacking. Per the misguided whims of the interweb gods, a web page in your browser isn’t permitted to listen to change events that it alone triggers. However, in the event you'd like to keep an ear out for changes, localDataStorage will let you. The interface fires a custom event on key value changes, such as those made by the *chopget*, *clear*, *forceset*, *remove*, *rename*, *safeset*, *set* and *softset* methods. The event returns an activity timestamp and message, as well as expected details about the affected key with its old and new values (and old and new data types, etc.) Insert your own function here to catch the changes. This code snippet shows what's exposed so you can respond accordingly: 72 | 73 | ```js 74 | const nowICanSeeLocalStorageChangeEvents = function( e ) { 75 | console.log( 76 | "subscriber: " + e.currentTarget.nodeName + "\n" + 77 | "date: " + e.detail.date + "\n" + 78 | "timestamp: " + e.detail.timestamp + "\n" + 79 | "prefix: " + e.detail.prefix + "\n" + 80 | "message: " + e.detail.message + "\n" + 81 | "method: " + e.detail.method + "\n" + 82 | "old key: " + e.detail.oldkey + "\n" + 83 | "new key: " + e.detail.newkey + "\n" + 84 | "old value: " + e.detail.oldval + "\n" + 85 | "new value: " + e.detail.newval + "\n" + 86 | "old type: " + e.detail.oldtype + "\n" + 87 | "new type: " + e.detail.newtype + "\n" + 88 | "old base: " + e.detail.oldbase + "\n" + 89 | "new base: " + e.detail.newbase 90 | ); 91 | 92 | // respond to key change by passing key name 93 | myCustomChangeFunction( e.detail.oldkey ); 94 | } 95 | 96 | document.addEventListener( 97 | "localDataStorage" 98 | , nowICanSeeLocalStorageChangeEvents 99 | , false 100 | ); 101 | 102 | ``` 103 |
 
104 | 105 | 106 | ## Dependencies: 107 | There are no external dependencies. 108 | 109 | Internally, obfuscation is supported by [fisherYatesDurstenfeldKnuthShuffle](#refs) and [aleaPRNG](#refs) (my own libraries). 110 |
 
111 | 112 | 113 | ## SemVer: 114 | Recognizing there is no way I can predict how a change in my software will affect users, I still use [semantic versioning](https://archive.ph/Z02ta) (semver) to signal those changes. 115 | 116 | Per [Hyrum’s Law](https://archive.ph/IGprL), I gently suggest you may enjoy, but I do not promise you will actually have a bug-free upgrade experience. 117 |
 
118 | 119 | 120 | ## Falsy pedantics: 121 | There is a universe of difference between a variable considered _null_ and one that is _undefined_. In JavaScript, both of these are [falsy](https://archive.ph/PCDvQ) and both are primitive types (despite what `typeof null` tells you). Yet they are also quite distinct. 122 | 123 | A value of null means the variable has been set to nothing whatsoever, but it has been set nevertheless. 124 | 125 | In contrast, an undefined variable has no value because the variable itself doesn't exist (it is undeclared). 126 | 127 | With null, the variable is set to no value but if undefined, it isn't set. The distinction is important. The native localStorage API returns _null_ when getting a key that doesn't exist. (Pedantically, this is false.) 128 | 129 | However, localDataStorage returns _undefined_ for an undeclared key simply because it isn't present in the store. Further, you could actually store a null value key using localDataStorage if your use case required, but at no time will non-existant keys be returned as nulls. The distinction is just. Too. Important. 130 |
 
131 | 132 | 133 | ## Wiki: 134 | Here's the documentation for the interface (95% complete). 135 |
 
136 | 137 | 138 | ## Example usage: 139 | 140 | Create an instance of localDataStorage using the specified key name prefix 141 | > localData = localDataStorage( 'passphrase.life' ) 142 | 143 | --> Instantiated. Prefix adds 16.00 bytes to every key name (stored using 32.00 bytes). 144 | 145 | 146 |
 
147 | typical set/get calls (data types are respected and returned transparently) 148 | > localData.set( 'key1', 19944.25 ) 149 | 150 | > localData.get( 'key1' ) 151 | 152 | --> 19944.25 153 | 154 | > localData.set( 'key2', 2519944 ) 155 | 156 | > localData.get( 'key2' ) 157 | 158 | --> 2519944 159 | 160 | > localData.set( 'key3', true ) 161 | 162 | > localData.get( 'key3' ) 163 | 164 | --> true 165 | 166 | > localData.set( 'key4', 'data' ) 167 | 168 | > localData.get( 'key4' ) 169 | 170 | --> "data" 171 | 172 | > localData.set( 'key5', [1,2,3,4,9] ) 173 | 174 | > localData.get( 'key5' ) 175 | 176 | --> [1, 2, 3, 4, 9] 177 | 178 | > localData.set( 'key6', new Date() ) 179 | 180 | > localData.get( 'key6' ) 181 | 182 | --> Mon May 01 2017 14:39:11 GMT-0400 (Eastern Daylight Time) 183 | 184 | > localData.set( 'key7', {'a': [1,2,3] } ) 185 | 186 | > localData.get( 'key7' ) 187 | 188 | --> Object {a: Array(3)} 189 | 190 | 191 | 192 | 193 |
 
194 | get the "size" of a key's value (codepoints) 195 | > localData.size( 'key4' ) 196 | 197 | --> 4 198 |
total codepoints in value (not length, not graphemes) 199 | 200 | 201 | 202 | 203 |
 
204 | results when querying a non-existing key 205 | > localData.forceget( 'non-existing key' ) 206 | 207 | --> null 208 |
same as localStorage.getItem( 'non-existing key' ) 209 | 210 | > localData.get( 'non-existing key' ) 211 | 212 | --> undefined 213 |
the key is undefined because it does not exist, it is NOT null 214 | 215 | > localData.chopget( 'non-existing key' ) 216 | 217 | --> undefined 218 | 219 | > localData.safeget( 'non-existing key' ) 220 | 221 | --> undefined 222 | 223 | 224 | 225 |
 
226 | read then delete a key 227 | > x = localData.chopget( 'key7' ) 228 | 229 | --> Object {a: Array(3)} 230 | 231 | > localData.get( 'key7' ) 232 | 233 | --> undefined 234 | 235 | 236 | 237 |
 
238 | don't overwrite an existing key 239 | > localData.softset( 'key4', 'new data' ) 240 | 241 | > localData.get( 'key4' ) 242 | 243 | --> "data" 244 | 245 | 246 | 247 |
 
248 | set/get key, bypassing any data type embedding, but still observing key prefixes 249 | > localData.forceset( 'api', 13579 ) 250 | 251 | all values are stored as strings, in this case under the key passphrase.life.api 252 | 253 | > localData.forceget( 'api' ) 254 | 255 | --> "13579" 256 | 257 | > localData.forceget( 'key6' ) 258 | 259 | --> ""2017-05-01T18:39:11.443Z"" 260 | 261 | 262 | 263 |
 
264 | find duplicate key values 265 | > localData.set( 'key8', 'data' ) 266 | 267 | now key4 and key8 have the same values 268 | 269 | > localData.countdupes() 270 | 271 | --> 1 272 | 273 | > localData.showdupes() 274 | 275 | --> ["data"] 276 |
this key value occurs twice minimum 277 | 278 |
 
279 | // handling duplicates; localData vs localStorage API 280 | 281 | > localData.forceset( 'dupekey1', 1234 ) 282 | 283 | will be stored as a string 284 | 285 | > localData.forceset( 'dupekey2', '1234' ) 286 | 287 | will be stored as a string 288 | 289 |
 
290 | // look for duplicates (among localStorage keys) 291 | 292 | > localData.showdupes() 293 | 294 | --> [1234, "data"] 295 | 296 |
 
297 | // remove a key 298 | 299 | > localData.remove( 'dupekey1' ) 300 | 301 | prep 302 | 303 | > localData.remove( 'dupekey2' ) 304 | 305 | prep 306 | 307 | > localData.remove( 'key8' ) 308 | 309 | prep 310 | 311 |
 
312 | > localData.set( 'dupekey3', 1234 ) 313 | 314 | stored as string, but recognized as integer 315 | 316 | > localData.set( 'dupekey4', '1234' ) 317 | 318 | stored and recognized as string 319 | 320 |
 
321 | // look for duplicates (among localData types) 322 | 323 | > localData.showdupes() 324 | 325 | --> [] 326 |
since data types are respected, no dupes were found 327 | 328 |
 
329 | > localData.set( 'dupekey1', 1234 ) 330 | 331 | prep 332 | 333 | > localData.set( 'dupekey2', '1234' ) 334 | 335 | prep 336 | 337 | > localData.set( 'key8', 'data' ) 338 | 339 | prep 340 | 341 |
 
342 | > localData.countdupes() 343 | 344 | --> 3 345 | 346 | > localData.listdupes() 347 | 348 | --> Object {dupecount: 3, dupes: Object} 349 | 350 | > localData.listdupes().dupecount 351 | 352 | --> 3 353 | 354 | > localData.listdupes().dupes 355 | 356 | --> Object {0: Object, 1: Object, 2: Object} 357 | 358 | > localData.listdupes().dupes[0] 359 | 360 | --> Object {value: 1234, keys: Array(2)} 361 | 362 | > localData.listdupes().dupes[0].value 363 | 364 | --> 1234 365 | 366 | > localData.listdupes().dupes[0].keys 367 | 368 | --> ["dupekey1", "dupekey3"] 369 | 370 | 371 | 372 |
 
373 | check if key exists 374 | > localData.haskey( 'dupekey3' ) 375 | 376 | --> true 377 | 378 | 379 | 380 |
 
381 | check if value exists 382 | > localData.hasval( 1234 ) 383 | 384 | --> true 385 |
checks value AND data type 386 | 387 |
 
388 | > localData.set( 'testkey', 89.221 ) 389 | 390 | prep 391 | 392 | > localData.hasval( '89.221' ) 393 | 394 | --> false 395 |
the float (number) type does not match the string type 396 | 397 |
 
398 | > localData.forceset( 'LSkey1', 98765 ) 399 | 400 | set key value using localStorage API (handled as string) 401 | 402 | > localData.forcehasval( 98765 ) 403 | 404 | --> true 405 | 406 | > localData.forcehasval( '98765' ) 407 | 408 | --> true 409 |
localStorage API does not discern between data types 410 | 411 |
 
412 | > localData.hasval( 98765 ) 413 | 414 | --> true 415 |
localData attempts to coerce any value not explicity set by it 416 | 417 | > localData.hasval( '98765' ) 418 | 419 | --> false 420 |
localData will first coerce a value to a number, if possible 421 | 422 | 423 | 424 |
 
425 | show key's value type 426 | > localData.showtype( 'dupekey3' ) 427 | 428 | --> "integer" 429 | 430 | > localData.showtype( 'dupekey4' ) 431 | 432 | --> "string" 433 | 434 | > localData.showtype( 'key1' ) 435 | 436 | --> "float" 437 | 438 | > localData.showtype( 'key3' ) 439 | 440 | --> "boolean" 441 | 442 | > localData.showtype( 'key5' ) 443 | 444 | --> "array" 445 | 446 | > localData.showtype( 'key6' ) 447 | 448 | --> "date" 449 | 450 | > localData.set( 'key7', {'local' : ['d', 'a', 't', 'a']} ) 451 | 452 | prep 453 | 454 | > localData.showtype( 'key7' ) 455 | 456 | --> "object" 457 | 458 | 459 | 460 |
 
461 | boolean check the data type of a key's value 462 | > localData.isarray( 'key5' ) 463 | 464 | --> true 465 | 466 | > localData.isfloat( 'testkey' ) 467 | 468 | --> true 469 | 470 | > localData.isnumber( 'testkey' ) 471 | 472 | --> true 473 | 474 | 475 | 476 |
 
477 | query by key value, not key name (returns first found) 478 | > localData.showkey( 1234 ) 479 | 480 | --> "dupekey1" 481 | 482 | > localData.showkey( '1234' ) 483 | 484 | --> "dupekey2" 485 | 486 |
 
487 | // returns all found 488 | 489 | > localData.showkeys( 1234 ) 490 | 491 | --> ["dupekey1", "dupekey3"] 492 | 493 | 494 | 495 |
 
496 | using the global scramble key for obfuscation 497 | > localData.getscramblekey() 498 | 499 | --> 123456789 500 |
default global scramble key (integer) 501 | 502 | > localData.safeset( 'ss1', '007' ) 503 | 504 | --> (stored scrambled) 505 | 506 | > localData.safeget( 'ss1' ) 507 | 508 | --> "007" 509 | 510 |
 
511 | > localData.setscramblekey( new Date() ) 512 | 513 | // set global scramble key to the current date, as date object 514 | 515 | > localData.getscramblekey() 516 | 517 | --> Mon May 01 2017 22:28:11 GMT-0400 (Eastern Daylight Time) 518 | 519 |
 
520 | > localData.safeget( 'ss1' ) 521 | 522 | --> (garbled data) 523 |
different global scramble key used for retrieval 524 | 525 |
 
526 | // using an individual scramble key for obfuscation 527 | 528 | > localData.safeset( 'ss2', 'test', {'scramble': ['key']} ) 529 | 530 | --> (stored scrambled) 531 |
scramble keys can be any value and of any data type 532 | 533 | > localData.safeget( 'ss2', {'scramble': ['key']} ) 534 | 535 | --> "test" 536 | 537 |
 
538 | > localData.safeget( 'ss1', 123456789 ) 539 | 540 | -> "007" 541 | 542 | 543 | 544 |
 
545 | safeget will not retrieve an unscrambled key 546 | > localData.safeget( 'key4' ) 547 | 548 | --> (garbled data) 549 | 550 | 551 | 552 |
 
553 | renaming keys 554 | // non-scambled keys can safely be renamed 555 | 556 | > localData.rename( 'key4', 'key4-renamed' ) 557 | 558 | key4 no longer exists 559 | 560 | > localData.get( 'key4' ) 561 | 562 | --> undefined 563 | 564 | > localData.get( 'key4-renamed' ) 565 | 566 | --> "data" 567 | 568 |
 
569 | // scrambled keys cannot be renamed: the key name and the value together produce the obfuscation 570 | 571 | > localData.rename( 'ss1', 'ss1-renamed' ) 572 | 573 | key ss1 no longer exists 574 | 575 | > localData.safeget( 'ss1' ) 576 | 577 | --> undefined 578 | 579 | > localData.safeget( 'ss1-renamed', 123456789 ) 580 | 581 | --> (garbled data) 582 |
this was the correct scramble key for the 'ss1' key, but not for the 'ss1-renamed' key 583 | 584 |
 
585 | > localData.rename( 'ss1-renamed', 'ss1' ) 586 | key ss1-renamed no longer exists 587 | 588 | > localData.safeget( 'ss1-renamed' ) 589 | 590 | --> undefined 591 | 592 | > localData.safeget( 'ss1', 123456789 ) 593 | 594 | --> "007" 595 | 596 | 597 | 598 |
 
599 | how localDataStorage reacts to values set via the localStorage API 600 | > localData.forceset( 'lsAPIkey', 77.042 ) 601 | 602 | always stored as a string by the native API 603 | 604 | > localData.forceget( 'lsAPIkey' ) 605 | 606 | --> "77.042" 607 | 608 | > localData.get( 'lsAPIkey' ) 609 | 610 | --> 77.042 611 |
localData will coerce value to number when possible 612 | 613 | > localData.showtype( 'lsAPIkey' ) 614 | 615 | --> "presumed number" 616 |
('presumed' because value was coerced, not set) 617 | 618 | 619 | 620 |
 
621 | there are several ways to track memory usage 622 | 623 | // show memory required to store key value 624 | 625 | > localData.showtype( 'dupekey4' ) 626 | 627 | --> "string"; 628 | 629 | > localData.get( 'dupekey4' ) 630 | 631 | --> "1234" 632 | 633 | > localData.size( 'dupekey4' ) 634 | 635 | --> 4 636 | 637 | > localData.valbytes( 'dupekey4' ) 638 | 639 | --> "8.00 bytes" 640 |
localStorage uses 16 bits to store 1 byte (only the data is counted) 641 | 642 | > localData.valbytesall( 'dupekey4' ) 643 | 644 | --> "12.00 bytes" 645 |
now we include the 2-byte embedded marker (total data) 646 | 647 |
 
648 | // show memory required to store key name 649 | > localData.keybytes( 'dupekey4' ) 650 | 651 | --> "48.00 bytes" 652 |
the prefix ('passphrase.life' + '.') is 32 bytes, plus key name is 16 bytes more ('dupekey4' ), yielding 48 bytes 653 | 654 |
 
655 | // show memory used by the key-value pair 656 | 657 | // key name + raw value 658 | 659 | > localData.bytes( 'dupekey4' ) 660 | 661 | --> "56.00 bytes" 662 |
8 bytes for raw value and 48 bytes for name, i.e. valbytes + keybytes 663 | 664 |
 
665 | // key name + total value (include value marker byte) 666 | > localData.bytesall( 'dupekey4' ) 667 | 668 | --> "60.00 bytes" 669 |
now includes the embedded data type marker (it's 2 bytes, stored as 4) 670 | 671 | 672 | 673 |
 
674 | view memory usage of compressed key values 675 | > localData.set( 'crunchedkey', 'this is some test data' ) 676 | 677 | only strings can be compressed; other data types will ignore compression 678 | 679 | > localData.size( 'crunchedkey' ) 680 | 681 | --> 22 682 | 683 | > localData.valbytes( 'crunchedkey' ) 684 | 685 | --> "44.00 bytes" 686 |
memory used to store raw string of 22 graphemes (each is 7-bit ASCII) 687 | 688 | > localData.valbytesall( 'crunchedkey' ) 689 | 690 | --> "34.00 bytes" 691 |
total memory required to store compressed string + embedded data type marker 692 | 693 | 694 | 695 |
 
696 | unicode-safe data storage 697 | > localData.set( 'unicodeKey1', '😀' ) 698 | 699 | storing an emoji; 1 grapheme (1 codepoint in 4 bytes) 700 | 701 | > localData.get( 'unicodeKey1' ) 702 | 703 | --> "😀" 704 | 705 | > localData.size( 'unicodeKey1' ) 706 | 707 | --> 1; one codepoint 708 | 709 | > localData.valbytes( 'unicodeKey1' ) 710 | 711 | --> "8.00 bytes" 712 | 713 | > localData.valbytesall( 'unicodeKey1' ) 714 | 715 | --> "12.00 bytes" 716 | 717 |
 
718 | > localData.set( 'unicodeKey2', '🕔🔚🔈🔔♅' ) 719 | 720 | storing 5 graphemes (5 codepoints in 19 bytes) 721 | 722 | > localData.get( 'unicodeKey2' ) 723 | 724 | --> "🕔🔚🔈🔔♅" 725 | 726 | > localData.size( 'unicodeKey2' ) 727 | 728 | --> 5 729 | 730 | > localData.valbytes( 'unicodeKey2' ) 731 | 732 | --> "38.00 bytes" 733 | 734 | > localData.valbytesall( 'unicodeKey2' ) 735 | 736 | --> "42.00 bytes" 737 | 738 |
 
739 | // using emojis for key name, key value and individual scramble key 740 | 741 | > localData.safeset( '👊🌐🔷', '💕🚻', '🔙' ) 742 | 743 | > localData.safeget( '👊🌐🔷', '🔙' ) 744 | 745 | --> "💕🚻" 746 | 747 |
 
748 | // using emojis in the global scramble key 749 | 750 | > localData.setscramblekey( '🎵🎶🔶🔻' ) 751 | 752 | > localData.safeset( 'Ron Wyden', '.@NSAGov 💻📱📡📞🔎👂👀🔚 #EndThisDragnet' ) 753 | 754 | > localData.safeget( 'Ron Wyden' ) 755 | 756 | --> ".@NSAGov 💻📱📡📞🔎👂👀🔚 #EndThisDragnet" 757 | 758 | 759 | 760 |
 
761 | get tally of keys 762 | > localData.keys() 763 | 764 | --> 24 765 | 766 | 767 | 768 |
 
769 | delete all prefixed keys in the domain (unprefixed localStorage keys are not affected) 770 | > localStorage.setItem( 'API-key', 'test data' ) 771 | 772 | create a key in the same domain completely outside our instance of localDataStorage 773 | 774 | > localData.clear() 775 | 776 | --> "24 keys removed" 777 | 778 | > localStorage.getItem( 'API-key' ) 779 | 780 | --> "test data" 781 |
any unprefixed localStorage keys are untouched 782 | 783 | > localData.safeget( 'Ron Wyden' ) 784 | 785 | --> undefined 786 |
all localData keys have been removed 787 | 788 | 789 | ## REFS: 790 | https://github.com/macmcmeans/aleaPRNG 791 | 792 | https://github.com/macmcmeans/fisherYatesDurstenfeldKnuthShuffle 793 |
 
794 | 795 | 796 | ## Tested: 797 | Chrome(ium) browsers (blink engine) and FireFox (gecko) on Win 10 (x64). 798 |
 
799 | 800 | 801 | ## Version notes: 802 | * 3.0.0 - 12 AUG 2022
803 | ``release`` Major release. Added major features, fixed numerous bugs and refactored code.
804 | ``patch`` Consolidated private references to the localStorage.removeItem() method.
805 | ``feature`` Added length property.
806 | ``patch`` Fixed bug where clear() method did not remove all prefixed keys.
807 | ``feature`` Added import/export methods.
808 | ``feature`` Adjusted logic that computes memory storage requirements for keys.
809 | ``patch`` Improved the logic for string compression checks.
810 | ``patch`` Streamlined error checking for localStorage availability prior to instantiation.
811 | ``feature`` Added key copy method.
812 | ``patch`` Improved the efficiency of storage flags by 50%.
813 | ``patch`` Strengthened the obfuscation of data protected by the safeset method.
814 | ``major feature`` Added Memory Keys (and associated methods).
815 | ``major feature`` Added Array Keys (and associated methods).
816 | ``major feature`` Added ability to broadcast change events across the origin.
817 | ``feature`` On startup, the library computes the browser's quota.
818 | ``feature`` Added channel property.
819 | ``feature`` Added backup/restore methods.
820 | ``feature`` Dates, floats and integers are now automatically stored compressed.
821 | ``update`` Revised the wiki. 822 |
 
823 | 824 | * 2.0.1 - 12 MAY 2022
825 | ``patch`` Fixed minor bugs, light refactoring.
826 | ``patch`` Updated the internal custom event to show both the date and the timestamp.
827 | ``update`` Revised the wiki. 828 |
 
829 | 830 | * 2.0.0 - 1 MAY 2022
831 | ``release`` Major release. Added support for BigInt. Fixed numerous bugs and refactored code. 832 |
 
833 | 834 | * 1.3.1 - 21 FEB 2022
835 | ``patch`` Fixed a bug where the Clear() method did not fire an event upon deletion of keys.
836 | ``patch`` Corrected logic in the Rename() method.
837 | ``patch`` Updated the internal custom event to display old key name and new key name.
838 | ``update`` Revised the wiki. 839 |
 
840 | 841 | * 1.3.0 - 4 MAY 2020
842 | ``feature`` Implement optional flag useful on instantiation to mute console messages warning of the existence of previous keys and the space required for prefix storage. 843 |
 
844 | 845 | * 1.2.0 - 19 JUN 2017
846 | ``update`` Checks whether localStorage is available and if not, gracefully fails when called. This means that all methods will simply return false instead of nasty type errors. 847 |
 
848 | 849 | * 1.1.0 - 17 MAY 2017
850 | ``feature`` Add ability to listen to key value change events (in same window/tab). 851 |
 
852 | 853 | * 1.0.0 - 15 MAY 2017
854 | ``release`` Initial release. 855 |
 
856 | 857 | 858 | ## License (BSD) 859 | Copyright (c) 2017-2022, W. "Mac" McMeans
860 | All rights reserved. 861 | 862 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 863 | 864 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 865 | 866 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 867 | 868 | 3. Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 869 | 870 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 871 | -------------------------------------------------------------------------------- /localDataStorage-3.0.0.min.js: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////////////////// 2 | localDataStorage 3.0.0 3 | https://cdn.jsdelivr.net/gh/macmcmeans/localDataStorage@master/localDataStorage-3.0.0.min.js 4 | //////////////////////////////////////////////////////////////////////////////////////////// 5 | Copyright 2017 - 2022 William P. "Mac" McMeans 6 | LICENSE: BSD 3-Clause License 7 | */ 8 | const localDataStorage=function(e,r){return function e(r,t){"use strict";let n,o={this:["is"],not:["cryptographic","strength"]},i=0,f="localDataStorage";n=new BroadcastChannel(f);const s="𝗡𝗼 𝘀𝗲𝗲𝗱 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱",u="𝗡𝗼 𝗸𝗲𝘆 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱",l="𝗡𝗼 𝗸𝗲𝘆 𝘃𝗮𝗹𝘂𝗲 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱",c="𝗩𝗮𝗹𝘂𝗲 𝗶𝘀 𝗮𝗻 𝘂𝗻𝘀𝘂𝗽𝗽𝗼𝗿𝘁𝗲𝗱 𝘁𝘆𝗽𝗲",h="𝗞𝗲𝘆 𝗱𝗼𝗲𝘀 𝗻𝗼𝘁 𝗲𝘅𝗶𝘀𝘁",d="𝗞𝗲𝘆 𝗺𝘂𝘀𝘁 𝗯𝗲 𝗮𝗻 𝗔𝗿𝗿𝗮𝘆 𝗞𝗲𝘆",w="𝗨𝗻𝗸𝗻𝗼𝘄𝗻 𝗱𝗮𝘁𝗮 𝘁𝘆𝗽𝗲",g="𝗡𝗼 𝗱𝗮𝘁𝗮 𝘁𝘆𝗽𝗲 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱",y="𝗡𝗼 𝗶𝗻𝗱𝗲𝘅 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱",v="𝗜𝗹𝗹𝗲𝗴𝗮𝗹 𝗶𝗻𝗱𝗲𝘅 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱",p="𝗨𝗻𝗸𝗻𝗼𝘄𝗻 𝘀𝘁𝗿𝗶𝗻𝗴 𝗶𝗻𝗱𝗲𝘅 𝗸𝗲𝘆𝘄𝗼𝗿𝗱",b="𝗨𝗻𝗸𝗻𝗼𝘄𝗻 𝗻𝘂𝗺𝗲𝗿𝗶𝗰 𝗶𝗻𝗱𝗲𝘅",m="𝗨𝗻𝗸𝗻𝗼𝘄𝗻 𝗶𝗻𝗱𝗲𝘅",E="𝗡𝗼 𝘀𝘁𝗿𝗶𝗻𝗴 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱",k=["array","bigint","boolean","date","float","integer","null","number","object","string"],S=String.fromCodePoint(1),N=String.fromCodePoint(2),A=String.fromCodePoint(3),O=String.fromCodePoint(4),_=String.fromCodePoint(5),C=String.fromCodePoint(6),x=String.fromCodePoint(7),J=String.fromCodePoint(8),I=String.fromCodePoint(9),P=String.fromCodePoint(10),T="__storage_test__",j=(new Date).getTime()+":"+(1e8*Math.random()|0),M=""===r?"":void 0===r?j:r,R=function(){return se(),function(e){let r,t=T;try{return(r=window[e]).setItem(t,t),r.removeItem(t),!0}catch(e){return!1}}("localStorage")},D=function(){return function(e){var r,t,n,o,i,f=new Uint32Array(3),a="",s="aleaPRNG 1.1";function u(e){var i,f,s=(i=4022871197,(f=function(e){for(var r=0,t=(e=e.toString()).length;r>>0,i=(n*=i)>>>0,i+=4294967296*(n-=i)}return 2.3283064365386963e-10*(i>>>0)}).version="Mash 0.9",f);r=s(" "),t=s(" "),n=s(" "),o=1;for(var u=0;uarguments[1]&&(e=arguments[1],r=arguments[0]),l(e)&&l(r)?Math.floor(c()*(r-e+1))+e:c()*(r-e)+e},c.restart=function(){u(i)},c.seed=function(){u(Array.prototype.slice.call(arguments))},c.version=function(){return s},c.versions=function(){return s+", "+a},0===e.length&&(window.crypto.getRandomValues(f),e=[f[0],f[1],f[2]]),u(i=e),c}(Array.prototype.slice.call(arguments))},B=function(){const e="0123456789",r="ABCDEFGHIJKLMNOPQRSTUVWXYZ",t="abcdefghijklmnopqrstuvwxyz",n=e+r+t+"+/!#$%&()*,-:;<=>?@[]^_`{|}~\\. '\"¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĆćĈĉĊċČčĜĝĞğĠġĢģĤĥĦħIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŊŋŔŕŖŗŘřŜŝŞşŠšŢţŤťŦŧŲųŴŵŶŷŸŹźŻżŽžΔΛΣΓ",o="./"+e+r+t,i=function(e){var r,t;if(void 0===e)r=o;else if("number"==typeof e){if(e<2)throw new Error("Glyph set must contain at least 2 graphemes");r=n.slice(0,e)}else if(e instanceof Array){if("number"==typeof(t=e=Number(e[0]))&&0!=t&&!t)throw new Error("Array must be number");if(e<2)throw new Error("Glyph set must contain at least 2 graphemes");r=(r=f(n,e)).slice(0,e)}else if("BASE64"===e.toUpperCase())r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";else if("B64"===e.toUpperCase())r=o;else if("UUENCODE"===e.toUpperCase())r=" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";else if("XXENCODE"===e.toUpperCase())r="+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";else if("BINHEX"===e.toUpperCase())r="!\"#$%&'()*+,-0123456789@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";else if("7BIT"===e.toUpperCase())r="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/!#$%&()*,-:;<=>?@[]^_`{|}~\\. '\"";else if("FPN"===e.toUpperCase())r="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/!#$%&()*,-:;<=>?@[]^_`{|}~\\";else{if(e.length<2)throw new Error("Glyph set must contain at least 2 graphemes");if(a(e))throw new Error("Glyph set contains duplicate graphemes");r=e}return r},f=function(e,r){var t,n,o;return o=.059886774281039834*(n=r),o+=21845.33332824707,o-=n=0|o,n=0|(o*=n),t=function(e){return function(e){function r(r){var f=r;if(r<10)throw new Error("Specified seed must be greater than 9");t=(f+="").length,n="";for(var a=0;a>>0),function(e,r){var t,n=e.length;for(r=r||function(){var e=new Uint32Array(2);return window.crypto.getRandomValues(e),parseFloat("0."+e[0]+e[1])};--n;)e[t=Math.floor(r()*(n+1))]=[e[n],e[n]=e[t]][0]}(e=e.split(""),t),e.join("")},a=function(e){for(var r=e.length,t=0;t>>0,n=(o*=n)>>>0,n+=4294967296*(o-=n)}return 2.3283064365386963e-10*(n>>>0)})(r)+"";var n;return t=+(t=t.replace("0.",""))}(),K=function(e){let r,t="";const n=function(r){return e.substr(-1,1)===r},o=function(e){return e.substr(0,e.length-1)},i=function(e){return JSON.parse(e,le)};if(void 0===e)throw new Error("𝗡𝗼 𝘃𝗮𝗹𝘂𝗲 𝘁𝗼 𝗰𝗼𝗻𝘃𝗲𝗿𝘁 𝗳𝗿𝗼𝗺");if(function(){let e=arguments.length,r=Object.values(arguments);return{areIn(t){for(let n=0;ne}}(O,_,C,x,J,I,A,P).areIn(e.substr(-1,1)))""===t&&n(r=A)&&(e=o(e),t=e=Ce(e)),""===t&&n(r=P)&&(t=e=o(e)),""===t&&n(r=x)&&(e=o(e),t=B.radixToBase10(e,"7BIT"),t=new Date(t)),""===t&&n(r=O)&&(t=i(e=o(e))),""===t&&n(r=J)&&(e=o(e),t=B.radixToBase10(e,"FPN")),""===t&&n(r=C)&&(t="1"===(e=o(e))),""===t&&n(r=_)&&(e=o(e),t=BigInt(e)),""===t&&n(r=I)&&(t=i(e=o(e)));else if("presumed bigint"===ie("VALUE_OVERRIDE",e))e=e.substring(0,e.length-1),t=BigInt(e);else if("{"===e[0]||"["===e[0])try{t=i(e)}catch(r){t=e}else t=e==+e?+e:e;return t},U=function(e){let r="",t="";if(void 0===e)throw new Error("𝗡𝗼 𝘃𝗮𝗹𝘂𝗲 𝘁𝗼 𝗰𝗼𝗻𝘃𝗲𝗿𝘁 𝘁𝗼");return"string"==typeof e?(t="string",r=P,ue(e)&&(t="compressed string",e=q(e),r=A)):"object"==typeof e&&e instanceof Date?(t="date",r=x,e=+e,e=B.base10ToRadix(e,"7BIT")):"object"==typeof e&&e instanceof Array?(t="array",r=O,e=JSON.stringify(e,ce)):"number"==typeof e?(t="integer",-1!==(e+"").indexOf(".")&&(t="float"),r=J,e=B.base10ToRadix(e,"FPN")):"boolean"==typeof e?(t="boolean",r=C,e=Number(e),e+=""):"bigint"==typeof e?(t="bigint",r=_,e+=""):"object"==typeof e&&(t="object",null===e&&(t="null"),r=I,e=JSON.stringify(e,ce)),""!==r&&(e+=r),[e,t]},q=function(e){return Ne.compress(e)},G=function(e){localStorage.removeItem(e)},F=function(e,r=!1){let t=0,n=1024;for(r&&(n=1e3);e>n;)t++,e/=n;return e=(e=1==e?"1 byte":e.toFixed(2)+" "+["bytes","KB","MB"][t]).replace(".00 "," ")},V=function(e,r){var t,n=e.length;for(r=r||a;--n;)e[t=Math.floor(r()*(n+1))]=[e[n],e[n]=e[t]][0]},X=function(e,r){for(var t,n=new Array(e.length),o=new Array(e.length),i=e.length,f=0;f0;f--)t=Math.floor(r()*(f+1)),o[f]=[o[t],o[t]=o[f]][0];for(f=0;f>>0},H=function(e){if(void 0===e)throw new Error(u);let r=pe(e);return r?K(r):void 0},Y=function(e=!1){let r,t=$(),n=new Array;for(let o=localStorage.length;o--;)(r=localStorage.key(o)).substr(0,t.length)===t&&(e&&(r=Ae(r)),n.push(r));return n},Z=function(e=!1){let r=new Array;for(let t in Le)"#"===t.substr(0,1)&&(e&&(t=Oe(t)),r.push(t));return r},z=function(e){for(var r=(e=""+e).length,t=r-1;t>=0;t--){let n=e.charCodeAt(t);n>127&&2047>=n?r++:n>2047&&65535>=n&&(r+=2),n>=56320&&57343>=n&&t--}return r},W=function(e){return _e(e=""+e).length},$=function(){return M+"."},ee=function(e){return fe(be(e))},re=function(e){if(void 0===e)return;let r="bigint"==typeof e?e.toString():JSON.stringify(e,ce),t=0,n="",o="";const i=function(e){return De(e)()};var f;n=e instanceof Array?"ARRAY1":"bigint"==typeof e?"BIGINT2":"boolean"==typeof e?"BOOLEAN4":e instanceof Date?"DATE8":"number"==typeof e?(e+"").includes(".")?"FLOAT16":"INTEGER32":"string"==typeof e?"STRING64":"OBJECT128",o=r+r.length+n+i(r)+i((f=r,Array.from(f).reverse().join("")));for(let e=0;ee}}(O,_,C,x,J,I,A,P).areIn(n.substr(-1,1))?"["===n[0]?t="presumed array":"{"===n[0]?t="presumed object":"n"===n.substr(-1,1)&&parseInt(n,10)===+n.substring(0,n.length-1)?t="presumed bigint":n==+n?t="presumed number":(null!==e&&(n=Be(n,o,e.replace($(),"")),n=xe(n,o,e.replace($(),""))),i(P)?t="obfuscated string":i(_)?t="obfuscated bigint":i(x)?t="obfuscated date":i(O)?t="obfuscated array":i(J)?(t="obfuscated number",t=n.includes(".")?"obfuscated float":"obfuscated integer"):t=i(C)?"obfuscated boolean":i(I)?"obfuscated object":"presumed string"):(i(A)&&(t="compressed string"),""===t&&i(P)&&(t="string"),""===t&&i(x)&&(t="date"),""===t&&i(O)&&(t="array"),""===t&&i(J)&&(t="number",t=n.includes(".")?"float":"integer"),""===t&&i(C)&&(t="boolean"),""===t&&i(_)&&(t="bigint"),""===t&&i(I)&&(t="object",n[0]+n[1]+n[2]+n[3]==="null"&&(t="null"))),t},fe=function(e){let r="",t=typeof e;return"string"===t&&(r="string",e.includes(A)&&(r="compressed string")),""===r&&"number"===t&&(r=(e+"").includes(".")?"float":"integer"),""===r&&"boolean"===t&&(r="boolean"),""===r&&"bigint"===t&&(r="bigint"),""===r&&"object"===t?r=e instanceof Array?"array":e instanceof Date?"date":null===e?"null":"object":""===r&&(r="unknown"),r},ae=function(e){return null!==pe(e)},se=function(){Le.version="localDataStorage 3.0.0",Le.channel=f},ue=function(e){let r=!1,t=!1,n=Ne.compress(e)+A;return r=e===K(n),t=z(n)+0<=z(e+P),!(!r||!t)},le=function(e,r){return"string"==typeof r&&"`"===r.substr(-1,1)&&"n"===r.substr(-2,1)&&parseInt(r,10)===+r.substring(0,r.length-2)?BigInt(r.substring(0,r.length-2)):r},ce=function(e,r){return"bigint"==typeof r?r.toString()+"n`":r},he=function(e){let r=Y(!0).join(""),t=0;return void 0===e?t=z(r):ae(e)&&(t=z(Ae(e))),t},de=function(e){let r=Y().join(""),t=0;return void 0===e?t=z(r):ae(e)&&(t=z(e)),t},we=function(e){let r=Y().join(""),t=0;return void 0===e?t=z(r):ae(e)&&(t=z(e)),t*=2},ge=e=>()=>(2**31-1&(e=Math.imul(48271,e)))/2**31,ye=e=>r=>(e=e+1831565813|0,r=Math.imul(e^e>>>15,1|e),r=r+Math.imul(r^r>>>7,61|r)^r,((r^r>>>14)>>>0)/2**32),ve=function(e){return e.sort((e,r)=>("$"===(e+"").substr(0,1)?(e+"").substr(1,(e+"").length):e+"").localeCompare(r,"en",{ignorePunctuation:!0,numeric:!0,sensitivity:"base"}))},pe=function(e){let r;try{r=localStorage.getItem(e)}catch(e){throw new Error("𝗔𝗻 𝗲𝗿𝗿𝗼𝗿 𝗼𝗰𝗰𝘂𝗿𝗿𝗲𝗱 𝗿𝗲𝗮𝗱𝗶𝗻𝗴 𝗳𝗿𝗼𝗺 𝗹𝗼𝗰𝗮𝗹𝗦𝘁𝗼𝗿𝗮𝗴𝗲")}return r},be=function(e){return Le["#"+e]},me=function(e){return Array.from(e).reverse().join("")},Ee=function(e,r,t,o,i,a,s,u,l,c,h){let d={},w=new Date,g=new CustomEvent("localDataStorage",{detail:{prefix:e,method:r,message:t,date:w,timestamp:+w,oldkey:o,newkey:i,oldval:"bigint"===u?a:JSON.stringify(a,ce),newval:"bigint"===l?s:JSON.stringify(s,ce),oldtype:u,newtype:l,oldbase:c,newbase:h},bubbles:!1,cancelable:!0});document.dispatchEvent(g),""!==f&&(d={id:"localDataStorage",prefix:e,method:r,message:t,date:w,timestamp:+w,oldkey:o,newkey:i,oldval:"bigint"===u?a:JSON.stringify(a,ce),newval:"bigint"===l?s:JSON.stringify(s,ce),oldtype:u,newtype:l,oldbase:c,newbase:h},n.postMessage(d))},ke=function(){let e=Y(!0),r=e.length,t=new Array(r),n=new Array;for(let n=r;n--;)t[n]=H(te(e[n]));return 0===(n=function(e){let r=new Array,t=new Array,n=e.length;for(let o=0;o.75&&p();if(o()>.5){i=e.split(" ");for(let e=0;e2&&(f=f.split(""),V(f,o),f=f.join("")),i[e]=f;e=i.join(" ")}return e=(e+=S).split(""),V(e,d),(e=e.join(""))+h},Ne=function(){const e=function(){};return e.codebook={" ":0,the:1,'","':2,'":"':3,'"}}':4,of:5,o:6,and:7,'":{"':8,n:9,s:10,"e ":11,r:12," th":13," t":14,in:15,he:16,th:17,h:18,"he ":19,to:20,"\r\n":21,l:22,"s ":23,d:24," a":25,an:26,er:27,c:28," o":29,"d ":30,on:31," of":32,re:33,"of ":34,"t ":35,", ":36,is:37,u:38,at:39," ":40,"n ":41,or:42,which:43,f:44,m:45,as:46,it:47,that:48,"\n":49,was:50,en:51," ":52," w":53,es:54," an":55," i":56,"\r":57,"f ":58,g:59,p:60,nd:61," s":62,"nd ":63,"ed ":64,w:65,ed:66,"https://":67,for:68,te:69,ing:70,"y ":71,The:72," c":73,ti:74,"r ":75,his:76,st:77," in":78,ar:79,nt:80,",":81," to":82,y:83,ng:84," h":85,with:86,le:87,al:88,"to ":89,b:90,ou:91,be:92,were:93," b":94,se:95,"o ":96,ent:97,ha:98,"ng ":99,their:100,'"':101,hi:102,from:103," f":104,"in ":105,de:106,ion:107,me:108,v:109,".":110,ve:111,all:112,"re ":113,ri:114,ro:115,"is ":116,co:117,"f t":118,are:119,ea:120,". ":121,her:122," m":123,"er ":124," p":125,"es ":126,by:127,they:128,di:129,ra:130,ic:131,not:132,"s, ":133,"d t":134,"at ":135,ce:136,la:137,"h ":138,ne:139,"as ":140,tio:141,"on ":142,"n t":143,io:144,we:145," a ":146,om:147,", a":148,"s o":149,ur:150,li:151,ll:152,ch:153,had:154,this:155,"e t":156,"g ":157,"e\r\n":158," wh":159,ere:160," co":161,"e o":162,"a ":163,us:164," d":165,ss:166,"\n\r\n":167,"\r\n\r":168,'="':169," be":170," e":171,"s a":172,ma:173,one:174,"t t":175,"or ":176,but:177,el:178,so:179,"l ":180,"e s":181,"s,":182,no:183,ter:184," wa":185,iv:186,ho:187,"e a":188," r":189,hat:190,"s t":191,ns:192,"ch ":193,wh:194,tr:195,ut:196,"/":197,have:198,"ly ":199,ta:200," ha":201," on":202,tha:203,"-":204," l":205,ati:206,"en ":207,pe:208," re":209,there:210,ass:211,si:212," fo":213,wa:214,ec:215,our:216,who:217,its:218,"https://www.":219,fo:220,rs:221,">":222,ot:223,un:224,"<":225,im:226,"th ":227,nc:228,ate:229,"><":230,ver:231,ad:232," we":233,ly:234,ee:235," n":236,id:237," cl":238,ac:239,il:240,"1?(t.push(String.fromCodePoint(255)),t.push(String.fromCodePoint(e.length-1))):t.push(String.fromCodePoint(254)),n=0,o=e.length;n0;i=i<=0?++s:--s)if(null!=(t=e.codebook[r.substr(o,i)])){a&&(f=f.concat(e.flush_verbatim(a)),a=""),f.push(String.fromCodePoint(t)),o+=i,n=!0;break}n||(a+=r[o],o++,256===a.length&&(f=f.concat(e.flush_verbatim(a)),a=""))}return a&&(f=f.concat(e.flush_verbatim(a))),f.join("")},e.decompress=function(r){var t,n,o,i,f,a;for(i="",n=function(){var e,n,o;for(o=[],t=e=0,n=r.length;0<=n?en;t=0<=n?++e:--e)o.push(r.codePointAt(t));return o}(),t=0;tn.length)throw"Malformed SMAZ";i+=r[t+1],t+=2}else if(255===n[t]){if(t+n[t+1]+2>=n.length)throw"Malformed SMAZ";for(o=f=0,a=n[t+1]+1;0<=a?fa;o=0<=a?++f:--f)i+=r[t+2+o];t+=3+n[t+1]}else i+=e.reverse_codebook[n[t]],t++;return i},e.getLongestKeyLength=function(e){let r=0,t=0;for(let n=0;nt&&(r=n,t=e[n].length);return e[r].length},e.reverse_codebook=e.make_reverse_codebook(e.codebook),e.longestKeyLength=e.getLongestKeyLength(e.reverse_codebook),e}(),Ae=function(e){return e.slice($().length,e.length)},Oe=function(e){return e.replace("#","")},_e=function(e){for(var r,t,n=[],o=0,i=e.length;i>o;)(r=e.charCodeAt(o++))>=55296&&56319>=r&&i>o?56320==(64512&(t=e.charCodeAt(o++)))?n.push(((1023&r)<<10)+(1023&t)+65536):(n.push(r),o--):n.push(r);return n},Ce=function(e){return Ne.decompress(e)},xe=function(e,r,t){let n=e.substr(-3),o=e.replace(n,""),i=De(t),f=ye(i()),a="",s="",u=0,l=re(r)[0]+re(t)[0],c=Q(l)+"",h=me(c),d=Number(h),w=D(""+d+l,c,h+n),g=Number((d+"").charAt(2))+Number((d+"").charAt(1))+Number((d+"").charAt(0));for(let e=W(re(t)[1])+W(re(r)[1])+g;e--;)w()<.75&&f(),f();if(o=o.split(""),u=(o=(o=X(o,w)).join("")).indexOf(S),o=o.substr(0,u),f()>.5){a=o.split(" ");for(let e=0;e2&&(s=s.split(""),s=(s=X(s,f)).join("")),a[e]=s;o=a.join(" ")}return o},Je=function(){setTimeout(()=>Le.length=Y().length,0),Le.version="localDataStorage 3.0.0"},Ie=function(e){let r="",t=0,n=new Array,o=0,i="",f="";if(void 0===e){for(let e=o=(n=Y()).length;e--;)i=n[e],r+=f=(f=(f=(f=(f=(f=(f=(f=(f=(f=pe(i)).replace(O,"")).replace(_,"")).replace(C,"")).replace(x,"")).replace(J,"")).replace(I,"")).replace(P,"")).replace(A,"")).replace(N,"");t=z(r)}else ae(e)&&(f=(f=(f=(f=(f=(f=(f=(f=(f=(f=pe(e)).replace(O,"")).replace(_,"")).replace(C,"")).replace(x,"")).replace(J,"")).replace(I,"")).replace(P,"")).replace(A,"")).replace(N,""),t=z(f));return t},Pe=function(e){let r="",t=0,n=new Array,o=0,i="",f="";if(void 0===e){for(let e=o=(n=Y()).length;e--;)i=n[e],r+=f=pe(i);t=z(r)}else ae(e)&&(f=pe(e),t=z(f));return t},Te=function(e){return 2*Pe(e)},je=function(e){let r=!0,t=typeof e;for(let e=k.length;e--;)if(t===k[e]){r=!1;break}return r},Me=function(e,r){return"]"===JSON.stringify(e,ce).substr(-1)?function(e,r){let t=!1,n=!0;if(e.length===r.length){for(let t=0;t>>17,n=(n^=Math.imul(r,461845907))<<13|n>>>19,n=Math.imul(n,5)+3864292196|0;return n^=e.length,function(){return n^=n>>>16,n=Math.imul(n,2246822507),n^=n>>>13,n=Math.imul(n,3266489909),(n^=n>>>16)>>>0}},Be=function(e,r,t){let n=JSON.stringify(r,ce),o=De(n),i=ge(o()),f=De(t),a=ye(f()),s="",u=re(r)[0],l=Q(u)+"",c=me(l),h=Number(c)+re(t)[0]+re(r)[0],d=h+"",w=u+"",g=o()+"",y=D(d,w,g),v=u+Number((h+"").charAt(0))+Number((h+"").charAt(1))+Number((h+"").charAt(2))+Number(l.charAt(0)),p=W(re(t)[1])+W(re(r)[1])+v,b=(A=4022871197,function(e){for(var r=0,t=(e=e.toString()).length;r>>0,A=(n*=A)>>>0,A+=4294967296*(n-=A)}return 2.3283064365386963e-10*(A>>>0)}),m=re(r)[1],E=0,k=0,S=0,N=0;var A;e+="";for(let e=0;e.75&&a(),a()>.55&&i();for(let r=0,t=e.length;ro)t=i;else if(!(t>0&&to)r=i;else if(!(r>0&&ro)t=i;else if(!(t>0&&t2){for(let e=1;e>> 0, i = (n *= i) >>> 0, i += 4294967296 * (n -= i); 34 | } 35 | return 2.3283064365386963e-10 * (i >>> 0); 36 | }).version = "Mash 0.9", f); 37 | r = s(" "), t = s(" "), n = s(" "), o = 1; 38 | for (var u = 0; u < e.length; u++) (r -= s(e[u])) < 0 && (r += 1), (t -= s(e[u])) < 0 && (t += 1), 39 | (n -= s(e[u])) < 0 && (n += 1); 40 | a = s.version, s = null; 41 | } 42 | function l(e) { 43 | return parseInt(e, 10) === e; 44 | } 45 | var c = function() { 46 | var e = 2091639 * r + 2.3283064365386963e-10 * o; 47 | return r = t, t = n, n = e - (o = 0 | e); 48 | }; 49 | return c.fract53 = function() { 50 | return c() + 1.1102230246251565e-16 * (2097152 * c() | 0); 51 | }, c.int32 = function() { 52 | return 4294967296 * c(); 53 | }, c.cycle = function(e) { 54 | (e = void 0 === e ? 1 : +e) < 1 && (e = 1); 55 | for (var r = 0; r < e; r++) c(); 56 | }, c.range = function() { 57 | var e, r; 58 | return r = 1 === arguments.length ? arguments[e = 0] : (e = arguments[0], arguments[1]), 59 | arguments[0] > arguments[1] && (e = arguments[1], r = arguments[0]), l(e) && l(r) ? Math.floor(c() * (r - e + 1)) + e : c() * (r - e) + e; 60 | }, c.restart = function() { 61 | u(i); 62 | }, c.seed = function() { 63 | u(Array.prototype.slice.call(arguments)); 64 | }, c.version = function() { 65 | return s; 66 | }, c.versions = function() { 67 | return s + ", " + a; 68 | }, 0 === e.length && (window.crypto.getRandomValues(f), e = [ f[0], f[1], f[2] ]), 69 | u(i = e), c; 70 | }(Array.prototype.slice.call(arguments)); 71 | }, B = function() { 72 | const e = "0123456789", r = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", t = "abcdefghijklmnopqrstuvwxyz", n = e + r + t + "+/!#$%&()*,-:;<=>?@[]^_`{|}~\\. '\"¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĆćĈĉĊċČčĜĝĞğĠġĢģĤĥĦħIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŊŋŔŕŖŗŘřŜŝŞşŠšŢţŤťŦŧŲųŴŵŶŷŸŹźŻżŽžΔΛΣΓ", o = "./" + e + r + t, i = function(e) { 73 | var r, t; 74 | if (void 0 === e) r = o; else if ("number" == typeof e) { 75 | if (e < 2) throw new Error("Glyph set must contain at least 2 graphemes"); 76 | r = n.slice(0, e); 77 | } else if (e instanceof Array) { 78 | if ("number" == typeof (t = e = Number(e[0])) && 0 != t && !t) throw new Error("Array must be number"); 79 | if (e < 2) throw new Error("Glyph set must contain at least 2 graphemes"); 80 | r = (r = f(n, e)).slice(0, e); 81 | } else if ("BASE64" === e.toUpperCase()) r = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; else if ("B64" === e.toUpperCase()) r = o; else if ("UUENCODE" === e.toUpperCase()) r = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; else if ("XXENCODE" === e.toUpperCase()) r = "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; else if ("BINHEX" === e.toUpperCase()) r = "!\"#$%&'()*+,-0123456789@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; else if ("7BIT" === e.toUpperCase()) r = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/!#$%&()*,-:;<=>?@[]^_`{|}~\\. '\""; else if ("FPN" === e.toUpperCase()) r = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/!#$%&()*,-:;<=>?@[]^_`{|}~\\"; else { 82 | if (e.length < 2) throw new Error("Glyph set must contain at least 2 graphemes"); 83 | if (a(e)) throw new Error("Glyph set contains duplicate graphemes"); 84 | r = e; 85 | } 86 | return r; 87 | }, f = function(e, r) { 88 | var t, n, o; 89 | return o = .059886774281039834 * (n = r), o += 21845.33332824707, o -= n = 0 | o, 90 | n = 0 | (o *= n), t = function(e) { 91 | return function(e) { 92 | function r(r) { 93 | var f = r; 94 | if (r < 10) throw new Error("Specified seed must be greater than 9"); 95 | t = (f += "").length, n = ""; 96 | for (var a = 0; a < t; a++) n += f[t - a - 1]; 97 | "string" == typeof e && (t = 2 * (t + 1)), o = +("0." + n), i = +("0." + t); 98 | for (var s = 0; s < 20; s++) o = ((i += o) * o + i) % 1; 99 | } 100 | var t, n, o, i, f = new Date().getTime(); 101 | r(e || f); 102 | var a = function() { 103 | return o = ((i += o) * o + i) % 1; 104 | }; 105 | return a.seed = function(e) { 106 | r(e); 107 | }, a; 108 | }(e); 109 | }((n ^= 4294967296 * (o -= n)) >>> 0), function(e, r) { 110 | var t, n = e.length; 111 | for (r = r || function() { 112 | var e = new Uint32Array(2); 113 | return window.crypto.getRandomValues(e), parseFloat("0." + e[0] + e[1]); 114 | }; --n; ) e[t = Math.floor(r() * (n + 1))] = [ e[n], e[n] = e[t] ][0]; 115 | }(e = e.split(""), t), e.join(""); 116 | }, a = function(e) { 117 | for (var r = e.length, t = 0; t < r; t++) for (var n = e[t], o = t + 1; o <= r - 1; o++) if (n === e[o]) return !0; 118 | return !1; 119 | }, s = function(e, r, t) { 120 | var n, o = i(r), a = o.length, s = Math.floor(e), u = ""; 121 | for (void 0 !== t && (o = f(o, t)); n = s % a, u = o.charAt(n) + u, 0 !== (s = Math.floor(s / a)); ) ; 122 | return u; 123 | }, u = function(e, r, t) { 124 | var n = i(r), o = n.length, a = 0; 125 | void 0 !== t && (n = f(n, t)); 126 | for (var s = 0; s < e.length; s++) a = a * o + n.indexOf(e[s]); 127 | return a; 128 | }; 129 | return { 130 | base10ToRadix: function(e, r, t) { 131 | if (e !== parseInt(e, 10) && "fpn" !== r.toLowerCase()) throw new Error("Number must be positive integer in Base-10"); 132 | if (void 0 !== t && "number" != typeof t) throw new Error("Scramble key must be a number"); 133 | if ("fpn" === r.toLowerCase() && (e + "").includes(".")) { 134 | let r = (e + "").split("."), n = s(+r[0], "fpn", t), o = s(+r[1], "fpn", t), i = ""; 135 | return "0" === (r[1] + "").substr(0, 1) && (i = " "), n + "." + i + o; 136 | } 137 | return s(e, r, t); 138 | }, 139 | changeRadix: function(e, r, t, n) { 140 | var o = this.radixToBase10(e, r, n); 141 | return this.base10ToRadix(o, t, n); 142 | }, 143 | radixToBase10: function(e, r, t) { 144 | if (void 0 !== t && "number" != typeof t) throw new Error("Scramble key must be a number"); 145 | if ("fpn" === r.toLowerCase() && e.includes(".")) { 146 | let r = e.split("."), n = u(r[0], "fpn", t) + "", o = ""; 147 | return r[1].includes(" ") ? (r[1] = r[1].replace(" ", ""), o = "0" + u(r[1], "fpn", t)) : o = u(r[1], "fpn", t) + "", 148 | +(n + "." + o); 149 | } 150 | return u(e, r, t); 151 | }, 152 | version: function() { 153 | return "customRadix v1.1.0"; 154 | } 155 | }; 156 | }(), L = function() { 157 | let r = e.toString(), t = (n = 4022871197, function(e) { 158 | for (var r = 0, t = (e = e.toString()).length; r < t; r++) { 159 | var o = .02519603282416938 * (n += e.charCodeAt(r)); 160 | o -= n = o >>> 0, n = (o *= n) >>> 0, n += 4294967296 * (o -= n); 161 | } 162 | return 2.3283064365386963e-10 * (n >>> 0); 163 | })(r) + ""; 164 | var n; 165 | return t = +(t = t.replace("0.", "")); 166 | }(), K = function(e) { 167 | let r, t = ""; 168 | const n = function(r) { 169 | return e.substr(-1, 1) === r; 170 | }, o = function(e) { 171 | return e.substr(0, e.length - 1); 172 | }, i = function(e) { 173 | return JSON.parse(e, le); 174 | }; 175 | if (void 0 === e) throw new Error("𝗡𝗼 𝘃𝗮𝗹𝘂𝗲 𝘁𝗼 𝗰𝗼𝗻𝘃𝗲𝗿𝘁 𝗳𝗿𝗼𝗺"); 176 | if (function() { 177 | let e = arguments.length, r = Object.values(arguments); 178 | return { 179 | areIn(t) { 180 | for (let n = 0; n < e; n++) if (r[n] === t) return !0; 181 | return !1; 182 | }, 183 | total: () => e 184 | }; 185 | }(O, _, C, x, J, I, A, P).areIn(e.substr(-1, 1))) "" === t && n(r = A) && (e = o(e), 186 | t = e = Ce(e)), "" === t && n(r = P) && (t = e = o(e)), "" === t && n(r = x) && (e = o(e), 187 | t = B.radixToBase10(e, "7BIT"), t = new Date(t)), "" === t && n(r = O) && (t = i(e = o(e))), 188 | "" === t && n(r = J) && (e = o(e), t = B.radixToBase10(e, "FPN")), "" === t && n(r = C) && (t = "1" === (e = o(e))), 189 | "" === t && n(r = _) && (e = o(e), t = BigInt(e)), "" === t && n(r = I) && (t = i(e = o(e))); else if ("presumed bigint" === ie("VALUE_OVERRIDE", e)) e = e.substring(0, e.length - 1), 190 | t = BigInt(e); else if ("{" === e[0] || "[" === e[0]) try { 191 | t = i(e); 192 | } catch (r) { 193 | t = e; 194 | } else t = e == +e ? +e : e; 195 | return t; 196 | }, U = function(e) { 197 | let r = "", t = ""; 198 | if (void 0 === e) throw new Error("𝗡𝗼 𝘃𝗮𝗹𝘂𝗲 𝘁𝗼 𝗰𝗼𝗻𝘃𝗲𝗿𝘁 𝘁𝗼"); 199 | return "string" == typeof e ? (t = "string", r = P, ue(e) && (t = "compressed string", 200 | e = q(e), r = A)) : "object" == typeof e && e instanceof Date ? (t = "date", r = x, 201 | e = +e, e = B.base10ToRadix(e, "7BIT")) : "object" == typeof e && e instanceof Array ? (t = "array", 202 | r = O, e = JSON.stringify(e, ce)) : "number" == typeof e ? (t = "integer", -1 !== (e + "").indexOf(".") && (t = "float"), 203 | r = J, e = B.base10ToRadix(e, "FPN")) : "boolean" == typeof e ? (t = "boolean", 204 | r = C, e = Number(e), e += "") : "bigint" == typeof e ? (t = "bigint", r = _, e += "") : "object" == typeof e && (t = "object", 205 | null === e && (t = "null"), r = I, e = JSON.stringify(e, ce)), "" !== r && (e += r), 206 | [ e, t ]; 207 | }, q = function(e) { 208 | return Ne.compress(e); 209 | }, G = function(e) { 210 | localStorage.removeItem(e); 211 | }, F = function(e, r = !1) { 212 | let t = 0, n = 1024; 213 | for (r && (n = 1e3); e > n; ) t++, e /= n; 214 | return e = (e = 1 == e ? "1 byte" : e.toFixed(2) + " " + [ "bytes", "KB", "MB" ][t]).replace(".00 ", " "); 215 | }, V = function(e, r) { 216 | var t, n = e.length; 217 | for (r = r || a; --n; ) e[t = Math.floor(r() * (n + 1))] = [ e[n], e[n] = e[t] ][0]; 218 | }, X = function(e, r) { 219 | for (var t, n = new Array(e.length), o = new Array(e.length), i = e.length, f = 0; f < i; f++) o[f] = f; 220 | for (f = i - 1; f > 0; f--) t = Math.floor(r() * (f + 1)), o[f] = [ o[t], o[t] = o[f] ][0]; 221 | for (f = 0; f < i; f++) n[o[f]] = e[f]; 222 | return n; 223 | }, Q = function(e) { 224 | let r = .059886774281039834 * e; 225 | return r += 21845.33332824707, r -= e = 0 | r, e = 0 | (r *= e), (e ^= 4294967296 * (r -= e)) >>> 0; 226 | }, H = function(e) { 227 | if (void 0 === e) throw new Error(u); 228 | let r = pe(e); 229 | return r ? K(r) : void 0; 230 | }, Y = function(e = !1) { 231 | let r, t = $(), n = new Array(); 232 | for (let o = localStorage.length; o--; ) (r = localStorage.key(o)).substr(0, t.length) === t && (e && (r = Ae(r)), 233 | n.push(r)); 234 | return n; 235 | }, Z = function(e = !1) { 236 | let r = new Array(); 237 | for (let t in Le) "#" === t.substr(0, 1) && (e && (t = Oe(t)), r.push(t)); 238 | return r; 239 | }, z = function(e) { 240 | for (var r = (e = "" + e).length, t = r - 1; t >= 0; t--) { 241 | let n = e.charCodeAt(t); 242 | n > 127 && 2047 >= n ? r++ : n > 2047 && 65535 >= n && (r += 2), n >= 56320 && 57343 >= n && t--; 243 | } 244 | return r; 245 | }, W = function(e) { 246 | return _e(e = "" + e).length; 247 | }, $ = function() { 248 | return M + "."; 249 | }, ee = function(e) { 250 | return fe(be(e)); 251 | }, re = function(e) { 252 | if (void 0 === e) return; 253 | let r = "bigint" == typeof e ? e.toString() : JSON.stringify(e, ce), t = 0, n = "", o = ""; 254 | const i = function(e) { 255 | return De(e)(); 256 | }; 257 | var f; 258 | n = e instanceof Array ? "ARRAY1" : "bigint" == typeof e ? "BIGINT2" : "boolean" == typeof e ? "BOOLEAN4" : e instanceof Date ? "DATE8" : "number" == typeof e ? (e + "").includes(".") ? "FLOAT16" : "INTEGER32" : "string" == typeof e ? "STRING64" : "OBJECT128", 259 | o = r + r.length + n + i(r) + i((f = r, Array.from(f).reverse().join(""))); 260 | for (let e = 0; e < o.length; e++) t += o.codePointAt(e); 261 | return [ t, o ]; 262 | }, te = function(e) { 263 | return $() + e; 264 | }, ne = function(e) { 265 | return H(te(e)); 266 | }, oe = function(e) { 267 | return U(e)[1]; 268 | }, ie = function(e, r) { 269 | if (void 0 === e) throw new Error(u); 270 | let t = "", n = ""; 271 | const i = function(e) { 272 | return n.includes(e); 273 | }; 274 | if (void 0 === r) { 275 | if (!ae(e)) return; 276 | n = pe(e); 277 | } else n = r; 278 | return !function() { 279 | let e = arguments.length, r = Object.values(arguments); 280 | return { 281 | areIn(t) { 282 | for (let n = 0; n < e; n++) if (r[n] === t) return !0; 283 | return !1; 284 | }, 285 | total: () => e 286 | }; 287 | }(O, _, C, x, J, I, A, P).areIn(n.substr(-1, 1)) ? "[" === n[0] ? t = "presumed array" : "{" === n[0] ? t = "presumed object" : "n" === n.substr(-1, 1) && parseInt(n, 10) === +n.substring(0, n.length - 1) ? t = "presumed bigint" : n == +n ? t = "presumed number" : (null !== e && (n = Be(n, o, e.replace($(), "")), 288 | n = xe(n, o, e.replace($(), ""))), i(P) ? t = "obfuscated string" : i(_) ? t = "obfuscated bigint" : i(x) ? t = "obfuscated date" : i(O) ? t = "obfuscated array" : i(J) ? (t = "obfuscated number", 289 | t = n.includes(".") ? "obfuscated float" : "obfuscated integer") : t = i(C) ? "obfuscated boolean" : i(I) ? "obfuscated object" : "presumed string") : (i(A) && (t = "compressed string"), 290 | "" === t && i(P) && (t = "string"), "" === t && i(x) && (t = "date"), "" === t && i(O) && (t = "array"), 291 | "" === t && i(J) && (t = "number", t = n.includes(".") ? "float" : "integer"), "" === t && i(C) && (t = "boolean"), 292 | "" === t && i(_) && (t = "bigint"), "" === t && i(I) && (t = "object", n[0] + n[1] + n[2] + n[3] === "null" && (t = "null"))), 293 | t; 294 | }, fe = function(e) { 295 | let r = "", t = typeof e; 296 | return "string" === t && (r = "string", e.includes(A) && (r = "compressed string")), 297 | "" === r && "number" === t && (r = (e + "").includes(".") ? "float" : "integer"), 298 | "" === r && "boolean" === t && (r = "boolean"), "" === r && "bigint" === t && (r = "bigint"), 299 | "" === r && "object" === t ? r = e instanceof Array ? "array" : e instanceof Date ? "date" : null === e ? "null" : "object" : "" === r && (r = "unknown"), 300 | r; 301 | }, ae = function(e) { 302 | return null !== pe(e); 303 | }, se = function() { 304 | Le.version = "localDataStorage 3.0.0", Le.channel = f; 305 | }, ue = function(e) { 306 | let r = !1, t = !1, n = Ne.compress(e) + A; 307 | return r = e === K(n), t = z(n) + 0 <= z(e + P), !(!r || !t); 308 | }, le = function(e, r) { 309 | return "string" == typeof r && "`" === r.substr(-1, 1) && "n" === r.substr(-2, 1) && parseInt(r, 10) === +r.substring(0, r.length - 2) ? BigInt(r.substring(0, r.length - 2)) : r; 310 | }, ce = function(e, r) { 311 | return "bigint" == typeof r ? r.toString() + "n`" : r; 312 | }, he = function(e) { 313 | let r = Y(!0).join(""), t = 0; 314 | return void 0 === e ? t = z(r) : ae(e) && (t = z(Ae(e))), t; 315 | }, de = function(e) { 316 | let r = Y().join(""), t = 0; 317 | return void 0 === e ? t = z(r) : ae(e) && (t = z(e)), t; 318 | }, we = function(e) { 319 | let r = Y().join(""), t = 0; 320 | return void 0 === e ? t = z(r) : ae(e) && (t = z(e)), t *= 2; 321 | }, ge = e => () => (2 ** 31 - 1 & (e = Math.imul(48271, e))) / 2 ** 31, ye = e => r => (e = e + 1831565813 | 0, 322 | r = Math.imul(e ^ e >>> 15, 1 | e), r = r + Math.imul(r ^ r >>> 7, 61 | r) ^ r, 323 | ((r ^ r >>> 14) >>> 0) / 2 ** 32), ve = function(e) { 324 | return e.sort((e, r) => ("$" === (e + "").substr(0, 1) ? (e + "").substr(1, (e + "").length) : e + "").localeCompare(r, "en", { 325 | ignorePunctuation: !0, 326 | numeric: !0, 327 | sensitivity: "base" 328 | })); 329 | }, pe = function(e) { 330 | let r; 331 | try { 332 | r = localStorage.getItem(e); 333 | } catch (e) { 334 | throw new Error("𝗔𝗻 𝗲𝗿𝗿𝗼𝗿 𝗼𝗰𝗰𝘂𝗿𝗿𝗲𝗱 𝗿𝗲𝗮𝗱𝗶𝗻𝗴 𝗳𝗿𝗼𝗺 𝗹𝗼𝗰𝗮𝗹𝗦𝘁𝗼𝗿𝗮𝗴𝗲"); 335 | } 336 | return r; 337 | }, be = function(e) { 338 | return Le["#" + e]; 339 | }, me = function(e) { 340 | return Array.from(e).reverse().join(""); 341 | }, Ee = function(e, r, t, o, i, a, s, u, l, c, h) { 342 | let d = {}, w = new Date(), g = new CustomEvent("localDataStorage", { 343 | detail: { 344 | prefix: e, 345 | method: r, 346 | message: t, 347 | date: w, 348 | timestamp: +w, 349 | oldkey: o, 350 | newkey: i, 351 | oldval: "bigint" === u ? a : JSON.stringify(a, ce), 352 | newval: "bigint" === l ? s : JSON.stringify(s, ce), 353 | oldtype: u, 354 | newtype: l, 355 | oldbase: c, 356 | newbase: h 357 | }, 358 | bubbles: !1, 359 | cancelable: !0 360 | }); 361 | document.dispatchEvent(g), "" !== f && (d = { 362 | id: "localDataStorage", 363 | prefix: e, 364 | method: r, 365 | message: t, 366 | date: w, 367 | timestamp: +w, 368 | oldkey: o, 369 | newkey: i, 370 | oldval: "bigint" === u ? a : JSON.stringify(a, ce), 371 | newval: "bigint" === l ? s : JSON.stringify(s, ce), 372 | oldtype: u, 373 | newtype: l, 374 | oldbase: c, 375 | newbase: h 376 | }, n.postMessage(d)); 377 | }, ke = function() { 378 | let e = Y(!0), r = e.length, t = new Array(r), n = new Array(); 379 | for (let n = r; n--; ) t[n] = H(te(e[n])); 380 | return 0 === (n = function(e) { 381 | let r = new Array(), t = new Array(), n = e.length; 382 | for (let o = 0; o < n; o++) t = e[o], e.lastIndexOf(t) !== o && -1 === r.indexOf(t) && r.push(t); 383 | return r; 384 | }(t)).length ? [] : n; 385 | }, Se = function(e, r, t) { 386 | let n = De(t), o = ye(n()), i = "", f = "", a = re(r)[0] + re(t)[0], s = Q(a) + "", u = me(s), l = Number(u), c = "" + l + a, h = (b = 100, 387 | m = 999, Math.floor(window.crypto.getRandomValues(new Uint32Array(1))[0] / 2 ** 32 * (m - b + 1)) + b + ""), d = D(c, s, u + h), w = Number((l + "").charAt(2)) + Number((l + "").charAt(1)) + Number((l + "").charAt(0)), g = W(re(t)[1]) + W(re(r)[1]) + w, y = JSON.stringify(r, ce), v = De(y), p = ge(v()); 388 | D(); 389 | var b, m; 390 | for (let e = g; e--; ) d() < .75 && o(), o() > .75 && p(); 391 | if (o() > .5) { 392 | i = e.split(" "); 393 | for (let e = 0; e < i.length; e++) (f = i[e]).length > 2 && (f = f.split(""), V(f, o), 394 | f = f.join("")), i[e] = f; 395 | e = i.join(" "); 396 | } 397 | return e = (e += S).split(""), V(e, d), (e = e.join("")) + h; 398 | }, Ne = function() { 399 | const e = function() {}; 400 | return e.codebook = { 401 | " ": 0, 402 | the: 1, 403 | '","': 2, 404 | '":"': 3, 405 | '"}}': 4, 406 | of: 5, 407 | o: 6, 408 | and: 7, 409 | '":{"': 8, 410 | n: 9, 411 | s: 10, 412 | "e ": 11, 413 | r: 12, 414 | " th": 13, 415 | " t": 14, 416 | in: 15, 417 | he: 16, 418 | th: 17, 419 | h: 18, 420 | "he ": 19, 421 | to: 20, 422 | "\r\n": 21, 423 | l: 22, 424 | "s ": 23, 425 | d: 24, 426 | " a": 25, 427 | an: 26, 428 | er: 27, 429 | c: 28, 430 | " o": 29, 431 | "d ": 30, 432 | on: 31, 433 | " of": 32, 434 | re: 33, 435 | "of ": 34, 436 | "t ": 35, 437 | ", ": 36, 438 | is: 37, 439 | u: 38, 440 | at: 39, 441 | " ": 40, 442 | "n ": 41, 443 | or: 42, 444 | which: 43, 445 | f: 44, 446 | m: 45, 447 | as: 46, 448 | it: 47, 449 | that: 48, 450 | "\n": 49, 451 | was: 50, 452 | en: 51, 453 | " ": 52, 454 | " w": 53, 455 | es: 54, 456 | " an": 55, 457 | " i": 56, 458 | "\r": 57, 459 | "f ": 58, 460 | g: 59, 461 | p: 60, 462 | nd: 61, 463 | " s": 62, 464 | "nd ": 63, 465 | "ed ": 64, 466 | w: 65, 467 | ed: 66, 468 | "https://": 67, 469 | for: 68, 470 | te: 69, 471 | ing: 70, 472 | "y ": 71, 473 | The: 72, 474 | " c": 73, 475 | ti: 74, 476 | "r ": 75, 477 | his: 76, 478 | st: 77, 479 | " in": 78, 480 | ar: 79, 481 | nt: 80, 482 | ",": 81, 483 | " to": 82, 484 | y: 83, 485 | ng: 84, 486 | " h": 85, 487 | with: 86, 488 | le: 87, 489 | al: 88, 490 | "to ": 89, 491 | b: 90, 492 | ou: 91, 493 | be: 92, 494 | were: 93, 495 | " b": 94, 496 | se: 95, 497 | "o ": 96, 498 | ent: 97, 499 | ha: 98, 500 | "ng ": 99, 501 | their: 100, 502 | '"': 101, 503 | hi: 102, 504 | from: 103, 505 | " f": 104, 506 | "in ": 105, 507 | de: 106, 508 | ion: 107, 509 | me: 108, 510 | v: 109, 511 | ".": 110, 512 | ve: 111, 513 | all: 112, 514 | "re ": 113, 515 | ri: 114, 516 | ro: 115, 517 | "is ": 116, 518 | co: 117, 519 | "f t": 118, 520 | are: 119, 521 | ea: 120, 522 | ". ": 121, 523 | her: 122, 524 | " m": 123, 525 | "er ": 124, 526 | " p": 125, 527 | "es ": 126, 528 | by: 127, 529 | they: 128, 530 | di: 129, 531 | ra: 130, 532 | ic: 131, 533 | not: 132, 534 | "s, ": 133, 535 | "d t": 134, 536 | "at ": 135, 537 | ce: 136, 538 | la: 137, 539 | "h ": 138, 540 | ne: 139, 541 | "as ": 140, 542 | tio: 141, 543 | "on ": 142, 544 | "n t": 143, 545 | io: 144, 546 | we: 145, 547 | " a ": 146, 548 | om: 147, 549 | ", a": 148, 550 | "s o": 149, 551 | ur: 150, 552 | li: 151, 553 | ll: 152, 554 | ch: 153, 555 | had: 154, 556 | this: 155, 557 | "e t": 156, 558 | "g ": 157, 559 | "e\r\n": 158, 560 | " wh": 159, 561 | ere: 160, 562 | " co": 161, 563 | "e o": 162, 564 | "a ": 163, 565 | us: 164, 566 | " d": 165, 567 | ss: 166, 568 | "\n\r\n": 167, 569 | "\r\n\r": 168, 570 | '="': 169, 571 | " be": 170, 572 | " e": 171, 573 | "s a": 172, 574 | ma: 173, 575 | one: 174, 576 | "t t": 175, 577 | "or ": 176, 578 | but: 177, 579 | el: 178, 580 | so: 179, 581 | "l ": 180, 582 | "e s": 181, 583 | "s,": 182, 584 | no: 183, 585 | ter: 184, 586 | " wa": 185, 587 | iv: 186, 588 | ho: 187, 589 | "e a": 188, 590 | " r": 189, 591 | hat: 190, 592 | "s t": 191, 593 | ns: 192, 594 | "ch ": 193, 595 | wh: 194, 596 | tr: 195, 597 | ut: 196, 598 | "/": 197, 599 | have: 198, 600 | "ly ": 199, 601 | ta: 200, 602 | " ha": 201, 603 | " on": 202, 604 | tha: 203, 605 | "-": 204, 606 | " l": 205, 607 | ati: 206, 608 | "en ": 207, 609 | pe: 208, 610 | " re": 209, 611 | there: 210, 612 | ass: 211, 613 | si: 212, 614 | " fo": 213, 615 | wa: 214, 616 | ec: 215, 617 | our: 216, 618 | who: 217, 619 | its: 218, 620 | "https://www.": 219, 621 | fo: 220, 622 | rs: 221, 623 | ">": 222, 624 | ot: 223, 625 | un: 224, 626 | "<": 225, 627 | im: 226, 628 | "th ": 227, 629 | nc: 228, 630 | ate: 229, 631 | "><": 230, 632 | ver: 231, 633 | ad: 232, 634 | " we": 233, 635 | ly: 234, 636 | ee: 235, 637 | " n": 236, 638 | id: 237, 639 | " cl": 238, 640 | ac: 239, 641 | il: 240, 642 | " 1 ? (t.push(String.fromCodePoint(255)), t.push(String.fromCodePoint(e.length - 1))) : t.push(String.fromCodePoint(254)), 662 | n = 0, o = e.length; n < o; n++) r = e[n], t.push(r); 663 | return t; 664 | }, e.compress = function(r) { 665 | var t, n, o, i, f, a, s; 666 | for (a = "", f = [], o = 0; o < r.length; ) { 667 | for (n = !1, i = e.longestKeyLength, r.length - o < e.longestKeyLength && (i = r.length - o), 668 | i = s = i; i <= 0 ? s < 0 : s > 0; i = i <= 0 ? ++s : --s) if (null != (t = e.codebook[r.substr(o, i)])) { 669 | a && (f = f.concat(e.flush_verbatim(a)), a = ""), f.push(String.fromCodePoint(t)), 670 | o += i, n = !0; 671 | break; 672 | } 673 | n || (a += r[o], o++, 256 === a.length && (f = f.concat(e.flush_verbatim(a)), a = "")); 674 | } 675 | return a && (f = f.concat(e.flush_verbatim(a))), f.join(""); 676 | }, e.decompress = function(r) { 677 | var t, n, o, i, f, a; 678 | for (i = "", n = function() { 679 | var e, n, o; 680 | for (o = [], t = e = 0, n = r.length; 0 <= n ? e < n : e > n; t = 0 <= n ? ++e : --e) o.push(r.codePointAt(t)); 681 | return o; 682 | }(), t = 0; t < n.length; ) if (254 === n[t]) { 683 | if (t + 1 > n.length) throw "Malformed SMAZ"; 684 | i += r[t + 1], t += 2; 685 | } else if (255 === n[t]) { 686 | if (t + n[t + 1] + 2 >= n.length) throw "Malformed SMAZ"; 687 | for (o = f = 0, a = n[t + 1] + 1; 0 <= a ? f < a : f > a; o = 0 <= a ? ++f : --f) i += r[t + 2 + o]; 688 | t += 3 + n[t + 1]; 689 | } else i += e.reverse_codebook[n[t]], t++; 690 | return i; 691 | }, e.getLongestKeyLength = function(e) { 692 | let r = 0, t = 0; 693 | for (let n = 0; n < e.length; n++) e[n].length > t && (r = n, t = e[n].length); 694 | return e[r].length; 695 | }, e.reverse_codebook = e.make_reverse_codebook(e.codebook), e.longestKeyLength = e.getLongestKeyLength(e.reverse_codebook), 696 | e; 697 | }(), Ae = function(e) { 698 | return e.slice($().length, e.length); 699 | }, Oe = function(e) { 700 | return e.replace("#", ""); 701 | }, _e = function(e) { 702 | for (var r, t, n = [], o = 0, i = e.length; i > o; ) (r = e.charCodeAt(o++)) >= 55296 && 56319 >= r && i > o ? 56320 == (64512 & (t = e.charCodeAt(o++))) ? n.push(((1023 & r) << 10) + (1023 & t) + 65536) : (n.push(r), 703 | o--) : n.push(r); 704 | return n; 705 | }, Ce = function(e) { 706 | return Ne.decompress(e); 707 | }, xe = function(e, r, t) { 708 | let n = e.substr(-3), o = e.replace(n, ""), i = De(t), f = ye(i()), a = "", s = "", u = 0, l = re(r)[0] + re(t)[0], c = Q(l) + "", h = me(c), d = Number(h), w = D("" + d + l, c, h + n), g = Number((d + "").charAt(2)) + Number((d + "").charAt(1)) + Number((d + "").charAt(0)); 709 | for (let e = W(re(t)[1]) + W(re(r)[1]) + g; e--; ) w() < .75 && f(), f(); 710 | if (o = o.split(""), u = (o = (o = X(o, w)).join("")).indexOf(S), o = o.substr(0, u), 711 | f() > .5) { 712 | a = o.split(" "); 713 | for (let e = 0; e < a.length; e++) (s = a[e]).length > 2 && (s = s.split(""), s = (s = X(s, f)).join("")), 714 | a[e] = s; 715 | o = a.join(" "); 716 | } 717 | return o; 718 | }, Je = function() { 719 | setTimeout(() => Le.length = Y().length, 0), Le.version = "localDataStorage 3.0.0"; 720 | }, Ie = function(e) { 721 | let r = "", t = 0, n = new Array(), o = 0, i = "", f = ""; 722 | if (void 0 === e) { 723 | for (let e = o = (n = Y()).length; e--; ) i = n[e], r += f = (f = (f = (f = (f = (f = (f = (f = (f = (f = pe(i)).replace(O, "")).replace(_, "")).replace(C, "")).replace(x, "")).replace(J, "")).replace(I, "")).replace(P, "")).replace(A, "")).replace(N, ""); 724 | t = z(r); 725 | } else ae(e) && (f = (f = (f = (f = (f = (f = (f = (f = (f = (f = pe(e)).replace(O, "")).replace(_, "")).replace(C, "")).replace(x, "")).replace(J, "")).replace(I, "")).replace(P, "")).replace(A, "")).replace(N, ""), 726 | t = z(f)); 727 | return t; 728 | }, Pe = function(e) { 729 | let r = "", t = 0, n = new Array(), o = 0, i = "", f = ""; 730 | if (void 0 === e) { 731 | for (let e = o = (n = Y()).length; e--; ) i = n[e], r += f = pe(i); 732 | t = z(r); 733 | } else ae(e) && (f = pe(e), t = z(f)); 734 | return t; 735 | }, Te = function(e) { 736 | return 2 * Pe(e); 737 | }, je = function(e) { 738 | let r = !0, t = typeof e; 739 | for (let e = k.length; e--; ) if (t === k[e]) { 740 | r = !1; 741 | break; 742 | } 743 | return r; 744 | }, Me = function(e, r) { 745 | return "]" === JSON.stringify(e, ce).substr(-1) ? function(e, r) { 746 | let t = !1, n = !0; 747 | if (e.length === r.length) { 748 | for (let t = 0; t < e.length && !0 == (n = -1 !== r.indexOf(e[t])); t++) ; 749 | t = n; 750 | } 751 | return t; 752 | }(e, r) : e === r; 753 | }, Re = function(e, r) { 754 | if (void 0 === e) throw new Error(u); 755 | if (void 0 === r) throw new Error(l); 756 | try { 757 | localStorage.setItem(e, r); 758 | } catch (e) { 759 | throw !e || "QUOTA_EXCEEDED_ERR" !== e.name && "NS_ERROR_DOM_QUOTA_REACHED" !== e.name && "QuotaExceededError" !== e.name ? new Error("𝗔𝗻 𝗲𝗿𝗿𝗼𝗿 𝗼𝗰𝗰𝘂𝗿𝗿𝗲𝗱 𝘄𝗿𝗶𝘁𝗶𝗻𝗴 𝘁𝗼 𝗹𝗼𝗰𝗮𝗹𝗦𝘁𝗼𝗿𝗮𝗴𝗲") : new Error("𝗖𝗮𝗻𝗻𝗼𝘁 𝗮𝘀𝘀𝗶𝗴𝗻 𝘃𝗮𝗹𝘂𝗲 𝗯𝗲𝗰𝗮𝘂𝘀𝗲 𝗹𝗼𝗰𝗮𝗹𝗦𝘁𝗼𝗿𝗮𝗴𝗲 𝗾𝘂𝗼𝘁𝗮 𝗶𝘀 𝗳𝘂𝗹𝗹"); 760 | } 761 | }, De = function(e) { 762 | for (var r, t = 0, n = 2166136261; t < e.length; t++) r = (r = Math.imul(e.charCodeAt(t), 3432918353)) << 15 | r >>> 17, 763 | n = (n ^= Math.imul(r, 461845907)) << 13 | n >>> 19, n = Math.imul(n, 5) + 3864292196 | 0; 764 | return n ^= e.length, function() { 765 | return n ^= n >>> 16, n = Math.imul(n, 2246822507), n ^= n >>> 13, n = Math.imul(n, 3266489909), 766 | (n ^= n >>> 16) >>> 0; 767 | }; 768 | }, Be = function(e, r, t) { 769 | let n = JSON.stringify(r, ce), o = De(n), i = ge(o()), f = De(t), a = ye(f()), s = "", u = re(r)[0], l = Q(u) + "", c = me(l), h = Number(c) + re(t)[0] + re(r)[0], d = h + "", w = u + "", g = o() + "", y = D(d, w, g), v = u + Number((h + "").charAt(0)) + Number((h + "").charAt(1)) + Number((h + "").charAt(2)) + Number(l.charAt(0)), p = W(re(t)[1]) + W(re(r)[1]) + v, b = (A = 4022871197, 770 | function(e) { 771 | for (var r = 0, t = (e = e.toString()).length; r < t; r++) { 772 | var n = .02519603282416938 * (A += e.charCodeAt(r)); 773 | n -= A = n >>> 0, A = (n *= A) >>> 0, A += 4294967296 * (n -= A); 774 | } 775 | return 2.3283064365386963e-10 * (A >>> 0); 776 | }), m = re(r)[1], E = 0, k = 0, S = 0, N = 0; 777 | var A; 778 | e += ""; 779 | for (let e = 0; e < p; e++) y() > .75 && a(), a() > .55 && i(); 780 | for (let r = 0, t = e.length; r < t; r++) E = Math.floor(256 * y()) + 0, a() < .45 && (E += (O = 1, 781 | _ = 100, Math.floor(i() * (_ - O + 1)) + O)), S = E, N = u, k = Math.floor(b(m) * (N - S + 1)) + S, 782 | y() < a() ? s += String.fromCodePoint(E ^ e.codePointAt(r)) : s += String.fromCodePoint(k ^ e.codePointAt(r)); 783 | var O, _; 784 | return s; 785 | }, Le = function(e = !1) { 786 | let r = "", t = "" === f ? " (not currently broadcasting)" : ", broadcasting on channel " + f; 787 | return e ? (r = !0 === i ? ". " + Le.showquotaused() : " where " + F(Le.showquotaused(!0)) + " are used", 788 | "localDataStorage v3.0.0 (checksum " + L + ") using " + ("" === M ? "no prefix" : "prefix " + M) + " with quota of " + Le.quota + r + t) : function() { 789 | if (!R()) return !1; 790 | const e = {}; 791 | return e.version = Le.version, e.checksum = L, e.prefix = M, e.quota = Le.quota, 792 | e.bytes_used = Le.showquotaused(!0), e.channel = Le.channel, { 793 | localDataStorage: e 794 | }; 795 | }(); 796 | }; 797 | Le._backup = function(e, r) { 798 | if (!R()) return !1; 799 | if (void 0 === e) throw new Error(u); 800 | if (!Le._haskey(e)) throw new Error("𝗦𝗼𝘂𝗿𝗰𝗲 𝗺𝗲𝗺𝗼𝗿𝘆 𝗸𝗲𝘆 𝗱𝗼𝗲𝘀 𝗻𝗼𝘁 𝗲𝘅𝗶𝘀𝘁"); 801 | let t = Le._get(e), n = Le._showtype(e), o = "", f = "", a = "", s = ""; 802 | const l = function() { 803 | o = U(t)[0], Re(te(e), o); 804 | }; 805 | if (ae(te(e))) { 806 | if (!r) throw new Error("𝗕𝗮𝗰𝗸𝘂𝗽 𝗰𝗮𝗻𝗻𝗼𝘁 𝗼𝘃𝗲𝗿𝘄𝗿𝗶𝘁𝗲 𝗲𝘅𝗶𝘀𝘁𝗶𝗻𝗴 𝗹𝗼𝗰𝗮𝗹𝗦𝘁𝗼𝗿𝗮𝗴𝗲 𝗸𝗲𝘆"); 807 | if (a = ne(e), s = ie(te(e)), l(), o = ne(e), f = ie(te(e)), !Me(t, o) || n !== f) throw new Error("𝗕𝗮𝗰𝗸𝘂𝗽 𝗲𝗿𝗿𝗼𝗿: 𝗰𝗮𝗻𝗻𝗼𝘁 𝗼𝘃𝗲𝗿𝘄𝗿𝗶𝘁𝗲 𝗲𝘅𝗶𝘀𝘁𝗶𝗻𝗴 𝗸𝗲𝘆"); 808 | if (Le._remove(e), Ee($(), "backup", "key value change", e, e, a, o, s, f, "memory", "disk"), 809 | i) return "Existing localStorage key has been overwritten by Memory Key and the value verified"; 810 | } else { 811 | if (l(), o = ne(e), f = ie(te(e)), !Me(t, o) || n !== f) throw new Error("𝗕𝗮𝗰𝗸𝘂𝗽 𝗲𝗿𝗿𝗼𝗿: 𝗰𝗮𝗻𝗻𝗼𝘁 𝗰𝗿𝗲𝗮𝘁𝗲 𝗻𝗲𝘄 𝗸𝗲𝘆"); 812 | if (Le._remove(e), Ee($(), "backup", "create new key", void 0, e, void 0, o, void 0, f, "memory", "disk"), 813 | i) return "New localStorage created from Memory Key (value verified)"; 814 | } 815 | }, Le.broadcast = function(e) { 816 | if (!R()) return !1; 817 | if (void 0 === e) throw new Error("𝗡𝗼 𝗯𝗿𝗼𝗮𝗱𝗰𝗮𝘀𝘁 𝗰𝗵𝗮𝗻𝗻𝗲𝗹 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱"); 818 | "" === e ? (n.close(), i && console.log("Broadcast Channel API closed")) : (f = e, 819 | n = new BroadcastChannel(f), i && console.log(`Broadcasting on channel ${f}`)); 820 | }, Le.bytes = function(e) { 821 | if (!R()) return !1; 822 | let r; 823 | return void 0 === e ? F(Ie() + he()) : "0 bytes" !== (r = F(Ie(te(e)) + he(te(e)))) ? r : void 0; 824 | }, Le.bytesall = function(e) { 825 | if (!R()) return !1; 826 | let r; 827 | return void 0 === e ? F(Pe() + de()) : "0 bytes" !== (r = F(Pe(te(e)) + de(te(e)))) ? r : void 0; 828 | }, Le.bytesmem = function(e) { 829 | if (!R()) return !1; 830 | let r; 831 | return void 0 === e ? F(Te() + we()) : "0 bytes" !== (r = F(Te(te(e)) + we(te(e)))) ? r : void 0; 832 | }, Le.cancrunch = function(e) { 833 | if (!R()) return !1; 834 | if (void 0 === e) throw new Error(l); 835 | if ("string" != typeof e) throw new Error("𝗗𝗮𝘁𝗮 𝘁𝘆𝗽𝗲 𝗺𝘂𝘀𝘁 𝗯𝗲 𝘀𝘁𝗿𝗶𝗻𝗴"); 836 | return ue(e); 837 | }, Le.chopget = function(e) { 838 | if (!R()) return !1; 839 | let r, t; 840 | return ae(te(e)) ? (r = ne(e), t = ie(te(e)), G(te(e)), Ee($(), "chopget", "excise key", e, void 0, r, void 0, t, void 0, "disk", "disk"), 841 | Le.length -= 1, Je(), r) : void 0; 842 | }, Le._chopget = function(e) { 843 | let r; 844 | return Le._haskey(e) ? (r = Le._get(e), Le._remove(e), r) : void 0; 845 | }, Le.clear = function() { 846 | if (!R()) return !1; 847 | let e, r, t, n = $(), o = Y(), i = o.length; 848 | for (let f = i; f--; ) e = o[f], r = H(e), t = ie(e), G(e), Ee(n, "clear", "remove all keys", e, void 0, r, void 0, t, void 0, "disk", "disk"); 849 | return Le.length = 0, 1 === i ? "1 key removed" : i + " keys removed"; 850 | }, Le._clear = function() { 851 | let e = Z(); 852 | for (let r = e.length; r--; ) Reflect.deleteProperty(Le, e[r]); 853 | }, Le.contains = function(e, r) { 854 | if (!R()) return !1; 855 | if (void 0 === e) throw new Error(u); 856 | if (void 0 === r) throw new Error(l); 857 | if (je(r)) throw new Error(c); 858 | if (!ae(te(e))) return; 859 | if ("array" !== ie(te(e))) throw new Error(d); 860 | let t = !1, n = ne(e); 861 | for (let e = 0; e < n.length; e++) if (JSON.stringify(n[e], ce) === JSON.stringify(r, ce)) { 862 | t = !0; 863 | break; 864 | } 865 | return t; 866 | }, Le.copy = function(e, r) { 867 | if (!R()) return !1; 868 | if (void 0 === e) throw new Error("𝗡𝗼 𝘀𝗼𝘂𝗿𝗰𝗲 𝗸𝗲𝘆 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱"); 869 | if (void 0 === r) throw new Error("𝗡𝗼 𝗱𝗲𝘀𝘁𝗶𝗻𝗮𝘁𝗶𝗼𝗻 𝗸𝗲𝘆 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱"); 870 | if (!ae(te(e))) throw new Error("𝗦𝗼𝘂𝗿𝗰𝗲 𝗸𝗲𝘆 𝗱𝗼𝗲𝘀 𝗻𝗼𝘁 𝗲𝘅𝗶𝘀𝘁"); 871 | if (ae(te(r))) throw new Error("𝗖𝗮𝗻𝗻𝗼𝘁 𝗼𝘃𝗲𝗿𝘄𝗿𝗶𝘁𝗲 𝗲𝘅𝗶𝘀𝘁𝗶𝗻𝗴 𝗱𝗲𝘀𝘁𝗶𝗻𝗮𝘁𝗶𝗼𝗻 𝗸𝗲𝘆"); 872 | let t, n = pe(te(e)); 873 | if (n.substr(0, 1) === N) throw new Error("𝗖𝗮𝗻𝗻𝗼𝘁 𝗰𝗼𝗽𝘆 𝗮𝗻 𝗼𝗯𝗳𝘂𝘀𝗰𝗮𝘁𝗲𝗱 𝗸𝗲𝘆"); 874 | return t = ie(null, n), Re(te(r), n), Ee($(), "copy", "create new key", e, r, void 0, n, void 0, t, "disk", "disk"), 875 | Le.length += 1, Je(), i ? "Created new key " + r + " with value copied from existing key " + e : void 0; 876 | }, Le.countdupes = function() { 877 | if (!R()) return !1; 878 | let e = "", r = ke().length; 879 | return i ? (e = 0 === r ? "No duplicate values" : 1 === r ? "One duplicate value" : r + " duplicate values") + " in storage" : ke().length; 880 | }, Le.crunch = function(e) { 881 | if (!R()) return !1; 882 | if ("symbol" == typeof e) throw new Error(c); 883 | return q(e); 884 | }, Le.export = function(e = "unsafe") { 885 | if (!R()) return !1; 886 | let r = Y(!0), t = r.length, n = M, o = new Array(t), i = new Array(), f = new Array(), a = +new Date(), s = {}; 887 | "safe" !== e && "unsafe" !== e && (e = "unsafe"); 888 | for (let u = 0; u < t; u++) o[u] = pe(M + "." + r[u]), f[u] = [ r[u], o[u] ], i.push(f[u]), 889 | ve(i), s = { 890 | ts: a, 891 | mode: e, 892 | keycount: t, 893 | prefix: n, 894 | keys: i 895 | }; 896 | return s; 897 | }, Le.forcehasval = function(e) { 898 | if (!R()) return !1; 899 | if (je(e)) throw new Error(c); 900 | let r = !1; 901 | for (let t = localStorage.length; t--; ) e == pe(localStorage.key(t)) && (r = !0); 902 | return r; 903 | }, Le.forceget = function(e) { 904 | if (!R()) return !1; 905 | if (void 0 === e) throw new Error(u); 906 | return pe(te(e)); 907 | }, Le.forceset = function(e, r) { 908 | if (!R()) return !1; 909 | if (void 0 === e) throw new Error(u); 910 | if (void 0 === r) throw new Error(l); 911 | if (je(r)) throw new Error(c); 912 | let t = oe(r), n = ne(e), o = ie(te(e)), i = "bigint" === o ? n : JSON.stringify(n, ce), f = "bigint" === t ? r + "n" : r + "", a = JSON.stringify(f, ce); 913 | r += "bigint" === t ? "n" : "", Re(te(e), r), i === a && "string" === o || (void 0 === n ? (Ee($(), "forceset", "create new key", void 0, e, n, f, o, "string", "disk", "disk"), 914 | Le.length += 1, Je()) : Ee($(), "forceset", "key value change", e, void 0, n, f, o, "string", "disk", "disk")); 915 | }, Le.get = function(e) { 916 | return !!R() && ne(e); 917 | }, Le._get = function(e) { 918 | let r = Reflect.get(Le, "#" + e); 919 | return "string" == typeof r && (r = K(r)), r; 920 | }, Le.getscramblekey = function() { 921 | return !!R() && o; 922 | }, Le.haskey = function(e) { 923 | return !!R() && ae(te(e)); 924 | }, Le._haskey = function(e) { 925 | return Reflect.has(Le, "#" + e); 926 | }, Le.hastype = function(e) { 927 | if (!R()) return !1; 928 | if (void 0 === e) throw new Error(g); 929 | if ("symbol" === e.toLowerCase()) throw new Error(c); 930 | if (!k.includes(e.toLowerCase())) throw new Error(w); 931 | e = e.toLowerCase(); 932 | let r, t = "", n = Y(), o = !1; 933 | for (let i = n.length; i--; ) if (r = n[i], t = ie(r), "number" === e && ("float" === t || "integer" === t) || "number" !== e && t === e) { 934 | o = !0; 935 | break; 936 | } 937 | return o; 938 | }, Le.hasval = function(e) { 939 | return !!R() && function(e) { 940 | let r = JSON.stringify(e, ce), t = "", n = "", o = !1; 941 | for (let e = localStorage.length; e--; ) if ((n = localStorage.key(e)).includes($()) && r === (t = JSON.stringify(H(n), ce))) { 942 | o = !0; 943 | break; 944 | } 945 | return o; 946 | }(e); 947 | }, Le.import = function(e, r = "") { 948 | if (!R()) return !1; 949 | let t, n, o = new Array(), i = e.keycount, f = e.prefix, a = new Date(e.ts), s = e.mode, u = 0, l = M, c = "", h = ""; 950 | if ("safe" !== s && "unsafe" !== s && (s = "unsafe"), "" !== r && ("safe" !== r && "unsafe" !== r && (r = "unsafe"), 951 | s = r), "safe" === s ? console.log("Importing upto " + i + (1 === i ? " key " : " keys ") + "from " + a + "...") : console.log("Overwriting " + i + (1 === i ? " key " : " keys ") + "from " + a + "..."), 952 | l === f) { 953 | for (let r = 0; r < i; r++) t = (o = e.keys[r])[0], n = o[1], "safe" === s && ae(h = M + "." + t) || (Le.forceset(t, n), 954 | u++); 955 | c = 0 === u ? "No keys" : 1 === u ? "One key" : u + " keys", console.log(c + " imported"); 956 | } else console.log("No keys imported: prefix does not match storage"); 957 | }, Le.isarray = function(e) { 958 | if (!R()) return !1; 959 | if (void 0 === e) throw new Error(u); 960 | return "array" === ie(te(e)); 961 | }, Le.isbigint = function(e) { 962 | if (!R()) return !1; 963 | if (void 0 === e) throw new Error(u); 964 | return "bigint" === ie(te(e)); 965 | }, Le.isboolean = function(e) { 966 | if (!R()) return !1; 967 | if (void 0 === e) throw new Error(u); 968 | return "boolean" === ie(te(e)); 969 | }, Le.iscrunch = function(e) { 970 | if (!R()) return !1; 971 | if (void 0 === e) throw new Error(u); 972 | return "compressed string" === ie(te(e)); 973 | }, Le.isdate = function(e) { 974 | if (!R()) return !1; 975 | if (void 0 === e) throw new Error(u); 976 | return "date" === ie(te(e)); 977 | }, Le.isfloat = function(e) { 978 | if (!R()) return !1; 979 | if (void 0 === e) throw new Error(u); 980 | return "float" === ie(te(e)); 981 | }, Le.isinteger = function(e) { 982 | if (!R()) return !1; 983 | if (void 0 === e) throw new Error(u); 984 | return "integer" === ie(te(e)); 985 | }, Le.isnull = function(e) { 986 | if (!R()) return !1; 987 | if (void 0 === e) throw new Error(u); 988 | return "null" === ie(te(e)); 989 | }, Le.isnumber = function(e) { 990 | if (!R()) return !1; 991 | if (void 0 === e) throw new Error(u); 992 | return "float" === ie(te(e)) || "integer" === ie(te(e)); 993 | }, Le.isobject = function(e) { 994 | if (!R()) return !1; 995 | if (void 0 === e) throw new Error(u); 996 | return "object" === ie(te(e)); 997 | }, Le.isstring = function(e) { 998 | if (!R()) return !1; 999 | if (void 0 === e) throw new Error(u); 1000 | return "string" === ie(te(e)) || "compressed string" === ie(te(e)); 1001 | }, Le._isarray = function(e) { 1002 | if (void 0 === e) throw new Error(u); 1003 | return "array" === ee(e); 1004 | }, Le._isbigint = function(e) { 1005 | if (void 0 === e) throw new Error(u); 1006 | return "bigint" === ee(e); 1007 | }, Le._isboolean = function(e) { 1008 | if (void 0 === e) throw new Error(u); 1009 | return "boolean" === ee(e); 1010 | }, Le._iscrunch = function(e) { 1011 | if (void 0 === e) throw new Error(u); 1012 | return "compressed string" === ee(e); 1013 | }, Le._isdate = function(e) { 1014 | if (void 0 === e) throw new Error(u); 1015 | return "date" === ee(e); 1016 | }, Le._isfloat = function(e) { 1017 | if (void 0 === e) throw new Error(u); 1018 | return "float" === ee(e); 1019 | }, Le._isinteger = function(e) { 1020 | if (void 0 === e) throw new Error(u); 1021 | return "integer" === ee(e); 1022 | }, Le._isnull = function(e) { 1023 | if (void 0 === e) throw new Error(u); 1024 | return "null" === ee(e); 1025 | }, Le._isnumber = function(e) { 1026 | if (void 0 === e) throw new Error(u); 1027 | return "float" === ee(e) || "integer" === ee(e); 1028 | }, Le._isobject = function(e) { 1029 | if (void 0 === e) throw new Error(u); 1030 | return "object" === ee(e); 1031 | }, Le._isstring = function(e) { 1032 | if (void 0 === e) throw new Error(u); 1033 | return "string" === ee(e) || "compressed string" === ee(e); 1034 | }, Le.key = function(e, r = !1) { 1035 | if (!R()) return !1; 1036 | if (void 0 === e) throw new Error(y); 1037 | if (e !== Number(e)) throw new Error(v); 1038 | if (e < 0) throw new Error(v); 1039 | let t = Y(), n = t.length; 1040 | return r && ve(t), e < n ? t[e] : void 0; 1041 | }, Le._key = function(e, r = !1) { 1042 | if (void 0 === e) throw new Error(y); 1043 | if (e !== Number(e)) throw new Error(v); 1044 | if (e < 0) throw new Error(v); 1045 | let t = Z(), n = t.length; 1046 | return r && ve(t), e < n ? Oe(t[e]) : void 0; 1047 | }, Le.keybytes = function(e) { 1048 | if (!R()) return !1; 1049 | let r; 1050 | return void 0 === e ? F(he()) : "0 bytes" !== (r = F(he(te(e)))) ? r : void 0; 1051 | }, Le.keybytesall = function(e) { 1052 | if (!R()) return !1; 1053 | let r; 1054 | return void 0 === e ? F(de()) : "0 bytes" !== (r = F(de(te(e)))) ? r : void 0; 1055 | }, Le.keybytesmem = function(e) { 1056 | if (!R()) return !1; 1057 | let r; 1058 | return void 0 === e ? F(we()) : "0 bytes" !== (r = F(we(te(e)))) ? r : void 0; 1059 | }, Le.keys = function() { 1060 | return !!R() && (Le.length = Y().length, Le.length); 1061 | }, Le._keys = function() { 1062 | return Z().length; 1063 | }, Le.listdupes = function(e = !0) { 1064 | if (!R()) return !1; 1065 | let r = function(e) { 1066 | let r = ke(), t = {}, n = {}, o = "", i = localStorage.length; 1067 | if (e && ve(r), r.length) for (let t = 0, f = r.length; t < f; t++) { 1068 | let f = new Array(); 1069 | for (let e = i; e--; ) o = localStorage.key(e), JSON.stringify(H(o), ce) === JSON.stringify(r[t], ce) && (o = Ae(o), 1070 | f.push(o)); 1071 | e && ve(f), n[t] = { 1072 | value: r[t], 1073 | keys: f, 1074 | keycount: f.length 1075 | }; 1076 | } 1077 | return t = { 1078 | dupecount: r.length, 1079 | dupes: n 1080 | }; 1081 | }(e); 1082 | return 0 !== r.dupecount ? r : void 0; 1083 | }, Le.poke = function(e, r, t) { 1084 | if (!R()) return !1; 1085 | if (void 0 === e) throw new Error(u); 1086 | if (void 0 === r) throw new Error(l); 1087 | if (je(r)) throw new Error(c); 1088 | if (!ae(te(e))) throw new Error(h); 1089 | if ("array" !== ie(te(e))) throw new Error(d); 1090 | let n = ne(e), o = n.length, i = o + 1, f = ""; 1091 | if (void 0 === t) t = i; else if ("string" == typeof t) if ("start" === t.toLowerCase()) t = 0; else { 1092 | if ("end" !== t.toLowerCase()) throw new Error(p); 1093 | t = i; 1094 | } else { 1095 | if ("number" != typeof t) throw new Error(m); 1096 | if (t < 1) t = 0; else if (t > o) t = i; else if (!(t > 0 && t < i)) throw new Error(b); 1097 | } 1098 | t === i ? (n.push(r), f = "append") : 0 === t ? (n.unshift(r), f = "prepend") : (n.splice(t - 1, 1, r), 1099 | f = "replace"), f += " value"; 1100 | let a, s = ne(e), w = ie(te(e)), g = "bigint" === w ? s : JSON.stringify(s, ce), y = U(r)[1], v = "bigint" === y ? a : JSON.stringify(a, ce); 1101 | n = U(n)[0], Re(te(e), n), a = ne(e), g === v && w === y || Ee($(), "poke", f, e, void 0, s, a, w, y, "disk", "disk"); 1102 | }, Le.pull = function(e, r, t = !1) { 1103 | if (!R()) return !1; 1104 | if (void 0 === e) throw new Error(u); 1105 | if (!ae(te(e))) return; 1106 | if ("array" !== ie(te(e))) throw new Error(d); 1107 | let n = ne(e), o = n.length, i = o + 1, f = "", a = 0, s = !t; 1108 | if (void 0 === r) r = i; else if ("string" == typeof r) { 1109 | if ("start" === r.toLowerCase()) r = 0; else if ("end" === r.toLowerCase()) r = i; else if ("" === r) throw new Error(p); 1110 | } else if ("number" == typeof r) { 1111 | if (s) if (r < 2) r = 0; else if (r > o) r = i; else if (!(r > 0 && r < i)) throw new Error(b); 1112 | } else if ("bigint" == typeof r) ; else if ("number" == typeof r) ; else if ("boolean" == typeof r) ; else if ("object" != typeof r) throw new Error(m); 1113 | if (s && r === i) n.pop(), f = "from end"; else if (s && 0 === r) n.shift(), f = "from start"; else if (s && "number" == typeof r) n.splice(r - 1, 1), 1114 | f = "from contents"; else { 1115 | for (let e = 0; e < n.length; e++) if (JSON.stringify(n[e], ce) === JSON.stringify(r, ce)) { 1116 | a = e + 1; 1117 | break; 1118 | } 1119 | if (!a) return; 1120 | n.splice(a - 1, 1), f = "from contents"; 1121 | } 1122 | let l, c = ne(e), h = ie(te(e)), w = "bigint" === h ? c : JSON.stringify(c, ce), g = JSON.stringify(l, ce); 1123 | n = U(n)[0], Re(te(e), n), l = ne(e), w === g && void 0 === h || JSON.stringify(c, ce) !== JSON.stringify(l, ce) && Ee($(), "pull", "remove value " + f, e, void 0, c, l, h, void 0, "disk", "disk"); 1124 | }, Le.pullall = function(e, r) { 1125 | if (!R()) return !1; 1126 | if (void 0 === e) throw new Error(u); 1127 | if (void 0 === r) throw new Error(l); 1128 | if (je(r)) throw new Error(c); 1129 | if (!ae(te(e))) return; 1130 | if ("array" !== ie(te(e))) throw new Error(d); 1131 | let t = ne(e); 1132 | !function(e, r) { 1133 | let t = e.length; 1134 | for (;t--; ) e[t] === r && e.splice(e.indexOf(r), 1); 1135 | }(t, r); 1136 | let n, o = ne(e), i = ie(te(e)), f = "bigint" === i ? o : JSON.stringify(o, ce), a = JSON.stringify(n, ce); 1137 | t = U(t)[0], Re(te(e), t), n = ne(e), f === a && void 0 === i || JSON.stringify(o, ce) !== JSON.stringify(n, ce) && Ee($(), "pullall", "remove all values from contents", e, void 0, o, n, i, void 0, "disk", "disk"); 1138 | }, Le.push = function(e, r, t) { 1139 | if (!R()) return !1; 1140 | if (void 0 === e) throw new Error(u); 1141 | if (void 0 === r) throw new Error(l); 1142 | if (je(r)) throw new Error(c); 1143 | if (ae(te(e)) && "array" !== ie(te(e))) throw new Error(d); 1144 | if (ae(te(e))) { 1145 | let n = ne(e), o = n.length, i = o + 1, f = ""; 1146 | if (void 0 === t) t = i; else if ("string" == typeof t) if ("start" === t.toLowerCase()) t = 0; else { 1147 | if ("end" !== t.toLowerCase()) throw new Error(p); 1148 | t = i; 1149 | } else { 1150 | if ("number" != typeof t) throw new Error(m); 1151 | if (t < 2) t = 0; else if (t > o) t = i; else if (!(t > 0 && t < i)) throw new Error(b); 1152 | } 1153 | t === i ? (n.push(r), f = "append") : 0 === t ? (n.unshift(r), f = "prepend") : (n.splice(t - 1, 0, r), 1154 | f = "insert"), f += " value"; 1155 | let a, s = ne(e), u = ie(te(e)), l = "bigint" === u ? s : JSON.stringify(s, ce), c = U(r)[1], h = "bigint" === c ? a : JSON.stringify(a, ce); 1156 | n = U(n)[0], Re(te(e), n), a = ne(e), l === h && u === c || Ee($(), "push", f, e, void 0, s, a, u, c, "disk", "disk"); 1157 | } else { 1158 | let t = new Array(), n = arguments.length; 1159 | if (n > 2) { 1160 | for (let e = 1; e < n; e++) "array" === oe(arguments[e]) ? t = t.concat(arguments[e]) : t.push(arguments[e]); 1161 | r = t; 1162 | } else if ("array" !== oe(r)) { 1163 | for (let e = 1; e < n; e++) t.push(arguments[e]); 1164 | r = t; 1165 | } 1166 | let o = ne(e), i = ie(te(e)), f = ("bigint" === i || JSON.stringify(o, ce), r), a = U(r)[1]; 1167 | "bigint" === a || JSON.stringify(f, ce); 1168 | r = U(r)[0], Re(te(e), r), Ee($(), "push", "create new key", void 0, e, o, f, i, a, "disk", "disk"), 1169 | Le.length += 1, Je(); 1170 | } 1171 | }, Le.remove = function(e) { 1172 | if (!R()) return !1; 1173 | if (void 0 === e) throw new Error(u); 1174 | let r = ne(e), t = ie(te(e)); 1175 | return ae(te(e)) ? (G(te(e)), Ee($(), "remove", "remove key", e, void 0, r, void 0, t, void 0, "disk", "disk"), 1176 | Le.length -= 1, Je(), i ? "key removed" : void 0) : void 0; 1177 | }, Le._remove = function(e) { 1178 | Reflect.deleteProperty(Le, "#" + e); 1179 | }, Le.rename = function(e, r) { 1180 | if (!R()) return !1; 1181 | if (void 0 === e) throw new Error(u); 1182 | if (!ae(te(e))) throw new Error(h); 1183 | if (void 0 === r) throw new Error("𝗡𝗼 𝗻𝗲𝘄 𝗸𝗲𝘆 𝗻𝗮𝗺𝗲 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱"); 1184 | if (e === r) throw new Error("𝗖𝗮𝗻𝗻𝗼𝘁 𝗿𝗲𝗻𝗮𝗺𝗲 𝗸𝗲𝘆 𝘁𝗼 𝗶𝘁𝘀 𝗼𝘄𝗻 𝗻𝗮𝗺𝗲"); 1185 | if (ae(te(r))) throw new Error("𝗗𝗲𝘀𝘁𝗶𝗻𝗮𝘁𝗶𝗼𝗻 𝗸𝗲𝘆 𝗮𝗹𝗿𝗲𝗮𝗱𝘆 𝗲𝘅𝗶𝘀𝘁𝘀"); 1186 | let t = ne(e), n = ie(te(e)), o = U(t)[0]; 1187 | G(te(e)), Re(te(r), o), Ee($(), "rename", "key name change", e, r, t, t, n, n, "disk", "disk"); 1188 | }, Le._restore = function(e, r) { 1189 | if (void 0 === e) throw new Error(u); 1190 | if (!ae(te(e))) throw new Error("𝗦𝗼𝘂𝗿𝗰𝗲 𝗹𝗼𝗰𝗮𝗹𝗦𝘁𝗼𝗿𝗮𝗴𝗲 𝗸𝗲𝘆 𝗱𝗼𝗲𝘀 𝗻𝗼𝘁 𝗲𝘅𝗶𝘀𝘁"); 1191 | let t = ne(e), n = ie(te(e)), o = "", f = "", a = "", s = ""; 1192 | if (Le._haskey(e)) { 1193 | if (!r) throw new Error("𝗥𝗲𝘀𝘁𝗼𝗿𝗲 𝗰𝗮𝗻𝗻𝗼𝘁 𝗼𝘃𝗲𝗿𝘄𝗿𝗶𝘁𝗲 𝗲𝘅𝗶𝘀𝘁𝗶𝗻𝗴 𝗺𝗲𝗺𝗼𝗿𝘆 𝗸𝗲𝘆"); 1194 | if (a = Le._get(e), s = Le._showtype(e), Le._set(e, t), o = Le._get(e), f = Le._showtype(e), 1195 | !Me(t, o) || n !== f) throw new Error("𝗥𝗲𝘀𝘁𝗼𝗿𝗲 𝗲𝗿𝗿𝗼𝗿: 𝗰𝗮𝗻𝗻𝗼𝘁 𝗼𝘃𝗲𝗿𝘄𝗿𝗶𝘁𝗲 𝗲𝘅𝗶𝘀𝘁𝗶𝗻𝗴 𝗸𝗲𝘆"); 1196 | if (G(te(e)), Ee($(), "restore", "key value change", e, e, a, o, s, f, "disk", "memory"), 1197 | i) return "Existing Memory Key has been overwritten from localStorage and the value verified"; 1198 | } else { 1199 | if (Le._set(e, t), o = Le._get(e), f = Le._showtype(e), !Me(t, o) || n !== f) throw new Error("𝗥𝗲𝘀𝘁𝗼𝗿𝗲 𝗲𝗿𝗿𝗼𝗿: 𝗰𝗮𝗻𝗻𝗼𝘁 𝗰𝗿𝗲𝗮𝘁𝗲 𝗻𝗲𝘄 𝗸𝗲𝘆"); 1200 | if (G(te(e)), Ee($(), "restore", "create new key", void 0, e, void 0, o, void 0, f, "disk", "memory"), 1201 | i) return "New Memory Key created from localStorage (value verified)"; 1202 | } 1203 | }, Le.safeget = function(e, r) { 1204 | if (!R()) return !1; 1205 | let t; 1206 | if (ae(te(e))) { 1207 | if ((t = pe(te(e))).substr(0, 1) !== N) throw new Error("𝗞𝗲𝘆 𝗶𝘀 𝗻𝗼𝘁 𝗼𝗯𝗳𝘂𝘀𝗰𝗮𝘁𝗲𝗱"); 1208 | return t = t.substr(1), void 0 === r ? (t = Be(t, o, e), t = xe(t, o, e)) : (t = Be(t, r, e), 1209 | t = xe(t, r, e)), t = K(t); 1210 | } 1211 | }, Le.safeset = function(e, r, t) { 1212 | if (!R()) return !1; 1213 | if (void 0 === e) throw new Error(u); 1214 | if (void 0 === r) throw new Error(l); 1215 | if (je(r)) throw new Error(c); 1216 | let n = "", f = pe(te(e)), a = null === f ? void 0 : f, s = ie(te(e)), h = "bigint" === s ? a : JSON.stringify(a, ce), d = "", w = "obfuscated key", g = JSON.stringify(d, ce); 1217 | if (r = U(r)[0], void 0 === t ? (r = Se(r, o, e), r = Be(r, o, e), n = " with global scramble key") : (r = Se(r, t, e), 1218 | r = Be(r, t, e), n = " with user scramble key"), r = N + r, Re(te(e), r), d = pe(te(e)), 1219 | h !== g || s !== w) if (void 0 === a) { 1220 | if (Ee($(), "safeset", "create new key" + n, void 0, e, a, d, s, w, "disk", "disk"), 1221 | Le.length += 1, Je(), i) return "New obfuscated key created" + n; 1222 | } else if (a !== d && (Ee($(), "safeset", "key value change" + n, e, void 0, a, d, s, w, "disk", "disk"), 1223 | i)) return "Existing key has been overwritten with obfuscated value created" + n; 1224 | }, Le.set = function(e, r) { 1225 | if (!R()) return !1; 1226 | if (void 0 === e) throw new Error(u); 1227 | if (void 0 === r) throw new Error(l); 1228 | if (je(r)) throw new Error(c); 1229 | let t = ne(e), n = ie(te(e)), o = "bigint" === n ? t : JSON.stringify(t, ce), f = r, a = U(r)[1], s = "bigint" === a ? f : JSON.stringify(f, ce); 1230 | if (r = U(r)[0], Re(te(e), r), o !== s || n !== a) if (void 0 === t) { 1231 | if (Ee($(), "set", "create new key", void 0, e, t, f, n, a, "disk", "disk"), Le.length += 1, 1232 | Je(), i) return "New " + a + " key created"; 1233 | } else if (Ee($(), "set", "key value change", e, void 0, t, f, n, a, "disk", "disk"), 1234 | i) return "Existing key has been overwritten"; 1235 | }, Le._set = function(e, r) { 1236 | if (void 0 === e) throw new Error(u); 1237 | if (void 0 === r) throw new Error(l); 1238 | if (je(r)) throw new Error(c); 1239 | "string" == typeof r && (r = U(r)[0]), Reflect.set(Le, "#" + e, r); 1240 | }, Le.setscramblekey = function(e) { 1241 | if (!R()) return !1; 1242 | if (void 0 === e) throw new Error("𝗡𝗼 𝘀𝗰𝗿𝗮𝗺𝗯𝗹𝗲 𝗸𝗲𝘆 𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗲𝗱"); 1243 | if (je(e)) throw new Error(c); 1244 | return o = e, i ? "The new global scramble key is set" : void 0; 1245 | }, Le.showdupes = function(e = !0) { 1246 | if (!R()) return !1; 1247 | let r = ke(); 1248 | return e && ve(r), r.length ? r : i ? "No duplicate values in storage" : void 0; 1249 | }, Le.showkeys = function(e, r = !0, t = !0) { 1250 | if (!R()) return !1; 1251 | if (void 0 === e) throw new Error(l); 1252 | if (je(e)) throw new Error(c); 1253 | let n, o = "", f = new Array(), a = Y(); 1254 | for (let t = a.length; t--; ) n = a[t], o = H(n), JSON.stringify(o, ce) === JSON.stringify(e, ce) && (r && (n = Ae(n)), 1255 | f.push(n)); 1256 | return t && ve(f), f.length ? f : i ? "No keys have that value" : void 0; 1257 | }, Le.showkeytypes = function(e, r = !0, t = !0) { 1258 | if (!R()) return !1; 1259 | if (void 0 === e) throw new Error(g); 1260 | if ("symbol" === e.toLowerCase()) throw new Error(c); 1261 | if (!k.includes(e.toLowerCase())) throw new Error(w); 1262 | e = e.toLowerCase(); 1263 | let n, o = "", f = new Array(), a = Y(); 1264 | for (let t = a.length; t--; ) n = a[t], o = ie(n), ("number" === e && ("float" === o || "integer" === o) || "number" !== e && o === e) && (r && (n = Ae(n)), 1265 | f.push(n)); 1266 | return t && ve(f), f.length ? f : i ? "No keys are of that type" : void 0; 1267 | }, Le.showprefix = function() { 1268 | return !!R() && (i ? "The key prefix (" + M + ".) adds " + _keyNameOverhead + " to each key name (stored using " + _keyNameOverhead2 + ")" : M + "."); 1269 | }, Le.showquota = function() { 1270 | if (!R()) return !1; 1271 | const e = function() { 1272 | let e, r = 0; 1273 | try { 1274 | for (r = 250; r <= 2e4; r += 250) localStorage.setItem(T, new Array(1024 * r + 1).join("~")); 1275 | } catch (e) { 1276 | localStorage.setItem(T + T, r - 250); 1277 | } 1278 | return e = localStorage.getItem(T + T), e = parseInt(e, 10), e *= 1e3, G(T), G(T + T), 1279 | e; 1280 | }(); 1281 | return Le.quota = F(e, !0), i ? "Total storage allocated is " + F(e, !0) + " (consuming " + F(2 * e, !0) + " of memory)" : F(e, !0); 1282 | }, Le.showquotaused = function(e = !1) { 1283 | if (!R()) return !1; 1284 | let r, t, n, o = "", f = localStorage.length; 1285 | if (0 !== localStorage.length) { 1286 | for (let e = f; e--; ) o += (r = localStorage.key(e)) + (t = pe(r)); 1287 | return n = z(o), e ? n : i ? "Total storage used is " + F(n) + " (consuming " + F(2 * n, !0) + " of memory)" : F(n); 1288 | } 1289 | return F(0); 1290 | }, Le.showtype = function(e) { 1291 | if (!R()) return !1; 1292 | let r; 1293 | if (void 0 === e) throw new Error(u); 1294 | return r = ie(te(e)), i ? void 0 === r ? "Key does not exist and cannot be checked" : "array" === r ? "This key is an Array Key" : "Key has value whose data type is " + r : r; 1295 | }, Le._showtype = function(e) { 1296 | if (void 0 === e) throw new Error(u); 1297 | let r = "", t = be(e); 1298 | return r = fe(t); 1299 | }, Le.shufflestring = function(e, r, t) { 1300 | if (!R()) return !1; 1301 | if (void 0 === e) throw new Error(E); 1302 | if (void 0 === r) throw new Error(s); 1303 | if (void 0 === t) throw new Error(u); 1304 | return Se(e, r, t); 1305 | }, Le.size = function(e) { 1306 | if (!R()) return !1; 1307 | let r = ne(e); 1308 | return void 0 !== r && (r = W(r)), i ? void 0 === r ? "Key does not exist and cannot be checked" : "Key value has " + r + " codepoints" : r; 1309 | }, Le.softset = function(e, r) { 1310 | if (!R()) return !1; 1311 | if (void 0 === e) throw new Error(u); 1312 | if (void 0 === r) throw new Error(l); 1313 | if (je(r)) throw new Error(c); 1314 | let t, n = U(r)[1], o = r; 1315 | return ae(te(e)) ? 1 === i ? "Key already exists and cannot be overwritten" : void 0 : (r = U(r)[0], 1316 | Re(te(e), r), Ee($(), "softset", "create new key", void 0, e, void 0, o, void 0, n, "disk", "disk"), 1317 | Le.length += 1, Je(), 1 === i ? t = "array" === n ? "New Array Key created" : "New " + n + " key created" : void 0); 1318 | }, Le._store = function(e = !1) { 1319 | let r, t, n = Z(!0), o = n.length, i = new Array(); 1320 | e && ve(n); 1321 | for (let e = 0; e < o; e++) r = n[e], t = Reflect.get(Le, "#" + r), i.push([ r, t ]); 1322 | return 0 === i.length ? void 0 : i; 1323 | }, Le.uncrunch = function(e) { 1324 | return !!R() && Ce(e); 1325 | }, Le.unshufflestring = function(e, r, t) { 1326 | if (!R()) return !1; 1327 | if (void 0 === e) throw new Error(E); 1328 | if (void 0 === r) throw new Error(s); 1329 | if (void 0 === t) throw new Error(u); 1330 | return xe(e, r, t); 1331 | }, Le.valbytes = function(e) { 1332 | if (!R()) return !1; 1333 | let r; 1334 | return void 0 === e ? F(Ie()) : "0 bytes" !== (r = F(Ie(te(e)))) ? r : void 0; 1335 | }, Le.valbytesall = function(e) { 1336 | if (!R()) return !1; 1337 | let r; 1338 | return void 0 === e ? F(Pe()) : "0 bytes" !== (r = F(Pe(te(e)))) ? r : void 0; 1339 | }, Le.valbytesmem = function(e) { 1340 | if (!R()) return !1; 1341 | let r; 1342 | return void 0 === e ? F(Te()) : "0 bytes" !== (r = F(Te(te(e)))) ? r : void 0; 1343 | }, Le.verbosity = function(e) { 1344 | return !!R() && (void 0 !== (e = Boolean(e)) && function(e) { 1345 | i = Boolean(e); 1346 | }(e), "Verbosity is " + (i ? "on" : "off")); 1347 | }, Le.where = function(e, r) { 1348 | if (!R()) return !1; 1349 | if (void 0 === e) throw new Error(u); 1350 | if (void 0 === r) throw new Error(l); 1351 | if (je(r)) throw new Error(c); 1352 | if (!ae(te(e))) return; 1353 | if ("array" !== ie(te(e))) throw new Error(d); 1354 | let t = !1, n = ne(e); 1355 | for (let e = 0; e < n.length; e++) if (JSON.stringify(n[e], ce) === JSON.stringify(r, ce)) { 1356 | t = e + 1; 1357 | break; 1358 | } 1359 | return i ? "Value was found in the Array Key at position " + t : t; 1360 | }, Le.xorstring = function(e, r, t) { 1361 | if (!R()) return !1; 1362 | if (void 0 === e) throw new Error(E); 1363 | if (void 0 === r) throw new Error(s); 1364 | if (void 0 === t) throw new Error(u); 1365 | return Be(e, r, t); 1366 | }; 1367 | try { 1368 | localStorage.length; 1369 | Le.version = "localDataStorage 3.0.0", Object.defineProperty(Le, "length", { 1370 | enumerable: !1, 1371 | configurable: !1, 1372 | writable: !0, 1373 | value: Y().length 1374 | }); 1375 | let e = F(z(Le.showprefix())), o = F(2 * z(Le.showprefix())); 1376 | return function() { 1377 | Le.quota = Le.showquota(); 1378 | let i, f = !1, a = !1, s = localStorage.length, u = Le.showprefix(); 1379 | if (R()) { 1380 | if (void 0 !== r || t && t.includes("/q") || (a = !0, console.info("No prefix specified. Creating a %crandom %cprefix --\x3e %c" + u, "font-style: italic;", "font-style: normal;", "font-weight: bold;")), 1381 | "" !== r || t && -1 !== t.indexOf("/q") || console.info("Empty prefix given (%c" + u + "%c), but a usable prefix is %cstrongly recommended%c to organize keys!", "font-weight: bold;", "font-style: normal;", "text-decoration: underline;", "text-decoration: none;"), 1382 | t && -1 !== t.indexOf("/q") || console.log("💼 localDataStorage instantiated. " + (!0 === a ? "The random prefix" : "Your specified prefix") + " (%c" + u + "%c) adds " + e + " to every key name (stored using " + o + ").", "font-weight: bold;", "font-style: normal;"), 1383 | t && t.includes("/w")) { 1384 | for (let e = s; e--; ) if (-1 !== (i = localStorage.key(e)).indexOf(u)) { 1385 | f = !0; 1386 | break; 1387 | } 1388 | f && console.warn("%cAttention! %cKeys with this prefix already exist in localStorage for this domain!", "color: rgb(230,0,0); font-weight: bold;", "color: rgb(230,0,0);"); 1389 | } 1390 | t && t.includes("/t") && function() { 1391 | let e = !1; 1392 | return Le.safeset(T, T, T), T === Le.safeget(T, T) && (e = !0), Le.remove(T), e; 1393 | }() && console.log("Tested good: The localStorage API is available"); 1394 | } else n.close(), console.warn("%cWarning! Cannot access localStorage! %cBailing out...", "color: rgb(230,0,0); font-weight: bold;", "color: rgb(230,0,0);"); 1395 | }(), Le; 1396 | } catch (e) { 1397 | n.close(), console.error("%cFatal error! %cThe localStorage API appears to be disabled! Please check your browser’s settings for cookies and storage.", "color: rgb(230,0,0); font-weight: bold;", "color: rgb(230,0,0);"); 1398 | } 1399 | }(e, r); 1400 | }; 1401 | -------------------------------------------------------------------------------- /wiki-extra/Memory-Requirements2.md: -------------------------------------------------------------------------------- 1 | # Memory Requirements 2 | 3 | 👉🏻 **Return to main** [**Wiki**](https://github.com/macmcmeans/localDataStorage/wiki/Memory-Requirements)

4 | 5 | There is a difference between the memory required to store a key value and the memory consumed in the process. For JavaScript, _consumption_ is doubled that of _storage_. 6 | 7 | The following table illustrates memory storage and consumption, for both a key name and its value, as well as the available methods for determining each: 8 | 9 | Prefix | Example | Key
Name | Key
Memory
Storage
_[keybytes](.keybytes)_ | Full Key
Memory
Storage ⑴
_[keybytesall](.keybytesall)_ | Full Key
Memory
Consumed
_[keybytesmem](.keybytesmem)_ | Data
Type | Data
Value | Internally
Stored As | Value
Memory
Storage
_[valbytes](.valbytes)_ | Full Value
Memory
Storage ⑵
_[valbytesall](.valbytesall)_ | Full Value
Memory
Consumed
_[valbytesmem](.valbytesmem)_ 10 | :-----:| :-----: | :-----: | :-----: | :-----: | :----: | :----: | :-----: | :-----: | :-----: | :-----: | :-----: 11 | lds-1.| _.set( 'skey1', '["x"]' )_ | skey1 | 5 bytes | 11 bytes | 22 bytes | Array | ["x"] | ["x"]� | 5 bytes | 6 bytes | 12 bytes 12 | ☝ | _.set( 'skey1', 12n )_ | ☝ | ☝ | ☝ | ☝ | BigInt | 12n | 12� | 2 bytes | 3 bytes | 6 bytes 13 | ☝ | _.set( 'skey1', true )_ | ☝ | ☝ | ☝ | ☝ | Boolean | true | 1� | 1 byte | 2 bytes | 4 bytes 14 | ☝ | _.set( 'skey1', false )_ | ☝ | ☝ | ☝ | ☝ | Boolean | false | 0� | 1 byte | 2 bytes | 4 bytes 15 | ☝ | _.set( 'skey1', Date() )_ | ☝ | ☝ | ☝ | ☝ | Date | ~ | ZVRnbZS� ⑸ | 7 bytes | 8 bytes | 16 bytes 16 | ☝ | _.set( 'skey1', 19.99 )_ | ☝ | ☝ | ☝ | ☝ | Float | 2149.99 | 1w.14� ⑹ | 5 bytes | 6 bytes | 12 bytes 17 | ☝ | _.set( 'skey1', 1234 )_ | ☝ | ☝ | ☝ | ☝ | Integer | 9182736450 | 1g]vJ(� ⑹ | 6 bytes | 7 bytes | 14 bytes 18 | ☝ | _.set( 'skey1', null )_ | ☝ | ☝ | ☝ | ☝ | null | null | null� | 4 bytes | 5 bytes | 10 bytes 19 | ☝ | _.set( 'skey1', {'a':1} )_ | ☝ | ☝ | ☝ | ☝ | Object | {'a':1} | {'a':1}� | 7 bytes | 8 bytes | 16 bytes 20 | ☝ | _.set( 'skey1', 'lds' )_ | ☝ | ☝ | ☝ | ☝ | String | 'lds' | lds� | 3 bytes | 4 bytes | 8 bytes 21 | ☝ | _.set( 'skey1', 'test string' )_ | ☝ | ☝ | ☝ | ☝ | Compressed
String | 'this is some string data' | \x9B8\x17³l>ÃF¥'þa� ⑷ | 17 bytes | 18 bytes | 36 bytes ⑶ 22 | 23 |

24 | **Footnotes:**
25 | ⑴ includes the namespace prefix (6 bytes, in this example)
26 | ⑵ includes the data type marker flag (always 1 byte)
27 | ⑶ text compression—even on a small scale—makes an impact (uncompressed this string consumes 24 bytes, not 17)
28 | ⑷ note that string length is inconsequential (13 in this case); for storage the only metric that counts is byte count
29 | ⑸ dates are automatically stored compressed, providing a degree of obfuscation as well
30 | ⑹ numbers (floats and integers) are automatically stored compressed, providing a degree of obfuscation as well 31 | --------------------------------------------------------------------------------