1// --------------------------------------------------------------------- 2// Global JavaScript 3// Authors: Andrew Ross & a little help from my friends 4// --------------------------------------------------------------------- 5 6/*jshint esversion: 6 */ 7var andrewrossco = andrewrossco || {}; 8 9(function($, APP) { 10 11$(function() { 12 APP.Global.init(); 13 APP.Viewport.init(); 14 APP.Modal.init(); 15 APP.ScrollTo.init(); 16 APP.Tabs.init(); 17 APP.Accordion.init(); 18 APP.Timezones.init(); 19 APP.Filters.init(); 20 APP.Form.init(); 21 APP.Carousel.init(); 22 APP.Countdown.init(); 23}); 24 25// --------------------------------------------------------------------- 26// Browser and Feature Detection 27// --------------------------------------------------------------------- 28 29APP.Global = { 30 init: function() { 31 32 $('body').addClass('page-ready'); 33 $('body').removeClass('no-js'); 34 35 if ( ! ('ontouchstart' in window) ) { 36 document.documentElement.classList.add('no-touch'); 37 } 38 39 if ( 'ontouchstart' in window ) { 40 document.documentElement.classList.add('is-touch'); 41 } 42 43 if (document.documentMode || /Edge/.test(navigator.userAgent)) { 44 if(navigator.appVersion.indexOf('Trident') === -1) { 45 document.documentElement.classList.add('isEDGE'); 46 } else { 47 $('html').addClass('isIE isIE11'); 48 } 49 } 50 51 var isSafari = /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || (typeof safari !== 'undefined' && safari.pushNotification)); 52 53 if(isSafari){ 54 document.body.classList.add('browser-safari'); 55 } 56 57 if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { 58 document.body.classList.add('darkmode'); 59 document.getElementById('favicon').setAttribute('href', '/assets/img/favicons/favicon-light.png'); 60 } 61 62 if(window.location.hostname == 'localhost' | window.location.hostname == '127.0.0.1'){ 63 document.body.classList.add('localhost'); 64 } 65 66 $('.js-menu-trigger').click(function(e){ 67 e.preventDefault(); 68 if( $('body').hasClass('menu-is-active') ) { 69 $('body').removeClass('menu-is-active'); 70 } else { 71 $('body').addClass('menu-is-active'); 72 } 73 }); 74 75 $(window).keyup(function (e) { 76 var code = (e.keyCode ? e.keyCode : e.which); 77 if (code == 9){ 78 if ($(window).width() < 768) { 79 if ( $('.navigation__inner a:focus, .navigation__inner input:focus').length) { 80 $('body').addClass('menu-is-active'); 81 } else { 82 $('body').removeClass('menu-is-active'); 83 } 84 } 85 } 86 }); 87 88 89 $('.fancy-click').click(function(){ 90 let el = $(this); 91 el.addClass('active'); 92 93 setTimeout(function(){ 94 el.removeClass('active'); 95 }, 600); 96 }); 97 98 $('.has-sub-nav > a').click(function(e){ 99 e.preventDefault(); 100 }); 101 102 $(window).keyup(function (e) { 103 var code = (e.keyCode ? e.keyCode : e.which); 104 if (code == 9){ 105 //if ($(window).width() < 768) { 106 if ( $('.site-header a:focus').length) { 107 $('.site-header').addClass('is-focused'); 108 } else { 109 $('.site-header').removeClass('is-focused'); 110 } 111 //} 112 } 113 }); 114 } 115}; 116 117 118// --------------------------------------------------------------------- 119// Detect when an element is in the viewport 120// --------------------------------------------------------------------- 121 122APP.Viewport = { 123 124 init: function() { 125 let items = document.querySelectorAll('*[data-animate-in], *[data-detect-viewport]'), 126 pageOffset = window.pageYOffset; 127 128 function isScrolledIntoView(el) { 129 var rect = el.getBoundingClientRect(), 130 elemTop = rect.top, 131 elemBottom = rect.top + el.offsetHeight, 132 bottomWin = pageOffset + window.innerHeight; 133 return (elemTop < bottomWin && elemBottom > 0); 134 } 135 136 function detect() { 137 for(var i = 0; i < items.length; i++) { 138 if ( isScrolledIntoView(items[i]) ) { 139 if( !items[i].classList.contains('in-view') ) { 140 items[i].classList.add('in-view'); 141 } 142 } 143 } 144 } 145 146 function throttle(fn, wait) { 147 var time = Date.now(); 148 return function() { 149 if ((time + wait - Date.now()) < 0) { 150 fn(); 151 time = Date.now(); 152 } 153 }; 154 } 155 156 window.addEventListener('scroll', throttle(detect, 150)); 157 158 window.addEventListener('resize', detect); 159 160 for(var i = 0; i < items.length; i++) { 161 var d = 0, 162 el = items[i]; 163 164 if( items[i].getAttribute('data-animate-in-delay') ) { 165 d = items[i].getAttribute('data-animate-in-delay') / 1000 + 's'; 166 } else { 167 d = 0; 168 } 169 el.style.transitionDelay = d; 170 } 171 $(document).ready(detect); 172 } 173 174}; 175 176 177// --------------------------------------------------------------------- 178// Modal 179// --------------------------------------------------------------------- 180 181APP.Modal = { 182 183 init: function() { 184 185 const modalOpen = $('*[data-modal]'); 186 187 modalOpen.on('click touchstart:not(touchmove)', function(event) { 188 event.preventDefault(); 189 let el = $(this); 190 let trigger = el.attr('data-modal'); 191 let target = $("#" + trigger); 192 193 if( target.hasClass('is-active') ) { 194 target.removeClass('is-active'); 195 $('body').removeClass('modal-is-active'); 196 target.find('.modal__content').removeClass('d-none'); 197 target.find('.share-modal-content').addClass('d-none'); 198 window.location.hash = ''; 199 } else { 200 target.addClass('is-active'); 201 $('body').addClass('modal-is-active'); 202 window.location.hash = trigger; 203 window._octo = window._octo || []; 204 window._octo.push(['recordPageView']) 205 } 206 }); 207 208 $(document).ready(function(){ 209 let hash = window.location.hash.replace('#', ''); 210 $('.modal-wrap').each(function(){ 211 if( $(this).attr('id') === hash ) { 212 $(this).addClass('is-active'); 213 $('body').addClass('modal-is-active'); 214 window.location.hash = hash; 215 window._octo = window._octo || []; 216 window._octo.push(['recordPageView']) 217 } 218 }); 219 }); 220 } 221}; 222 223 224 225// --------------------------------------------------------------------- 226// Scroll to 227// --------------------------------------------------------------------- 228 229APP.ScrollTo = { 230 init: function() { 231 if( $('*[data-scroll-to]').length ) { 232 this.bind(); 233 } else { 234 return; 235 } 236 }, 237 238 bind: function() { 239 $('*[data-scroll-to]').on('click touchstart:not(touchmove)', function() { 240 window.dispatchEvent(new Event('resize')); 241 var trigger = $(this).attr('data-scroll-to'), 242 target = $("#" + trigger), 243 ss = 1000, //scroll speed 244 o = 0; // offset 245 246 if( $(this).attr('data-scroll-speed') ) { 247 ss = $(this).attr('data-scroll-speed'); 248 } 249 250 if( $(this).attr('data-scroll-offset') ) { 251 o = $(this).attr('data-scroll-offset'); 252 } 253 254 $('html, body').animate({ 255 scrollTop: target.offset().top - o 256 }, ss); 257 }); 258 } 259}; 260 261 262 263 264// --------------------------------------------------------------------- 265// Tabs 266// --------------------------------------------------------------------- 267 268APP.Tabs = { 269 270 init: function() { 271 const tabs = $('.tab'); 272 273 $('.js-tab-bd.is-active').show() 274 tabs.click(function() { 275 let el = $(this); 276 let target = el.attr('data-tab'); 277 let newActive = $('.js-tab-bd[data-tab-bd=' + target + ']'); 278 let curActive = $('.js-tab-bd.is-active'); 279 tabs.removeClass('is-active'); 280 el.addClass('is-active'); 281 curActive.removeClass('is-active').fadeOut(100); 282 newActive.addClass('is-active').fadeIn(400); 283 }); 284 285 const tabs2 = $('.tabs__tab'); 286 tabs2.click(function() { 287 let el = $(this); 288 let target = el.attr('data-tab'); 289 let newActive = $('.tabs__content[data-tab-bd=' + target + ']'); 290 let curActive = $('.tabs__content.is-active'); 291 tabs2.removeClass('is-active'); 292 el.addClass('is-active'); 293 curActive.removeClass('is-active'); 294 newActive.addClass('is-active'); 295 }); 296 297 var hash = window.location.hash.replace('#', ''); 298 $(document).ready(function(){ 299 if( hash.length && $('.schedule-tabs .tab[data-tab=' + hash + ']').length ) { 300 $('.schedule-tabs .tab[data-tab=' + hash + ']').click(); 301 setTimeout(function(){ 302 $('html, body').animate({ 303 scrollTop: $('#schedule').offset().top - 72 304 }, 400); 305 }, 200); 306 } 307 if( hash.length && $('.tabs__tab[data-tab=' + hash + ']').length ) { 308 $('.tabs__tab[data-tab=' + hash + ']').click(); 309 } 310 }); 311 } 312}; 313 314 315// --------------------------------------------------------------------- 316// Accordion 317// --------------------------------------------------------------------- 318 319APP.Accordion = { 320 321 init: function() { 322 if( $('.accordion').length ) { 323 this.bind(); 324 } else { 325 return; 326 } 327 }, 328 329 bind: function() { 330 const acc = $('.accordion__hd'); 331 acc.click(function(){ 332 $(this).parents('.accordion').toggleClass('is-open'); 333 $(this).next('.accordion__bd').slideToggle(400); 334 }); 335 $('.accordions .accordion:first-child .accordion__hd').each(function(){ 336 $(this).parents('.accordion').addClass('is-open'); 337 $(this).next('.accordion__bd').show(); 338 }); 339 } 340}; 341 342 343 344// --------------------------------------------------------------------- 345// Timezones 346// --------------------------------------------------------------------- 347 348APP.Timezones = { 349 350 init: function() { 351 352 let times = $('.js-time'); 353 let timeWithZone = $('.js-time-timezone'); 354 let dateTime = $('.js-time-dateTime'); 355 let dateTimeLong = $('.js-time-dateTime-long'); 356 357 function get_tz() { 358 return /\((.*)\)/.exec(new Date().toString())[1]; 359 } 360 361 //let dt = new Date();
362 let curTimeZone = get_tz(); 363 364 $('.js-current-timezone').text(curTimeZone); 365 366 let twelveHourTime = false; 367 if( Intl.DateTimeFormat().resolvedOptions().timeZone.includes("America") ) { 368 twelveHourTime = true; 369 } 370 371 // Set all session times 372 function setSessionTimes() { 373 times.each(function(){ 374 let el = $(this), 375 time = el.attr('data-time'); 376 let parsedTime = parseTime(time); 377 el.html(parsedTime); 378 }); 379 timeWithZone.each(function(){ 380 let el = $(this); 381 let time = el.attr('data-time'); 382 let parsedTime = parseTimeZone(time); 383 el.html(parsedTime); 384 }); 385 386 dateTime.each(function(){ 387 let el = $(this); 388 let time = el.attr('data-time'); 389 let parsedTime = parseTimeDate(time, "short"); 390 el.html(parsedTime); 391 }); 392 dateTimeLong.each(function(){ 393 let el = $(this); 394 let time = el.attr('data-time'); 395 let parsedTime = parseTimeDate(time, "long"); 396 parsedTime = parsedTime.replace(", ", " ⢠"); 397 el.html(parsedTime); 398 }); 399 400 $('.js-time-day').each(function(){ 401 let el = $(this); 402 let time = el.attr('data-time'); 403 let parsedTime = parseDay(time); 404 str = parsedTime.substr(0, parsedTime.lastIndexOf(",")); 405 406 if( time.includes("26") ) { 407 if( !str.includes("26") ) { 408 el.html('*' + str); 409 } else { 410 el.remove(); 411 } 412 } 413 if( time.includes("27") ) { 414 if( !str.includes("27") ) { 415 el.html('*' + str); 416 } else { 417 el.remove(); 418 } 419 } 420 }); 421 422 $('.js-day').each(function(){ 423 let el = $(this); 424 let time = el.attr('data-time'); 425 let parsedTime = parseDay(time); 426 str = parsedTime.substr(0, parsedTime.lastIndexOf(",")); 427 el.html(str); 428 }); 429 } 430 431 function parseTimeDate(date, month) { 432 let seshTime = new Date(date); 433 let setFormat = seshTime.toLocaleTimeString([], {month: month, day: "numeric", hour12: twelveHourTime, hour: "numeric", minute: "numeric", timeZoneName: "short"}); 434 return setFormat; 435 } 436 437 function parseTimeZone(date) { 438 let seshTime = new Date(date); 439 setFormat = seshTime.toLocaleTimeString([], {hour12: twelveHourTime, hour: "numeric", minute: "numeric", timeZoneName: "short"}); 440 return setFormat; 441 } 442 443 function parseTime(date) { 444 let seshTime = new Date(date); 445 //https://www.jsman.net/manual/Standard-Global-Objects/Date/toLocaleTimeString 446 // weekday: "long", 447 // hour12: false, 448 let setFormat = seshTime.toLocaleTimeString([], {hour12: twelveHourTime, hour: "numeric", minute: "numeric"}); 449 return setFormat; 450 } 451 452 function parseDay(date) { 453 let seshTime = new Date(date); 454 //console.log(seshTime); 455 let setFormat = seshTime.toLocaleTimeString([], {month: "long", day: "numeric"}); 456 return setFormat; 457 } 458 459 function parseDay(date) { 460 let seshTime = new Date(date); 461 let setFormat = seshTime.toLocaleTimeString([], {month: "long", day: "numeric"});; 462 return setFormat; 463 } 464 465 function getTimezoneOffset() { 466 function z(n){return (n<10? '0' : '') + n;} 467 var offset = new Date().getTimezoneOffset(); 468 var sign = offset < 0? '+' : '-'; 469 offset = Math.abs(offset); 470 return sign + z(offset/60 | 0) + z(offset%60); 471 } 472 473 474 $(document).ready(function(){ 475 setSessionTimes(); 476 }); 477 } 478}; 479 480 481 482// --------------------------------------------------------------------- 483// Filter 484// --------------------------------------------------------------------- 485 486APP.Filters = { 487 488 init: function() { 489 490 if( !document.getElementById('filters') ) { 491 return; 492 } 493 494 const filters = $('.category label'); 495 const sessionsWrap = $('.sessions'); 496 const session = $('.js-session'); 497 const timeslots = $('.on-demand__sessions'); 498 499 let activeChannels = []; 500 501 filters.click(function(){ 502 let el = $(this); 503 let filter = el.prev('input').val(); 504 505 sessionsWrap.addClass('is-thinking'); 506 507 setTimeout(function(){ 508 sessionsWrap.removeClass('filtered-tag-open-source'); 509 sessionsWrap.removeClass('filtered-tag-devops'); 510 if( filter == 'clear' ) { 511 localStorage.setItem('satelliteSchedFilter', 'all'); 512 $('.timeslot').removeClass('is-empty'); 513 $('.session').removeClass('is-active'); 514 } else { 515 sessionsWrap.addClass('filtered-'+filter); 516 localStorage.setItem('satelliteSchedFilter', filter); 517 session.each(function(){ 518 if( $(this).hasClass(filter) ) { 519 $(this).addClass('is-active'); 520 } else { 521 $(this).removeClass('is-active'); 522 } 523 }); 524 timeslots.each(function(){ 525 if( $(this).find('.session.is-active').length == 0) { 526 $(this).parent('.timeslot').addClass('is-empty'); 527 } else { 528 $(this).parent('.timeslot').removeClass('is-empty'); 529 } 530 }); 531 } 532 533 sessionsWrap.removeClass('is-thinking'); 534 }, 800); 535 }); 536 537 // Check for query params 538 $(document).ready(function(){ 539 let activeFilter = localStorage.getItem('satelliteSchedFilter');
540 if( activeFilter != null ) { 541 filter = activeFilter; 542 } 543 544 let urlParams = new URLSearchParams(window.location.search); 545 if( urlParams.get('filter') ) { 546 //console.log('param hit'); 547 filter = 'tag-' + urlParams.get('filter'); 548 localStorage.setItem('satelliteSchedFilter', filter); 549 } 550 551 if( filter != null ) { 552 //console.log('Active filter = ' + filter); 553 $('.category label[for="'+ filter +'"]').click(); 554 } 555 }); 556 } 557}; 558 559 560// --------------------------------------------------------------------- 561// Form 562// --------------------------------------------------------------------- 563 564APP.Form = { 565 566 init: function() { 567 if( $('.dynamic-form').length ) { 568 this.bind(); 569 } else { 570 return; 571 } 572 }, 573 574 bind: function() { 575 576 var form = document.getElementById("eloquaForm"); 577 578 if( localStorage.getItem('satelliteSessionTitle') ) { 579 document.getElementById("sessionTitle").value = localStorage.getItem('satelliteSessionTitle'); 580 } 581 582 form.addEventListener("submit", function(event) { 583 event.preventDefault(); 584 event.stopPropagation(); 585 586 valid = true; 587 588 $('input[required]').each(function(){ 589 if( $(this).attr('type') === 'tel' ){ 590 if ( /^\d{3}-?\d{3}-?\d{4}$/g.test($(this).val()) ) { 591 } else { 592 $(this).parents('.form-group').addClass('error'); 593 valid = false; 594 }; 595 } else { 596 if( $(this).val().length === 0 ) { 597 $(this).parents('.form-group').addClass('error'); 598 valid = false; 599 } 600 } 601 }); 602 603 // Prevent form submission and contact with server 604 if (valid) { 605 // $('input[required]').each(function(){ 606 // if( $(this).val().length === 0 ) { 607 // $(this).parents('.form-group').addClass('error'); 608 // } 609 // }); 610 onSubmit(); 611 } else { 612 //onSubmit(); 613 } 614 form.classList.add("validated"); 615 }, false); 616 617 618 // reCaptcha callback function, generate reCaptcha token client side 619 function onSubmit() { 620 var form = document.getElementById("eloquaForm"); 621 var action = form.action; 622 var http = new XMLHttpRequest(); 623 http.open('POST', action, true); 624 var formData = new FormData( form ); 625 http.send(formData); 626 627 //Call a function when the state changes. 628 http.onreadystatechange = function() { 629 if (http.readyState === 4) { 630 if (http.status === 200) { 631 var thankYou = document.createElement('p'); 632 thankYou.classList = 'py-6 py-6 text-white f3'; 633 thankYou.innerHTML = 'Thank you! We will be in touch shortly.'; 634 $('.sales-modal-hd').addClass('d-none'); 635 form.parentNode.appendChild(thankYou); 636 form.remove(); 637 } else { 638 form.classList.remove('is-thinking'); 639 var failMsg = document.createElement('p'); 640 failMsg.classList = 'py-4 text-error f3'; 641 failMsg.innerHTML = 'There was an issue with your submission. Please try again.'; 642 form.parentNode.appendChild(failMsg); 643 } 644 } 645 }; 646 } 647 648 function showStateStudy() { 649 var y = document.getElementById("countryStudy").value; 650 var x = document.getElementById("stateProvStudyBlock"); 651 if (y == 'US' || y == 'CA') { 652 x.style.display="block"; 653 } else { 654 x.style.display="none"; 655 } 656 } 657 658 form.addEventListener("change", function() { 659 showStateStudy(); 660 }); 661 662 var $ = jQuery; 663 $('.dynamic-form input, .dynamic-form select').on('focus', function() { 664 $(this).parents('.form-group').addClass('is-active'); 665 }); 666 667 $('.dynamic-form input, .dynamic-form select').on('focusout', function() { 668 if( $(this).val().length === 0 ) { 669 $(this).parents('.form-group').removeClass('is-active'); 670 } else { 671 $(this).parents('.form-group').removeClass('error'); 672 } 673 }); 674 675 $(document).ready(function(){ 676 $('.dynamic-form input, .dynamic-form select').each(function() { 677 if( $(this).val().length !== 0 ) { 678 $(this).parents('.form-group').addClass('is-active'); 679 } 680 }); 681 }); 682 683 } 684}; 685 686 687 688 689 690// --------------------------------------------------------------------- 691// Carousel
692// --------------------------------------------------------------------- 693 694APP.Carousel = { 695 696 init: function() { 697 if( $('.js-carousel').length ) { 698 this.bind(); 699 } else { 700 return; 701 } 702 }, 703 704 bind: function() { 705 706 const arrowPrev = '<span class="slick-prev"><svg viewBox="0 0 4.7 8"><path d="M0.1,3.7l3.7-3.6C3.8,0,3.9,0,4,0 c0.1,0,0.2,0,0.3,0.1l0.2,0.2c0.1,0.1,0.1,0.1,0.1,0.2c0,0.1,0,0.2-0.1,0.3L1.3,4l3.2,3.1c0.1,0.1,0.1,0.2,0.1,0.3 c0,0.1,0,0.2-0.1,0.2L4.3,7.9C4.2,8,4.1,8,4,8C3.9,8,3.8,8,3.8,7.9L0.1,4.2C0,4.2,0,4.1,0,4S0,3.8,0.1,3.7z"/></svg></span>'; 707 const arrowNext = '<span class="slick-next"><svg viewBox="0 0 4.7 8"><path d="M4.7,4c0,0.1,0,0.2-0.1,0.2L0.9,7.9 C0.8,8,0.7,8,0.6,8C0.5,8,0.4,8,0.3,7.9L0.1,7.7C0.1,7.6,0,7.5,0,7.4c0-0.1,0-0.2,0.1-0.3L3.3,4L0.1,0.9C0,0.8,0,0.7,0,0.6 c0-0.1,0-0.2,0.1-0.2l0.2-0.2C0.4,0,0.5,0,0.6,0c0.1,0,0.2,0,0.2,0.1l3.7,3.6C4.6,3.8,4.7,3.9,4.7,4z" /></svg></span>'; 708 709 const car = $('.js-carousel'); 710 711 car.each(function(){ 712 $(this).slick({ 713 dots: false, 714 infinite: false, 715 arrows: true, 716 speed: 1000, 717 autoplay: false, 718 prevArrow: arrowPrev, 719 nextArrow: arrowNext, 720 slidesToShow: 4, 721 slidesToScroll: 2, 722 responsive: [ 723 { 724 breakpoint: 1024, 725 settings: { 726 slidesToShow: 3, 727 slidesToScroll: 2, 728 speed: 400 729 } 730 }, 731 { 732 breakpoint: 600, 733 settings: { 734 slidesToShow: 2, 735 slidesToScroll: 1, 736 speed: 400 737 } 738 }, 739 { 740 breakpoint: 480, 741 settings: { 742 slidesToShow: 2, 743 slidesToScroll: 1, 744 speed: 400 745 } 746 } 747 ] 748 }); 749 }); 750 } 751}; 752 753 754// --------------------------------------------------------------------- 755// Countdown Timer 756// --------------------------------------------------------------------- 757 758APP.Countdown = { 759 760 init: function() { 761 if( $('.js-countdown').length ) { 762 this.bind(); 763 } else { 764 return; 765 } 766 }, 767 768 bind: function() { 769 let time = $('.js-countdown').attr('data-time'); 770 let end = new Date( time ); 771 772 //console.log('countdown end ' + end); 773 let shutdown = new Date( time ); 774 let minutesOffset = 30; 775 shutdown.setMinutes(shutdown.getMinutes() - minutesOffset); 776 777 //console.log('countdown end ' + end); 778 //console.log('countdown shutdown ' + shutdown); 779 780 let _second = 1000; 781 let _minute = _second * 60; 782 let _hour = _minute * 60; 783 let _day = _hour * 24; 784 let timer; 785 let countdownWrap = document.querySelectorAll('.countdown-wrap'); 786 var countdown = document.querySelectorAll('.js-countdown'); 787 788 var now = new Date(); 789 var distance = end - now - (getESTOffset()) * _hour; 790 if (now > shutdown) { 791 $('.countdown-wrap').remove(); 792 } 793 794 setTimeout(function(){ 795 $('.countdown-wrap').addClass('is-active'); 796 }, 500); 797 798 function getESTOffset() { 799 return new Date().getTimezoneOffset() - (end.getTimezoneOffset()); 800 } 801 802 function showRemaining() { 803 var now = new Date(); 804 var distance = end - now - (getESTOffset()) * _hour; 805 var close = shutdown - now - (getESTOffset()) * _hour; 806 if (close < 0) { 807 clearInterval(timer); 808 $('.countdown-wrap').slideUp(); 809 return; 810 } 811 let days = Math.floor(distance / _day); 812 let hours = Math.floor((distance % _day) / _hour); 813 let minutes = Math.floor((distance % _hour) / _minute); 814 let seconds = Math.floor((distance % _minute) / _second); 815 816 countdown[0].innerHTML = days + "<span>d </span> " + hours + "<span>h </span> " + minutes + "<span>m </span> " + seconds + "<span>s</span> "; 817 } 818 819 timer = setInterval(showRemaining, 1000); 820 821 } 822}; 823 824 825}(jQuery, andrewrossco));
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.