PageSourceSearch

https://www.cybersecuritydive.com/static/js/divecounter.js?511915290926

js cybersecuritydive.com collected 2026-10-01 07:35:13 UTC 16,471 bytes, 476 lines download raw bytes

1function Divecounter() {
2  // Number of pages to visit until interstitial is displayed
3  const interstitialPageCount = 3;
4  // Number of days after the interstitial was last displayed before it can be displayed again
5  const interstitialMinDays = 3;
6  // Number of content (non-trendline) pages a user must view before the metering gate can show
7  const meteringPageCount = 2;
8  // Cookie names for the three-cookie split (Osano compliance)
9  const coreCookieName = '_divecounter_core';
10  const personalizationCookieName = '_divecounter_personalization';
11  const marketingCookieName = '_divecounter_marketing';
12  const cookieExpire = 365;
13  // Core data (cookie classified in Osano as "Essential")
14  let coreData = {
15    page_views: 0,
16    last_shown: 0,
17    first_page_view: 0,
18    is_staff: false,
19    metering_page_views: 0,
20  };
21  // Personalization data (cookie classified in Osano as "Personalization")
22  let personalizationData = {
23    is_subscriber: false,
24  };
25  // Marketing data (cookie classified in Osano as "Marketing")
26  let marketingData = {
27    is_subscriber: false,
28  };
29
30  this.testing = function() {
31    // Disable interstitial testing params if configured (e.g., for WardsAuto to prevent bot signups)
32    if (this.getOption('disableInterstitialTestingParams')) {
33      return false;
34    }
35    return location.search.indexOf('show_hit_ad') !== -1 || location.search.indexOf('show_interstitial') !== -1;
36  };
37
38  this.resetCookie = function() {
39    // Expiration in past deletes cookies.
40    setCookie(coreCookieName, '', -100);
41    setCookie(personalizationCookieName, '', -100);
42    setCookie(marketingCookieName, '', -100);
43    // Also delete old _divecounter cookie if it exists. TODO: remove refs to old _divecounter cookie after 5/1/2027
44    setCookie('_divecounter', '', -100);
45  };
46
47  this.countPageViews = function() {
48    if (coreData.page_views === 0) {
49      coreData.first_page_view = (new Date()).getTime();
50    }
51    coreData.page_views++;
52    return coreData.page_views;
53  };
54
55  this.canShow = function(pageCount = interstitialPageCount, minDays = interstitialMinDays) {
56    // Check personalization data to see if user is a subscriber
57    if (personalizationData.is_subscriber) {
58      return false;
59    }
60    // Interstitial is displayed after 'pageCount' pages, no less than 'minDays' days from the last time it was displayed
61    if (coreData.page_views > 0 && coreData.page_views % pageCount === 0) {
62      if (!coreData.last_shown || (new Date()).getTime() - coreData.last_shown >= minDays * 24 * 60 * 60 * 1000) {
63        return true;
64      }
65    }
66    return false;
67  };
68
69  this.markShown = function() {
70    coreData.last_shown = (new Date()).getTime();
71  };
72
73  this.countMeteringPageViews = function() {
74    coreData.metering_page_views++;
75    return coreData.metering_page_views;
76  };
77
78  this.canShowMeteringGate = function(pageCount = meteringPageCount) {
79    // Once the user has viewed 'pageCount' metered pages, keep gating them on every metered page after that.
80    return coreData.metering_page_views >= pageCount;
81  };
82
83  // Helper function to check Osano consent state
84  const hasOsanoConsent = function(category) {
85    // If Osano isn't loaded, conservatively assume no consent
86    // Optional chaining returns undefined if any part of the chain is undefined
87    const consent = window.Osano?.cm?.getConsent?.();
88    // Osano uses 'ACCEPT' / 'DENY' strings, not booleans
89    return consent?.[category] === 'ACCEPT';
90  };
91
92  this.markSubscriber = function(valueIn) {
93    // Typecast to bool with default value of true.
94    const value = (typeof valueIn === 'undefined') ? true : !!valueIn;
95
96    // Only set personalization if user has consented to Personalization
97    if (hasOsanoConsent('PERSONALIZATION')) {
98      personalizationData.is_subscriber = value;
99    } else {
100      personalizationData.is_subscriber = false;
101    }
102
103    // Only set marketing if user has consented to Marketing
104    if (hasOsanoConsent('MARKETING')) {
105      marketingData.is_subscriber = value;
106    } else {
107      marketingData.is_subscriber = false;
108    }
109  };
110
111  this.markStaff = function(valueIn) {
112    // Typecast to bool with default value of true.
113    const value = (typeof valueIn === 'undefined') ? true : !!valueIn;
114    coreData.is_staff = value;
115  };
116
117  this.save = function() {
118    writeCoreData();
119    writePersonalizationData();
120    writeMarketingData();
121  };
122
123  // Accessor methods for specific cookie data
124  this.getCoreData = function() {
125    return coreData;
126  };
127
128  this.getPersonalizationData = function() {
129    return personalizationData;
130  };
131
132  this.getMarketingData = function() {
133    return marketingData;
134  };
135
136  this.getOption = function(key) {
137    const defaults = {
138      showSignupAd: false,
139      showWhichAd: false, /** "original" or "choice" **/
140      markStaff: false,
141      isMeteringPage: false,
142    };
143    if ( (typeof divecounter_settings !== 'undefined') && (key in divecounter_settings) ) {
144      return divecounter_settings[key];
145    }
146    return defaults[key];
147  };
148
149  // The purpose of this method is to make debugging easier by printing a string that consists of
150  // cookie values setup in `divecounter.js` and screen dimensions
151  this.prettyPrint = function() {
152    let s = '';
153
154    // Core data
155    for (const core_key in coreData) {
156      if (!coreData.hasOwnProperty(core_key)) continue;
157      let core_value = coreData[core_key];
158      // Check for keys to convert to date strings.
159      if (['first_page_view', 'last_shown'].indexOf(core_key) >= 0) {
160        if (parseInt(core_value, 10) > 0) {
161          core_value = (new Date(parseInt(core_value, 10))).toString(); // JS timestamp to string.
162        } else {
163          core_value = '';
164        }
165      }
166      s += core_key + ': ' + core_value + '\n';
167    }
168
169    // Personalization data
170    s += 'is_subscriber (personalization): ' + personalizationData.is_subscriber + '\n';
171
172    // Marketing data
173    s += 'is_subscriber (marketing): ' + marketingData.is_subscriber + '\n';
174
175    // Add in bonus stats not technically part of divecounter data.
176    s += 'initial referrer: ' + getCookie('_referrer') + '\n';
177    s += 'screen dimensions: ' + window.screen.availWidth.toString() + 'x' + window.screen.availHeight.toString() + '\n';
178
179    return s.trim();
180  };
181
182  const setCookie = function(c_name, value, expiredays) {
183    const exdate = new Date();
184    exdate.setDate(exdate.getDate() + expiredays);
185    document.cookie = c_name + '=' + escape(value) +
186            ((expiredays === null) ? '' : ';expires=' + exdate.toUTCString()) + '; path=/';
187  };
188
189  const getCookie = function(c_name) {
190    let c_start;
191    let c_end;
192    if (document.cookie.length > 0) {
193      c_start = document.cookie.indexOf(c_name + '=');
194      if (c_start !== -1) {
195        c_start = c_start + c_name.length + 1;
196        c_end = document.cookie.indexOf(';', c_start);
197        if (c_end === -1) c_end = document.cookie.length;
198        return unescape(document.cookie.substring(c_start, c_end));
199      }
200    }
201    return '';
202  };
203
204  // Core cookie read/write functions
205  const readCoreData = function() {
206    const c = getCookie(coreCookieName);
207    if (c !== '') {
208      const arr = c.split('\t');
209      coreData.page_views = arr[0];
210      coreData.last_shown = arr[1];
211      if (arr.length > 2) {
212        coreData.first_page_view = arr[2];
213      }
214      if (arr.length > 3) {
215        coreData.is_staff = !!parseInt(arr[3], 10);
216      }
217      if (arr.length > 4) {
218        coreData.metering_page_views = arr[4];
219      }
220    }
221  };
222
223  const buildCoreCookie = function() {
224    const arr = [
225      coreData.page_views,
226      coreData.last_shown,
227      coreData.first_page_view,
228      coreData.is_staff ? 1 : 0,
229      coreData.metering_page_views,
230    ];
231    return arr.join('\t');
232  };
233
234  const writeCoreData = function() {
235    setCookie(coreCookieName, buildCoreCookie(), cookieExpire);
236  };
237
238  // Personalization cookie read/write functions
239  const readPersonalizationData = function() {
240    const c = getCookie(personalizationCookieName);
241    if (c !== '') {
242      personalizationData.is_subscriber = !!parseInt(c, 10);
243    }
244  };
245
246  const writePersonalizationData = function() {
247    setCookie(personalizationCookieName, personalizationData.is_subscriber ? '1' : '0', cookieExpire);
248  };
249
250  // Marketing cookie read/write functions
251  const readMarketingData = function() {
252    const c = getCookie(marketingCookieName);
253    if (c !== '') {
254      marketingData.is_subscriber = !!parseInt(c, 10);
255    }
256  };
257
258  const writeMarketingData = function() {
259    setCookie(marketingCookieName, marketingData.is_subscriber ? '1' : '0', cookieExpire);
260  };
261
262  // Auto-load all cookies on initialization
263  readCoreData();
264  readPersonalizationData();
265  readMarketingData();
266
267  // Deleting old _divecounter cookie on first load. TODO: Remove any _divecounter cookie code after 5/1/2027
268  if (getCookie('_divecounter') !== '') {
269    setCookie('_divecounter', '', -100);
270  }
271}
272
273
274function divecounter_close_ad() {
275  $.modal.close();
276  // adds back in scrolling to body
277  $('body').removeClass('no-scroll');
278}
279
280function isAtLeastOneNewsletterSelected() {
281  return $('#newsletter-list-section li input:checked').length > 0;
282}
283
284function isSignupWithMultiPub() {
285  return $('#newsletter-list-section li input').length > 0;
286}
287
288function isNewsletterSelectionValid() {
289  return isSignupWithMultiPub() ? isAtLeastOneNewsletterSelected() : true;
290}
291
292function isUserConsentChecked() {
293  return $('#interstitial-consent-container input:checked').length > 0;
294}
295
296function windowLargeEnough() {
297  return $(window).width() > 640 && $(window).height() > 640;
298}
299
300function divecounter_open_ad() {
301  // Figure out if window is wide/high enough to show a prestitial
302  if (windowLargeEnough()) {
303    $(function() {
304      var $form = $('#signup-inter').find('form');
305      $form.find('.newsletter-partner').hide(); // hide all partnership info, see #1029
306      var current_dialog;
307      $('#signup-inter').modal({
308        minWidth: 400,
309        maxWidth: 600,
310        minHeight: 180,
311        autoResize: true,
312        autoPosition: true,
313        overlayClose: false,
314        focus: false,
315        opacity: 80,
316        closeHTML: `<a href="#" title="${window.pgettext('verb', 'Close')}" class="modal-close"></a>`,
317        onClose: divecounter_close_ad,
318        // force resize of box. See https://stackoverflow.com/questions/1407059/jquery-simplemodal-dynamic-height
319        onShow: function(dialog) {
320          $('#interstitial-error').hide();
321          current_dialog = dialog;
322          // prevents scrolling on body when modal is open
323          $('body').addClass('no-scroll');
324          dialog.container.css('height', 'auto');
325          $.modal.setContainerDimensions();
326          $.modal.setPosition();
327        },
328      });
329
330
331      // add email checking -- see email_check_js.html
332      $form.find('input.email').on('blur', function() {
333        checkEmailAndRespond(this);  // eslint-disable-line no-undef
334      });
335
336      $form.find('input.email').focus();
337      if (current_dialog !== 'undefined') {
338        $(current_dialog.container).css('height', 'auto');
339      }
340
341      // Validation for submit.
342      $('#signup-inter form').submit(function(event) {
343        var email_regex =  new RegExp('[^@]+@[^@]+[\.][^@]+');
344        var email_value = $(this.email).val();
345        var match_test = email_regex.test(email_value);
346        var $interstitialError = $('#interstitial-error');
347        var error_msg = '';
348
349        $interstitialError.hide();
350        $(this).find('input[type=email]').removeClass('form-error__highlight');
351
352        if (match_test && isNewsletterSelectionValid() && isUserConsentChecked()) {
353          return true;
354        } else if (!match_test) {
355          error_msg = window.gettext('That is not a valid email address. Please enter a valid email.');
356          $(this).find('input[type=email]').addClass('form-error__highlight');
357        } else if (!isNewsletterSelectionValid() && !isUserConsentChecked()) {
358          error_msg = window.gettext('You must select at least one newsletter and agree to our Terms of Use and Privacy Policy.');
359        } else if (!isUserConsentChecked()) {
360          error_msg = window.gettext('You must agree to our Terms of Use and Privacy Policy.');
361        } else if (!isNewsletterSelectionValid()) {
362          error_msg = window.gettext('Please select at least one newsletter.');
363        }
364
365        $interstitialError.text(error_msg);
366        $interstitialError.show();
367        // force resize of box. See https://stackoverflow.com/questions/1407059/jquery-simplemodal-dynamic-height
368        $('#simplemodal-container').css({
369          'height': 'auto',
370          'max-height': '90%',
371        });
372        // Make sure the content is scrollable if it exceeds the container height
373        $('.simplemodal-wrap').css('overflow', 'scroll');
374        $.modal.setContainerDimensions();
375        $.modal.setPosition();
376        event.preventDefault();
377        return false;
378      });
379
380      // wait a moment and then allow user to close by clicking on the background
381      setTimeout(function() { $('.simplemodal-overlay').click($.modal.close); }, 750);
382    });
383  }
384}
385
386var divecounter = new Divecounter();
387
388divecounter.countPageViews();
389
390if (divecounter.getOption('isMeteringPage')) {
391  divecounter.countMeteringPageViews();
392}
393
394if (window.location.search.indexOf('utm_source=Sailthru') !== -1) {
395  // if they came from a newsletter, assume they are a subscriber
396  divecounter.markSubscriber();
397}
398
399if (divecounter.getOption('markStaff')) {
400  divecounter.markStaff();
401}
402
403if (divecounter.getOption('showSignupAd') || divecounter.testing()) {
404  if (divecounter.canShow() || divecounter.testing()) {
405    // Use a 50 ms interval to detect whether prestitial.js has determined whether the
406    // page is prestitial eligible or if the prestitial ad was empty. Interstitial should display only if
407    // prestitial is not displaying - prestitial should always have preference.
408    var prestitial_sniffer = setInterval(function() {
409      if (typeof prestitial_ad_is_empty === 'undefined' || prestitial_ad_is_empty === true) {  // eslint-disable-line no-undef
410        clearInterval(prestitial_sniffer);
411        divecounter_open_ad();
412        // Don't set cookies if we're testing
413        if (!divecounter.testing()) {
414          divecounter.markShown();
415          divecounter.save();
416        }
417      } else if (typeof prestitial_ad_is_loaded !== 'undefined' && prestitial_ad_is_loaded === true) {  // eslint-disable-line no-undef
418        // If the prestitial loads, we can stop sniffing
419        clearInterval(prestitial_sniffer);
420        clearInterval(window.prestitial_sniffer_clear);
421      }
422      // Make sure prestitial_ads exists and we only set the timeout once
423      if (typeof window.prestitialAds !== 'undefined' && typeof window.prestitial_sniffer_clear === 'undefined') {
424        // Stop looking for the prestitial after the prescribed timeout + 1 second of flex
425        window.prestitial_sniffer_clear = setTimeout(
426          function() {
427            clearInterval(prestitial_sniffer);
428          },
429          3900  // this number is 2900 from prestitial.html + 1000
430        );  // eslint-disable-line no-undef
431      }
432    }, 50);
433  }
434}
435
436divecounter.save();
437
438//
439// Following is not actually stored in divecounter cookier (yet)
440//
441
442// Save initial referrer
443(function() {
444  function createCookie(name, value, days) {
445    if (days) {
446      var date = new Date();
447      date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
448      var expires = '; expires=' + date.toGMTString();
449    } else {
450      var expires = '';  // eslint-disable-line no-redeclare
451    }
452    document.cookie = name + '=' + value + expires + '; path=/';
453  }
454
455  function readCookie(name) {
456    var nameEQ = name + '=';
457    var ca = document.cookie.split(';');
458    for (var i = 0; i < ca.length; i++) {
459      var c = ca[i];
460      while (c.charAt(0) === ' ') c = c.substring(1, c.length);
461      if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
462    }
463    return null;
464  }
465
466  // save referrer if doesn't already exist
467  if (!readCookie('_referrer')) {
468    // get referring page unless it's unavailable, then grab current (i.e. first) page
469    var referrer = document.referrer ? document.referrer : window.location;
470    // limit length
471    if (referrer.length > 150) {
472      referrer = referrer.slice(0, 150);
473    }
474    createCookie('_referrer', referrer);
475  }
476})();

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.