PageSourceSearch

https://gamechannel.io/freecell-solitaire/v-util.js

js gamechannel.io collected 2026-09-24 15:03:32 UTC 10,688 bytes, 346 lines download raw bytes

1var VAWLT_MAX_COOKIE_AGE =  (15 * 365 * 24 * 60 * 60); // 15 years in the future, not accounting for leap years
2
3function getMMDDYYYY() {
4    var today = new Date();
5    var dd = today.getDate(); 
6    var mm = today.getMonth() + 1; 
7
8    var yyyy = today.getFullYear(); 
9    if (dd < 10) { 
10        dd = '0' + dd; 
11    } 
12    if (mm < 10) { 
13        mm = '0' + mm; 
14    } 
15    return mm + '/' + dd + '/' + yyyy; 
16}
17
18
19///
20// If we don't have an anonymous uuid, let's get one. 
21///
22if (!getPersistedValue("va_uuid")) {
23    setPersistedValue("va_uuid", createGUID());
24    setPersistedValue("va_start_date", getMMDDYYYY());
25}
26
27var vURLParams = new URLSearchParams(window.location.search);
28
29if (vURLParams.has('g') || vURLParams.has('G')) {
30
31    var g = parseInt(vURLParams.get('g') || vURLParams.get('G'), 10);
32    if (!isNaN(g) && g >= 1 && g <= 2) {
33        setPersistedValue("g", g);
34    }
35}
36
37if (vURLParams.has('a') || vURLParams.has('A')) {
38    var av = vURLParams.get('a') || vURLParams.get('A');
39    if (av.indexOf("-") > 0) {
40        var ab = -1;
41        var ae = -1;
42        var aparts = av.split("-");
43        if (aparts.length >= 2) {
44            ab = parseInt(aparts[0]);
45            ae = parseInt(aparts[1]);
46        } else if (aparts.length === 1) {
47            ab = parseInt(aparts[0]);
48            ae = 99;
49        }
50        if (!isNaN(ab) && !isNaN(ae) && ab > 13 && ae >= ab) {
51            setPersistedValue("a", ab + "-" + ae);
52        } 
53    } else {
54        var a = parseInt(vURLParams.get('a') ||vURLParams.get('A'), 10);
55        if (!isNaN(a) && a >= 13) {
56            setPersistedValue("a", a);
57        }
58    }
59}
60
61if (vURLParams.has('i') || vURLParams.has('I')) {
62    var i = vURLParams.get('i') || vURLParams.get('I');
63    var ei = getPersistedValue('i');
64    if (ei) {
65        var eiparts = ei.split("|");
66        var has = false;
67        for (var ii=0; ii < eiparts.length; ii++) {
68            if (eiparts[ii] === i) { console.log("Already has", i); has = true; break; }
69        }
70        if (!has) { setPersistedValue("i", ei + "|"  + i); }
71    } else {
72        setPersistedValue("i", i);
73    }
74}
75
76
77/// Our Vawlt Anonymous Unique User Id. 
78var _VAUUID
79function getVAUUID() {
80    if (!_VAUUID) {  _VAUUID = getPersistedValue("va_uuid"); }
81    return _VAUUID;
82}
83
84function getStartDate() {
85    return getPersistedValue("va_start_date");
86}
87
88///
89// Just for getting started purposees. Maybe not use this guid function in real life due to Math.random
90// TODO: Validate this is ok solution, but we are static site generation at the moment with no backend.
91///
92function S4() {
93    return (((1+Math.random())*0x10000)|0).toString(16).substring(1); 
94}
95function createGUID() {
96    console.log("CREATE GUID TEMPORARY. REPLACE WITH MORE ROBUST SOLUTION");
97    // then to call it, plus stitch in '4' in the third group
98    guid = (S4() + S4() + "-" + S4() + "-4" + S4().substr(0,3) + "-" + S4() + "-" + S4() + S4() + S4()).toLowerCase();
99    return guid;
100}
101
102
103///
104// Can we use local storage?
105///
106function canUseLocalStorage() {
107
108    try {
109        if (localStorage === undefined || localStorage === null) { return false; }
110        const key = createGUID();
111        localStorage.setItem(key, key);
112        localStorage.removeItem(key);
113        return true;
114    } catch (e) {
115        return false;
116    }
117}
118
119///
120// Do we think we are on iOS?
121///
122function isIOS() {
123    return /iPhone|iPod|iPad/.test(navigator.platform);
124}
125
126function isAndroid() {
127    console.log("User Agent is:", navigator.userAgent);
128    return  /(android)/i.test(navigator.userAgent);
129}
130
131function isSafari () {
132    return  navigator.userAgent.toLowerCase().indexOf('safari') > -1;
133}
134
135function isMobile() {
136    return isIOS() || isAndroid(); 
137}
138
139function isDesktop() {
140    return !isMobile();
141}
142
143function isSamsung() {
144    //return navigator.userAgent.match(/SAMSUNG|Samsung|SGH-[I|N|T]|GT-[I|N]|SM-[A|N|P|T|Z]|SHV-E|SCH-[I|J|R|S]|SPH-L/i);
145    return /SamsungBrowser/.test(navigator.userAgent);
146}
147
148function isChrome() {
149    return !!window.chrome;
150}
151
152///
153// What is our root domain? E.g subdomain.domain.com will return domain.com. localhost is localhost
154///
155function rootDomain() {
156    if (location.hostname === "localhost") { return location.hostname; }
157    var rootDomain = location.hostname.split('.').reverse()[1] + "." + 
158                     location.hostname.split('.').reverse()[0];
159    console.log("RootDomain:" + rootDomain);
160    return rootDomain;
161}
162
163///
164// Set a cookie value by key. Set persisted to true to make "permanent"
165///
166function setCookieValue (key, value, persist=true) {
167    var cookieStr =""  + key + "=" + value + ";";
168    if (persist) { cookieStr  += " max-age=" + VAWLT_MAX_COOKIE_AGE +";"; }
169    cookieStr +=" domain=" + rootDomain()  +"; path=/;";
170    console.log("CookieStr:" + cookieStr);
171    document.cookie = cookieStr;
172}
173
174///
175// Get a cookie value by key
176///
177function getCookieValue (key) {
178    var d=[],
179    e=document.cookie.split(";");
180    a=RegExp("^\\s*"+key+"=\\s*(.*?)\\s*$");
181    for(var b=0;b<e.length;b++){
182        var f=e[b].match(a);
183        f&&d.push(f[1])
184    }
185    return (d ? d[0] : undefined);
186}
187
188///
189// Clear out a cookie value 
190///
191function clearCookieValue (key) {
192    var cookieStr ="" + key + "=; expires=Thu, 01 Jan 1970 00:00:01 GMT"; // Valid Epoch usage. WITNESS!
193    document.cookie = cookieStr;
194}
195
196///
197// Persisted Values try to set values in both cookie and localstorage
198// Localstorage has priority over cookies and should be sync'd. reading a value will result
199// in the cookie being set as well. 
200///
201function getPersistedValue(key, defaultVal=undefined) {
202    var val = undefined;
203    
204    // We check the cookie value first, as it is second priority
205    var cookieVal = getCookieValue(key) 
206    val = cookieVal; // Initially set the value to be the cookie value (including undefined)
207
208    // Can we use local storage? If so, grab the value
209    if (canUseLocalStorage()) {
210        localVal = localStorage.getItem(key);
211        // We have a local value
212        if (localVal) { 
213            val = localVal;  // return local
214            setCookieValue(key, localVal); // Set the cookie value to sync
215
216        // We don't have a local, but we have a cookievalue, so use that and set local
217        } else if (cookieVal) { localStorage.setItem(key, cookieVal); }     
218    }
219    
220    // return the value if we have one, otherwise return default value.
221    return (val ? val : defaultVal);
222    
223}
224
225///
226// Set a value in the most persistent way we can. Set in a cookie and localStorage if possible
227///
228function setPersistedValue(key, val) {
229    console.log("Setting Persistent Value", val);
230    setCookieValue(key, val, true);
231    if (canUseLocalStorage()) {
232        localStorage.setItem(key, val);
233    }
234}
235
236///
237// Do we think we are in a PWA instance?
238///
239function isPWA() {
240    var displayModes = ["fullscreen", "standalone", "minimal-ui"];
241
242    for (var ii=0; ii < displayModes.length; ii++) {
243        var displayMode = displayModes[ii];
244        if (window.matchMedia('(display-mode: ' + displayMode + ')').matches) {
245            console.log("is PWA true with displaymode:" + displayMode);
246            return true;
247        }
248    }
249    console.log("is PwA no match");
250    return false;
251}
252// gaReportEvent will use this to queue up pending events if ga() is not defined
253// This can happen if a game is using defer.js to push all 3rd party libs/etc to load after the page is fully loaded
254// call flushPendingGAEvents() to clear. gaReportEvent will also call  
255var _pendingGAEvents = [];
256
257///
258// Send this event to google analytics
259///
260function gaReportEvent(category, action, label, value = 1) {
261    if (typeof ga != "function") {
262        console.log("GA not ready yet");
263        _pendingGAEvents.push({category: category, action: action, label: label, value: value});
264        return; // We don't have ga loaded yet
265    }
266
267    // If there are any things pending, let's get them out of here before we do our call. 
268    // Note: We don't use the queue unnecessarily as ga will handle queueing itself. We have our own queue in just a defer load case
269    flushPendingGAEvents();
270
271    console.log("GA Report Event: Category:" + category + " Action:" + action + " Label:" + label + " Value:" + value);
272    ga('send', {
273        hitType: 'event',
274        eventCategory: category,
275        eventAction: action,
276        eventLabel: label,
277        eventValue: value,
278        hitCallback: function() {
279            console.log("gaReportEvent callback");
280        }
281    });
282}
283
284function flushPendingGAEvents() {
285
286    if (_pendingGAEvents.length > 0) {
287        console.log("Flusing pending GA events*********");
288        for (var ii=0; ii < _pendingGAEvents.length; ii++ ) {
289            var pending = _pendingGAEvents.pop();
290            ga('send', {
291                hitType: 'event',
292                eventCategory: pending.category,
293                eventAction: pending.action,
294                eventLabel: pending.label,
295                eventValue: pending.value,
296                hitCallback: function() {
297                    console.log("gaReportEvent callback");
298                }
299            });
300        }
301    }
302}
303
304// Is WebView Code
305//var isIosWebview =/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent)
306//  if (typeof Android != "undefined") { means you are in a webview
307
308var vGameConfig = {};
309//
310// Parse out the game configuration from the gc paramater and/or persistent storage.
311// For now the full string is stored, not distinct values. 
312// The gc parameter is encoded with | as the separator. 
313function initGameConfig(gameName="default") {
314    var configString = "";
315    if (vURLParams.has('gc') || vURLParams.has('GC')) {
316        configString = vURLParams.get('gc') || vURLParams.get('GC');
317    } else {
318        configString = getPersistedValue(gameName + "_gc");
319    }
320    
321    // Do we have a config string to parse?
322    if (!configString) { 
323        return;  // If not, let's bail
324    } else {
325        setPersistedValue(gameName + "_gc", configString); // Store the config string for future use.
326    }
327
328    console.log("ConfigString", configString);
329    var configParts = configString.split("|");
330    console.log("ConfigParts", configParts);
331    for (var ii=0; ii < configParts.length; ii++) {
332        console.log("Checking Parts", configParts[ii]);
333        switch(configParts[ii]) {
334           
335            case "cf0":   // Card Faces
336                console.log("SZetting card faces to false");
337                vGameConfig["card_faces"] = "false";
338                break;
339
340            case "cf1":
341                vGameConfig["card_faces"] = "true";
342                break;
343        }
344    }
345    console.log("vGameConfig", vGameConfig);
346}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.