diff --git a/index.html b/index.html
index ab42131..05c58c0 100644
--- a/index.html
+++ b/index.html
@@ -85,6 +85,13 @@
>
Tokenizer
+
@@ -389,6 +396,54 @@
+
+
+
diff --git a/js/app.js b/js/app.js
index f4f6779..ee1273f 100644
--- a/js/app.js
+++ b/js/app.js
@@ -82,6 +82,19 @@ window.app = new Vue({
tokenizerCharCount: 0,
tokenizerWordCount: 0,
+ // Fuzzer
+ fuzzerInput: '',
+ fuzzerCount: 20,
+ fuzzerSeed: '',
+ fuzzUseRandomMix: true,
+ fuzzZeroWidth: true,
+ fuzzUnicodeNoise: true,
+ fuzzZalgo: false,
+ fuzzWhitespace: true,
+ fuzzCasing: true,
+ fuzzEncodeShuffle: false,
+ fuzzerOutputs: [],
+
// History of copied content
copyHistory: [],
maxHistoryItems: 10,
@@ -1702,6 +1715,74 @@ window.app = new Vue({
});
}
,
+ // -------- Fuzzer --------
+ seededRandomFactory(seedStr) {
+ if (!seedStr) return Math.random;
+ let h = 1779033703 ^ seedStr.length;
+ for (let i=0;i>> 19);
+ }
+ return function() {
+ h ^= h >>> 16; h = Math.imul(h, 2246822507); h ^= h >>> 13; h = Math.imul(h, 3266489909); h ^= h >>> 16;
+ return (h >>> 0) / 4294967296;
+ };
+ },
+ pick(arr, rnd) { return arr[Math.floor(rnd()*arr.length)]; },
+ injectZeroWidth(text, rnd) {
+ const zw = ['\u200B','\u200C','\u200D','\u2060'];
+ return [...text].map(ch => (rnd()<0.2 ? ch+this.pick(zw,rnd) : ch)).join('');
+ },
+ injectUnicodeNoise(text, rnd) {
+ const marks = ['\u0301','\u0300','\u0302','\u0303','\u0308','\u0307','\u0304'];
+ return [...text].map(ch => (rnd()<0.15 ? ch+this.pick(marks,rnd) : ch)).join('');
+ },
+ whitespaceChaos(text, rnd) {
+ return text.replace(/\s/g, (m)=> (rnd()<0.5? m : (rnd()<0.5?'\t':'\u00A0')));
+ },
+ casingChaos(text, rnd) {
+ return [...text].map(c => /[a-z]/i.test(c)? (rnd()<0.5? c.toUpperCase():c.toLowerCase()) : c).join('');
+ },
+ encodeShuffle(text, rnd) {
+ const opts = ['base64','base32','hex','base58','base62','url'];
+ const t = this.pick(opts, rnd);
+ const tx = {
+ base64: ()=> window.transforms.base64.func(text),
+ base32: ()=> window.transforms.base32.func(text),
+ hex: ()=> window.transforms.hex.func(text),
+ base58: ()=> window.transforms.base58.func(text),
+ base62: ()=> window.transforms.base62.func(text),
+ url: ()=> window.transforms.url.func(text)
+ };
+ return (tx[t]||(()=>text))();
+ },
+ generateFuzzCases() {
+ const src = String(this.fuzzerInput || '');
+ if (!src) { this.fuzzerOutputs = []; return; }
+ const rnd = this.seededRandomFactory(String(this.fuzzerSeed||''));
+ const out = [];
+ for (let i=0;iURL.revokeObjectURL(url), 200);
+ },
// Quick estimate of token count for Tokenade
estimateTokenadeTokens() {
// Roughly approximate tokens by estimated character length