1/** @license 2 * DHTML Snowstorm! JavaScript-based snow for web pages 3 * Making it snow on the internets since 2003. You're welcome. 4 * ----------------------------------------------------------- 5 * Version 1.44.20131208 (Previous rev: 1.44.20131125) 6 * Copyright (c) 2007, Scott Schiller. All rights reserved. 7 * Code provided under the BSD License 8 * http://schillmania.com/projects/snowstorm/license.txt 9 */ 10 11/*jslint nomen: true, plusplus: true, sloppy: true, vars: true, white: true */ 12/*global window, document, navigator, clearInterval, setInterval */ 13 14var snowStorm = (function(window, document) { 15 16 Array.prototype.random = function () { 17 return this[Math.floor((Math.random()*this.length))]; 18 } 19 20 var snowflakeContainer = document.createElement('div'); 21 snowflakeContainer.classList.add('snowflakeContainer'); 22 document.body.appendChild(snowflakeContainer); 23 24 var isMobile = navigator.userAgent.match(/mobile|opera m(ob|in)/i); 25 26 var sty = document.createElement('style'); 27 sty.innerHTML = ''+ 28 '.snowflakeContainer { position:fixed; pointer-events:none; inset:0; overflow:hidden; z-index:1000; opacity:0.4; filter:saturate(0); }' + 29 '.snowflake { color:#8dc9ff; transform-origin:center; transition:opacity 0.5s; font-family:arial,verdana; font-weight:normal; padding:0px; margin:0px; text-align:center; vertical-align:baseline; } ' + 30 '.snowflake:nth-child(1n) { animation:spin1 4s linear infinite; } '+ 31 '.snowflake:nth-child(2n) { animation:spin2 4s linear infinite; }' + 32 '.snowflake:nth-child(3n) { animation:spin1 8s linear infinite; } '+ 33 '.snowflake:nth-child(4n) { animation:spin2 8s linear infinite; }' + 34 '@keyframes spin1 { 0% { transform:rotate(0deg); } 100% { transform:rotate(360deg); } }' + 35 '@keyframes spin2 { 0% { transform:rotate(0deg); } 100% { transform:rotate(-360deg); } }'; 36 document.querySelector('body').appendChild(sty); 37 38 // --- common properties --- 39 40 this.autoStart = true; // Whether the snow should start automatically or not. 41 this.excludeMobile = false; // Snow is likely to be bad news for mobile phones' CPUs (and batteries.) Enable at your own risk. 42 this.flakesMax = isMobile ? 16 : 96; // Limit total amount of snow made (falling + sticking) 43 this.flakesMaxActive = isMobile ? 8 : 32; // Limit amount of snow falling at once (less = lower CPU use) 44 this.animationInterval = 33; // Theoretical "miliseconds per frame" measurement. 20 = fast + smooth, but high CPU use. 50 = more conservative, but slower 45 this.useGPU = true; // Enable transform-based hardware acceleration, reduce CPU load. 46 this.className = 'snowflake'; // CSS class name for further customization on snow elements 47 this.flakeBottom = window.innerHeight; // Integer for Y axis snow limit, 0 or null for "full-screen" snow effect 48 this.followMouse = true; // Snow movement can respond to the user's mouse 49 this.snowCharacters = [ '❄', '❅', '❆' ]; 50 this.snowCharacter = '❄'; // • = bullet, · is square on some systems etc. ❅ 51 this.snowStick = true; // Whether or not snow should "stick" at the bottom. When off, will never collect. 52 this.targetElement = '.snowflakeContainer'; // element which snow will be appended to (null = document.body) - can be an element ID eg. 'myDiv', or a DOM node reference 53 this.useMeltEffect = false; // When recycling fallen snow (or rarely, when falling), have it "melt" and fade out if browser supports it 54 this.useTwinkleEffect = false; // Allow snow to randomly "flicker" in and out of view while falling 55 this.usePositionFixed = true; // true = snow does not shift vertically when scrolling. May increase CPU load, disabled by default - if enabled, used only where supported 56 this.usePixelPosition = false; // Whether to use pixel values for snow top/left vs. percentages. Auto-enabled if body is position:relative or targetElement is specified. 57 58 // --- less-used bits --- 59 60 this.freezeOnBlur = true; // Only snow when the window is in focus (foreground.) Saves CPU. 61 this.flakeLeftOffset = 0; // Left margin/gutter space on edge of container (eg. browser window.) Bump up these values if seeing horizontal scrollbars. 62 this.flakeRightOffset = 0; // Right margin/gutter space on edge of container 63 this.flakeWidth = isMobile ? 10 : 25; // Max pixel width reserved for snow element 64 this.flakeHeight = isMobile ? 10 : 25; // Max pixel height reserved for snow element 65 66 this.vMinX = 0.1; // Minimum X velocity range for snow (default 0.1)
67 this.vMaxX = 1; // Maximum X velocity range for snow 68 69 this.vMinY = 0.5; // Minimum Y velocity range for snow (default 0.1) 70 this.vMaxY = 0.5; // Maximum Y velocity range for snow 71 72 this.zIndex = 1000; // CSS stacking order applied to each snowflake 73 74 // --- "No user-serviceable parts inside" past this point, yadda yadda --- 75 76 var storm = this, 77 features, 78 // UA sniffing and backCompat rendering mode checks for fixed position, etc. 79 isIE = navigator.userAgent.match(/msie/i), 80 isIE6 = navigator.userAgent.match(/msie 6/i), 81 isBackCompatIE = (isIE && document.compatMode === 'BackCompat'), 82 noFixed = (isBackCompatIE || isIE6), 83 screenX = null, screenX2 = null, screenY = null, scrollY = null, docHeight = null, vRndX = null, vRndY = null, 84 windOffset = 1, 85 windMultiplier = 2, 86 flakeTypes = 8, 87 fixedForEverything = false, 88 targetElementIsRelative = false, 89 opacitySupported = (function(){ 90 try { 91 document.createElement('div').style.opacity = '0.5'; 92 } catch(e) { 93 return false; 94 } 95 return true; 96 }()), 97 didInit = false, 98 docFrag = document.createDocumentFragment(); 99 100 features = (function() { 101 102 var getAnimationFrame; 103 104 /** 105 * hat tip: paul irish 106 * http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 107 * https://gist.github.com/838785 108 */ 109 110 function timeoutShim(callback) { 111 window.setTimeout(callback, 1000/(storm.animationInterval || 20)); 112 } 113 114 var _animationFrame = (window.requestAnimationFrame || 115 window.webkitRequestAnimationFrame || 116 window.mozRequestAnimationFrame || 117 window.oRequestAnimationFrame || 118 window.msRequestAnimationFrame || 119 timeoutShim); 120 121 // apply to window, avoid "illegal invocation" errors in Chrome 122 getAnimationFrame = _animationFrame ? function() { 123 return _animationFrame.apply(window, arguments); 124 } : null; 125 126 var testDiv; 127 128 testDiv = document.createElement('div'); 129 130 function has(prop) { 131 132 // test for feature support 133 var result = testDiv.style[prop]; 134 return (result !== undefined ? prop : null); 135 136 } 137 138 // note local scope. 139 var localFeatures = { 140 141 transform: { 142 ie: has('-ms-transform'), 143 moz: has('MozTransform'), 144 opera: has('OTransform'), 145 webkit: has('webkitTransform'), 146 w3: has('transform'), 147 prop: null // the normalized property value 148 }, 149 150 getAnimationFrame: getAnimationFrame 151 152 }; 153 154 localFeatures.transform.prop = ( 155 localFeatures.transform.w3 || 156 localFeatures.transform.moz || 157 localFeatures.transform.webkit || 158 localFeatures.transform.ie || 159 localFeatures.transform.opera 160 ); 161 162 testDiv = null; 163 164 return localFeatures; 165 166 }()); 167 168 this.timer = null; 169 this.flakes = []; 170 this.disabled = false; 171 this.active = false; 172 this.meltFrameCount = 20; 173 this.meltFrames = []; 174 175 this.setXY = function(o, x, y) { 176 177 if (!o) { 178 return false; 179 } 180 181 if (storm.usePixelPosition || targetElementIsRelative) { 182 183 o.style.left = (x - storm.flakeWidth) + 'px'; 184 o.style.top = (y - storm.flakeHeight) + 'px'; 185 186 } else if (noFixed) { 187 188 o.style.right = (100-(x/screenX*100)) + '%'; 189 // avoid creating vertical scrollbars 190 o.style.top = (Math.min(y, docHeight-storm.flakeHeight)) + 'px'; 191 192 } else { 193 194 if (!storm.flakeBottom) { 195 196 // if not using a fixed bottom coordinate... 197 o.style.right = (100-(x/screenX*100)) + '%'; 198 o.style.bottom = (100-(y/screenY*100)) + '%'; 199 200 } else { 201 202 // absolute top. 203 o.style.right = (100-(x/screenX*100)) + '%'; 204 o.style.top = (Math.min(y, docHeight-storm.flakeHeight)) + 'px'; 205 206 } 207 208 } 209 210 }; 211 212 this.events = (function() { 213 214 var old = (!window.addEventListener && window.attachEvent), slice = Array.prototype.slice, 215 evt = { 216 add: (old?'attachEvent':'addEventListener'), 217 remove: (old?'detachEvent':'removeEventListener') 218 }; 219 220 function getArgs(oArgs) { 221 var args = slice.call(oArgs), len = args.length; 222 if (old) { 223 args[1] = 'on' + args[1]; // prefix 224 if (len > 3) { 225 args.pop(); // no capture 226 } 227 } else if (len === 3) { 228 args.push(false); 229 } 230 return args; 231 } 232 233 function apply(args, sType) { 234 var element = args.shift(), 235 method = [evt[sType]]; 236 if (old) { 237 element[method](args[0], args[1]); 238 } else { 239 element[method].apply(element, args); 240 } 241 } 242 243 function addEvent() { 244 apply(getArgs(arguments), 'add'); 245 } 246 247 function removeEvent() { 248 apply(getArgs(arguments), 'remove'); 249 } 250 251 return { 252 add: addEvent, 253 remove: removeEvent 254 }; 255 256 }()); 257 258 function rnd(n,min) { 259 if (isNaN(min)) { 260 min = 0; 261 } 262 return (Math.random()*n)+min; 263 } 264 265 function plusMinus(n) { 266 return (parseInt(rnd(2),10)===1?n*-1:n); 267 } 268 269 this.randomizeWind = function() { 270 var i; 271 vRndX = plusMinus(rnd(storm.vMaxX,0.8)); 272 vRndY = rnd(storm.vMaxY,0.8); 273 if (this.flakes) { 274 for (i=0; i<this.flakes.length; i++) { 275 if (this.flakes[i].active) { 276 this.flakes[i].setVelocities(); 277 } 278 } 279 } 280 }; 281 282 this.scrollHandler = function() { 283 var i; 284 // "attach" snowflakes to bottom of window if no absolute bottom value was given 285 scrollY = (storm.flakeBottom ? 0 : parseInt(window.scrollY || document.documentElement.scrollTop || (noFixed ? document.body.scrollTop : 0), 10)); 286 if (isNaN(scrollY)) { 287 scrollY = 0; // Netscape 6 scroll fix 288 } 289 if (!fixedForEverything && !storm.flakeBottom && storm.flakes) { 290 for (i=0; i<storm.flakes.length; i++) { 291 if (storm.flakes[i].active === 0) { 292 storm.flakes[i].stick(); 293 } 294 } 295 } 296 }; 297 298 this.resizeHandler = function() { 299 if (window.innerWidth || window.innerHeight) { 300 screenX = window.innerWidth - 16 - storm.flakeRightOffset; 301 screenY = (storm.flakeBottom || window.innerHeight); 302 } else { 303 screenX = (document.documentElement.clientWidth || document.body.clientWidth || document.body.scrollWidth) - (!isIE ? 8 : 0) - storm.flakeRightOffset; 304 screenY = storm.flakeBottom || document.documentElement.clientHeight || document.body.clientHeight || document.body.scrollHeight; 305 } 306 docHeight = document.body.offsetHeight; 307 screenX2 = parseInt(screenX/2,10); 308 }; 309 310 this.resizeHandlerAlt = function() { 311 screenX = storm.targetElement.offsetWidth - storm.flakeRightOffset; 312 screenY = storm.flakeBottom || storm.targetElement.offsetHeight; 313 screenX2 = parseInt(screenX/2,10); 314 docHeight = document.body.offsetHeight; 315 }; 316 317 this.freeze = function() { 318 // pause animation 319 if (!storm.disabled) { 320 storm.disabled = 1; 321 } else { 322 return false; 323 } 324 storm.timer = null; 325 }; 326 327 this.resume = function() { 328 if (storm.disabled) { 329 storm.disabled = 0; 330 } else { 331 return false; 332 } 333 storm.timerInit(); 334 }; 335 336 this.toggleSnow = function() { 337 if (!storm.flakes.length) { 338 // first run 339 storm.start(); 340 } else { 341 storm.active = !storm.active; 342 if (storm.active) { 343 storm.show(); 344 storm.resume(); 345 } else { 346 storm.stop(); 347 storm.freeze(); 348 } 349 } 350 }; 351 352 this.stop = function() { 353 var i; 354 this.freeze(); 355 for (i=0; i<this.flakes.length; i++) { 356 this.flakes[i].o.style.display = 'none'; 357 } 358 storm.events.remove(window,'scroll',storm.scrollHandler); 359 storm.events.remove(window,'resize',storm.resizeHandler); 360 if (storm.freezeOnBlur) { 361 if (isIE) { 362 storm.events.remove(document,'focusout',storm.freeze); 363 storm.events.remove(document,'focusin',storm.resume); 364 } else { 365 storm.events.remove(window,'blur',storm.freeze); 366 storm.events.remove(window,'focus',storm.resume); 367 } 368 } 369 }; 370 371 this.show = function() { 372 var i; 373 for (i=0; i<this.flakes.length; i++) { 374 this.flakes[i].o.style.display = 'block'; 375 } 376 }; 377 378 this.SnowFlake = function(type,x,y) { 379 var s = this; 380 this.type = type; 381 this.x = x||parseInt(rnd(screenX-20),10); 382 this.y = (!isNaN(y)?y:-rnd(screenY)-12); 383 this.vX = null; 384 this.vY = null; 385 this.vAmpTypes = [1.2,1.4,1.6,1.8]; // "amplification" for vX/vY (based on flake size/type) 386 this.vAmp = this.vAmpTypes[this.type] || 1; 387 this.melting = false; 388 this.meltFrameCount = storm.meltFrameCount; 389 this.meltFrames = storm.meltFrames; 390 this.meltFrame = 0; 391 this.twinkleFrame = 0; 392 this.active = 1; 393 this.fontSize = (15+(this.type/5)*20); 394 395 this.o = document.createElement('div'); 396 this.o.innerHTML = storm.snowCharacters.random(); 397 //this.o.innerHTML = storm.snowCharacter; 398 if (storm.className) { 399 this.o.setAttribute('class', storm.className); 400 } 401 402 this.o.style.position = (fixedForEverything?'fixed':'absolute'); 403 if (storm.useGPU && features.transform.prop) { 404 // GPU-accelerated snow. 405 this.o.style[features.transform.prop] = 'translate3d(0px, 0px, 0px)'; 406 } 407 this.o.style.width = storm.flakeWidth+'px'; 408 this.o.style.height = storm.flakeHeight+'px'; 409 this.o.style.zIndex = storm.zIndex; 410 docFrag.appendChild(this.o); 411 412 this.refresh = function() {
413 if (isNaN(s.x) || isNaN(s.y)) { 414 // safety check 415 return false; 416 } 417 storm.setXY(s.o, s.x, s.y); 418 }; 419 420 this.stick = function() { 421 s.setOpacity(s.o,0); 422 s.o.style.animationPlayState = 'paused'; 423 424 if (noFixed || (storm.targetElement !== document.documentElement && storm.targetElement !== document.body)) { 425 s.o.style.top = (screenY+scrollY-storm.flakeHeight)+'px'; 426 } else if (storm.flakeBottom) { 427 s.o.style.top = storm.flakeBottom+'px'; 428 } else { 429 //s.o.style.display = 'none'; 430 s.o.style.bottom = '0%'; 431 s.o.style.position = 'fixed'; 432 s.o.style.display = 'block'; 433 } 434 }; 435 436 this.vCheck = function() { 437 if (s.vX>=0 && s.vX<0.2) { 438 s.vX = 0.2; 439 } else if (s.vX<0 && s.vX>-0.2) { 440 s.vX = -0.2; 441 } 442 if (s.vY>=0 && s.vY<0.2) { 443 s.vY = 0.2; 444 } 445 }; 446 447 this.move = function() { 448 var vX = s.vX*windOffset, yDiff; 449 s.x += vX; 450 s.y += (s.vY*s.vAmp); 451 if (s.x >= screenX || screenX-s.x < storm.flakeWidth) { // X-axis scroll check 452 s.x = 0; 453 } else if (vX < 0 && s.x-storm.flakeLeftOffset < -storm.flakeWidth) { 454 s.x = screenX-storm.flakeWidth-1; // flakeWidth; 455 } 456 s.refresh(); 457 yDiff = screenY+scrollY-s.y+storm.flakeHeight; 458 if (yDiff<storm.flakeHeight) { 459 s.active = 0; 460 if (storm.snowStick) { 461 s.stick(); 462 } else { 463 s.recycle(); 464 } 465 } else { 466 if (storm.useMeltEffect && s.active && s.type < 3 && !s.melting && Math.random()>0.998) { 467 // ~1/1000 chance of melting mid-air, with each frame 468 s.melting = true; 469 s.melt(); 470 // only incrementally melt one frame 471 // s.melting = false; 472 } 473 if (storm.useTwinkleEffect) { 474 if (s.twinkleFrame < 0) { 475 if (Math.random() > 0.97) { 476 s.twinkleFrame = parseInt(Math.random() * 8, 10); 477 } 478 } else { 479 s.twinkleFrame--; 480 if (!opacitySupported) { 481 s.o.style.visibility = (s.twinkleFrame && s.twinkleFrame % 2 === 0 ? 'hidden' : 'visible'); 482 } else { 483 s.o.style.opacity = (s.twinkleFrame && s.twinkleFrame % 2 === 0 ? 0 : 1); 484 } 485 } 486 } 487 } 488 }; 489 490 this.animate = function() { 491 // main animation loop 492 // move, check status, die etc. 493 s.move(); 494 }; 495 496 this.setVelocities = function() { 497 s.vX = vRndX+rnd(storm.vMaxX*0.12,storm.vMinX); 498 s.vY = vRndY+rnd(storm.vMaxY*0.12,storm.vMinY); 499 }; 500 501 this.setOpacity = function(o,opacity) { 502 if (!opacitySupported) { 503 return false; 504 } 505 o.style.opacity = opacity; 506 }; 507 508 this.melt = function() { 509 if (!storm.useMeltEffect || !s.melting) { 510 s.recycle(); 511 } else { 512 if (s.meltFrame < s.meltFrameCount) { 513 s.setOpacity(s.o,s.meltFrames[s.meltFrame]); 514 //s.o.style.fontSize = s.fontSize-(s.fontSize*(s.meltFrame/s.meltFrameCount))+'px'; 515 //s.o.style.lineHeight = storm.flakeHeight+2+(storm.flakeHeight*0.75*(s.meltFrame/s.meltFrameCount))+'px'; 516 s.meltFrame++; 517 } else { 518 s.recycle(); 519 } 520 } 521 }; 522 523 this.recycle = function() { 524 s.o.style.display = 'none'; 525 s.o.style.animationPlayState = 'running'; 526 s.o.style.position = (fixedForEverything?'fixed':'absolute'); 527 s.o.style.bottom = 'auto'; 528 s.setVelocities(); 529 s.vCheck(); 530 s.meltFrame = 0; 531 s.melting = false; 532 s.setOpacity(s.o,1); 533 s.o.style.fontSize = s.fontSize+'px'; 534 //s.o.style.lineHeight = (storm.flakeHeight+2)+'px'; 535 s.x = parseInt(rnd(screenX-storm.flakeWidth-20),10); 536 s.y = parseInt(rnd(screenY)*-1,10)-storm.flakeHeight; 537 s.refresh(); 538 s.o.style.display = 'block'; 539 s.active = 1; 540 }; 541 542 this.recycle(); // set up x/y coords etc. 543 this.refresh();
544 545 }; 546 547 this.snow = function() { 548 var active = 0, flake = null, i, j; 549 for (i=0, j=storm.flakes.length; i<j; i++) { 550 if (storm.flakes[i].active === 1) { 551 storm.flakes[i].move(); 552 active++; 553 } 554 if (storm.flakes[i].melting) { 555 storm.flakes[i].melt(); 556 } 557 } 558 if (active<storm.flakesMaxActive) { 559 flake = storm.flakes[parseInt(rnd(storm.flakes.length),10)]; 560 if (flake.active === 0) { 561 flake.melting = true; 562 } 563 } 564 if (storm.timer) { 565 features.getAnimationFrame(storm.snow); 566 } 567 }; 568 569 this.mouseMove = function(e) { 570 if (!storm.followMouse) { 571 return true; 572 } 573 var x = parseInt(e.clientX,10); 574 if (x<screenX2) { 575 x -= screenX2; 576 windOffset = (x/screenX2)*windMultiplier; 577 } else { 578 windOffset = -windMultiplier+(x/screenX2*windMultiplier); 579 } 580 }; 581 582 this.createSnow = function(limit,allowInactive) { 583 var i; 584 for (i=0; i<limit; i++) { 585 storm.flakes[storm.flakes.length] = new storm.SnowFlake(parseInt(rnd(flakeTypes),10)); 586 if (allowInactive || i>storm.flakesMaxActive) { 587 storm.flakes[storm.flakes.length-1].active = -1; 588 } 589 } 590 storm.targetElement.appendChild(docFrag); 591 }; 592 593 this.timerInit = function() { 594 storm.timer = true; 595 storm.snow(); 596 }; 597 598 this.init = function() { 599 var i; 600 for (i=0; i<storm.meltFrameCount; i++) { 601 storm.meltFrames.push(1-(i/storm.meltFrameCount)); 602 } 603 storm.randomizeWind(); 604 storm.createSnow(storm.flakesMax); // create initial batch 605 storm.events.add(window,'resize',storm.resizeHandler); 606 storm.events.add(window,'scroll',storm.scrollHandler); 607 if (storm.freezeOnBlur) { 608 if (isIE) { 609 storm.events.add(document,'focusout',storm.freeze); 610 storm.events.add(document,'focusin',storm.resume); 611 } else { 612 storm.events.add(window,'blur',storm.freeze); 613 storm.events.add(window,'focus',storm.resume); 614 } 615 } 616 storm.resizeHandler(); 617 storm.scrollHandler(); 618 if (storm.followMouse) { 619 storm.events.add(isIE?document:window,'mousemove',storm.mouseMove); 620 } 621 storm.animationInterval = Math.max(20,storm.animationInterval); 622 storm.timerInit(); 623 }; 624 625 this.start = function(bFromOnLoad) { 626 if (!didInit) { 627 didInit = true; 628 } else if (bFromOnLoad) { 629 // already loaded and running 630 return true; 631 } 632 if (typeof storm.targetElement === 'string') { 633 var targetID = storm.targetElement; 634 storm.targetElement = document.querySelector(targetID); 635 if (!storm.targetElement) { 636 throw new Error('Snowstorm: Unable to get targetElement "'+targetID+'"'); 637 } 638 } 639 if (!storm.targetElement) { 640 storm.targetElement = (document.body || document.documentElement); 641 } 642 if (storm.targetElement !== document.documentElement && storm.targetElement !== document.body) { 643 // re-map handler to get element instead of screen dimensions 644 storm.resizeHandler = storm.resizeHandlerAlt; 645 //and force-enable pixel positioning 646 storm.usePixelPosition = true; 647 } 648 storm.resizeHandler(); // get bounding box elements 649 storm.usePositionFixed = (storm.usePositionFixed && !noFixed && !storm.flakeBottom); // whether or not position:fixed is to be used 650 if (window.getComputedStyle) { 651 // attempt to determine if body or user-specified snow parent element is relatlively-positioned. 652 try { 653 targetElementIsRelative = (window.getComputedStyle(storm.targetElement, null).getPropertyValue('position') === 'relative'); 654 } catch(e) { 655 // oh well 656 targetElementIsRelative = false; 657 } 658 } 659 fixedForEverything = storm.usePositionFixed; 660 if (screenX && screenY && !storm.disabled) { 661 storm.init(); 662 storm.active = true; 663 } 664 }; 665 666 function doDelayedStart() { 667 window.setTimeout(function() { 668 storm.start(true); 669 }, 20); 670 // event cleanup 671 storm.events.remove(isIE?document:window,'mousemove',doDelayedStart); 672 } 673 674 function doStart() { 675 if (!storm.excludeMobile || !isMobile) { 676 doDelayedStart(); 677 } 678 // event cleanup 679 storm.events.remove(window, 'load', doStart); 680 } 681 682 // hooks for starting the snow 683 if (storm.autoStart) { 684 storm.events.add(window, 'load', doStart, false); 685 } 686 687 return this; 688 689}(window, document));
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.