1if(typeof __wm==="undefined") __wm={}; 2(function(){ 3 var _JSON = typeof __wbhack != 'undefined' ? __wbhack.JSON : JSON; 4 var prettyMonths = [ 5 "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; 6 var $D=document,$R=document,$=function(n){return $R.getElementById(n)}; 7 8 function formatNumber(n) { 9 return (''+n).replace(/\B(?=(\d{3})+$)/g, ','); 10 } 11 var ajax=__wm.ajax=function ajax(method, url, callback, headers, data) { 12 var xmlhttp; 13 if (window.XMLHttpRequest) { 14 xmlhttp = new XMLHttpRequest(); 15 } else { 16 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 17 } 18 xmlhttp.onreadystatechange = function() { 19 if (this.readyState == 4) { 20 callback(xmlhttp); 21 } 22 }; 23 xmlhttp.open(method, url, true); 24 if (headers) { 25 for (var header in headers) { 26 if (headers.hasOwnProperty(header)) { 27 xmlhttp.setRequestHeader(header, headers[header]); 28 } 29 } 30 } 31 // pass cookies for user authorization 32 xmlhttp.withCredentials = true; 33 xmlhttp.send(data); 34 } 35 36 __wm.h=function hideToolbar(ev) { 37 $("wm-ipp").style.display="none"; 38 ev.stopPropagation(); 39 } 40 41 var $expand, $capinfo; 42 43 __wm.bt=function bootstrap(imgWidth,imgHeight,yearImgWidth,monthImgWidth, 44 coll,wbCurrentUrl,captureDate,firstYear, 45 static_prefix,bannerCss) { 46 __wm.static_prefix = static_prefix || '/static/'; 47 var wbPrefix='/'+(coll||'web')+'/'; 48 captureDate = captureDate.split('-'); 49 var displayDay = captureDate[2]; 50 var displayMonth = captureDate[1]; 51 var displayYear = captureDate[0]; 52 var trackerVal,curYear = -1,curMonth = -1; 53 var yearTracker,monthTracker; 54 55 // move #wm-ipp content to its shadowRoot if supported 56 var wmipp = $('wm-ipp-base'); 57 if (wmipp.attachShadow){ 58 var shadow = wmipp.attachShadow({mode:'open'}); 59 $R = shadow; // this changes the base of $() 60 var nav = wmipp.children[0];nav.id='wm-ipp'; 61 shadow.appendChild(nav); 62 if (bannerCss) { 63 for(var i = 0; i < bannerCss.length; i++) { 64 var link = $D.createElement('link'); 65 link.setAttribute('rel', 'stylesheet'); 66 link.setAttribute('type', 'text/css'); 67 link.setAttribute('href', static_prefix + bannerCss[i]); 68 shadow.appendChild(link); 69 } 70 } 71 } 72 if (window.top == window.self) { 73 wmipp.style.display = "block"; 74 } 75 76 var $spk=$('wm-ipp-sparkline') 77 $expand=$('wm-expand'); 78 $capinfo=$('wm-capinfo'); 79 80 function showTrackers(event) { 81 var val = event.type=="mouseenter"?1:0; 82 if (val===trackerVal) return; 83 var $ipp=$("wm-ipp"); 84 var $y=$("displayYearEl"),$m=$("displayMonthEl"),$d=$("displayDayEl"); 85 if (val) { 86 $ipp.className="hi"; 87 } else { 88 $ipp.className=""; 89 $y.innerHTML=displayYear;$m.innerHTML=prettyMonths[displayMonth-1];$d.innerHTML=displayDay; 90 } 91 yearTracker.style.display=val?"inline":"none"; 92 monthTracker.style.display=val?"inline":"none"; 93 trackerVal = val; 94 } 95 function getElementX2(el) { 96 var de = $D.documentElement; 97 var box = (typeof el.getBoundingClientRect!=='undefied')? 98 el.getBoundingClientRect():{top:0,left:0}; 99 return box.left + (window.pageXOffset||de.scrollLeft)-(de.clientLeft||0); 100 } 101 function navCaptures(captures) { 102 var $e = $("wm-nav-captures"); 103 var count = 0; 104 var years = captures.years; 105 var first_ts = captures.first_ts, last_ts = captures.last_ts; 106 for (var j = 0; j < years.length; j++) { 107 var months = years[j][1]; 108 for (var i = 0; i < months.length; i++) { 109 count += months[i]; 110 } 111 } 112 var html = '<a class="t" href="' + wbPrefix + '*/' + wbCurrentUrl + 113 '" title="See a list of every capture for this URL">' + 114 formatNumber(count) + ' ' + 115 (count > 1 ? "captures" : "capture") + '</a>'; 116 var timespan = __wbTs.format(first_ts, '%d %b %Y'); 117 if (last_ts != first_ts) { 118 timespan += ' - ' + __wbTs.format(last_ts, '%d %b %Y'); 119 } 120 html += '<div class="r" title="Timespan for captures of this URL">' + 121 timespan + '</div>'; 122 $e.innerHTML = html; 123 } 124 function trackMouseMove(event) { 125 //var element = event.target; 126 var element = $spk; 127 var eventX = getEventX(event); 128 var elementX = getElementX2(element); 129 var xOff = Math.min(Math.max(0, eventX - elementX),imgWidth); 130 var monthOff = xOff % yearImgWidth; 131 132 var year = Math.floor(xOff / yearImgWidth); 133 var monthOfYear = Math.min(11,Math.floor(monthOff / monthImgWidth)); 134 // 1 extra border pixel at the left edge of the year:
135 var month = (year * 12) + monthOfYear; 136 var day = monthOff % 2==1?15:1; 137 var dateString = zeroPad(year + firstYear) + zeroPad(monthOfYear+1,2) + 138 zeroPad(day,2) + "000000"; 139 140 $("displayYearEl").innerHTML=year+firstYear; 141 $("displayMonthEl").innerHTML=prettyMonths[monthOfYear]; 142 // looks too jarring when it changes.. 143 //$("displayDayEl").innerHTML=zeroPad(day,2); 144 var url = wbPrefix + dateString + '/' + wbCurrentUrl; 145 $("wm-graph-anchor").href=url; 146 147 if(curYear != year) { 148 var yrOff = year * yearImgWidth; 149 yearTracker.style.left = yrOff + "px"; 150 curYear = year; 151 } 152 if(curMonth != month) { 153 var mtOff = year + (month * monthImgWidth) + 1; 154 monthTracker.style.left = mtOff + "px"; 155 curMonth = month; 156 } 157 } 158 function disclaimElement(element) { 159 if (window.top == window.self) { 160 element.style.display = "block"; 161 $D.body.insertBefore(element, $D.body.firstChild); 162 } 163 } 164 yearTracker=$D.createElement('div'); 165 yearTracker.className='yt'; 166 with(yearTracker.style){ 167 display='none';width=yearImgWidth+"px";height=imgHeight+"px"; 168 } 169 monthTracker=$D.createElement('div'); 170 monthTracker.className='mt'; 171 with(monthTracker.style){ 172 display='none';width=monthImgWidth+"px";height=imgHeight+"px"; 173 } 174 $spk.appendChild(yearTracker); 175 $spk.appendChild(monthTracker); 176 177 var $cv=$('wm-sparkline-canvas'); 178 $spk.onmouseenter=showTrackers; 179 $spk.onmouseleave=showTrackers; 180 $spk.onmousemove=trackMouseMove; 181 182 //var $ipp=$("wm-ipp"); 183 //$ipp&&disclaimElement($ipp); 184 185 var canvas = $('wm-sparkline-canvas'); 186 if (!!(canvas.getContext && canvas.getContext('2d'))) { 187 var sparkline_url = "/__wb/sparkline?output=json&url=" + 188 encodeURIComponent(wbCurrentUrl) + 189 (coll && "&collection=" + coll || ''); 190 ajax("GET", sparkline_url, function(response) { 191 if(response.status == 200) { 192 var capnav=_JSON.parse(response.responseText); 193 var yearsobj = capnav.years; 194 var ykeys = Object.getOwnPropertyNames(yearsobj); 195 var years = (capnav.years = []); 196 for (var i = 0; i < ykeys.length; i++) { 197 var y = ykeys[i]; 198 if (yearsobj[y]) { 199 years.push([y, yearsobj[y]]); 200 } 201 } 202 navCaptures(capnav); 203 sparkline(capnav,imgWidth,imgHeight,canvas, 204 firstYear, displayYear, displayMonth); 205 } 206 }); 207 } else { 208 var sparklineImg = new Image(); 209 sparklineImg.src = "/__wb/sparkline?url=" + 210 encodeURIComponent(wbCurrentUrl) + 211 "&width=" + imgWidth + "&height=" + imgHeight +
212 "&selected_year=" + displayYear + "&selected_month=" + displayMonth + 213 (coll && "&collection=" + coll || ''); 214 sparklineImg.alt= "sparkline"; 215 sparklineImg.width=imgWidth; 216 sparklineImg.height=imgHeight; 217 sparklineImg.id="sparklineImgId"; 218 sparklineImg.border="0"; 219 $cv.parentNode.replaceChild(sparklineImg, $cv); 220 } 221 222 function process_autocomplete(data) { 223 var out = [] 224 var len = data.length; 225 for(var i=0; i<len; i++) { 226 if(typeof data[i].excluded === 'undefined') { 227 out.push(data[i].display_name); 228 } 229 } 230 return out; 231 } 232 new wbAutoComplete({ 233 selector: $('wmtbURL'), 234 delay: 400, 235 source: function(query, suggest) { 236 ajax("GET", '/__wb/search/host?q=' + encodeURIComponent(query), 237 function(data) { 238 var data = _JSON.parse(data.response); 239 if (typeof data.hosts!=='undefined' && data.hosts.length>0) { 240 var output = process_autocomplete(data.hosts); 241 suggest(output); 242 } else if (typeof data.isUrl!=='undefined' && data.isUrl===true && typeof data.excluded==='undefined') { 243 suggest([query]); 244 } else { 245 ajax("GET", '/__wb/search/anchor?q='+encodeURIComponent(query), 246 function(data) { 247 var data = _JSON.parse(data.response); 248 if (typeof data!=='undefined' && data.length>0) { 249 var output = process_autocomplete(data.slice(0,5)); 250 suggest(output); 251 } 252 }); 253 } 254 }); 255 }, 256 onSelect: function(e, term, item) { 257 $("wmtb").submit(); 258 } 259 }); 260 $("wmtb").onsubmit = function(e) { 261 var query = $("wmtbURL").value; 262 // if textbox value is not a URL, redirect to search 263 if (!(query.indexOf('https://') === 0 || query.indexOf('https://') === 0 || 264 query.match(/[\w\.]{2,256}\.[a-z]{2,4}/gi))) { 265 document.location.href="/web/*/" + $("wmtbURL").value; 266 e.preventDefault(); 267 return false; 268 } 269 }; 270 }; 271 function show_timestamps() { 272 // Populate capinfo with capture resources if empty. If not empty, it has 273 // already run before so avoid redoing AJAX. 274 var $capresources=$('wm-capresources'); 275 $capresources.innerHTML = ''; 276 //disable caching to be able to reload list when browsing frames. 277 //if($capresources.innerHTML.length !== 0) { 278 // return; 279 //} 280 var $wmloading=$("wm-capresources-loading"); 281 $wmloading.style.display='block'; 282 283 // calculate datetime difference with capture datetime and return relative 284 // value such as "-5 hours, 10 minutes". 285 var capture_ts = $('wmtb').elements.date.value; 286 var capture_msec = __wbTs.timestamp2datetime(capture_ts).getTime(); 287 function datetime_diff(dt_str) { 288 var dt_msec = Date.parse(dt_str); 289 var diff = dt_msec - capture_msec; 290 var prefix = ""; 291 if(diff < 0) { 292 prefix += "-"; 293 diff = Math.abs(diff); 294 } else { 295 prefix += "+"; 296 } 297 var highlight = false; 298 if(diff < 1000) { 299 // equal to the page datetime 300 return {delta: diff, text:"", highlight: highlight}; 301 } 302 var total_diff = diff; 303 var years_d = Math.floor(diff/1000/60/60/24/30/12); 304 diff -= years_d*1000*60*60*24*30*12; 305 var months_d = Math.floor(diff/1000/60/60/24/30); 306 diff -= months_d*1000*60*60*24*30; 307 var days_d = Math.floor(diff/1000/60/60/24); 308 diff -= days_d*1000*60*60*24; 309 var hours_d = Math.floor(diff/1000/60/60); 310 diff -= hours_d*1000*60*60; 311 var minutes_d = Math.floor(diff/1000/60); 312 diff -= minutes_d*1000*60; 313 var seconds_d = Math.floor(diff/1000); 314 315 var parts = []; 316 if(years_d > 1) { 317 parts.push(years_d + " years"); 318 highlight = true; 319 } else if(years_d == 1) { 320 parts.push(years_d + " year"); 321 highlight = true; 322 } 323 if(months_d > 1) { 324 parts.push(months_d + " months"); 325 highlight = true; 326 } else if(months_d == 1) { 327 parts.push(months_d + " month"); 328 highlight = true; 329 } 330 if(days_d > 1) { 331 parts.push(days_d + " days"); 332 } else if(days_d == 1) { 333 parts.push(days_d + " day"); 334 } 335 if(hours_d > 1) { 336 parts.push(hours_d + " hours"); 337 } else if(hours_d == 1) { 338 parts.push(hours_d + " hour"); 339 } 340 if(minutes_d > 1) { 341 parts.push(minutes_d + " minutes"); 342 } else if (minutes_d == 1) { 343 parts.push(minutes_d + " minute"); 344 } 345 if(seconds_d > 1) { 346 parts.push(seconds_d + " seconds"); 347 } else if(seconds_d == 1) { 348 parts.push(seconds_d + " second"); 349 } 350 if(parts.length > 2) { 351 parts = parts.slice(0, 2); 352 } 353 return {delta: total_diff, text: prefix + parts.join(" "), 354 highlight: highlight}; 355 } 356 // Utility method to find elements in dom (currently only img) using URL. 357 // Also look into embedded frames recursively 358 // Captured resources urls may have timestamps different from DOM URL 359 // so it is not possible to search with original path 360 // /web/20120407141544/https://example.com 361 // we must search for URLS ENDING WITH https://example.com 362 function find_elements_by_url(current_window, url) { 363 var orig_url = url.split("/").splice(6).join("/"); 364 var els=current_window.document.querySelectorAll( 365 "img[src$='" + orig_url + "'], iframe[src$='" + orig_url + "'], frame[src$='" + orig_url + "']" 366 ); 367 var els_array=Array.prototype.slice.call(els); 368 for(var i=0; i<current_window.frames.length; i++) { 369 try { 370 var frame_els_array=find_elements_by_url(current_window.frames[i].window, url); 371 els_array = els_array.concat(frame_els_array); 372 } catch(err) { 373 // pass 374 } 375 } 376 return els_array; 377 } 378 // invoked onmouseover of link to add highlight 379 function highlight_elm(e){ 380 if(e.tagName=='FRAME'||e.tagName=='IFRAME') 381 return e.contentWindow.document.documentElement; 382 else 383 return e; 384 } 385 function highlight_on(ev) { 386 var elements = find_elements_by_url(window, ev.target.href); 387 if(elements.length > 0) { 388 for(var i=0; i<elements.length; i++) { 389 highlight_elm(elements[i]).classList.add("wb-highlight"); 390 } 391 } 392 } 393 // invoked onmouseout of link to remove highlight 394 function highlight_off(ev) { 395 var elements = find_elements_by_url(window, ev.target.href); 396 if(elements.length > 0) { 397 for(var i=0; i<elements.length; i++) { 398 highlight_elm(elements[i]).classList.remove("wb-highlight"); 399 } 400 } 401 } 402 403 // Utility method to show capture elements link, datetime and content-type. 404 // AJAX follows redirects automatically, only status=200 responses are handled. 405 var inflight_urls = 0; 406 function get_resource_info(url) { 407 if(!url.match('^https?://')) return; 408 inflight_urls++; 409 ajax("HEAD", url, function(response) { 410 if(response.status==200) { 411 $wmloading.style.display='none'; 412 var dt=response.getResponseHeader('Memento-Datetime'); 413 var dt_span=document.createElement('span'); 414 var dt_result = datetime_diff(dt); 415 var style = dt_result.highlight ? "color:red;" : ""; 416 dt_span.innerHTML=" " + dt_result.text; 417 dt_span.title=dt; 418 dt_span.setAttribute('style', style); 419 var ct=response.getResponseHeader('Content-Type'); 420 var url=response.responseURL.replace(window.location.origin, ""); 421 var link=document.createElement('a'); 422 // remove /web/timestamp/ from appearance 423 link.innerHTML=url.split("/").splice(3).join("/"); 424 link.href=url; 425 link.title=ct; 426 link.onmouseover=highlight_on; 427 link.onmouseout=highlight_off; 428 var el=document.createElement('div'); 429 el.setAttribute('data-delta', dt_result.delta); 430 el.appendChild(link); 431 el.append(dt_span); 432 $capresources.appendChild(el); 433 // sort elements by delta in a descending order and update container
434 var items = Array.prototype.slice.call($capresources.childNodes, 0); 435 items.sort(function(a, b) { 436 return b.getAttribute('data-delta') - a.getAttribute('data-delta'); 437 }); 438 $capresources.innerHTML = ""; 439 for(var i=0, len=items.length; i<len; i++) { 440 $capresources.appendChild(items[i]); 441 } 442 } 443 if (--inflight_urls == 0) { 444 $wmloading.style.display = 'none'; 445 } 446 }); 447 } 448 // utility method to traverse the document and frames recursively to find 449 // element with specific tag. Always convert selector result (NodeList) 450 // to Array to be able to concat. 451 function find_elements_by_tag_name(current_window, tag) { 452 var els=current_window.document.getElementsByTagName(tag); 453 var els_array=Array.prototype.slice.call(els); 454 for(var i=0; i<current_window.frames.length; i++) { 455 try { 456 var frame_els_array=find_elements_by_tag_name(current_window.frames[i].window, tag); 457 els_array = els_array.concat(frame_els_array); 458 } catch(err) { 459 // pass 460 } 461 } 462 return els_array; 463 } 464 465 // images 466 var static_prefix=window.location.origin + __wm.static_prefix; 467 var srcList=[]; 468 var imgs=find_elements_by_tag_name(window, 'img'); 469 for(var i=0, len=imgs.length; i<len; i++) { 470 // exclude WBM /_static/images, leaked images and embedded data URIs 471 if(!imgs[i].src || imgs[i].src.startsWith(static_prefix) || 472 !imgs[i].src.startsWith(window.location.origin) || 473 imgs[i].src.startsWith("data:")) { 474 continue; 475 } 476 srcList.push(imgs[i].src); 477 } 478 // frames 479 var frames=find_elements_by_tag_name(window, 'frame'); 480 for(i=0, len=frames.length; i<len; i++) { 481 if(!frames[i].src) { 482 continue; 483 } 484 srcList.push(frames[i].src); 485 } 486 var iframes=find_elements_by_tag_name(window, 'iframe'); 487 for(i=0, len=iframes.length; i<len; i++) { 488 if(!iframes[i].src || (iframes[i].id && iframes[i].id === 'playback')) { 489 continue; 490 } 491 srcList.push(iframes[i].src); 492 } 493 var scripts=find_elements_by_tag_name(window, 'script'); 494 for(i=0, len=scripts.length; i<len; i++) { 495 if(!scripts[i].src || scripts[i].src.startsWith(static_prefix) || 496 !scripts[i].src.startsWith(window.location.origin)) { 497 continue; 498 } 499 srcList.push(scripts[i].src); 500 } 501 // link.href (CSS, RSS, etc) 502 var links=find_elements_by_tag_name(window, 'link'); 503 for(i=0, len=links.length; i<len; i++) { 504 if(!links[i].href || links[i].href.startsWith(static_prefix) || 505 !links[i].href.startsWith(window.location.origin)) { 506 continue; 507 } 508 if(links[i].rel && links[i].rel=="stylesheet") { 509 srcList.push(links[i].href); 510 } 511 } 512 // deduplicate 513 var deduped = srcList.filter(function(el, i, arr) { 514 return arr.indexOf(el) === i; 515 }); 516 if(deduped.length > 0) { 517 inflight_urls = 0; 518 deduped.map(get_resource_info); 519 } else { 520 $capresources.innerHTML = "There are no sub-resources in the page."; 521 $wmloading.style.display='none'; 522 } 523 } 524 __wm.ex=function expand(ev) { 525 ev.stopPropagation(); 526 var c=$expand.className; 527 if (c.match(/wm-closed/)) { // closed 528 $expand.className=c.replace(/wm-closed/,'wm-open'); 529 $capinfo.style.display='block'; 530 show_timestamps(); 531 } else { 532 $expand.className=c.replace(/wm-open/,'wm-closed'); 533 $capinfo.style.display='none'; 534 } 535 }; 536 537 function isArray(obj) { 538 return (typeof obj !== 'undefined' && obj && obj.constructor === Array); 539 } 540 541 function setDisplayStyle(id, display) { 542 var el = $(id); 543 if (el) { 544 el.style.display = display; 545 } 546 } 547 548 function show(ids) { 549 if (!isArray(ids)) { 550 ids = [ids]; 551 } 552 for (var i = 0; i < ids.length; i++) { 553 setDisplayStyle(ids[i], 'inline-block'); 554 } 555 } 556 557 function hide(ids) { 558 if (!isArray(ids)) { 559 ids = [ids]; 560 } 561 for (var i = 0; i < ids.length; i++) { 562 setDisplayStyle(ids[i], 'none'); 563 } 564 } 565 566 function userIsLoggedIn() { 567 show('wm-save-snapshot-open'); 568 hide('wm-sign-in'); 569 } 570 571 function userIsNotLoggedIn() { 572 hide([
573 'wm-save-snapshot-open', 574 'wm-save-snapshot-in-progress', 575 ]); 576 show('wm-sign-in'); 577 } 578 579 function startSnapShotSaving() { 580 hide([ 581 'wm-save-snapshot-fail', 582 'wm-save-snapshot-open', 583 'wm-save-snapshot-success', 584 ]); 585 show([ 586 'wm-save-snapshot-in-progress', 587 ]); 588 } 589 590 function successSnapshotSaving() { 591 hide([ 592 'wm-save-snapshot-fail', 593 'wm-save-snapshot-in-progress', 594 ]); 595 show([ 596 'wm-save-snapshot-open', 597 'wm-save-snapshot-success', 598 ]); 599 } 600 601 function failSnapshotSaving(err) { 602 hide([ 603 'wm-save-snapshot-in-progress', 604 'wm-save-snapshot-success', 605 ]); 606 show([ 607 'wm-save-snapshot-fail', 608 'wm-save-snapshot-open', 609 ]); 610 } 611 612 /** 613 * check whether cookie has field 614 * 615 * @param name 616 * @return boolean 617 */ 618 function hasCookie(name) { 619 return document.cookie.search(name) >= 0; 620 } 621 622 __wm.saveSnapshot = function (url, timestamp, tags) { 623 startSnapShotSaving(); 624 ajax('POST', '/__wb/web-archive/', function (res) { 625 if (res.status === 401) { 626 // it seems that user is not logged in 627 userIsNotLoggedIn(); 628 } else if (res.status >= 400) { 629 failSnapshotSaving(res.responseText); 630 console.log('You have got an error.'); 631 console.log('If you think something wrong here please send it to supp
631ort.'); 632 console.log('Response: "' + res.responseText + '"'); 633 console.log('status: "' + res.status + '"'); 634 } else { 635 successSnapshotSaving(res); 636 } 637 }, { 638 'Content-Type': 'application/json' 639 }, _JSON.stringify({ 640 url: url, 641 snapshot: timestamp, 642 tags: tags || [], 643 })); 644 645 return false; 646 }; 647 648 document.addEventListener('DOMContentLoaded', function () { 649 if (hasCookie('logged-in-user') && hasCookie('logged-in-sig')) { 650 userIsLoggedIn(); 651 } else { 652 userIsNotLoggedIn(); 653 } 654 }); 655})();
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.