javascript-obfuscator 5.1.0 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/CLAUDE.md +2 -2
  3. package/CODE_OF_CONDUCT.md +1 -1
  4. package/README.md +195 -31
  5. package/dist/index.browser.js +46 -2
  6. package/dist/index.browser.js.map +1 -1
  7. package/dist/index.cli.js +24 -2
  8. package/dist/index.cli.js.map +1 -1
  9. package/dist/index.js +24 -2
  10. package/dist/index.js.map +1 -1
  11. package/package.json +3 -6
  12. package/typings/src/analyzers/scope-analyzer/ScopeAnalyzer.d.ts +3 -0
  13. package/typings/src/enums/node-transformers/preparing-transformers/obfuscating-guards/ObfuscatingGuard.d.ts +1 -0
  14. package/typings/src/generators/identifier-names-generators/AbstractIdentifierNamesGenerator.d.ts +3 -0
  15. package/typings/src/generators/identifier-names-generators/DictionaryIdentifierNamesGenerator.d.ts +2 -0
  16. package/typings/src/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.d.ts +3 -0
  17. package/typings/src/generators/identifier-names-generators/MangledIdentifierNamesGenerator.d.ts +2 -0
  18. package/typings/src/interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator.d.ts +2 -0
  19. package/typings/src/node/NodeGuards.d.ts +1 -0
  20. package/typings/src/node-transformers/control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer.d.ts +1 -0
  21. package/typings/src/node-transformers/converting-transformers/ClassFieldTransformer.d.ts +1 -1
  22. package/typings/src/node-transformers/converting-transformers/ObjectExpressionKeysTransformer.d.ts +2 -3
  23. package/typings/src/node-transformers/preparing-transformers/obfuscating-guards/ProcessEnvObfuscationGuard.d.ts +8 -0
  24. package/typings/src/utils/EscapeSequenceEncoder.d.ts +1 -0
  25. package/dist/index.browser.js.LICENSE.txt +0 -45
  26. package/dist/index.cli.js.LICENSE.txt +0 -23
  27. package/dist/index.js.LICENSE.txt +0 -23
  28. package/dist/index_debug.js +0 -14907
  29. package/dist/index_debug.js.LICENSE.txt +0 -23
  30. package/dist/index_debug.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  Change Log
2
2
 
3
+ v5.2.1
4
+ ---
5
+ * Fixed `transformObjectKeys` incorrectly hoisting object literal outside of loop when loop body is a single statement without braces, causing all iterations to share the same object reference. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1300
6
+ * Fixed parsing error when `await` is used as an identifier in non-async context. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1127
7
+ * Fixed `deadCodeInjection` causing SyntaxError when `arguments` from collected block statements was injected into class field initializers or static initialization blocks. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1166
8
+ * Fixed `transformObjectKeys` with `mangled` identifier generator causing variable shadowing when extracted object variable name matched an existing inner scope variable. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1232
9
+
10
+ v5.2.0
11
+ ---
12
+ * Skip obfuscation of `process.env.*`
13
+ * Fixed `controlFlowFlattening` breaking short-circuit evaluation with spread operator and conditional objects. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1372
14
+ * Fix Annex B function hoisting: block-scoped function declarations are now correctly linked to references outside the block in non-strict mode
15
+ * Fixed `NodeUtils.cloneRecursive` corrupting `range` property when cloning AST nodes, causing scope analysis to incorrectly resolve destructuring default parameter references
16
+
3
17
  v5.1.0
4
18
  ---
5
19
  * Add `version` parameter to the `apiConfig` to use different versions JavaScript Obfuscator Pro via API
package/CLAUDE.md CHANGED
@@ -5,7 +5,7 @@
5
5
  **JavaScript Obfuscator** is a powerful, enterprise-grade code obfuscation tool for JavaScript and Node.js applications. It transforms readable JavaScript code into a protected, difficult-to-understand format while maintaining full functionality. The project is widely used for protecting intellectual property and preventing reverse engineering.
6
6
 
7
7
  - **Version**: 5.0.0
8
- - **Author**: Timofey Kachalov (@sanex3339)
8
+ - **Author**: Timofei Kachalov (@sanex3339)
9
9
  - **License**: BSD-2-Clause
10
10
  - **Repository**: https://github.com/javascript-obfuscator/javascript-obfuscator
11
11
  - **Homepage**: https://obfuscator.io/
@@ -1429,7 +1429,7 @@ Use [grunt-contrib-obfuscator](https://github.com/javascript-obfuscator/grunt-co
1429
1429
 
1430
1430
  **BSD-2-Clause License**
1431
1431
 
1432
- Copyright (C) 2016-2024 Timofey Kachalov
1432
+ Copyright (C) 2016-2026 Timofei Kachalov
1433
1433
 
1434
1434
  See `LICENSE.BSD` for full license text.
1435
1435
 
@@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
34
34
 
35
35
  ## Enforcement
36
36
 
37
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at sanex3339@yandex.ru. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at support@obfuscator.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38
38
 
39
39
  Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40
40
 
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <!--
2
2
  Title: JavaScript Obfuscator
3
3
  Description: A powerful obfuscator for JavaScript and Node.js.
4
- Author: Timofey Kachalov
4
+ Author: Timofei Kachalov
5
5
  -->
6
6
 
7
7
  #### You can support this project by donating:
@@ -13,10 +13,20 @@ Huge thanks to all supporters!
13
13
 
14
14
  ![logo](https://raw.githubusercontent.com/javascript-obfuscator/javascript-obfuscator/master/images/logo.png)
15
15
 
16
+ ---
17
+
18
+ ### :rocket: JavaScript Obfuscator Pro with VM Obfuscation is out!
19
+
20
+ **JavaScript Obfuscator Pro** features **VM-based bytecode obfuscation** — the most advanced code protection available. Your JavaScript functions are transformed into custom bytecode running on an embedded virtual machine, making reverse engineering extremely difficult.
21
+
22
+ [Try it at obfuscator.io](https://obfuscator.io)
23
+
24
+ ---
25
+
16
26
  JavaScript Obfuscator is a powerful free obfuscator for JavaScript, containing a variety of features which provide protection for your source code.
17
27
 
18
28
  **Key features:**
19
- - VM obfuscation (via [JavaScript Obfuscator Pro](https://obfuscator.io/))
29
+ - VM bytecode obfuscation (via [JavaScript Obfuscator Pro](https://obfuscator.io/))
20
30
  - variables renaming
21
31
  - strings extraction and encryption
22
32
  - dead code injection
@@ -1756,73 +1766,218 @@ The performance will be at a relatively normal level
1756
1766
 
1757
1767
  <!-- ##options-end## -->
1758
1768
 
1759
- ## JavaScript Obfuscator Pro VM options
1769
+ ## JavaScript Obfuscator Pro Options
1770
+
1771
+ > :warning: **The following VM obfuscation/Pro options are available only via the [JavaScript Obfuscator Pro API](https://obfuscator.io/).**
1772
+ >
1773
+ > To use these options, you need a Pro API token from [obfuscator.io](https://obfuscator.io) and must call the `obfuscatePro()` method instead of `obfuscate()`. See the [Pro API Methods](#shield-pro-api-methods-vm-obfuscation) section for details.
1760
1774
 
1761
1775
  ### `vmObfuscation`
1762
1776
  Type: `boolean` Default: `false`
1763
1777
 
1764
1778
  Enables VM-based bytecode obfuscation. When enabled, JavaScript functions are compiled into custom bytecode that runs on an embedded virtual machine. This provides the highest level of protection as the original code logic is completely transformed.
1765
1779
 
1766
- **Warning:** This significantly increases code size and may impact performance. Use `vmObfuscationThreshold` to control which root-level functions are transformed.
1780
+ **Example:**
1781
+ Your readable code like `return qty * price` becomes a list of numbers like `[0x15,0x03,0x17,...]` that only the embedded VM interpreter can execute. The original logic is no longer visible as JavaScript.
1767
1782
 
1768
1783
  ### `vmObfuscationThreshold`
1769
1784
  Type: `number` Default: `1`
1770
1785
 
1771
- The probability (from 0 to 1) that a function will be transformed to VM bytecode when `vmObfuscation` is enabled.
1786
+ Controls what percentage of your root-level functions get VM protection.
1787
+
1788
+ ### `vmPreprocessIdentifiers`
1789
+ Type: `boolean` Default: `true`
1790
+
1791
+ Renames all non-global identifiers to unique hexadecimal names before VM obfuscation. This eliminates variable shadowing that can cause scope resolution issues in the VM bytecode.
1772
1792
 
1773
- - `0` - no functions will be transformed
1774
- - `0.5` - 50% of functions will be transformed
1775
- - `1` - all functions will be transformed
1793
+ **When to disable:** Only disable this if you encounter specific compatibility issues. The preprocessing step ensures correct variable resolution in complex nested scopes.
1776
1794
 
1777
1795
  ### `vmTargetFunctions`
1778
1796
  Type: `string[]` Default: `[]`
1779
1797
 
1780
- Array of root-level function names to target for VM obfuscation. When specified, only these functions will be transformed (subject to `vmObfuscationThreshold`). Empty array means all functions are candidates.
1798
+ Specify exactly which root-level functions should get VM protection by name.
1799
+
1800
+ **Example:**
1801
+ ```javascript
1802
+ {
1803
+ vmObfuscation: true,
1804
+ vmTargetFunctions: ['someFunctionName']
1805
+ }
1806
+ ```
1807
+
1808
+ **Result:** Only these three functions get VM-protected. Everything else stays as regular (but still obfuscated) JavaScript. Perfect for protecting sensitive license checks or authentication logic while keeping the rest of your code lean.
1781
1809
 
1782
1810
  ### `vmExcludeFunctions`
1783
1811
  Type: `string[]` Default: `[]`
1784
1812
 
1785
- Array of root-level function names to exclude from VM obfuscation. These functions will never be transformed regardless of other settings.
1813
+ Specify root-level functions that should never get VM protection. Takes precedence over other settings.
1814
+
1815
+ **Example:**
1816
+ ```javascript
1817
+ {
1818
+ vmObfuscation: true,
1819
+ vmExcludeFunctions: ['someFunctionName']
1820
+ }
1821
+ ```
1822
+
1823
+ **When to use:** Performance-critical root-level functions (animation loops, real-time data processing) can be excluded to avoid VM overhead while still protecting everything else.
1824
+
1825
+ ### `vmTargetFunctionsMode`
1826
+ Type: `string` Default: `root`
1827
+
1828
+ Controls how functions/methods are selected for VM obfuscation.
1829
+
1830
+ | Mode | Description |
1831
+ |------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
1832
+ | `root` | Default behavior. Only root-level functions are considered for VM obfuscation. Uses `vmTargetFunctions` allow-list and `vmExcludeFunctions` deny-list to filter. |
1833
+ | `comment` | Only functions/methods decorated with `/* javascript-obfuscator:vm */` comment are VM-obfuscated. Works with functions/methods at **any nesting level**. |
1834
+
1835
+ **Example - Comment mode:**
1836
+ ```javascript
1837
+ // Source code
1838
+ function regularFunction() {
1839
+ return 'not virtualized';
1840
+ }
1841
+
1842
+ /* javascript-obfuscator:vm */
1843
+ function sensitiveFunction() {
1844
+ return 'this will be VM-protected';
1845
+ }
1846
+
1847
+ function outer() {
1848
+ /* javascript-obfuscator:vm */
1849
+ function nestedSensitive() {
1850
+ return 'nested but still VM-protected';
1851
+ }
1852
+ return nestedSensitive();
1853
+ }
1854
+ ```
1855
+
1856
+ ```javascript
1857
+ // Obfuscator options
1858
+ {
1859
+ vmObfuscation: true,
1860
+ vmTargetFunctionsMode: 'comment'
1861
+ }
1862
+ ```
1863
+
1864
+ **When to use:** When you need surgical control over exactly which functions get VM protection, especially nested functions that contain sensitive logic. Unlike `vmTargetFunctions` which only works with root-level named functions, comment mode lets you protect any function anywhere in your code.
1865
+
1866
+ ### `vmWrapTopLevelInitializers`
1867
+ Type: `boolean` Default: `false`
1868
+
1869
+ Wraps some top-level variable initializers in IIFEs (Immediately Invoked Function Expressions) so they can be VM-obfuscated.
1870
+
1871
+ **What it does:**
1872
+ Without this option, top-level constants and variables remain visible in the output:
1873
+ ```javascript
1874
+ // Input
1875
+ const MY_STRING = "my-string";
1876
+
1877
+ // Output (without vmWrapTopLevelInitializers)
1878
+ const MY_STRING = "my-string"; // String is visible!
1879
+ ```
1880
+
1881
+ With this option enabled, the initializer is wrapped in an IIFE that gets VM-obfuscated:
1882
+ ```javascript
1883
+ // Input
1884
+ const MY_STRING = "my-string";
1885
+
1886
+ // Output (with vmWrapTopLevelInitializers: true)
1887
+ const MY_STRING = (() => { return /* VM bytecode call */ })(); // String hidden in bytecode
1888
+ ```
1889
+
1890
+ **Note:** This option only works when `vmTargetFunctionsMode` is `'root'` (the default).
1891
+
1892
+ ### `vmDynamicOpcodes`
1893
+ Type: `boolean` Default: `false`
1894
+
1895
+ Makes the VM interpreter smaller and unique for each build.
1896
+
1897
+ **What it does:**
1898
+ 1. **Filters unused instructions** - If your code doesn't use classes, class-related instructions are removed entirely
1899
+ 2. **Randomizes structure** - The order of instruction handlers is shuffled each build
1900
+
1901
+ As the result - smaller output and each build looks different.
1786
1902
 
1787
1903
  ### `vmOpcodeShuffle`
1788
1904
  Type: `boolean` Default: `false`
1789
1905
 
1790
- Randomizes the opcode mapping for each obfuscation run. Makes static analysis more difficult as opcode meanings change between builds.
1906
+ Randomizes the numeric values assigned to each opcode. For example, the `LOAD` instruction might be `1` in one build and `47` in another.
1791
1907
 
1792
1908
  ### `vmBytecodeEncoding`
1793
1909
  Type: `boolean` Default: `false`
1794
1910
 
1795
- Encodes the bytecode instructions using XOR encryption. The decoding key is derived at runtime, adding another layer of protection.
1911
+ Encodes each bytecode instruction. Instructions are decoded one at a time during execution.
1796
1912
 
1797
1913
  ### `vmBytecodeArrayEncoding`
1798
1914
  Type: `boolean` Default: `false`
1799
1915
 
1800
- Applies additional encoding to the bytecode array, making it harder to identify bytecode patterns through static analysis.
1916
+ Encodes the entire bytecode array as a single block. The array is decoded once at startup before execution begins. Use together with `vmBytecodeEncoding` for two layers of protection.
1801
1917
 
1802
1918
  ### `vmJumpsEncoding`
1803
1919
  Type: `boolean` Default: `false`
1804
1920
 
1805
- Encodes jump targets and offsets in the bytecode. This obscures control flow and makes it harder to follow program execution.
1921
+ Encodes jump targets in the bytecode. Jump offsets are calculated at runtime, hiding the control flow structure (`if`/`else`, loops, etc.) from static analysis.
1806
1922
 
1807
1923
  ### `vmDecoyOpcodes`
1808
1924
  Type: `boolean` Default: `false`
1809
1925
 
1810
- Inserts fake opcodes into the dispatcher that are never executed. Increases code complexity and confuses reverse engineering attempts.
1926
+ Adds fake opcode handlers to the VM dispatcher that are never called. For example, if the VM uses 20 real opcodes, this might add 30 fake handlers, making the interpreter appear more complex than it really is.
1811
1927
 
1812
1928
  ### `vmDeadCodeInjection`
1813
1929
  Type: `boolean` Default: `false`
1814
1930
 
1815
- Injects dead code sequences into the VM bytecode. These sequences are valid but unreachable, adding noise to analysis.
1931
+ Injects fake bytecode sequences that are never executed. These look like real instructions but are skipped during runtime, confusing analysis tools that process them.
1816
1932
 
1817
1933
  ### `vmSplitDispatcher`
1818
1934
  Type: `boolean` Default: `false`
1819
1935
 
1820
- Splits the VM dispatcher into multiple smaller dispatchers. Makes the execution flow harder to follow.
1936
+ Splits the VM dispatcher into multiple smaller switch statements organized by opcode category, instead of one large monolithic switch. Each category (stack, arithmetic, control flow, etc.) gets its own switch, routed by if/else range checks.
1937
+
1938
+ This option supports `vmDynamicOpcodes` in both modes: `true` (shuffle first, then split into groups) and `false`.
1939
+
1940
+ > :warning: When `vmIndirectDispatch` is enabled, this option is ignored. Prefer `vmIndirectDispatch` as it provides better obfuscation with similar performance.
1941
+
1942
+ ### `vmIndirectDispatch`
1943
+ Type: `boolean` Default: `false`
1944
+
1945
+ Uses compile-time generated handler functions for opcode dispatch instead of switch statements. Handlers are generated at compile-time with inlined opcode logic and shuffled positions.
1946
+
1947
+ Instead of:
1948
+ ```javascript
1949
+ switch(op) {
1950
+ case 0: /* handle opcode 0 */ break;
1951
+ case 1: /* handle opcode 1 */ break;
1952
+ }
1953
+ ```
1954
+
1955
+ It generates:
1956
+ ```javascript
1957
+ var _hm = {0:42, 1:17, ...}; // opcode → handler index mapping
1958
+ var _h = [handler0, handler1, ...]; // shuffled handler array
1959
+ _h[_hm[op]](arg); // single lookup + function call
1960
+ ```
1961
+
1962
+ This option supports `vmDynamicOpcodes` in both modes.
1963
+
1964
+ > :warning: When enabled, this takes priority over `vmSplitDispatcher`. Both options cannot be active simultaneously.
1965
+
1966
+ ### `vmCompactDispatcher`
1967
+ Type: `boolean` Default: `false`
1968
+
1969
+ Uses a single unified dispatcher (generator-based) for both sync and async/generator code execution. By default (`false`), the VM generates two separate dispatchers: a non-generator version for sync code (faster) and a generator version for async/generator code. When enabled, only the generator-based dispatcher is used for all execution.
1970
+
1971
+ **Trade-offs:**
1972
+ - `false` (default): Larger code size due to dual dispatchers, but faster sync execution (no generator overhead)
1973
+ - `true`: Smaller code size with single dispatcher, but sync code has generator protocol overhead
1974
+
1975
+ Use this when code size is more important than sync execution speed.
1821
1976
 
1822
1977
  ### `vmMacroOps`
1823
1978
  Type: `boolean` Default: `false`
1824
1979
 
1825
- Combines common instruction sequences into single macro opcodes. This creates unique instruction patterns that are harder to recognize.
1980
+ Combines common instruction sequences into single "macro" opcodes. For example, `LOAD + ADD + STORE` might become a single `MACRO_ADD_TO_VAR` instruction. This breaks pattern recognition and can improve performance.
1826
1981
 
1827
1982
  ### `vmDebugProtection`
1828
1983
  Type: `boolean` Default: `false`
@@ -1832,34 +1987,43 @@ Adds anti-debugging measures to the VM runtime. Detects debugger presence and al
1832
1987
  ### `vmRuntimeOpcodeDerivation`
1833
1988
  Type: `boolean` Default: `false`
1834
1989
 
1835
- Derives opcode values at runtime through mathematical operations rather than using static values. Makes static analysis significantly harder.
1990
+ Derives the opcode mapping table at runtime from a seed value instead of hardcoding it. The seed is stored in the bytecode and used to generate the opcode-to-handler mapping via Fisher-Yates shuffle during execution.
1836
1991
 
1837
1992
  ### `vmStatefulOpcodes`
1838
1993
  Type: `boolean` Default: `false`
1839
1994
 
1840
- Makes opcode interpretation depend on VM state. The same opcode can have different meanings based on execution history.
1995
+ Makes opcode meanings depend on position in the bytecode. Each position has a different opcode-to-handler mapping derived from a seed, so the same opcode number performs different operations at different positions.
1841
1996
 
1842
1997
  ### `vmStackEncoding`
1843
1998
  Type: `boolean` Default: `false`
1844
1999
 
1845
- Encodes values pushed to and popped from the VM stack. Adds protection against memory inspection during execution.
1846
-
1847
- ### `vmRandomizeKeys`
1848
- Type: `boolean` Default: `false`
2000
+ Encrypts values on the VM stack during execution. Values are encoded when pushed and decoded when popped, so memory inspection shows encrypted data instead of actual values.
1849
2001
 
1850
- Randomizes encryption keys and other constants used by the VM. Each build produces unique key values.
2002
+ This option heavily affects performance.
1851
2003
 
1852
- ### `vmIndirectDispatch`
2004
+ ### `vmRandomizeKeys`
1853
2005
  Type: `boolean` Default: `false`
1854
2006
 
1855
- Uses indirect function calls for opcode dispatch instead of direct switch/case. Makes control flow analysis more difficult.
2007
+ Randomizes the property key names used in bytecode objects. Standard keys like `i` (instructions), `c` (constants) become random 2-character identifiers, making the bytecode structure different for each build.
1856
2008
 
1857
2009
  ### `vmBytecodeFormat`
1858
2010
  Type: `string` Default: `binary`
1859
2011
 
1860
- Specifies the format used to embed bytecode in the output:
1861
- - `binary` - Compact binary representation (smaller size)
1862
- - `json` - JSON format (easier debugging, larger size)
2012
+ Controls how bytecode is stored in the output.
2013
+
2014
+ **Options:**
2015
+ - `binary` - Compact binary format. Smaller size, recommended for production.
2016
+ - `json` - Human-readable JSON format. Larger size, useful for debugging.
2017
+
2018
+ ### `strictMode`
2019
+ Type: `boolean | null` Default: `null`
2020
+
2021
+ Allows to specify how the obfuscator should treat code regarding JavaScript strict mode.
2022
+
2023
+ Available values:
2024
+ * `null` (default) - auto-detect strict mode from the code. If the code has explicit `'use strict'` directive, ES module syntax, or class methods, it's treated as strict mode. Otherwise, sloppy mode is assumed.
2025
+ * `true` - force strict mode treatment for all code, even without explicit `'use strict'` directive. Use this when your code will run in strict mode context (e.g., in ES modules, bundlers, or modern frameworks).
2026
+ * `false` - only explicit strict mode indicators (`'use strict'`, ES modules, class methods) are treated as strict. Parent scope inheritance still applies per JS spec.
1863
2027
 
1864
2028
  ## Frequently Asked Questions
1865
2029
 
@@ -1954,7 +2118,7 @@ Become a sponsor and get your logo on our README on Github with a link to your s
1954
2118
  ## License
1955
2119
  [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjavascript-obfuscator%2Fjavascript-obfuscator.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjavascript-obfuscator%2Fjavascript-obfuscator?ref=badge_large)
1956
2120
 
1957
- Copyright (C) 2016-2024 [Timofey Kachalov](http://github.com/sanex3339).
2121
+ Copyright (C) 2016-2026 [Timofei Kachalov](http://github.com/sanex3339).
1958
2122
 
1959
2123
  Redistribution and use in source and binary forms, with or without
1960
2124
  modification, are permitted provided that the following conditions are met: