1 /*! SWFObject v2.2 <http://code.google.com/p/swfobject/>
2 is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
5 var swfobject = function() {
7 var UNDEF = "undefined",
9 SHOCKWAVE_FLASH = "Shockwave Flash",
10 SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
11 FLASH_MIME_TYPE = "application/x-shockwave-flash",
12 EXPRESS_INSTALL_ID = "SWFObjectExprInst",
13 ON_READY_STATE_CHANGE = "onreadystatechange",
20 domLoadFnArr = [main],
29 isExpressInstallActive = false,
31 dynamicStylesheetMedia,
34 /* Centralized function for browser feature detection
35 - User agent string detection is only used when no good alternative is possible
36 - Is executed directly for optimal performance
39 var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
40 u = nav.userAgent.toLowerCase(),
41 p = nav.platform.toLowerCase(),
42 windows = p ? /win/.test(p) : /win/.test(u),
43 mac = p ? /mac/.test(p) : /mac/.test(u),
44 webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
45 ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
46 playerVersion = [0,0,0],
48 if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
49 d = nav.plugins[SHOCKWAVE_FLASH].description;
50 if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
52 ie = false; // cascaded feature detection for Internet Explorer
53 d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
54 playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
55 playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
56 playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0;
59 else if (typeof win.ActiveXObject != UNDEF) {
61 var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
62 if (a) { // a will return null when ActiveX is disabled
63 d = a.GetVariable("$version");
65 ie = true; // cascaded feature detection for Internet Explorer
66 d = d.split(" ")[1].split(",");
67 playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
73 return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };
76 /* Cross-browser onDomLoad
77 - Will fire an event as soon as the DOM of a web page is loaded
78 - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/
79 - Regular onload serves as fallback
81 onDomLoad = function() {
82 if (!ua.w3) { return; }
83 if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically
84 callDomLoadFunctions();
87 if (typeof doc.addEventListener != UNDEF) {
88 doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);
90 if (ua.ie && ua.win) {
91 doc.attachEvent(ON_READY_STATE_CHANGE, function() {
92 if (doc.readyState == "complete") {
93 doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee);
94 callDomLoadFunctions();
97 if (win == top) { // if not inside an iframe
99 if (isDomLoaded) { return; }
101 doc.documentElement.doScroll("left");
104 setTimeout(arguments.callee, 0);
107 callDomLoadFunctions();
113 if (isDomLoaded) { return; }
114 if (!/loaded|complete/.test(doc.readyState)) {
115 setTimeout(arguments.callee, 0);
118 callDomLoadFunctions();
121 addLoadEvent(callDomLoadFunctions);
125 function callDomLoadFunctions() {
126 if (isDomLoaded) { return; }
127 try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early
128 var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span"));
129 t.parentNode.removeChild(t);
131 catch (e) { return; }
133 var dl = domLoadFnArr.length;
134 for (var i = 0; i < dl; i++) {
139 function addDomLoadEvent(fn) {
144 domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
148 /* Cross-browser onload
149 - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
150 - Will fire an event as soon as a web page including all of its assets are loaded
152 function addLoadEvent(fn) {
153 if (typeof win.addEventListener != UNDEF) {
154 win.addEventListener("load", fn, false);
156 else if (typeof doc.addEventListener != UNDEF) {
157 doc.addEventListener("load", fn, false);
159 else if (typeof win.attachEvent != UNDEF) {
160 addListener(win, "onload", fn);
162 else if (typeof win.onload == "function") {
163 var fnOld = win.onload;
164 win.onload = function() {
175 - Will preferably execute onDomLoad, otherwise onload (as a fallback)
186 /* Detect the Flash Player version for non-Internet Explorer browsers
187 - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description:
188 a. Both release and build numbers can be detected
189 b. Avoid wrong descriptions by corrupt installers provided by Adobe
190 c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports
191 - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available
193 function testPlayerVersion() {
194 var b = doc.getElementsByTagName("body")[0];
195 var o = createElement(OBJECT);
196 o.setAttribute("type", FLASH_MIME_TYPE);
197 var t = b.appendChild(o);
201 if (typeof t.GetVariable != UNDEF) {
202 var d = t.GetVariable("$version");
204 d = d.split(" ")[1].split(",");
205 ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
208 else if (counter < 10) {
210 setTimeout(arguments.callee, 10);
223 /* Perform Flash Player and SWF version matching; static publishing only
225 function matchVersions() {
226 var rl = regObjArr.length;
228 for (var i = 0; i < rl; i++) { // for each registered object element
229 var id = regObjArr[i].id;
230 var cb = regObjArr[i].callbackFn;
231 var cbObj = {success:false, id:id};
233 var obj = getElementById(id);
235 if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match!
236 setVisibility(id, true);
238 cbObj.success = true;
239 cbObj.ref = getObjectById(id);
243 else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported
245 att.data = regObjArr[i].expressInstall;
246 att.width = obj.getAttribute("width") || "0";
247 att.height = obj.getAttribute("height") || "0";
248 if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); }
249 if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); }
250 // parse HTML object param element's name-value pairs
252 var p = obj.getElementsByTagName("param");
254 for (var j = 0; j < pl; j++) {
255 if (p[j].getAttribute("name").toLowerCase() != "movie") {
256 par[p[j].getAttribute("name")] = p[j].getAttribute("value");
259 showExpressInstall(att, par, id, cb);
261 else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF
262 displayAltContent(obj);
263 if (cb) { cb(cbObj); }
267 else { // if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content)
268 setVisibility(id, true);
270 var o = getObjectById(id); // test whether there is an HTML object element or not
271 if (o && typeof o.SetVariable != UNDEF) {
272 cbObj.success = true;
282 function getObjectById(objectIdStr) {
284 var o = getElementById(objectIdStr);
285 if (o && o.nodeName == "OBJECT") {
286 if (typeof o.SetVariable != UNDEF) {
290 var n = o.getElementsByTagName(OBJECT)[0];
299 /* Requirements for Adobe Express Install
300 - only one instance can be active at a time
301 - fp 6.0.65 or higher
303 - no Webkit engines older than version 312
305 function canExpressInstall() {
306 return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312);
309 /* Show the Adobe Express Install dialog
310 - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
312 function showExpressInstall(att, par, replaceElemIdStr, callbackFn) {
313 isExpressInstallActive = true;
314 storedCallbackFn = callbackFn || null;
315 storedCallbackObj = {success:false, id:replaceElemIdStr};
316 var obj = getElementById(replaceElemIdStr);
318 if (obj.nodeName == "OBJECT") { // static publishing
319 storedAltContent = abstractAltContent(obj);
320 storedAltContentId = null;
322 else { // dynamic publishing
323 storedAltContent = obj;
324 storedAltContentId = replaceElemIdStr;
326 att.id = EXPRESS_INSTALL_ID;
327 if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; }
328 if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; }
329 doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
330 var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
331 fv = "MMredirectURL=" + win.location.toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
332 if (typeof par.flashvars != UNDEF) {
333 par.flashvars += "&" + fv;
338 // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
339 // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
340 if (ua.ie && ua.win && obj.readyState != 4) {
341 var newObj = createElement("div");
342 replaceElemIdStr += "SWFObjectNew";
343 newObj.setAttribute("id", replaceElemIdStr);
344 obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf
345 obj.style.display = "none";
347 if (obj.readyState == 4) {
348 obj.parentNode.removeChild(obj);
351 setTimeout(arguments.callee, 10);
355 createSWF(att, par, replaceElemIdStr);
359 /* Functions to abstract and display alternative content
361 function displayAltContent(obj) {
362 if (ua.ie && ua.win && obj.readyState != 4) {
363 // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
364 // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
365 var el = createElement("div");
366 obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content
367 el.parentNode.replaceChild(abstractAltContent(obj), el);
368 obj.style.display = "none";
370 if (obj.readyState == 4) {
371 obj.parentNode.removeChild(obj);
374 setTimeout(arguments.callee, 10);
379 obj.parentNode.replaceChild(abstractAltContent(obj), obj);
383 function abstractAltContent(obj) {
384 var ac = createElement("div");
385 if (ua.win && ua.ie) {
386 ac.innerHTML = obj.innerHTML;
389 var nestedObj = obj.getElementsByTagName(OBJECT)[0];
391 var c = nestedObj.childNodes;
394 for (var i = 0; i < cl; i++) {
395 if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
396 ac.appendChild(c[i].cloneNode(true));
405 /* Cross-browser dynamic SWF creation
407 function createSWF(attObj, parObj, id) {
408 var r, el = getElementById(id);
409 if (ua.wk && ua.wk < 312) { return r; }
411 if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
414 if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
416 for (var i in attObj) {
417 if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
418 if (i.toLowerCase() == "data") {
419 parObj.movie = attObj[i];
421 else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
422 att += ' class="' + attObj[i] + '"';
424 else if (i.toLowerCase() != "classid") {
425 att += ' ' + i + '="' + attObj[i] + '"';
430 for (var j in parObj) {
431 if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
432 par += '<param name="' + j + '" value="' + parObj[j] + '" />';
435 el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
436 objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
437 r = getElementById(attObj.id);
439 else { // well-behaving browsers
440 var o = createElement(OBJECT);
441 o.setAttribute("type", FLASH_MIME_TYPE);
442 for (var m in attObj) {
443 if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
444 if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
445 o.setAttribute("class", attObj[m]);
447 else if (m.toLowerCase() != "classid") { // filter out IE specific attribute
448 o.setAttribute(m, attObj[m]);
452 for (var n in parObj) {
453 if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
454 createObjParam(o, n, parObj[n]);
457 el.parentNode.replaceChild(o, el);
464 function createObjParam(el, pName, pValue) {
465 var p = createElement("param");
466 p.setAttribute("name", pName);
467 p.setAttribute("value", pValue);
471 /* Cross-browser SWF removal
472 - Especially needed to safely and completely remove a SWF in Internet Explorer
474 function removeSWF(id) {
475 var obj = getElementById(id);
476 if (obj && obj.nodeName == "OBJECT") {
477 if (ua.ie && ua.win) {
478 obj.style.display = "none";
480 if (obj.readyState == 4) {
481 removeObjectInIE(id);
484 setTimeout(arguments.callee, 10);
489 obj.parentNode.removeChild(obj);
494 function removeObjectInIE(id) {
495 var obj = getElementById(id);
498 if (typeof obj[i] == "function") {
502 obj.parentNode.removeChild(obj);
506 /* Functions to optimize JavaScript compression
508 function getElementById(id) {
511 el = doc.getElementById(id);
517 function createElement(el) {
518 return doc.createElement(el);
521 /* Updated attachEvent function for Internet Explorer
522 - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
524 function addListener(target, eventType, fn) {
525 target.attachEvent(eventType, fn);
526 listenersArr[listenersArr.length] = [target, eventType, fn];
529 /* Flash Player and SWF content version matching
531 function hasPlayerVersion(rv) {
532 var pv = ua.pv, v = rv.split(".");
533 v[0] = parseInt(v[0], 10);
534 v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
535 v[2] = parseInt(v[2], 10) || 0;
536 return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
539 /* Cross-browser dynamic CSS creation
540 - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
542 function createCSS(sel, decl, media, newStyle) {
543 if (ua.ie && ua.mac) { return; }
544 var h = doc.getElementsByTagName("head")[0];
545 if (!h) { return; } // to also support badly authored HTML pages that lack a head element
546 var m = (media && typeof media == "string") ? media : "screen";
548 dynamicStylesheet = null;
549 dynamicStylesheetMedia = null;
551 if (!dynamicStylesheet || dynamicStylesheetMedia != m) {
552 // create dynamic stylesheet + get a global reference to it
553 var s = createElement("style");
554 s.setAttribute("type", "text/css");
555 s.setAttribute("media", m);
556 dynamicStylesheet = h.appendChild(s);
557 if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
558 dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1];
560 dynamicStylesheetMedia = m;
563 if (ua.ie && ua.win) {
564 if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) {
565 dynamicStylesheet.addRule(sel, decl);
569 if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) {
570 dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
575 function setVisibility(id, isVisible) {
576 if (!autoHideShow) { return; }
577 var v = isVisible ? "visible" : "hidden";
578 if (isDomLoaded && getElementById(id)) {
579 getElementById(id).style.visibility = v;
582 createCSS("#" + id, "visibility:" + v);
586 /* Filter to avoid XSS attacks
588 function urlEncodeIfNecessary(s) {
589 var regex = /[\\\"<>\.;]/;
590 var hasBadChars = regex.exec(s) != null;
591 return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
594 /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
596 var cleanup = function() {
597 if (ua.ie && ua.win) {
598 window.attachEvent("onunload", function() {
599 // remove listeners to avoid memory leaks
600 var ll = listenersArr.length;
601 for (var i = 0; i < ll; i++) {
602 listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
604 // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
605 var il = objIdArr.length;
606 for (var j = 0; j < il; j++) {
607 removeSWF(objIdArr[j]);
609 // cleanup library's main closures to avoid memory leaks
614 for (var l in swfobject) {
624 - Reference: http://code.google.com/p/swfobject/wiki/documentation
626 registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {
627 if (ua.w3 && objectIdStr && swfVersionStr) {
629 regObj.id = objectIdStr;
630 regObj.swfVersion = swfVersionStr;
631 regObj.expressInstall = xiSwfUrlStr;
632 regObj.callbackFn = callbackFn;
633 regObjArr[regObjArr.length] = regObj;
634 setVisibility(objectIdStr, false);
636 else if (callbackFn) {
637 callbackFn({success:false, id:objectIdStr});
641 getObjectById: function(objectIdStr) {
643 return getObjectById(objectIdStr);
647 embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) {
648 var callbackObj = {success:false, id:replaceElemIdStr};
649 if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
650 setVisibility(replaceElemIdStr, false);
651 addDomLoadEvent(function() {
652 widthStr += ""; // auto-convert to string
655 if (attObj && typeof attObj === OBJECT) {
656 for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
660 att.data = swfUrlStr;
661 att.width = widthStr;
662 att.height = heightStr;
664 if (parObj && typeof parObj === OBJECT) {
665 for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
669 if (flashvarsObj && typeof flashvarsObj === OBJECT) {
670 for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
671 if (typeof par.flashvars != UNDEF) {
672 par.flashvars += "&" + k + "=" + flashvarsObj[k];
675 par.flashvars = k + "=" + flashvarsObj[k];
679 if (hasPlayerVersion(swfVersionStr)) { // create SWF
680 var obj = createSWF(att, par, replaceElemIdStr);
681 if (att.id == replaceElemIdStr) {
682 setVisibility(replaceElemIdStr, true);
684 callbackObj.success = true;
685 callbackObj.ref = obj;
687 else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install
688 att.data = xiSwfUrlStr;
689 showExpressInstall(att, par, replaceElemIdStr, callbackFn);
692 else { // show alternative content
693 setVisibility(replaceElemIdStr, true);
695 if (callbackFn) { callbackFn(callbackObj); }
698 else if (callbackFn) { callbackFn(callbackObj); }
701 switchOffAutoHideShow: function() {
702 autoHideShow = false;
707 getFlashPlayerVersion: function() {
708 return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
711 hasFlashPlayerVersion: hasPlayerVersion,
713 createSWF: function(attObj, parObj, replaceElemIdStr) {
715 return createSWF(attObj, parObj, replaceElemIdStr);
722 showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {
723 if (ua.w3 && canExpressInstall()) {
724 showExpressInstall(att, par, replaceElemIdStr, callbackFn);
728 removeSWF: function(objElemIdStr) {
730 removeSWF(objElemIdStr);
734 createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {
736 createCSS(selStr, declStr, mediaStr, newStyleBoolean);
740 addDomLoadEvent: addDomLoadEvent,
742 addLoadEvent: addLoadEvent,
744 getQueryParamValue: function(param) {
745 var q = doc.location.search || doc.location.hash;
747 if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark
749 return urlEncodeIfNecessary(q);
751 var pairs = q.split("&");
752 for (var i = 0; i < pairs.length; i++) {
753 if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
754 return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
761 // For internal usage only
762 expressInstallCallback: function() {
763 if (isExpressInstallActive) {
764 var obj = getElementById(EXPRESS_INSTALL_ID);
765 if (obj && storedAltContent) {
766 obj.parentNode.replaceChild(storedAltContent, obj);
767 if (storedAltContentId) {
768 setVisibility(storedAltContentId, true);
769 if (ua.ie && ua.win) { storedAltContent.style.display = "block"; }
771 if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }
773 isExpressInstallActive = false;