/*
** ZLIB JavaScript Function Library.
** Written by Zsolt Nagy-Perge in Pensacola, Fla.
** December 2019 Edition
**
*******************************************************/
// STOP! THIS IS NOT A STANDALONE PROGRAM.
if (typeof(document)=="undefined") { try { WScript.Sleep(200); WScript.Echo("This is not a standalone program.\nThis script must be included in a HTML file.\n\nZLIB JavaScript Function Library.\nWritten by Zsolt Nagy-Perge in Pensacola, Fla.\nDecember 2019 Edition"); WScript.Quit(); } catch (e) {} }
// PREVENT PAGE HIJAKING
if (top.location != self.location) top.location = self.location;
// CREATE SLIDE AND PIX IMAGE PAGE COUNTER
document.write("
");
// GET JAVASCRIPT ARGUMENTS
ARGJ = ""; Z = "zlib.js?"; i = document.scripts.length;
while (i--) { S = document.scripts[i].src; P = S.indexOf(Z); if (P >= 0) { ARGJ = S.slice(P + Z.length + 1); break; } }
// ARE WE ONLINE?
ONLINE = (location.protocol.toUpperCase().indexOf("HTTP") < 0) ? 0 : 1;
// DETECT MOBILE DEVICE
PF = navigator.platform.toUpperCase();
UA = navigator.userAgent.toUpperCase();
MOBILE = ((UA + PF).match(/PHONE|MOBILE|TABLET|IPOD|IPAD|BLACKBERRY|LUMIA|ANDROID|WEBOS|PLAYBOOK|BB10|MINI|CRMO|OPERA MINI|OPERA MOBI|PALM|WINDOWS CE|XOOM|SCH-I800|KINDLE/i) == null) ? 0 : 1;
// DETECT SCREEN SIZE & ORIENTATION
LANDSCAPE = 1;
WX = screen.width;
HX = screen.height;
if (HX > WX) { WX = HX; HX = screen.width; LANDSCAPE = 0; }
SCREEN = 1;
if (WX >= 1200) SCREEN = 4;
else if (WX >= 800) SCREEN = 3;
else if (WX >= 300) SCREEN = 2;
// This function converts fixed size to relative size depending on current screen resolution.
function SIZE(N) { return Math.round(WX * N / 500); }
// ARRAY FUNCTIONS
// This function returns the last element of array A without modifying the array.
function Last(A) { return A[A.length - 1]; }
// This function returns a new array full of zeros. A second argument may be provided to initialize the array with something other than zeros.
function InitArray(SIZE) { var i, A = new Array(SIZE), InitValue = (arguments.length > 1) ? arguments[1] : 0; for (i = 0; i < SIZE; i++) A[i] = InitValue; return A; }
// This function returns the length of the longest string in an array.
function LongestWordIn(A) { var L = 0, X, i = A.length; while(i--) { X = (A[i]).toString().length; if (X > L) L = X; } return L; }
// This function returns the length of the shortest string in an array.
function ShortestWordIn(A) { var L = 0x7FFFFFFF, X, i = A.length; while(i--) { X = (A[i]).toString().length; if (L > X) L = X; } return L; }
// This function copies elements of array B into array A without creating more duplicates. This function runs a case-sensitive search and does not sort the contents of either arrays.
function MergeArray(A, B) { var i, j, N = 0; for (i = 0; i < B.length; i++) { for (j = 0; j < A.length; j++) if (A[j] == B[i]) { j = -1; break; } if (j >= 0) { A.push(B[i]); N++; } } return N; }
// This function returns part of an array and reduces the length of the original array. It works just like the slice() method on strings, but this operates on arrays only. This function will change the size of array A.
function ArraySlice(A, X) { var R = []; if (X < 0) X += A.length; if (X < 0 || X > A.length) return R; for (var i = X; i < A.length; i++) R.push(A[i]); A.length = X; return R; }
//////////////////////////////////////////////////
// v2019.12.27
// This function splits string S into N-byte sized
// chunks and returns an array. If a third argument
// is given, it will use as padding. The padding must
// be either one byte or two bytes. If it is one byte,
// it will be added in front of the last group.
// If it is two bytes, the second byte will be added
// at the end of the last group.
// Usage: ARRAY = Group(STRING, LENGTH, [PADDING])
// Example: Group('abcd', 3) -> ['abc', 'd']
// Group('abcd', 3, '-') -> ['abc', '--d']
// Group('abcd', 3, ' -') -> ['abc', 'd--']
//
function Group(S, N, PADDING)
{
var i, j = -1, A = [];
if (S.length == 0) return A;
for (i = 0; i < S.length; i += N)
A[++j] = S.substr(i, N);
if (typeof(PADDING) === "string")
{
if (PADDING.length == 1)
while (A[j].length < N)
A[j] = "" + PADDING + A[j];
if (PADDING.length == 2)
while (A[j].length < N)
A[j] += "" + PADDING.charAt(1);
}
return A;
}
//////////////////////////////////////////////////
// This function converts a string to an array of ASCII character codes.
function charCodeArray(S) { var i, A = []; for (i = 0; i < S.length; i++) A[i] = S.charCodeAt(i); return A; }
// This function assembles a string from an array of ASCII character codes. It's the opposite of charCodeArray() with one important difference: 16-bit and 32-bit numbers are converted into multiple bytes. For example, 0x20 becomes a space character. But 0x4020 becomes a "@" followed by a space character! And 0x41424344 becomes a string "ABCD". Now, this function won't know the size of the desired output if the input array holds just one zero. It can't tell whether that stands for 2 zero bytes or just one or four, because there's no difference between 0x00 and 0x0000. So, in that case, it will assume that Zero stands for just one byte. For example, this works: STRING = fromCharCodeArray( [0x33, 0x00414243, 0x204748, 0x20, 0x49] ); -- zero character becomes omitted.
function fromCharCodeArray(ARRAY) { var i, N, S = []; for (i = 0; i < ARRAY.length; i++) { N = ARRAY[i]; if (N <= 0xff) S[i] = String.fromCharCode(N); else if (N <= 0xffff) S[i] = String.fromCharCode((N>> 8) & 0xff) + "" + String.fromCharCode(N & 0xff); else if (N <= 0xffffff) S[i] = String.fromCharCode((N >> 16) & 0xff) + "" + String.fromCharCode((N >> 8) & 0xff) + "" + String.fromCharCode(N & 0xff); else S[i] = String.fromCharCode((N >> 24) & 0xff) + "" + String.fromCharCode((N >> 16) & 0xff) + "" + String.fromCharCode((N >> 8) & 0xff) + "" + String.fromCharCode(N & 0xff); } return S.join(""); }
// This function trims each element of array A and removes empty strings elements. This function shortens the original array.
function RemoveBlank(A) { var L, i, j = 0; for (i = 0; i < A.length; i++) { L = Trim(A[i]); if (L.length) { if (j < i) A[j] = L; j++; } } A.length = j; }
// This function sorts array A and removes duplicate elements.
function RemoveDuplicates(A) { var i, P = ""; A.sort(); for (i = 0; i < A.length; i++) if (A[i] == P) { P = A[i]; A[i] = ""; } else P = A[i]; RemoveBlank(A); }
// This function removes duplicate items from an array and returns a new array containing the items that have been removed. The scan is case sensitive. This function also sorts the array.
//function ExtractDuplicates(A) { if (A.length < 2) return 0; A.sort(); var i = 0, j = 1, D = []; while (j < A.length) { if (A[i] == A[j]) { A.splice(j, 1); D.push(A[i]); } else { i++; j++; } } return D; }
// This function extracts elements of small array B from big array A. This function reduces the size of array A.
function ExtractFrom(A, B) { var i, j; for (i = 0; i < A.length; i++) for (j = 0; j < B.length; j++) if (A[i] == B[j]) { A[i] = ""; break; } }
// This function looks for string S in array A and returns the index where it is found. The scan is non-case sensitive.
function FindInArray(S, A) { S = S.toUpperCase(); for (var i = 0; i < A.length; i++) if (A[i].toUpperCase().indexOf(S) >= 0) return i; return -1; }
// This function returns the first matching index
// where A[index] is an exact match with string S.
// LookUp() is case-sensitive: will treat upper/lower case letters differently
// LOOKUP() is non-case-sensitive: will match upper/lower case letters
function LookUp(S, A) { S = S + ""; for (var i = 0; i < A.length; i++) if (S == A[i]) return i; return -1; }
function LOOKUP(S, A) { S = S.toUpperCase(); for (var i = 0; i < A.length; i++) if (S == A[i].toUpperCase()) return i; return -1; }
// This function swaps two elements of array A.
function Swap(A, x, y) { var T = A[x]; A[x] = A[y]; A[y] = T; }
// This function is designed to sort a two-dimensional array. ROW tells which row to sort by. This function rearranges the contents of ARRAY.
function SortBy(ARRAY, ROW) { function COMPARE(A, B) { if (isNaN(A[ROW]) || isNaN(B[ROW])) { if (A[ROW] > B[ROW]) return 1; if (A[ROW] < B[ROW]) return -1; return 0; } return A[ROW] - B[ROW]; } ARRAY = ARRAY.sort(COMPARE); }
// QSort algorithm written in JavaScript. I took this code from a QBasic program written by Ethan Winer and translated it to JavaScript. In Chrome and Safari, qsort runs 2X faster than the builtin sort() method. In KMeleon, qsort is 8X faster! The only browsers where qsort is actually slower is QupZilla and Internet Explorer. In QupZilla, the difference is barely noticeable, however in IE6, the old sort() method is 6X faster. Most people, however, don't use IE6 anymore, so I think, we can ignore that. Example : SortArrays(AGE, NAME, HEIGHT, SCORE) would rearrange all four arrays by age.
function SortArrays(A) { var i, j, k, m, x, Q = [], First = 0, Last = A.length - 1; for (;;) { do { m = A[((First+Last)/2)|0]; i = First; j = Last; do { while (A[i] < m) i++; while (A[j] > m) j--; if (i > j) break; if (i < j) { for (k = 0; k < arguments.length; k++) { x = arguments[k][i]; arguments[k][i] = arguments[k][j]; arguments[k][j] = x; } } i++; j--; } while (i <= j); if (i < Last) { Q.push(i); Q.push(Last); } Last = j; } while (First < Last); if (Q.length == 0) break; Last = Q.pop(); First = Q.pop(); } }
// CONVERTERS
_ = "";
HEX = "0123456789ABCDEF".split("");
B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/+';
BIN4 = "0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111".split(" ");
// Converts a decimal number to hexadecimal format. Limit: 0 to 255
function toHex(D) { D = Math.round(D); if (isNaN(D) || D < 1) return "00"; if (D > 254) return "ff"; return (D < 16 ? "0" : "") + D.toString(16); }
// Converts a decimal number to hexadecimal format. Limit: 0 to 65536
function toHexWord(N) { if (N > 65534) return "ffff"; var Z = "0000"; if (N < 1) return Z; N = N.toString(16); return Z.substr(0, 4 - N.length) + N; }
// This function converts a 32-bit signed integer to 8-digit hex format.
function toHexLong(N) { N |= 0; var i, X = ""; for (i = 0; i < 32; i += 4) X = "0123456789ABCDEF".charAt((N >> i) & 15) + X; return X; }
// Converts a binary string to a number. Limit: 0xFFFFFFFF
function Bin2Int(B) { var i = B.length, V = 0, N = 1; while (i-- > 0) { V += ((B.charAt(i) == "1") ? N : 0); if (N >= 0x80000000) break; N += N; } return V; }
// Converts a binary string to hex string. No limit.
// This function arranges binary digits into groups of eight
// before converting them. If the last group doesn't have
// eight digits, zeros are added to the end.
function Bin2Hex(B) { var c, i = 0, V = 0, N = 8, X = []; while (i < B.length) { c = B.charCodeAt(i++) & 255; if (c < 48 || c > 49) continue; if (c == 49) V += N; if (N > 1) N >>= 1; else { X.push(HEX[V]); V = 0; N = 8; } } if (N < 8) X.push(HEX[V]); if (X.length & 1) X.push("0"); return X.join(""); }
//////////////////////////////////////////////////
// v2019.12.27
// Converts a long integer to a binary string.
// A number may be provided as a second argument
// to get a custom-length binary string of N digits.
// Usage: STRING = toBin(INTEGER, [LENGTH])
//
function toBin(LONG)
{
var OUTPUT = [],
i = (arguments.length > 1) ? arguments[1] : 32,
MASK = [
1, 2, 4, 8, 0x10, 0x20,
0x40, 0x80, 0x100, 0x200,
0x400, 0x800, 0x1000, 0x2000,
0x4000, 0x8000, 0x10000, 0x20000,
0x40000, 0x80000, 0x100000, 0x200000,
0x400000, 0x800000, 0x1000000, 0x2000000,
0x4000000, 0x8000000, 0x10000000, 0x20000000,
0x40000000, 0x80000000];
while (i--)
OUTPUT.push((LONG & MASK[i]) ? "1" : "0");
return OUTPUT.join("");
}
//////////////////////////////////////////////////
// v2019.12.27
// Converts a series of binary numbers to a raw string.
// Usage: STRING = Bin2Str(STRING)
//
function Bin2Str(B)
{
B = Group(B, 8, ".0");
for (var i = 0; i < B.length; i++)
B[i] = String.fromCharCode(parseInt(B[i], 2));
return B.join("");
}
//////////////////////////////////////////////////
// v2019.12.27
// Converts a raw string to series of binary numbers.
// Usage: STRING = Str2Bin(STRING)
//
function Str2Bin(S)
{
var i = 0, C, OUTPUT = [];
for (; i < S.length; i++)
{
C = S.charCodeAt(i).toString(2);
OUTPUT[i] = "00000000".slice(C.length) + C;
}
return OUTPUT.join("");
}
//////////////////////////////////////////////////
// Converts string S to a series of hex numbers. Faster than toString(16)
function Str2Hex(S) { var c, i, x = []; for(i = 0; i < S.length; i++) { c = S.charCodeAt(i) & 255; x.push(HEX[c >> 4] + HEX[c & 15]); } return x.join(_); }
// Converts a hex string to binary string. No Limit!
function Hex2Bin(X) { var i, c, B = []; for (i = 0; i < X.length; i++) { c = X.charCodeAt(i); if (c < 48 || c > 102) continue; c |= 32; if (c > 96) c -= 87; else c -= 48; B.push(BIN4[c]); } return B.join(""); }
// Converts a series of hexadecimal numbers to a raw string.
function Hex2Str(X) { var i, $ = []; X += ""; for (i = 0; i < X.length; i += 2) $.push(String.fromCharCode(parseInt(X.substr(i, 2), 16))); return $.join(""); }
// Converts a hexadecimal string to a number.
function Hex2Int(H) { if (H.length < 8) return parseInt(H, 16); H = H.toUpperCase(); var C, D = 0, S = 1, i = H.length; while (i--) { C = "0123456789ABCDEF".indexOf(H.charAt(i)); if (C < 0) return D; else { if (C) D += C * S; S *= 16; } } return D; }
//function Hex2Int(X) { return parseInt(X, 16); }
// Converts a large positive integer to a 14-byte hex string. Valid range: 0 to 9,007,199,254,740,992
function Int2Hex(N) { if (typeof(N)==="undefined") return "0"; if (isNaN(N)) return "0"; if (N < 1) return "0"; N = Math.floor(N); if (N <= 4294967295) return N.toString(16); if (N > 9007199254740991) return "20000000000000"; var LOW = (N & 0x0FFFFFFF).toString(16); if (LOW.length < 7) LOW = "0000000".slice(LOW.length) + LOW; return (Math.floor(N/268435456) & 0x0FFFFFFF).toString(16) + "" + LOW; }
// Encodes a binary string to Base64 string
function EncodeB64(S) { var i, j, k = -4, SHIFT = 6, $ = []; for (i = j = 0; i < S.length; i++, j++) { if (SHIFT > 5) { SHIFT = 0; k += 4; $[k] = 0; j++; } SHIFT += 2; $[j] = S.charCodeAt(i); $[k] += ($[j] & 0xC0) >> SHIFT; $[j] = $[j] & 63; } while (--j >= 0) $[j] = String.fromCharCode($[j] + 63); return $.join(""); }
// Decodes a Base64 string to binary string
function DecodeB64(S) { var i, c, H, $ = []; for (i = 0; i < S.length; i++) { c = S.charCodeAt(i) - 63; c = (c < 0) ? 0 : c & 63; if (i % 4) { H <<= 2; $.push(String.fromCharCode(c + (H & 0xC0))); } else H = c; } return $.join(""); }
// Converts an integer to Base64 character(s).
function Int2B64(N) { var B = []; do { B.push(B64.charAt(N & 63)); N >>>= 6; } while (N > 0); return B.reverse().join(""); }
// This function converts a 2-byte string (big endian) to an unsigned int.
function StrInt(S) {return S.charCodeAt(0)<<8|S.charCodeAt(1);}
// This function converts an integer to a 2-byte string (big endian format).
function IntStr(N) {return String.fromCharCode(N>>>8&255)+String.fromCharCode(N&255);}
// This function converts a 4-byte string (big endian) to a long int.
function StrLong(S) {return S.charCodeAt(0)<<24|S.charCodeAt(1)<<16|S.charCodeAt(2)<<8|S.charCodeAt(3);}
// This function converts a 32-bit long to a 4-byte string (big endian format).
function LongStr(N) {return String.fromCharCode(N>>>24&255)+String.fromCharCode(N>>>16&255)+String.fromCharCode(N>>>8&255)+String.fromCharCode(N&255);}
// This function converts a positive integer N to any base using digits listed in string S.
function Num2Set(N, S) {var Z=S.charAt(0);if(typeof(N)==="undefined")return Z;if(isNaN(N))return Z;if(N<1)return Z;N=Math.floor(N);if(N==1)return S.charAt(1);if(N>9007199254740991)N=9007199254740992;var L=S.length;var $=[];while(N>1){C=N%L;$.push(S.charAt(C));N=Math.floor((N-C)/L);}if(N)$.push(S.charAt(N));return $.reverse().join("");}
// This function converts string N from any base to a positive integer. Digit set must be provided in string S.
function Set2Num(N, S) {var D,PWR=1,X=0,i=N.length,L=S.length;while(i--){D=S.indexOf(N.charAt(i));if(D<0)return X;else{if(D)X+=D*PWR;PWR*=L;}}return X;}
// NOTE: The Array2Double() and Double2Array() functions
// will work with Chrome 7, Firefox 4, MSIE10, Edge,
// Safari 5.1, Vivaldi 1, QupZilla 1.8.6, KMeleon 7.5.
// They won't work in Opera 7.54, IE6, and KMeleon 1.5.4.
// To use these functions in older web browsers, try
// using _Float2Array() and _Array2Float() instead.
// This function converts an array of 8 integers between 0-255 to a native JavaScript number (IEEE-754 double format). The input array must have at least 8 elements!!!
function Array2Double(A) { var F = new ArrayBuffer(8); var B = new Uint8Array(F); var N = new Float64Array(F); for (var i = 0; i < 8; i++) B[i] = A[i]; return N[0]; }
// This function converts a JavaScript number to an array of 8 integers between 0-255.
function Double2Array(V) { var F = new ArrayBuffer(8); var B = new Uint8Array(F); var N = new Float64Array(F); N[0] = V; var i, A = []; for (i = 0; i < 8; i++) A[i] = B[i]; return A; }
// This function converts an array of 8 numbers (0-255) to a limited JavaScript float. Note: This function will not work with all double-precision numbers. It will only work when there's no exponent. Use _SmallFloat() to make sure it will work.
function _Array2Float(A) { var N = 0, M = 1, i = 7; while (i) { N += A[i--] * M; M *= 256; } if ((M = A[0] & 127)) { N = "0000000000" + N; N = N.substr(0, N.length - M) + "." + N.substr(N.length - M); } return N * (A[0] & 128 ? -1 : 1); }
// This function converts a JavaScript float number to an array of 8 numbers (0-255). Note: This function will not work with all double-precision numbers. It will only work when there's no exponent. Use _SmallFloat() to make sure it will work.
function _Float2Array(V) { var i = 7, A = [0]; if (V < 0) { A[0] = 128; V = -V; } V = (V+".").split("."); A[0] |= V.length > 2 ? V[1].length : 0; V = V.join(""); while (i) { A[i--] = V & 255; V = Math.floor(V / 256); } return A; }
// This function reduces the size of a double-precision JavaScript number to a safe float that only has 15 significant digits and no exponent.
function _SmallFloat(N) { var S = (N < 0) ? -1 : 1; N += ""; if (S < 0) N = N.slice(1); N = N.split("."); var L = N[0].length; if (L > 15) N[0] = N[0].substr(0, 15); else if (L + N[1].length > 15) N[1] = N[1].substr(0, 15 - L); return S * N.join(".").toUpperCase().split("E")[0]; }
// FAST STRING MANIPULATION
// Note: Prototypes take up to 4-5 times longer to execute
// vs. plain functions. So, these are all plain functions.
// Returns the last N bytes of a string.
function sliceLast(S, N) {if(S.length==0)return"";if(typeof(N)=="undefined")return"";if(N<1)return"";if(N>=S.length)return S;return S.substr(S.length-N,N);}
// This function repeats a string N number of times.
function Repeat(S, N) { return (new Array(N+1)).join(S); }
// This function overwrites a part of string S with character C at byte position X and returns a new string. Example: vec("ABCDEF", 2, 42) --> "AB*DEF"
//function vec(S, X, C) { X |= 0; S += ""; if (X < 0) return S; C = String.fromCharCode(C & 255); if (X == 0) return C + S.slice(1); if (X < S.length) return S.substr(0, X) + "" + C + S.slice(X+1); while (S.length < X) S += " "; return S + "" + C; }
// This function overwrites the input string with one character and returns a new string.
function vec(STRING, INDEX, CHARCODE)
{
if (typeof(STRING) === "undefined") return "";
if (STRING == null) return "";
STRING += "";
if (typeof(INDEX) === "undefined") return STRING;
if (typeof(CHARCODE) === "undefined") return STRING;
var C = String.fromCharCode(CHARCODE & 255);
INDEX |= 0;
if (INDEX < 0) return STRING;
if (INDEX == 0) return C + STRING.slice(1);
if (INDEX == STRING.length) return STRING + C;
if (INDEX < STRING.length) return STRING.substr(0, INDEX) + C + STRING.slice(INDEX+1);
if (STRING.length == 0) return (new Array(INDEX+1)).join(" ") + C;
return STRING + (new Array(INDEX - STRING.length+1)).join(" ") + C;
}
// Adds padding characters C to string S on the left. Returns a string that is exactly L bytes long.
function _LEFT(S, C, L) {S=S.toString();if(S.length>L)return S.slice(S.length-L);while(S.lengthL)return S.slice(S.length-L);while(S.length 32) { if (i < 0) i = x; j = x + 1; } return T.slice(i, j); }
// This function removes whitespace from the left and returns a new string.
function LTRIM$(T) { T += ""; var i = 0; while (T.charCodeAt(i) < 33) i++; return T.slice(i); }
// This function removes whitespace from the right and returns a new string.
function RTRIM$(T) { T += ""; var i = T.length; while (T.charCodeAt(--i) < 33); return T.substr(0, i+1); }
// Converts all adjacent whitespace characters to a single space.
function CollapseWhitespace(S) { S = S.split(""); var i, x, c = 0; for (i = 0; i < S.length; i++) { x = c; c = S[i].charCodeAt(0); if (c < 14) c = 32; if (c == 32) S[i] = (x == 32) ? "" : " "; } return S.join(""); }
// This function trims text T and removes excess characters from the end and adds "..."
function Truncate(T, MAXLEN) { T = Trim(T); if (T.length <= MAXLEN) return T; return T.substr(0, MAXLEN - 3) + "..."; }
// This function removes all characters found in string L from string S and returns what's left of string S.
function RemoveChars(S, L) { var i, c; for (i = 0; i < L.length; i++) { c = L.charAt(i); S = S.split(c).join(""); } return S; }
// This function calculates a revolver index for strings. A revolver index means it wraps around. For example, if the string is 5 bytes long and you want to grab byte 7, then the index wraps around, so you'll get byte 2. This function returns 2. And if you want to grab the last byte of the string, you simply reach for -1 and this function will return the index to the last byte of string.
function rvx(INDEX, LEN) { INDEX %= LEN; if (INDEX < 0) INDEX += LEN; return INDEX; }
// This function returns a character from string S using revolver index X.
function CharAt(S, X) { return S.charAt(rvx(X, S.length)); }
// This function returns a character at position X. If X is longer than the length of string, it wraps around. If X is a negative index, it will start counting from the end of string S.
function CharCodeAt(S, X) { return S.charCodeAt(rvx(X, S.length)); }
// Returns 1 if the first byte of string S is a letter of the alphabet.
function isLetter(S) { var c = S.charCodeAt(0) & 223; return (c > 64 && c < 91) ? 1 : 0; }
// This function extracts a section from string S that lies between string L and R.
// Returns an empty string if either L or R is not found.
function Between(S, L, R) { var p1 = S.indexOf(L); if (p1 < 0) return ""; var p2 = S.lastIndexOf(R); if (p2 <= p1) return ""; return S.substring(p1 + L.length, p2); }
// This function returns a section of string S that comes before the first occurrence of string M. The match is case sensitive.
function StrBefore(S, M) { var E = S.indexOf(M); return (E > 0) ? S.substr(0, E) : ""; }
// This function returns a section of string S that comes after the first occurrence of string M. The match is case sensitive.
function StrAfter(S, M) { var E = S.indexOf(M); return (E > 0) ? S.slice(E + M.length) : ""; }
// This function counts how many times string M occurs in string S and returns an integer.
function StrCount(S, M) { return S.split(M).length - 1; }
// Returns 1 if string S starts with string M.
function StartsWith(S, M) { return (S.indexOf(M) == 0) ? 1 : 0; }
// Returns 1 if string S ends with string M.
function EndsWith(S, M) { return (S.lastIndexOf(M) == S.length - M.length) ? 1 : 0; }
// Ensures string S starts with prefix X.
function EnsureStart(S, X) { S += ""; X += ""; return (S.indexOf(X) == 0) ? S : X + S; }
// Ensures string S ends with suffix X.
function EnsureEnd(S, X) { S += ""; X += ""; return (S.lastIndexOf(M) == S.length - X.length) ? S : S + X; }
// Returns 1 if string S contains letters only.
function isLettersOnly(S) { S += ""; var i, c; for (i = 0; i < S.length; i++) { c = S.charCodeAt(i); if (c < 65 || c > 122) return 0; if (c > 90 && c < 97) return 0; } return 1; }
// Returns 1 if string S contains letters and numbers only.
function isAlphaNumberic(S) { S += ""; var i, c; for (i = 0; i < S.length; i++) { c = S.charCodeAt(i); if (c < 48 || c > 122) return 0; if (c > 90 && c < 97) return 0; if (c > 57 && c < 65) return 0; } return 1; }
// Returns 1 if string S is solely composed of whitespace or is null/undefined.
function isEmpty(S) { if (typeof S === "undefined") return 1; if (S == null) return 1; S += ""; var i, c; for (i = 0; i < S.length; i++) { c = S.charCodeAt(i); if (c < 14 || c == 32); else return 0; } return 1; }
// Returns 1 if string S is lower case only.
function isLower(S) { S += ""; return (S == S.toLowerCase()) ? 1 : 0; }
// Returns 1 if string S is upper case only.
function isUpper(S) { S += ""; return (S == S.toUpperCase()) ? 1 : 0; }
// Returns 1 if string S contains 0123456789 digits only.
function isNumeric(S) { S += ""; var i, c; for (i = 0; i < S.length; i++) { c = S.charCodeAt(i); if (c < 48 || c > 57) return 0; } return 1; }
// This function splits string S at pointer X and puts the first half of the string into global variable $A and the second half into $B. When X is a negative index, it starts counting from the end of string S. This function always returns the length of $A.
function SplitAt(S, X) { if (X >= S.length) { $A = S; $B = ""; return S.length; } if (X == 0 || X <= -S.length) { $A = ""; $B = S; return 0; } $A = S.substr(0, (X < 0) ? S.length + X : X); $B = S.slice(X); return $A.length; }
// This function splits string S into two parts along the first occurrence of pattern P. The two parts will be stored in global variables named $A and $B. This function returns 1 if the pattern was found, or zero if it was not found.
function SplitAB(S, P) { var N = S.indexOf(P); if (N < 0) { $A = S; $B = ""; return 0; } $A = S.slice(0, N); $B = S.slice(N + P.length); return 1; }
// This function splits string S into two parts along the last occurrence of pattern P. The two parts will be stored in global variables named $A and $B. This function returns 1 if the pattern was found, or zero if it was not found.
function LastSplitAB(S, P) { var N = S.lastIndexOf(P); if (N < 0) { $A = S; $B = ""; return 0; } $A = S.slice(0, N); $B = S.slice(N + P.length); return 1; }
// This function scans string S and replaces every occurrence of string A with B and returns a new string. Case sensitive search.
function StrReplace(S, A, B) { return S.split(A).join(B); }
// This function uses replace() with RegExp() to run a non-case-sensitive replace.
function StrReplaceAll(S, A, B) { return S.replace(RegExp(A, "gi"), B); }
// This function reverses string S.
function StrReverse(S) { return S.split("").reverse().join(""); }
// This function returns the first N characters of string S.
function StrLeft(S, N) { if (N < 1) return ""; return S.substr(0, N); }
// This function returns the last N characters of string S.
function StrRight(S, N) { if (N < 1) return ""; if (N >= S.length) return S; return S.slice(S.length - N); }
// This function is similar to the original split() method, however this will treat
// space, tab, new line, return, comma, semicolon, and period as separator characters.
// Also, the result will be all uppercase letters!
function Split(TEXT) { var i, A = [], C, START = null; TEXT = TEXT.toUpperCase() + "\n"; for (i = 0; i < TEXT.length; i++) { C = TEXT.charAt(i); if (C == ' ' || C == '\t' || C == '\n' || C == '\r' || C == ',' || C == ';' || C == '.') { if (START != null) A.push(TEXT.substring(START, i)); START = null; } else if (START == null) START = i; } return A; }
// This function splits a string along new-line characters and returns an array.
// Recognizes \r\n \n\n \r\r
function SplitLines(S) { if (S.indexOf("\r") < 0) return S.split("\n"); if (S.indexOf("\n") < 0) return S.split("\r"); return S.split("\r\n"); }
//////////////////////////////////////////////////////
//
// This function splits a string, stuffing digits and
// non-digits into alternating elements of an array.
// Example:
// SplitNumbers("34DX5g") -> ["34", "DX", "5", "g"]
// SplitNumbers("-x39.4") -> ["-x", "39", ".", "4"]
//
function SplitNumbers(S)
{
var A = [], p = 0, m = -1, i, d;
for (i = 0; i < S.length; i++)
{
d = S.charCodeAt(i);
d = d > 47 && d < 58;
if (m == d) { A.push(S.substring(p, i)); p = i; }
m = !d;
}
A.push(S.substring(p, i));
return A;
}
//////////////////////////////////////////////////////
//
// This function extracts digits from a string and
// returns them in an array.
// Example:
// SplitNumbers("34DX5g") -> ["34", "5"]
// SplitNumbers("-x39.4") -> ["39", "4"]
//
function GetNumbers(S)
{
var A = [], p = -1, i, c;
for (i = 0; i <= S.length; i++)
{
c = S.charCodeAt(i);
if (c < 48 || c > 57)
{
if (p >= 0) A.push(S.substring(p, i));
p = -1;
}
else if (p < 0) p = i;
}
return A;
}
//////////////////////////////////////////////////////
//
// This function extracts digits from strings and
// returns them in an array.
// Usage: ARRAY = GetNumberList(STRING, [STRING]...)
// Example:
// GetNumberList("34DX5g", 55, "a41") -> ["34", "5", "55", "41"]
// GetNumberList("-x39.4") -> ["39", "4"]
//
function GetNumberList()
{
var A = [], S, p = -1, i = 0, c;
while (i < arguments.length)
A.push(arguments[i++] + "/");
S = A.join("");
A = [];
for (i = 0; i < S.length; i++)
{
c = S.charCodeAt(i);
if (c < 48 || c > 57)
{
if (p >= 0) A.push(S.substring(p, i));
p = -1;
}
else if (p < 0)
p = i;
}
return A;
}
//////////////////////////////////////////////////////
// This function counts the letters in a string.
// If an optional second argument is passed: if it's zero, returns
// the number of vowels, otherwise returns the number of consonants.
function LetterCount(S) { var c, n = 0, v = 0, i = S.length; while (i-- > 0) { c = S.charCodeAt(i) | 32; if (c < 97 || c > 122) continue; if (c == 97 || c == 101 || c == 105 || c == 111 || c == 117) v++; else n++; } if (arguments.length > 1) return (arguments[1]) ? n : v; return n+v; }
// This function encodes or decodes a string using a password string, and returns the result.
function XOR(STRING, PW) { var i, j, r, OUTPUT = [""]; for (r = i = j = 0; i < STRING.length; i++, j++) { if (j > PW.length) j = 0; OUTPUT[r] += String.fromCharCode(STRING.charCodeAt(i) ^ PW.charCodeAt(j)); if (OUTPUT[r].length > 100) { r++; OUTPUT[r] = ""; } } return OUTPUT.join(""); }
// Replaces SEARCHSTR with PASTE globally (not case sensitive)
function REP(STRING, SEARCHSTR, PASTE) { document.write(A.replace(RegExp(SEARCHSTR, "gi"), PASTE)); }
// Capitalizes the first LETTER of string S and returns a new string.
function Capitalize(S) { var i, c; S = S.toLowerCase().split(""); for (i = 0; i < S.length; i++) { c = S[i].charCodeAt(0); if (c > 96 && c < 123) { S[i] = S[i].toUpperCase(); break; } } return S.join(""); }
// Capitalizes the first letter of every word, and returns a new string.
function TitleCase(S) { S = S.toLowerCase().split(""); var i, F = 1, WS = " .,:;!?/\()[]{}<>|-+=\t\n\r\xFF"; for (i = 0; i < S.length; i++) { if (WS.indexOf(S[i]) >= 0) F = 1; else if (F == 1) { S[i] = S[i].toUpperCase(); F = 0; } } return S.join(""); }
// Capitalizes the first letter of each sentence and returns a new string.
function SentenceCase(S) { S = S.toLowerCase().split(""); var i, N = 1, SP = " ,:;/\()[]{}<>|-+=\t\r\n\xFF"; for (i = 0; i < S.length; i++) { if (SP.indexOf(S[i]) >= 0); else if (".!?".indexOf(S[i]) >= 0) N = 1; else if (N) { S[i] = S[i].toUpperCase(); N = 0; } } return S.join(""); }
// Capitalizes every other letter of string S and returns a new string.
function EveryOther(S) { S = S.toLowerCase().split(""); for (var i = 1; i < S.length; i += 2) S[i] = S[i].toUpperCase(); return S.join(""); }
// Reverses uppercase letters with lowercase and vice versa.
function ReverseCase(S) { S = S.split(""); var i, c; for (i = 0; i < S.length; i++) { c = S[i].charCodeAt(0); if (c < 65 || c > 122) continue; if (c > 90 && c < 97) continue; S[i] = String.fromCharCode(c ^ 32); } return S.join(""); }
// Capitalizes each instance of the word W in string S.
function MatchWord(S, W) { return S.toLowerCase().split(W.toLowerCase()).join(W.toUpperCase()); }
// Inserts string B into A starting at offset N.
// If N > 0, then inserts from the beginning of string.
// If N < 0, then inserts from the end of string.
function StrInsert(A, B, N) { A += ""; B += ""; if (A.length == 0) return B; if (B.length == 0) return A; if (N > A.length) N = A.length; if (N < 0) N += A.length; if (N < 0) N = 0; var PART1 = A.substr(0, N); var PART2 = A.slice(N); return PART1 + B + PART2; }
// This function removes all foreign characters from string S
// that are not "allowed" and returns a new string.
function strFilter(S, ALLOWED) { var i, c, $ = []; S += ""; for (i = 0; i < S.length; i++) { c = S.charAt(i); if (ALLOWED.indexOf(c) >= 0) $.push(c); } return $.join(""); }
// COMPRESSION LIBRARY
//////////////////////////////////////////////////
// v2019.12.27
// This function compresses a text to binary string
// by removing the highest 0 bit from every byte
// thus shrinking the output by 8:7 ratio.
// Usage: STRING = Compress8to7(TEXT)
//
function Compress8to7(T)
{
var i, j, L = T.length,
BINARY = [(((L-1) & 7) == 0) || (((L-2) & 7) == 0) ? '1' : '0'];
for (i = j = 0; i < L; i++)
BINARY[++j] = toBin(T.charCodeAt(i) & 127, 7);
BINARY = BINARY.join("");
// This line is really unnecessary.
// It is here just for clarification only:
// while (BINARY.length & 7) BINARY += '0';
return Bin2Str(BINARY);
}
//////////////////////////////////////////////////
// v2019.12.27
// This function expands a binary string to a text
// by inserting a '0' in the high bit of each byte,
// thus expanding the output by a 7:8 ratio.
// Usage: TEXT = Expand7to8(STRING)
//
function Expand7to8(S)
{
var BINARY = Str2Bin(S);
var L = BINARY.length - 1;
var OUTPUT = [];
for (i = 1; i < L; i += 7)
OUTPUT.push(String.fromCharCode(parseInt(BINARY.substr(i, 7), 2)));
if (BINARY.charCodeAt(0) == 48)
OUTPUT.pop();
return OUTPUT.join("");
}
//////////////////////////////////////////////////
//
// LZW-compress a string
// [This function was copied from LZ-String.js]
//
function LzwCompress(s)
{
var dict = {};
var data = (s + "").split("");
var out = [];
var currChar;
var phrase = data[0];
var code = 256;
for (var i=1; i 1 ? dict[phrase] : phrase.charCodeAt(0));
dict[phrase + currChar] = code;
code++;
phrase=currChar;
}
}
out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
for (var i=0; i
Character Statistics
"]; var A = CharCount(S); var max = Math.max.apply(0, A) >> 8; A.reverse(); function HTMLCHR(c) { var B = String.fromCharCode(c); if (B == " ") return " "; if (B == "&") return "&"; if (B == "<") return "<"; if (B == ">") return ">"; return (c < 32 || c == 173 || (c > 126 && c < 161)) ? "." : B; } for (i = 0; i < 256; i++) { X = A.shift(); C = X & 0xFF; N = (X & 0xFFFFFF00) >> 8; X = HTMLCHR(C); if (N == 0) break; HTML.push("
0x" + toHex(C).toUpperCase() + " =
" + C + "
= \"" + X + "\"
:
" + N + "
" + Repeat("▒", Math.floor(40 * N / max))); } HTML.push("
The following characters never occur in the string: "); A.sort(function(a, b) {return a-b}); for (N = 0; i < A.length; i++) { C = A[i] & 0xFF; X = HTMLCHR(C); if (!(N++ % 10)) HTML.push(" "); HTML.push(" 0x" + toHex(C).toUpperCase() + "=" + X + ""); } HTML.push("
Length of input string : " + S.length + " bytes
"); document.write(HTML.join("")); }
// This function returns a section of a full character set. A full character set always contains 256 characters from 0 to 255. But this function returns only a certain segment of that set defined by MIN and MAX. If MIN is smaller than MAX, then you get a normal character set starting at MIN and ending at MAX. Example: charSet(97, 99) --> "abc" However, if MIN is greater than MAX, then you get the inverse character set that includes every character EXCEPT those defined by MIN and MAX.
function charRange(MIN, MAX) { var A = []; if (MIN > MAX) MIN++; else MAX++; MIN &= 255; MAX &= 255; while (MIN != MAX) { A.push(String.fromCharCode(MIN++)); MIN &= 255; } return A.join(""); }
// This function returns the inverse set of characters that are not found anywhere in string S.
// Example: inverseCharSet("YELLOW") will take a 256-byte long character set and remove the letters Y E L O W from the set and return what's left.
function inverseCharSet(S) { var i, A = []; for (i = 0; i < 256; i++) A.push(String.fromCharCode(i)); for (i = 0; i < S.length; i++) A[S.charCodeAt(i)] = ""; return A.join(""); }
// This function lists the characters that are used in string S and returns a sorted string.
function regularCharSet(S) { S += ""; if (S.length == 0) return ""; var A = [], i = S.length; while (i-- > 0) A[S.charCodeAt(i)] = 2; while (i < 256) { A[i] = (A[i] == 2) ? String.fromCharCode(i) : ""; i++; } return A.sort().join(""); }
// This function returns 1 if string S is strictly made up of
// characters listed in string KNOWN. Returns 0 if string S
// contains any "unknown" characters.
function isFromCharSet(S, KNOWN) { S += ""; for (var i = 0; i < S.length; i++) if (KNOWN.indexOf(S.charAt(i)) < 0) return 0; return 1; }
// This function translates each character of string S according to new character table NEWSET.
// Example:
// ConvertCharSet("aacb", "abc", "123") --> "1132"
// ConvertCharSet("hello", "abcdefghijklmno", "-+0123456789XYZ") --> "5299Z"
function ConvertCharSet(S, OLDSET, NEWSET) { var i, P; S = S.split(""); for (i = 0; i < S.length; i++) { P = OLDSET.indexOf(S[i].charAt(0)); S[i] = (P >= 0) ? NEWSET.charAt(P) : ""; } return S.join(""); }
B64SET = "?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
URLSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz|_";
// This function takes any kind of binary string and converts it to a safe string that can be passed as an argument in the URL.
function EncodeURL(S) { return ConvertCharSet(EncodeB64(S), B64SET, URLSET); }
// This function takes an URL-safe string that contains letters and numbers only and returns a binary string.
function DecodeURL(S) { return DecodeB64(ConvertCharSet(S, URLSET, B64SET)); }
// This function converts a binary string (can be HTML or JavaScript) to a safe string that can be used in a HTML file within JavaScript tags.
function EncodeHTML(S) { var i, C; S = S.split(""); for (i = 0; i < S.length; i++) { C = S[i].charCodeAt(0); if (C == 7) S[i] = "\\t"; else if (C == 10) S[i] = "\\r"; else if (C == 13) S[i] = "\\n"; else if (C == 92) S[i] = "\\\\"; else if (C == 34 || C == 38 || C == 39 || C == 60 || C == 62 || C < 32 || C > 126) S[i] = "\\x" + toHex(C); } return '"' + S.join("") + '"'; }
// This function converts a Js safe string with quotation marks around it to its original source. It's the opposite of EncodeHTML()
function DecodeHTML(S) { S += ""; if (S.length > 1) { if (S.charAt(0) == '"' || S.charAt(0) == "'") S = S.slice(1, -1); } S = S.split("\\t").join("\t").split("\\r").join("\r").split("\\n").join("\n").split("\\\\").join("\\").split("\\x"); for (var i = 1; i < S.length; i++) S[i] = String.fromCharCode(parseInt(S[i].substr(0, 2), 16)) + S[i].slice(2); return S.join(""); }
// NUMBER FUNCTIONS
// This function returns 1 if S is a valid hex number.
function isHex(S) { return isFromCharSet(S, "0123456789abcdefABCDEF"); }
// This function returns 1 if S contains digits only.
function isDec(S) { return isFromCharSet(S, "0123456789"); }
// This function returns 1 if string S is a valid binary number.
function isBin(S) { return isFromCharSet(S, "01"); }
// This function returns a hex string.
// It filters string S and only allows hex digits to pass through.
function ForceHex(S) { return strFilter(S, "0123456789abcdefABCDEF").toUpperCase(); }
// This function filters string S and only allows digits to pass through.
function ForceDec(S) { return strFilter(S, "0123456789"); }
// This function returns a binary number.
// It filters string S and only allows ones and zeros to pass through.
function ForceBin(S) { return strFilter(S, "01"); }
// This function converts number N to a positive integer that is exactly X number of bytes long. It does that by either chopping off some of the first few digits or putting some zeros in the front.
function FIX(X, N) { if (isNaN(N) || N == null) N = "0"; else N = Math.floor(Math.abs(N)) + ""; if (N.length > X) return N.substr(N.length - X, X); while (N.length < X) N = "0" + N; return N; }
// This function extracts the last whole number from string s and returns that number
function lastNumber(s) { var i, c, L = 0, p = -1; for (i = s.length - 1; i >= 0; i--) { c = s.charCodeAt(i); if (c > 47 && c < 58) { if (p < 0) p = i; L++; } else { if (L > 0) break; } } return s.substr(p - L + 1, L); }
// This function splits binary string S into groups of 8 and removes the first digit of each group and returns a new string. This function can remove the first N digits if a second argument is provided.
// Example:
// DiscardHighBit("1000000010000000"); --> "00000000000000"
// DiscardHighBit("1100000011000000", 2); --> "000000000000"
// DiscardHighBit("1110000011100000", 3); --> "0000000000"
function DiscardHighBit(S) { S = Group(S, 8); var i, N = (arguments.length == 2) ? arguments[1] : 1; for (i = 0; i < S.length; i++) S[i] = S[i].slice(N); return S.join(""); }
// This function is the opposite of DiscardHighBit() function. If a string is provided as a second argument, this string will be inserted at the beginning of every group.
// Example:
// InsertHighBit("11111111111111"); --> "0111111101111111"
// InsertHighBit("1111111111", "000"); --> "0001111100011111"
// InsertHighBit("00000000", "1111"); --> "1111000011110000"
function InsertHighBit(S) { var BITS = (arguments.length > 1) ? arguments[1] : "0"; var N = (8 - BITS.length); S = Group(S, N); for (var i = 0; i < S.length; i++) S[i] = BITS + S[i]; return S.join(""); }
// TIME FUNCTIONS
NOW = new Date();
TIMEZONE = Math.round(Math.abs(NOW.getTimezoneOffset() / 60));
LOADTIME = now(); // Current time in milliseconds since Jan 1970
// Returns the number of milliseconds since Jan 1970.
function now() { return (new Date()).getTime(); }
// Returns the milliseconds portion of current time (0-1000)
function M() { return (new Date()).getMilliseconds(); }
// Returns the number of seconds since Jan 2019 in a 4-byte binary string.
function MakeTimeStamp() {return LongStr(Math.floor(((new Date()).getTime()-1546300800000)/2000));}
// Converts 4-byte TimeStamp string to milliseconds since Jan 1970.
function ReadTimeStamp(S) {return StrLong(S)*2000+1546300800000;}
// This function returns a text string that says how long
// ago time T was recorded. Example: "5 minutes ago"
function TimeAgo(T) { var DIFF = Math.abs(now() - T); if (DIFF < 70000) return "just now"; if (DIFF < 120000) return "1 minute ago"; if (DIFF < 3000000) return Math.round(DIFF / 60000) + " minutes ago"; if (DIFF < 6000000) return "about an hour ago"; if (DIFF < 86400000) return Math.floor(DIFF / 3600000) + " hours ago"; if (DIFF < 604800000) return Math.floor(DIFF / 86400000) + " days ago"; if (DIFF < 950400000) return "last week"; if (DIFF < 2298240000) return Math.floor(DIFF / 604800000) + " weeks ago"; if (DIFF < 3110400000) return "last month"; if (DIFF < 3110400000) return Math.floor(DIFF / 2635200000) + " months ago"; if (DIFF < 59918400000) return "a year ago"; return Math.round(DIFF / 31536000000) + " years ago"; }
// This function is called by CreateTimeAgo()
function UpdateTimeAgo(OBJECT_ID, T) { document.getElementById(OBJECT_ID).innerText = TimeAgo(T); }
// This function creates a text label that gets updated every 15 seconds showing how long ago it was created.
function CreateTimeAgo(OBJECT_ID, T) { var DIFF = Math.abs(now() - T); UpdateTimeAgo(OBJECT_ID, T); if (DIFF < 86400000) setInterval("UpdateTimeAgo('" + OBJECT_ID + "', " + T + ");", 15100); }
// COLOR MANIPULATION
// Converts 3 decimal numbers to hex color code.
function toColor(R, G, B) { return toHex(R) + toHex(G) + toHex(B); }
// WARNING: This function overwrites global variables: R,G,B
// Converts a hex color code to individual R, G, B numbers.
function GetRGB(C) { C = Hex2Int(C); R = (C & 0xFF0000) >>> 16; G = (C & 0xFF00) >>> 8; B = C & 0xFF; }
// WARNING: This function overwrites global variables: R,G,B
// This function returns the opposite color of C in hex format
function InvertColor(C) { GetRGB(C); return toColor(255-R, 255-G, 255-B); }
// WARNING: This function overwrites global variables: R,G,B,R1,G1,B1,R2,G2,B2,RX,GX,BX
// Returns an array of colors which is a transition from C1 to C2 in N steps
function GetColorShades(C1, C2, N) { var i, A = [C1]; if (N > 2) { CalculateColorGain(C1, C2, N); for (i = 0; i < N-2; i++) { R1 += RX; G1 += GX; B1 += BX; A.push(toColor(R1, G1, B1)); } } A.push(C2); return A; }
// WARNING: This function overwrites global variables: R,G,B,R1,G1,B1,R2,G2,B2,RX,GX,BX
// This function calculates how much R, G, B values need to change
// in order go from color C1 to color C2 in N steps.
// Side effects: C1 ---> R,G,B
function CalculateColorGain(C1, C2, N) { GetRGB(C2); R2=R; G2=G; B2=B; GetRGB(C1); R1=R; G1=G; B1=B; RX = (R2 - R1) / (N - 1); GX = (G2 - G1) / (N - 1); BX = (B2 - B1) / (N - 1); }
// WARNING: This function overwrites global variables: R,G,B,R1,G1,B1,R2,G2,B2,RX,GX,BX
// Prints each letter in a different color from C1 to C2.
function WriteInColor(S, C1, C2) { var i, c; CalculateColorGain(C1, C2, S.length); for (i = 0; i < S.length; i++) { c = S.charCodeAt(i); if (c < 33) PRINT(" "); else { if (c == 38) c = "&"; else if (c == 60) c = "<"; else if (c == 62) c = ">"; else c = S.charAt(i); PRINT(""+c+""); } R += RX; G += GX; B += BX; } }
// WARNING: This function overwrites global variables: R,G,B
// This function converts Hue, Saturation, and Luminance to RGB values
// Source: www.rapidtables.com/convert/color/hsv-to-rgb.htm
function HSL2RGB(H, S, L) { H = H * 1; if (H < 0) H = 0; if (H > 360) H = 359; H = H / 60; S = S * 1; if (S < 0) S = 0; if (S > 100) S = 100; S /= 100; L = L * 1; if (L < 0) L = 0; if (L > 100) L = 100; L /= 100; R = 0; G = 0; B = 0; var C = L * S; var M = L - C; var X = C * (1 - Math.abs(H % 2 - 1)); if (H >= 0 && H < 1) { R = C; G = X; } else if (H >= 1 && H < 2) { R = X; G = C; } else if (H >= 2 && H < 3) { G = C; B = X; } else if (H >= 3 && H < 4) { G = X; B = C; } else if (H >= 4 && H < 5) { R = X; B = C; } else { R = C; B = X; } R += M; R *= 255; R = Math.round(R); G += M; G *= 255; G = Math.round(G); B += M; B *= 255; B = Math.round(B); }
// This function converts RGB values to HSL format and returns
// these three values in an array: [Hue, Saturation, Luminance]
// Source: www.javascripter.net/faq/rgb2hsv.htm
function RGB2HSL(R, G, B) { R = R * 1; if (R < 0) R = 0; if (R > 255) R = 255; R = R / 255; G = G * 1; if (G < 0) G = 0; if (G > 255) G = 255; G = G / 255; B = B * 1; if (B < 0) B = 0; if (B > 255) B = 255; B = B / 255; var minRGB = Math.min(R, Math.min(G, B)); var maxRGB = Math.max(R, Math.max(G, B)); if (minRGB == maxRGB) return [0, 0, minRGB]; var S = (maxRGB - minRGB) / maxRGB; var D = (R == minRGB) ? G - B : ((B == minRGB) ? R - G : B - R); var H = (R == minRGB) ? 3 : ((B == minRGB) ? 1 : 5); H = 60 * (H - D / (maxRGB - minRGB)); return [H, S, maxRGB]; }
// This function can increase or decrease R-G-B brightness of a color and return a new color.
function ColorGain(C, R_GAIN, G_GAIN, B_GAIN) { GetRGB(C); R += R_GAIN; G += G_GAIN; B += B_GAIN; return toColor(R, G, B); }
// ARGUMENT PROCESSING & NAVIGATION CONTROL
function Alert(S) {if(window)alert(S);else WScript.Echo(S);}
function DebugURL() {var i,X=[],L="SELF PATH FILE HOST BOOKMARK ONLINE ARGS ARGC ARGN ARGV".split(" ");for(i=0;i=0){BOOKMARK=URL.slice(P+1);SELF=URL.substr(0,P);}P=SELF.indexOf("?");if(P>=0){ARGS=SELF.slice(P+1);SELF=SELF.substr(0,P);A=unescape(ARGS).split("&");for(i=0;i=0){ARGN[ARGC]=A[i].substr(0,P).toUpperCase();ARGV[ARGC++]=A[i].slice(P+1);}}}SELF=SELF.split("\\").join("/");P=SELF.lastIndexOf("/");PATH=SELF.substr(0,P+1);FILE=SELF.slice(P+1);P=PATH.indexOf(":///");if(P>=0)PATH=PATH.slice(P+4);P=PATH.indexOf("://");if(P>=0)PATH=PATH.slice(P+3);PATH=unescape(PATH);P=PATH.indexOf("/");if(ONLINE){HOST=(P>0)?PATH.substr(0,P):PATH;if(HOST.substr(0,4).toUpperCase()=="WWW.")HOST=HOST.slice(4);}else HOST="localhost";}
SplitURL(location.href);
/*
ARGC = 0; ARGN = []; ARGV = []; ARGS = "";
LastSplitAB(location.href, "#"); SELF = $A; BOOKMARK = $B;
if (SplitAB(SELF, "?")) { SELF = $A; ARGS = $B; A = unescape(ARGS).split("&"); for (i = 0; i < A.length; i++) if (SplitAB(A[i], "=")) { ARGN.push($A.toUpperCase()); ARGV.push($B); ARGC++; } }
SELF = StrReplace(SELF, "\\", "/");
LastSplitAB(SELF, "/"); PATH = $A; FILE = $B;
P = PATH.indexOf(":///"); if (P >= 0) PATH = PATH.slice(P+4);
P = PATH.indexOf("://"); if (P >= 0) PATH = PATH.slice(P+3);
PATH = unescape(PATH);
*/
// BOOKMARK holds whatever comes after the # sign in the URL
// ARGS holds location.search without the ? mark
// ARGC holds the argument count (number of values)
// ARGN holds the names for each value
// ARGV holds the corresponding values
// FILE holds the name of the current web page (file name only)
// SELF holds the URL of the current web page without arguments
// PATH holds the current working directory, always ending with a /
// HOST holds the hostname of the current domain without the www. part
// This function returns the value of the named argument. If undefined, DEFAULT is returned.
function GetArgStr(NAME, DEFAULT) { NAME = NAME.toUpperCase(); for (var i = 0; i < ARGC; i++) if (ARGN[i] == NAME) return ARGV[i]; return DEFAULT; }
// This function returns the named argument as an integer. If undefined, DEFAULT is returned. If two more optional arguments are provided, the return value will be an integer between those two values.
function GetArgInt(NAME, DEFAULT) { var MAX = 0x7FFFFFFF; var MIN = -MAX; if (arguments.length > 2) MIN = arguments[2]; if (arguments.length > 3) MAX = arguments[3]; var P = "_TRUE_YES_ALL_ON_", $ = GetArgStr(NAME, DEFAULT); if (isNaN($)) if (P.indexOf(("_"+$.toUpperCase()+"_")) >= 0) $ = 1; if (isNaN($)) $ = 0; $ = Math.round($); if ($ < MIN) $ = MIN; if ($ > MAX) $ = MAX; return $|0; }
// This function loads a given URL address.
function Goto(URL) { location.href = URL; }
// This function extracts email addresses from a string and returns them in an array.
function ExtractEmails(S) { var A = S.match(/([a-zA-Z0-9._\-+]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi); return A ? A : []; }
// This function returns 1 if the given URL does not contain
// any tabs, spaces, or illegal characters such as É Ñ µ ƒ ¥ £ ¡
function isValidURL(URL) { var c, i = URL.length; while (i-- > 0) { c = URL.charCodeAt(i); if (c < 33 || c > 126) return 0; } return 1; }
// This function returns 1 if the given email address has valid format, otherwise returns 0.
function isValidEmail(E) { var L = E.length; if (L < 3 || L > 253) return 0; var i, c, ATS = 0, DOT = 0, DOTS = 0, LTRS = 0; for (i = 0; i < L; i++) { c = E.charCodeAt(i); if (c > 57 && c < 61) return 0; if (c > 90 && c < 94) return 0; if (c < 33) return 0; if (c == 62 || c == 34 || c == 44) return 0; if (c == 46) { if (DOT == i) return 0; DOT = i+1; DOTS++; continue; } if (c == 64) { if (DOT == i) return 0; DOT = i+1; ATS++; if (i == 0 || ATS > 1) return 0; continue; } LTRS++; } if (ATS != 1 || DOTS == 0 || DOT == i || LTRS < 2) return 0; return 1; }
// This function returns 1 if the person's name provided has valid format, otherwise returns 0.
function isValidName(N) { var L = N.length; if (N < 2 || N > 64) return 0; var i, c; for (i = 0; i < L; i++) { c = N.charCodeAt(i); if (c < 33) return 0; if (c > 33 && c < 38) return 0; if (c > 39 && c < 44) return 0; if (c > 46 && c < 65) return 0; if (c > 90 && c < 97) return 0; if (c > 122 && c < 128) return 0; } return 1; }
///////////////////////////////////////////////////
// HTML GET
// This function is called when data downloaded by
// WGET() arrives and becomes available.
function RECEIVER(DATA)
{
// IF WE DIDN'T GET ANYTHING
if (DATA.length == 0) { alert("ERROR: No data received.\n\nYour browser may not allow cross domain resource access."); return; }
alert("DATA: " + DATA);
}
// The WGET function downloads a file from the internet
// and allows us to work with it. But unfortunately,
// not all web browsers support this feature, so its
// behavior is somewhat unpredictable. For example:
// * Safari 5.1.7 receives a blank string
// * Firefox 19.0 receives a blank string unless an addon called "Force CORS" is installed and enabled.
// * KMeleon 1.5.4 displays an error message and doesn't receive anything
// * Internet Explorer 9 works fine
function WGET(URL) { try { var REQUEST = (typeof window.ActiveXObject != "undefined") ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(); REQUEST.open("GET", URL, true); REQUEST.onreadystatechange = function() { if (REQUEST.readyState == 4) RECEIVER(REQUEST.responseText); }; REQUEST.send(null); } catch (e) { alert("ERROR: Could not fetch data from\n\n" + URL + "\n\n(" + e.message + ")"); } }
// TASK MANAGER written by Zsolt Nagy-Perge on Oct 21, 2017.
//
// The task manager is initiated by calling AddTimer();
// This function creates a timer hook like setInterval()
// but here you MUST specify how many times a function
// should be called. The DELAY is given in tenths of a second.
//
// Usage: AddTimer(FUNCTION, DELAY, ITERATIONS, [INSTRUCTIONS]);
//
// Example: AddTimer("MyFunc", 2, 5, "callback();");
//
// This executes MyFunc(0,4); immediately and then 2/10 seconds later,
// it executes MyFunc(1,4); and then 200ms later,
// it calls MyFunc(2,4); and 200ms later
// calls MyFunc(3,4); and 200ms later
// calls MyFunc(4,4); and callback(); and stops.
//
// FUNCTION only gets executed when ITERATIONS > 0
// INSTRUCTIONS always get executed at the end.
//
// These functions rely on a global variable called $TIMER,
// so this array must be created before AddTimer() can be used.
//
$TIMER = [0, 0]; // $TIMER[0] = TIMER STATUS, $TIMER[1] = TIMER HANDLE
// Adds a task to the task tray and starts the timer.
function AddTimer(FUNC, DELAY, REP) { var CALLBACK = (arguments.length > 3) ? arguments[3] : ""; if (REP < 2) { while (--REP >= 0) eval(FUNC+"(0,"+REP+");"); eval(CALLBACK); return; } $TIMER.push(FUNC, 0, REP, 1, DELAY, CALLBACK); StartTimer(); }
// Starts the timer.
function StartTimer() { if (!$TIMER[0]) $TIMER[1] = setInterval("TaskMGR();", 100); $TIMER[0] = 1; }
// Removes task from the task tray and stops the timer if no tasks are left. Finally, executes callback instructions (if any).
function StopTimer(N) { var CALLBACK = ""; if ($TIMER.length > N+5) { CALLBACK = $TIMER[N+5]; $TIMER.splice(N, 6); } if ($TIMER.length < 3) if ($TIMER[0]) { clearInterval($TIMER[1]); $TIMER[0] = 0; } eval(CALLBACK); }
// This function is called every 100 milliseconds.
function TaskMGR() { var RUNCOUNT, MAXRUNS, DELAY, i; for (i = 2; i < $TIMER.length; i += 6) { DELAY = $TIMER[i+4]; if (DELAY > 1) { if (++$TIMER[i+3] < DELAY) continue; $TIMER[i+3] = 1; } RUNCOUNT = ++$TIMER[i+1]; MAXRUNS = $TIMER[i+2]; eval($TIMER[i] + "(" + RUNCOUNT + "," + MAXRUNS + ");"); if (RUNCOUNT >= MAXRUNS) StopTimer(i); } }
// BENCHMARK
TIMER = [];
function Timer(E) { D = new Date(); TIMER.push(D.getTime()); TIMER.push(E); }
function ShowTimer() { var i, E, PREV, DIFF, T = 0; PRINT("
Raw Time (ms)
Delay (ms)
Description"); while (TIMER.length > 0) { PREV = T; T = TIMER.shift(); E = TIMER.shift(); DIFF = Math.abs(PREV - T); if (PREV == 0) continue; PRINT("
" + T + "
" + DIFF + "
" + E); } PRINT("
"); TIMER = []; FLUSH(); }
// BITWISE ROTATE
// This function performs bitwise rotate of a byte by N bits.
// If N is a positive number, it rotates right by N bits.
// If N is a negative number, it rotates left by N bits.
//function ROR8(BYTE, N) { N &= 7; if (N == 0) return (BYTE & 0xFF); var MASK = [0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F]; var BITS = BYTE & MASK[N]; BITS <<= (8 - N); BYTE >>>= N; return BYTE + BITS; }
function ROL8(C,N){if(N&=7){var M=[,127,63,31,15,7,3,1][N];C=((C&M)<>(8-N));}return C&255;}
// This function rotates byte C to the RIGHT by N number of bits.
function ROR8(C,N){return ROL8(C,8-N);}
// This function performs bitwise rotate right on a 16-bit word.
function ROR16(WORD, N) { N &= 15; if (N == 0) return (WORD & 0xFFFF); var MASK = [0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF]; var BITS = WORD & MASK[N]; BITS <<= (16 - N); WORD >>>= N; return WORD + BITS; }
// This function performs bitwise rotate right on a 32-bit long.
function ROR32(LONG, N) { N &= 31; if (N == 0) return (LONG & 0xFFFFFFFF); var MASK = [0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF]; var BITS = LONG & MASK[N]; BITS <<= (32 - N); LONG >>>= N; return LONG + BITS; }
// This function performs bitwise rotate on a string segment
// marked by StartBit and EndBit. Rotates to the right by N bits.
function RORS(S, N, StartBit, EndBit) { var LEFT = (N < 0) ? 0 : 1; if (StartBit >= EndBit) return S; N = Math.abs(N) % (EndBit - StartBit); if (N == 0) return S; var B = Str2Bin(S); if (EndBit > B.length) return ""; var UNCH1 = B.substr(0, StartBit); var UNCH2 = B.slice(EndBit); B = B.substring(StartBit, EndBit); if (LEFT) N = B.length - N; var PART1 = B.substr(0, N); var PART2 = B.slice(N); return Bin2Str(UNCH1 + PART2 + PART1 + UNCH2); }
// BINARY ARRAY I/O
// Each 32-bit integer in an array can hold 4 bytes of data.
// The following functions allow us to access all the bits and bytes of an array.
// For example, we could store the word "GOLDSTAR" in an array of 2 elements.
// If memory usage is of concern but speed is not, then we
// This function reads one bit from an array of 32-bit integers.
function ReadBIT(ARRAY, BIT_INDEX) { var LONG = ARRAY[BIT_INDEX >> 5]; var X = BIT_INDEX & 31; if (X) LONG >>>= X; return LONG & 1; }
// This function returns one byte-size int from an array of 32-bit integers.
function ReadBYTE(ARRAY, BYTE_INDEX) { var SHIFT = [0, 8, 16, 24]; var LONG = ARRAY[BYTE_INDEX >> 2]; var X = BYTE_INDEX & 3; if (X) LONG >>>= SHIFT[X]; return LONG & 255; }
// This function overwrites one bit in an array of 32-bit integers.
function WriteBIT(ARRAY, BIT_INDEX, BIT) { BIT &= 1; var INDEX = BIT_INDEX >> 5; var LONG = ARRAY[INDEX]; var MASK = 1 << (BIT_INDEX & 31); if (BIT) LONG |= MASK; else LONG &= (~MASK); ARRAY[INDEX] = LONG; }
// This function writes one byte (int) to an array of 32-bit integers.
function WriteBYTE(ARRAY, BYTE_INDEX, BYTE) { BYTE &= 255; var INDEX = BYTE_INDEX >> 2; var LONG = ARRAY[INDEX]; var MASK = [0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0x00FFFFFF]; var X = BYTE_INDEX & 3; if (X) BYTE <<= (X << 3); LONG &= MASK[X]; LONG += BYTE; ARRAY[INDEX] = LONG; }
// This function writes a word (int) to an array of 32-bit integers.
function WriteWORD(ARRAY, WORD_INDEX, WORD) { WORD &= 0xFFFF; var MASK = [0xFFFF0000, 0x0000FFFF]; var INDEX = WORD_INDEX >> 1; var LONG = ARRAY[INDEX]; var X = WORD_INDEX & 1; if (X) WORD <<= 16; LONG &= MASK[X]; LONG += WORD; ARRAY[INDEX] = LONG; }
// This function writes a string into an array of 32-bit integers. See Also: fromCharCodeArray()
function WriteSTRING(ARRAY, BYTE_INDEX, STRING) { var i, C; for (i = 0; i < STRING.length; i++) { C = STRING.charCodeAt(i) & 255; WriteBYTE(ARRAY, BYTE_INDEX++, C); } }
// ENCRYPTION
SEED = 1;
RANDOM = [];
RND = [55, 170, 125.92057732, 416.71870025, 193.23450510];
//////////////////////////////////////////////////
// v2019.12.27
// Returns an encrypted string. The "password" consists
// of four decimal numbers stored in a global array
// named RND[], and RND[0] is the initial seed.
// Usage: STRING = EncryptString(STRING)
//
function EncryptString(S)
{
var c, L = S.length, OUTPUT = [];
while (L--)
{
RND[0] *= RND[2] + RND[3];
RND[0] -= RND[4] * Math.floor(RND[0] / RND[4]);
c = S.charCodeAt(L);
c = ((c & 3) << 6) | (c >> 2);
OUTPUT[L] = String.fromCharCode((c ^ RND[1]) - Math.floor(RND[0]) & 255);
}
return OUTPUT.join("");
}
//////////////////////////////////////////////////
// v2019.12.27
// Decrypts a string. The "password" consists of
// four decimal numbers stored in a global array
// named RND, and RND[0] is the initial seed.
// Usage: STRING = DecryptString(STRING)
//
function DecryptString(S)
{
var c, L = S.length, OUTPUT = [];
while (L--)
{
RND[0] *= RND[2] + RND[3];
RND[0] -= RND[4] * Math.floor(RND[0] / RND[4]);
c = ((S.charCodeAt(L) + Math.floor(RND[0])) & 255) ^ RND[1];
OUTPUT[L] = String.fromCharCode(((c & 63) << 2) | (c >> 6));
}
return OUTPUT.join("");
}
//////////////////////////////////////////////////
// These two functions encrypt/decrypt string S using passcode P which is an optional argument.
// The encryption algorithm in this function incorporates a random number generator, addition, bit rotate, and CRC check. Decrypt() will return an empty string if the data has been modified or tampered with in any way.
function Encrypt(S,P){if(S=="")return"";var c,i=S.length+4;if(typeof(P)=="undefined")P=0;c=Math.round((new Date()).getMilliseconds()+Math.random()*64536);P+=i+c;S=(S+"7X29"+IntStr(c)).split("");while(i--){P=(P*389+1.1)%2875;c=S[i].charCodeAt(0)-(P&255);c=ROL8(c,(P&0x700)>>8);S[i]=String.fromCharCode(c);}return S.join("");}
function Decrypt(S,P){var c,i,L=S.length-6;if(L<1)return"";if(typeof(P)=="undefined")P=0;i=L+4;P+=StrInt(S.slice(i))+i;S=S.split("");while(i--){P=(P*389+1.1)%2875;c=S[i].charCodeAt(0);c=ROL8(c,8-(P&0x700)>>8);c=(c+(P&255))&255;S[i]=String.fromCharCode(c);}S=S.join("");return(S.substr(L,4)=="7X29")?S.substr(0,L):"";}
// This function replaces each letter, number, $, and _ character with a different character from the same set and returns a new string. Uses the XOR operator. What this function does is more like plain encoding than encryption.
function tXt(S) {var c,P,i=S.length,$=[],A="0123456789$ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_",L=37;while(i--){c=S.charAt(i);P=A.indexOf(c);if(P>=0){P^=((i&3)*77+(i&3)+L++);c=A.charAt(P&63);}$[i]=c;}return $.join("");}
// This function calculates the checksum on a string and returns a 32-bit integer.
function Checksum(S) { var C = 0x55555555, i = S.length; while (i--) { C += ((S.charCodeAt(i) + 1) << ((i & 3) << 3)); C = ((C >> 31) & 1) | ((C << 1) & 0xFFFFFFFe); } return C & 0xFFFFFFFF; }
// This function saves random values in an array. A random value may be provided as an argument or the current time is used.
function CollectRND() { RANDOM.length = 255; var R = (arguments.length) ? arguments[0] : now(); RANDOM.unshift(R); }
// This function returns random numbers between 0 and 255.
function RND(SALT) { SEED = Math.floor(Math.abs(SEED * (SALT + 37719) - 42117361) % 9869513); return Math.floor(SEED / 38703.968); }
// This function returns a 14-digit random number between 0 and 1.
function RNDL(SALT) { var N = []; while (N.length < 4) { RND(SALT); N.push(SEED); } return "0." + N.join("").substr(0, 14).split("").reverse().join(""); }
// This function returns a word-size random number between 0 and 65536.
function RNDW(SALT) { RND(SALT); return Math.floor(SEED / 150.599); }
// This function returns a simple 4-byte CRC.
function CRC(S) { var X, i = S.length; SEED = i; while (i-- > 0) X = RNDW(S.charCodeAt(i)); return X; }
// This function encrypts a string using the XOR operator.
function XCrypt(S, P) { var i, OUTPUT = []; SEED = CRC(P); for (i = 0; i < S.length; i++) OUTPUT.push(String.fromCharCode(RND(i) ^ S.charCodeAt(i))); return OUTPUT.join(""); }
// This function can shuffle the contents of an array or put the elements back in the original order.
function Shuffle(ARRAY, UNDO) { var i, R = []; var L = ARRAY.length; for (i = 0; i < L; i++) R.push(Math.floor(RNDL(i) * L)); if (UNDO) { for (i = 0; i < L; i++) Swap(ARRAY, R[i], i); } else { for (L--; L >= 0; L--) Swap(ARRAY, R[L], L); } }
// This function doubles the size of input string and returns a new string. The new string will not resemble the input string in any way or form. It will look like a totally mixed up encrypted string.
//function AddSalt(S, SET, N) { var S = S.split(""); while (N-- > 0) S.push(SET.charAt(Math.round(Math.random()*(SET.length-1)))); Shuffle(S, 0); return S.join(""); }
function AddSalt(TEXT) { var i, A, B, C, X = []; for (i = 0; i < TEXT.length; i++) { C = TEXT.charCodeAt(i); A = Math.round(Math.random() * 255); B = (C - A) & 255; X.push(A); X.push(B); } for (i = 0; i < X.length; i++) X[i] = String.fromCharCode(X[i]); return X.join(""); }
// This function removes the extra bytes added to it by AddSalt()
//function RemoveSalt(S, N) { var S = S.split(""); Shuffle(S, 1); S.length -= N; return S.join(""); }
function RemoveSalt(TEXT) { var i, A, B, C, X = []; for (i = 0; i < TEXT.length; i++) { A = TEXT.charCodeAt(i++); B = TEXT.charCodeAt(i); C = (A + B) & 255; X.push(String.fromCharCode(C)); } return X.join(""); }
CollectRND();
// COOKIE FUNCTIONS
// While items in localStorage can hold binary data, but
// cookie values may only contain the following bytes:
COOKIEJAR = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz []{}()<>-~+:?@#$&%*^`',_/|\\\t\"!.";
// Cookies expire; localStorage items do not.
// The most important difference between cookies and
// localStorage is that cookies are sent over the
// internet with each request, therefore the size of
// all cookies together on a page cannot exceed 5KB.
// LocalStorage is not automatically sent over the
// wire, therefore its capacity can be much larger
// (usually 10MB).
// The SetCookie() function sets a cookie in the
// client's browser that expires in N days. N can be
// either a number or string date such as "Feb 3 2014".
// When N is omitted, the default value for N is 1825,
// which is exactly 5 years.
// When N is zero, a session cookie is created that
// will be deleted when the browser is closed.
// If the VALUE is an empty string, the cookie will be
// deleted. This function returns 1 on success,
// or 0 if the cookie could not be created.
// Usage: STATUS = SetCookie(NAME, VALUE, EXPIRATION)
function SetCookie(N, V, E) {if(typeof(N)==="undefined"||N.length==0)return 0;if(typeof(V)==="undefined")V="";var VL=V.toString().length;if(VL&&document.cookie.length+N.length+VL>5000)return 0;if(!VL)E="Jan 01 1970 00:00:00 GMT";if(typeof(E)==="undefined")E=157680000;if(!isNaN(E)){if(E>0){var T=new Date();T.setTime(T.getTime()+E*1000);E=T.toGMTString();}else E="";}document.cookie=N+"="+V+";Expires="+E+";";return 1;}
//function SetCookie(NAME, VALUE, N) {if(typeof(NAME)==="undefined"||NAME.length==0)return 0;if(typeof(VALUE)==="undefined")VALUE="";var VL=VALUE.toString().length;if(VL&&document.cookie.length+NAME.length+VL>5000)return 0;if(!VL)N="Jan 01 1970 01:01:01 GMT";if(typeof(N)==="undefined")N=1825;if(!isNaN(N)){if(N>0){var T=new Date();T.setTime(T.getTime()+N*86400000);N=T.toGMTString();}else N="";}document.cookie=NAME+"="+VALUE+";Expires="+N+";";return 1;}
// Returns the value of a cookie. Cookie names are
// always case sensitive! If the cookie doesn't
// exist, then an empty string is returned.
function GetCookie(NAME) {var P,K=" "+document.cookie;P=K.indexOf(" "+NAME+"=");if(P<0)return"";K=K.slice(P+NAME.length+2);P=K.indexOf(";");if(P>=0)K=K.substr(0,P);return K;}
// Returns an array containing the names of existing cookies.
function GetCookieNames() {var i,S,L,C,K=document.cookie+";",SAVE=1,A=[];for(L=S=i=0;i32)if(L++==0)S=i;}return A;}
// Empties the named cookie and marks it for deletion.
function DeleteCookie(NAME) {document.cookie=NAME+"=;Expires=Jan 01 1970 01:01:01 GMT";}
// Deletes all cookies.
// Returns the number of cookies found & deleted.
function DeleteAllCookies() {var i,S,L,C,K=document.cookie+";",SAVE=1,CC=0;for(L=S=i=0;i32)if(L++==0)S=i;}return CC;}
// Creates a cookie that expires in 5 years.
//function SetCookie(NAME, VALUE) { var E = new Date(); E.setFullYear(E.getFullYear() + 5); document.cookie = NAME + "=" + VALUE + ";Expires=" + E.toGMTString(); }
// Returns the value of a cookie.
//function GetCookie(NAME) { var i, e, s, K = document.cookie.split(";"); for (i = 0; i < K.length; i++) { for (s = 0; K[i].charCodeAt(s) < 33; s++); e = K[i].indexOf("="); if (K[i].substring(s, e) == NAME) return K[i].slice(++e); } return ""; }
// Completely erases a cookie.
//function DeleteCookie(NAME) { document.cookie = NAME + "=;Expires=Thu, 01 Jan 1970 00:00:01 GMT"; }
// Deletes all cookies.
//function DeleteAllCookies() { var i, s, e, X, K = document.cookie.split(";"); for (i = 0; i < K.length; i++) { e = K[i].indexOf("="); if (e < 0) X = ""; else { for (s = 0; K[i].charCodeAt(s) < 33; s++); X = K[i].substring(s, e); } DeleteCookie(X); } }
// Creates a name-value pair and stores it in localStorage.
function SetItem(NAME, VALUE) { try { with (window.localStorage) { setItem(NAME, VALUE); if (getItem(NAME) == VALUE) return 1; } } catch (e) {} return 0; }
// Returns a value from localStorage. Returns null if failed or not found.
function GetItem(NAME) { var V = null; try { V = localStorage.getItem(NAME); } catch (e) {} return V; }
// Deletes a value from localStorage.
function DeleteItem(NAME) { try { with (window.localStorage) { setItem(NAME, ''); clear(NAME); } return 1; } catch (e) {} return 0; }
// Deletes everything from localStorage.
function DeleteAllItems() { try { localStorage.removeItem(); return 1; } catch (e) {} return 0; }
// Saves an encrpyted cookie that expires in 5 years.
// Also removes illegal characters from the cookie before saving it!
function SetXCookie(NAME, VALUE) { var i, c, r = VALUE.length, X = []; for (i = 0; i < VALUE.length; i++) { c = COOKIEJAR.indexOf(VALUE.charAt(i)); if (c < 0) continue; r = (r * 133) % 179; c = c - r; while (c < 0) c += COOKIEJAR.length; X.push(COOKIEJAR.charAt(c)); } SetCookie(NAME, X.join("")); }
// Returns the value of an encrypted cookie.
function GetXCookie(NAME) { var X = GetCookie(NAME); var i, c, r = X.length, K = []; for (i = 0; i < X.length; i++) { c = COOKIEJAR.indexOf(X.charAt(i)); r = (r * 133) % 179; c = (c + r) % COOKIEJAR.length; K.push(COOKIEJAR.charAt(c)); } return K.join(""); }
// This function saves an encryted string in localStorage and
// in a cookie. You may specify a password string as a third
// argument, or else the function will use a default password.
// (Note: This function encrypts only the VALUE, not the NAME.)
function SetValue(NAME, VALUE) { var PW = (arguments.length > 2) ? arguments[2] : ""; VALUE += ""; VALUE = XCrypt(VALUE, PW); SetCookie(NAME, EncodeB64(VALUE)); try { localStorage.setItem(NAME, VALUE); } catch (e) {} }
// This function retrieves an encrypted string from localStorage
// or from a cookie. Again, you may specify a password string as a
// third argument, or else the function will use a default password.
function GetValue(NAME) { var PW = (arguments.length > 2) ? arguments[2] : ""; var VALUE = ""; var C = DecodeB64(GetCookie(NAME)); try { VALUE = localStorage.getItem(NAME); } catch (e) {} if (VALUE == null || C.length > VALUE.length) VALUE = C; return XCrypt(VALUE, PW); }
// This function stores a test cookie to see if cookies are working.
function CookieTest() { var A = "ABC" + Math.round(Math.random() * 1000000); SetCookie(A, A); var X = GetCookie(A); DeleteCookie(A); if (X == A) return 2; return navigator.cookieEnabled ? 1 : 0; }
// This function stores a string in localStorage to see if it is working.
function StorageTest() { var A = "ABC" + Math.round(Math.random() * 1000000); try { with (window.localStorage) { setItem(A, A); if (getItem(A) == A) { removeItem(A); return 2; } } } catch (e) { return 0; } return 1; }
// Extracts a version number from string S starting after pattern A
function ExtractVersion(S, A) { var i, C, P = S.indexOf(A); if (P < 0) return ""; P += A.length + 1; for (i = P; i < S.length; i++) { C = S.charCodeAt(i); if (C < 46 || C > 57) break; } return S.substring(P, i); }
// DETECT OS
OS = PF;
if (PF == "") OS = "FirefoxOS";
if (PF == null) OS = "Android";
if (($ = ExtractVersion(UA, "WINDOWS NT")))
{ if ($ == 5) $ = 2000;
else if ($ == 5.1) $ = "XP";
else if ($ == 6.0) $ = "Vista";
else if ($ == 6.1) $ = 7;
else if ($ == 6.2) $ = 8;
else if ($ == 6.3) $ = 8;
OS = "Win" + $;
}
// DETECT 64-BIT MODE
CPU = ((UA + PF).match(/X86_64|X86-64|WIN64|X64|AMD64|WOW64|IA64|SPARC64|PPC64/i) == null) ? 32 : 64;
// GET BROWSER LANGUAGE
LANGUAGE = (navigator.userLanguage || navigator.language).toUpperCase().replace(/[^[A-Z]/g, "");
// DETECT JAVA
JAVA = navigator.javaEnabled() ? 1 : 0; // CHECK JAVA
// DETECT STORAGE
COOKIES = navigator.cookieEnabled ? 1 : 0;
STORAGE = 0; try { localStorage.getItem("A"); STORAGE = 1; } catch (e) {}
// DETECT WEB BROWSER
// Opera 8.0+ / Firefox 0.8+ / Safari 3+ / GoogleChrome 1+ / IE6
function testCSS(prop) { return prop in document.documentElement.style; }
isOpera = !!(window.opera && window.opera.version);
isFirefox = testCSS('MozBoxSizing');
isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
isChrome = !isSafari && testCSS('WebkitTransform');
isIE = /*@cc_on!@*/false || testCSS('msTransform');
// DETECT BROWSER:
// Opera 8.0+ / Firefox 0.8+ / Safari 3+ / GoogleChrome 1+ / IE6 / Edge 20+
function testCSS(prop) { return prop in document.documentElement.style; }
if (!!(window.opera && window.opera.version) || (!!window.opr && !!opr.addons) || (UA.match(/OPERA|OPR\//i))) $ = "OPERA";
else if (UA.toUpperCase().indexOf("QUPZILLA") >= 0) $ = "QUPZILLA";
else if (UA.toUpperCase().indexOf("K-MELEON") >= 0) $ = "K-MELEON";
else if (Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0) $ = "SAFARI";
else if (testCSS('MozBoxSizing') || typeof InstallTrigger !== 'undefined') $ = "FIREFOX";
else if (testCSS('WebkitTransform') || (!!window.chrome && !!window.chrome.webstore)) $ = "CHROME";
else if (/*@cc_on!@*/false || testCSS('msTransform') || !!document.documentMode) $ = "MSIE";
else if (!isIE && !!window.StyleMedia) $ = "EDGE";
BROWSER = $;
// EXTRACT BROWSER VERSION
if ($ == "SAFARI") $ = "VERSION";
BROWSER_VERSION = ExtractVersion(UA, $);
// HTML FUNCTIONS
HTML = [];
function PRINT(L) { HTML.push(L); }
function FLUSH() { document.write(HTML.join("")); HTML = []; }
function CLS() { HTML = [""]; RENDER(); }
function RENDER() { document.getElementById("SLIDE").innerHTML = HTML.join(""); HTML = []; }
function BUTTON(LABEL, W, H, HANDLE, ACTION, BGCOLOR, TEXTCOLOR) { var BTN_FONT_SIZE = 20; if (WX > 1000 || HX > 1000) BTN_FONT_SIZE = SIZE(6); PRINT(""); BUTTONS++; }
// Changes the transparency of an object. Usage: SetOpacity(ID, ALPHA)
function SetOpacity(E, A) { A = Math.round(A); if (A > 100) A = 100; if (A < 0) A = 0; E = document.getElementById(E); E.style.opacity = A / 100; E.style.filter = "alpha(opacity="+A+")"; }
// Causes an object to float and changes its coordinates.
function SetObjCoords(E, LEFT, TOP) { E = document.getElementById(E); LEFT = Math.round(LEFT); TOP = Math.round(TOP); E.style.position = "ABSOLUTE"; E.style.top = TOP; E.style.left = LEFT; }
function FadeIn(E) { for (var i = 0; i <= 100; i += 10) setTimeout("SetOpacity('" + E + "', " + i + ");", 7*i); }
function FadeOut(E) { for (var i = 0; i <= 100; i += 10) setTimeout("SetOpacity('" + E + "', " + i + ");", 7*(100-i)); }
// DIV or B is a lot faster than TABLE
function DrawBox(LEFT, TOP, WIDTH, HEIGHT, COLOR) { PRINT(""); }
function DrawFrame(LEFT, TOP, WIDTH, HEIGHT, BORDER_WIDTH, COLOR) { PRINT("
"); }
function DrawPixel(LEFT, TOP, COLOR) { PRINT(""); }
function DrawLine(WIDTH, THICKNESS, COLOR, MARGIN) { PRINT("
"); }
function DrawCover(LEFT, TOP, WIDTH, HEIGHT) { var ETC = (arguments.length > 4) ? arguments[4] : ""; PRINT(""); }
function DrawNiceBox(C1, C2, THICKNESS, CONTENT) { var i, $ = [], C = GetColorShades(C1, C2, THICKNESS); for (i = 0; i < THICKNESS; i++) $.push("
"); PRINT($.join("
") + CONTENT); for (i = 0; i < THICKNESS; i++) PRINT("
"); }
// This function estimates the approximate width of each character printed on the screen and returns a number.
function EstimateWidth(TEXT)
{
// CHARSET: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
var Z = "00122320002201011011111111002321333333333123332323323223323010230111110110010211110101121111013";
var $ = TEXT.length;
var i = $, c;
while (i--)
{
c = TEXT.charCodeAt(i);
$ += (c < 32 || c > 126) ? 0 : Z.charCodeAt(c-32) - 47;
}
return $;
}