Preview
Source Code
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- This script got from www.devanswer.com -->
<style>
.alertify,
.alertify-show,
.alertify-log {
-webkit-transition: all 500ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
-moz-transition: all 500ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
-ms-transition: all 500ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
-o-transition: all 500ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition: all 500ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
/* easeOutBack */
}
.alertify-hide {
-webkit-transition: all 250ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
-moz-transition: all 250ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
-ms-transition: all 250ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
-o-transition: all 250ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
transition: all 250ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
/* easeInBack */
}
.alertify-log-hide {
-webkit-transition: all 500ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
-moz-transition: all 500ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
-ms-transition: all 500ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
-o-transition: all 500ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
transition: all 500ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
/* easeInBack */
}
.alertify-cover {
position: fixed;
z-index: 99999;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: white;
filter: alpha(opacity=0);
opacity: 0;
}
.alertify-cover-hidden {
display: none;
}
.alertify {
position: fixed;
z-index: 99999;
top: 50px;
left: 50%;
width: 550px;
margin-left: -275px;
opacity: 1;
}
.alertify-hidden {
-webkit-transform: translate(0, -150px);
-moz-transform: translate(0, -150px);
-ms-transform: translate(0, -150px);
-o-transform: translate(0, -150px);
transform: translate(0, -150px);
opacity: 0;
display: none;
}
/* overwrite display: none; for everything except IE6-8 */
:root * > .alertify-hidden {
display: block;
visibility: hidden;
}
.alertify-logs {
position: fixed;
z-index: 5000;
bottom: 10px;
right: 10px;
width: 300px;
}
.alertify-logs-hidden {
display: none;
}
.alertify-log {
display: block;
margin-top: 10px;
position: relative;
right: -300px;
opacity: 0;
}
.alertify-log-show {
right: 0;
opacity: 1;
}
.alertify-log-hide {
-webkit-transform: translate(300px, 0);
-moz-transform: translate(300px, 0);
-ms-transform: translate(300px, 0);
-o-transform: translate(300px, 0);
transform: translate(300px, 0);
opacity: 0;
}
.alertify-dialog {
padding: 25px;
}
.alertify-resetFocus {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.alertify-inner {
text-align: center;
}
.alertify-text {
margin-bottom: 15px;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
font-size: 100%;
}
.alertify-button,
.alertify-button:hover,
.alertify-button:active,
.alertify-button:visited {
background: none;
text-decoration: none;
border: none;
/* line-height and font-size for input button */
line-height: 1.5;
font-size: 100%;
display: inline-block;
cursor: pointer;
margin-left: 5px;
}
@media only screen and (max-width: 680px) {
.alertify,
.alertify-logs {
width: 90%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.alertify {
left: 5%;
margin: 0;
}
}
/**
* Default Look and Feel
*/
.alertify,
.alertify-log {
font-family: sans-serif;
}
.alertify {
background: #FFF;
border: 10px solid #333;
/* browsers that don't support rgba */
border: 10px solid rgba(0, 0, 0, 0.7);
border-radius: 8px;
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.3);
-webkit-background-clip: padding;
/* Safari 4? Chrome 6? */
-moz-background-clip: padding;
/* Firefox 3.6 */
background-clip: padding-box;
/* Firefox 4, Safari 5, Opera 10, IE 9 */
}
.alertify-text {
border: 1px solid #CCC;
padding: 10px;
border-radius: 4px;
}
.alertify-button {
border-radius: 4px;
color: #FFF;
font-weight: bold;
padding: 6px 15px;
text-decoration: none;
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.5);
box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.5);
background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0));
background-image: -moz-linear-gradient(top, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0));
background-image: -ms-linear-gradient(top, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0));
background-image: -o-linear-gradient(top, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0));
background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0));
}
.alertify-button:hover,
.alertify-button:focus {
outline: none;
background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.1), transparent);
background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.1), transparent);
background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0.1), transparent);
background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.1), transparent);
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0));
}
.alertify-button:focus {
box-shadow: 0 0 15px #2B72D5;
}
.alertify-button:active {
position: relative;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.alertify-button-cancel,
.alertify-button-cancel:hover,
.alertify-button-cancel:focus {
background-color: #FE1A00;
border: 1px solid #D83526;
}
.alertify-button-ok,
.alertify-button-ok:hover,
.alertify-button-ok:focus {
background-color: #5CB811;
border: 1px solid #3B7808;
}
.alertify-log {
background: #1F1F1F;
background: rgba(0, 0, 0, 0.9);
padding: 15px;
border-radius: 4px;
color: #FFF;
text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.5);
}
.alertify-log-error {
background: #FE1A00;
background: rgba(254, 26, 0, 0.9);
}
.alertify-log-success {
background: #5CB811;
background: rgba(92, 184, 17, 0.9);
}
button {
min-width: 300px;
outline: none;
}
</style>
</head>
<body>
<br />
<div class="row text-center">
<div>
<button class="button large round success">Success notification</button>
</div>
<div>
<button class="button large round alert">Error notification</button>
</div>
</div>
<link rel='stylesheet' href='http://devanswer.com/codes/files/foundation.css'>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src='http://devanswer.com/codes/files/foundation.min.js'></script><div id="bcl"><a style="font-size:8pt;text-decoration:none;" href="http://www.devanswer.com">Developers Answer</a></div>
<script>
$(document).foundation();
/*global define*/
(function (global, undefined) {
"use strict";
var document = global.document,
Alertify;
Alertify = function () {
var _alertify = {},
dialogs = {},
isopen = false,
keys = { ENTER: 13, ESC: 27, SPACE: 32 },
queue = [],
$,btnCancel,btnOK,btnReset,btnResetBack,btnFocus,elCallee,elCover,elDialog,elLog,form,input,getTransitionEvent;
/**
* Markup pieces
* @type {Object}
*/
dialogs = {
buttons: {
holder: "<nav class=\"alertify-buttons\">{{buttons}}</nav>",
submit: "<button type=\"submit\" class=\"alertify-button alertify-button-ok\" id=\"alertify-ok\">{{ok}}</button>",
ok: "<button class=\"alertify-button alertify-button-ok\" id=\"alertify-ok\">{{ok}}</button>",
cancel: "<button class=\"alertify-button alertify-button-cancel\" id=\"alertify-cancel\">{{cancel}}</button>" },
input: "<div class=\"alertify-text-wrapper\"><input type=\"text\" class=\"alertify-text\" id=\"alertify-text\"></div>",
message: "<p class=\"alertify-message\">{{message}}</p>",
log: "<article class=\"alertify-log{{class}}\">{{message}}</article>" };
/**
* Return the proper transitionend event
* @return {String} Transition type string
*/
getTransitionEvent = function () {
var t,
type,
supported = false,
el = document.createElement("fakeelement"),
transitions = {
"WebkitTransition": "webkitTransitionEnd",
"MozTransition": "transitionend",
"OTransition": "otransitionend",
"transition": "transitionend" };
for (t in transitions) {
if (el.style[t] !== undefined) {
type = transitions[t];
supported = true;
break;
}
}
return {
type: type,
supported: supported };
};
/**
* Shorthand for document.getElementById()
*
* @param {String} id A specific element ID
* @return {Object} HTML element
*/
$ = function (id) {
return document.getElementById(id);
};
/**
* Alertify private object
* @type {Object}
*/
_alertify = {
/**
* Labels object
* @type {Object}
*/
labels: {
ok: "OK",
cancel: "Cancel" },
/**
* Delay number
* @type {Number}
*/
delay: 5000,
/**
* Whether buttons are reversed (default is secondary/primary)
* @type {Boolean}
*/
buttonReverse: false,
/**
* Which button should be focused by default
* @type {String} "ok" (default), "cancel", or "none"
*/
buttonFocus: "ok",
/**
* Set the transition event on load
* @type {[type]}
*/
transition: undefined,
/**
* Set the proper button click events
*
* @param {Function} fn [Optional] Callback function
*
* @return {undefined}
*/
addListeners: function (fn) {
var hasOK = typeof btnOK !== "undefined",
hasCancel = typeof btnCancel !== "undefined",
hasInput = typeof input !== "undefined",
val = "",
self = this,
ok,cancel,common,key,reset;
// ok event handler
ok = function (event) {
if (typeof event.preventDefault !== "undefined") event.preventDefault();
common(event);
if (typeof input !== "undefined") val = input.value;
if (typeof fn === "function") {
if (typeof input !== "undefined") {
fn(true, val);
} else
fn(true);
}
return false;
};
// cancel event handler
cancel = function (event) {
if (typeof event.preventDefault !== "undefined") event.preventDefault();
common(event);
if (typeof fn === "function") fn(false);
return false;
};
// common event handler (keyup, ok and cancel)
common = function (event) {
self.hide();
self.unbind(document.body, "keyup", key);
self.unbind(btnReset, "focus", reset);
if (hasOK) self.unbind(btnOK, "click", ok);
if (hasCancel) self.unbind(btnCancel, "click", cancel);
};
// keyup handler
key = function (event) {
var keyCode = event.keyCode;
if (keyCode === keys.SPACE && !hasInput || hasInput && keyCode === keys.ENTER) ok(event);
if (keyCode === keys.ESC && hasCancel) cancel(event);
};
// reset focus to first item in the dialog
reset = function (event) {
if (hasInput) input.focus();else
if (!hasCancel || self.buttonReverse) btnOK.focus();else
btnCancel.focus();
};
// handle reset focus link
// this ensures that the keyboard focus does not
// ever leave the dialog box until an action has
// been taken
this.bind(btnReset, "focus", reset);
this.bind(btnResetBack, "focus", reset);
// handle OK click
if (hasOK) this.bind(btnOK, "click", ok);
// handle Cancel click
if (hasCancel) this.bind(btnCancel, "click", cancel);
// listen for keys, Cancel => ESC
this.bind(document.body, "keyup", key);
if (!this.transition.supported) {
this.setFocus();
}
},
/**
* Bind events to elements
*
* @param {Object} el HTML Object
* @param {Event} event Event to attach to element
* @param {Function} fn Callback function
*
* @return {undefined}
*/
bind: function (el, event, fn) {
if (typeof el.addEventListener === "function") {
el.addEventListener(event, fn, false);
} else if (el.attachEvent) {
el.attachEvent("on" + event, fn);
}
},
/**
* Use alertify as the global error handler (using window.onerror)
*
* @return {boolean} success
*/
handleErrors: function () {
if (typeof global.onerror !== "undefined") {
var self = this;
global.onerror = function (msg, url, line) {
self.error("[" + msg + " on line " + line + " of " + url + "]", 0);
};
return true;
} else {
return false;
}
},
/**
* Append button HTML strings
*
* @param {String} secondary The secondary button HTML string
* @param {String} primary The primary button HTML string
*
* @return {String} The appended button HTML strings
*/
appendButtons: function (secondary, primary) {
return this.buttonReverse ? primary + secondary : secondary + primary;
},
/**
* Build the proper message box
*
* @param {Object} item Current object in the queue
*
* @return {String} An HTML string of the message box
*/
build: function (item) {
var html = "",
type = item.type,
message = item.message,
css = item.cssClass || "";
html += "<div class=\"alertify-dialog\">";
html += "<a id=\"alertify-resetFocusBack\" class=\"alertify-resetFocus\" href=\"#\">Reset Focus</a>";
if (_alertify.buttonFocus === "none") html += "<a href=\"#\" id=\"alertify-noneFocus\" class=\"alertify-hidden\"></a>";
// doens't require an actual form
if (type === "prompt") html += "<div id=\"alertify-form\">";
html += "<article class=\"alertify-inner\">";
html += dialogs.message.replace("{{message}}", message);
if (type === "prompt") html += dialogs.input;
html += dialogs.buttons.holder;
html += "</article>";
if (type === "prompt") html += "</div>";
html += "<a id=\"alertify-resetFocus\" class=\"alertify-resetFocus\" href=\"#\">Reset Focus</a>";
html += "</div>";
switch (type) {
case "confirm":
html = html.replace("{{buttons}}", this.appendButtons(dialogs.buttons.cancel, dialogs.buttons.ok));
html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel);
break;
case "prompt":
html = html.replace("{{buttons}}", this.appendButtons(dialogs.buttons.cancel, dialogs.buttons.submit));
html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel);
break;
case "alert":
html = html.replace("{{buttons}}", dialogs.buttons.ok);
html = html.replace("{{ok}}", this.labels.ok);
break;
default:
break;}
elDialog.className = "alertify alertify-" + type + " " + css;
elCover.className = "alertify-cover";
return html;
},
/**
* Close the log messages
*
* @param {Object} elem HTML Element of log message to close
* @param {Number} wait [optional] Time (in ms) to wait before automatically hiding the message, if 0 never hide
*
* @return {undefined}
*/
close: function (elem, wait) {
// Unary Plus: +"2" === 2
var timer = wait && !isNaN(wait) ? +wait : this.delay,
self = this,
hideElement,transitionDone;
// set click event on log messages
this.bind(elem, "click", function () {
hideElement(elem);
});
// Hide the dialog box after transition
// This ensure it doens't block any element from being clicked
transitionDone = function (event) {
event.stopPropagation();
// unbind event so function only gets called once
self.unbind(this, self.transition.type, transitionDone);
// remove log message
elLog.removeChild(this);
if (!elLog.hasChildNodes()) elLog.className += " alertify-logs-hidden";
};
// this sets the hide class to transition out
// or removes the child if css transitions aren't supported
hideElement = function (el) {
// ensure element exists
if (typeof el !== "undefined" && el.parentNode === elLog) {
// whether CSS transition exists
if (self.transition.supported) {
self.bind(el, self.transition.type, transitionDone);
el.className += " alertify-log-hide";
} else {
elLog.removeChild(el);
if (!elLog.hasChildNodes()) elLog.className += " alertify-logs-hidden";
}
}
};
// never close (until click) if wait is set to 0
if (wait === 0) return;
// set timeout to auto close the log message
setTimeout(function () {hideElement(elem);}, timer);
},
/**
* Create a dialog box
*
* @param {String} message The message passed from the callee
* @param {String} type Type of dialog to create
* @param {Function} fn [Optional] Callback function
* @param {String} placeholder [Optional] Default value for prompt input field
* @param {String} cssClass [Optional] Class(es) to append to dialog box
*
* @return {Object}
*/
dialog: function (message, type, fn, placeholder, cssClass) {
// set the current active element
// this allows the keyboard focus to be resetted
// after the dialog box is closed
elCallee = document.activeElement;
// check to ensure the alertify dialog element
// has been successfully created
var check = function () {
if (elLog && elLog.scrollTop !== null && elCover && elCover.scrollTop !== null) return;else
check();
};
// error catching
if (typeof message !== "string") throw new Error("message must be a string");
if (typeof type !== "string") throw new Error("type must be a string");
if (typeof fn !== "undefined" && typeof fn !== "function") throw new Error("fn must be a function");
// initialize alertify if it hasn't already been done
this.init();
check();
queue.push({ type: type, message: message, callback: fn, placeholder: placeholder, cssClass: cssClass });
if (!isopen) this.setup();
return this;
},
/**
* Extend the log method to create custom methods
*
* @param {String} type Custom method name
*
* @return {Function}
*/
extend: function (type) {
if (typeof type !== "string") throw new Error("extend method must have exactly one paramter");
return function (message, wait) {
this.log(message, type, wait);
return this;
};
},
/**
* Hide the dialog and rest to defaults
*
* @return {undefined}
*/
hide: function () {
var transitionDone,
self = this;
// remove reference from queue
queue.splice(0, 1);
// if items remaining in the queue
if (queue.length > 0) this.setup(true);else
{
isopen = false;
// Hide the dialog box after transition
// This ensure it doens't block any element from being clicked
transitionDone = function (event) {
event.stopPropagation();
// unbind event so function only gets called once
self.unbind(elDialog, self.transition.type, transitionDone);
};
// whether CSS transition exists
if (this.transition.supported) {
this.bind(elDialog, this.transition.type, transitionDone);
elDialog.className = "alertify alertify-hide alertify-hidden";
} else {
elDialog.className = "alertify alertify-hide alertify-hidden alertify-isHidden";
}
elCover.className = "alertify-cover alertify-cover-hidden";
// set focus to the last element or body
// after the dialog is closed
elCallee.focus();
}
},
/**
* Initialize Alertify
* Create the 2 main elements
*
* @return {undefined}
*/
init: function () {
// ensure legacy browsers support html5 tags
document.createElement("nav");
document.createElement("article");
document.createElement("section");
// cover
if ($("alertify-cover") == null) {
elCover = document.createElement("div");
elCover.setAttribute("id", "alertify-cover");
elCover.className = "alertify-cover alertify-cover-hidden";
document.body.appendChild(elCover);
}
// main element
if ($("alertify") == null) {
isopen = false;
queue = [];
elDialog = document.createElement("section");
elDialog.setAttribute("id", "alertify");
elDialog.className = "alertify alertify-hidden";
document.body.appendChild(elDialog);
}
// log element
if ($("alertify-logs") == null) {
elLog = document.createElement("section");
elLog.setAttribute("id", "alertify-logs");
elLog.className = "alertify-logs alertify-logs-hidden";
document.body.appendChild(elLog);
}
// set tabindex attribute on body element
// this allows script to give it focus
// after the dialog is closed
document.body.setAttribute("tabindex", "0");
// set transition type
this.transition = getTransitionEvent();
},
/**
* Show a new log message box
*
* @param {String} message The message passed from the callee
* @param {String} type [Optional] Optional type of log message
* @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding the log
*
* @return {Object}
*/
log: function (message, type, wait) {
// check to ensure the alertify dialog element
// has been successfully created
var check = function () {
if (elLog && elLog.scrollTop !== null) return;else
check();
};
// initialize alertify if it hasn't already been done
this.init();
check();
elLog.className = "alertify-logs";
this.notify(message, type, wait);
return this;
},
/**
* Add new log message
* If a type is passed, a class name "alertify-log-{type}" will get added.
* This allows for custom look and feel for various types of notifications.
*
* @param {String} message The message passed from the callee
* @param {String} type [Optional] Type of log message
* @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding
*
* @return {undefined}
*/
notify: function (message, type, wait) {
var log = document.createElement("article");
log.className = "alertify-log" + (typeof type === "string" && type !== "" ? " alertify-log-" + type : "");
log.innerHTML = message;
// append child
elLog.appendChild(log);
// triggers the CSS animation
setTimeout(function () {log.className = log.className + " alertify-log-show";}, 50);
this.close(log, wait);
},
/**
* Set properties
*
* @param {Object} args Passing parameters
*
* @return {undefined}
*/
set: function (args) {
var k;
// error catching
if (typeof args !== "object" && args instanceof Array) throw new Error("args must be an object");
// set parameters
for (k in args) {
if (args.hasOwnProperty(k)) {
this[k] = args[k];
}
}
},
/**
* Common place to set focus to proper element
*
* @return {undefined}
*/
setFocus: function () {
if (input) {
input.focus();
input.select();
} else
btnFocus.focus();
},
/**
* Initiate all the required pieces for the dialog box
*
* @return {undefined}
*/
setup: function (fromQueue) {
var item = queue[0],
self = this,
transitionDone;
// dialog is open
isopen = true;
// Set button focus after transition
transitionDone = function (event) {
event.stopPropagation();
self.setFocus();
// unbind event so function only gets called once
self.unbind(elDialog, self.transition.type, transitionDone);
};
// whether CSS transition exists
if (this.transition.supported && !fromQueue) {
this.bind(elDialog, this.transition.type, transitionDone);
}
// build the proper dialog HTML
elDialog.innerHTML = this.build(item);
// assign all the common elements
btnReset = $("alertify-resetFocus");
btnResetBack = $("alertify-resetFocusBack");
btnOK = $("alertify-ok") || undefined;
btnCancel = $("alertify-cancel") || undefined;
btnFocus = _alertify.buttonFocus === "cancel" ? btnCancel : _alertify.buttonFocus === "none" ? $("alertify-noneFocus") : btnOK,
input = $("alertify-text") || undefined;
form = $("alertify-form") || undefined;
// add placeholder value to the input field
if (typeof item.placeholder === "string" && item.placeholder !== "") input.value = item.placeholder;
if (fromQueue) this.setFocus();
this.addListeners(item.callback);
},
/**
* Unbind events to elements
*
* @param {Object} el HTML Object
* @param {Event} event Event to detach to element
* @param {Function} fn Callback function
*
* @return {undefined}
*/
unbind: function (el, event, fn) {
if (typeof el.removeEventListener === "function") {
el.removeEventListener(event, fn, false);
} else if (el.detachEvent) {
el.detachEvent("on" + event, fn);
}
} };
return {
alert: function (message, fn, cssClass) {_alertify.dialog(message, "alert", fn, "", cssClass);return this;},
confirm: function (message, fn, cssClass) {_alertify.dialog(message, "confirm", fn, "", cssClass);return this;},
extend: _alertify.extend,
init: _alertify.init,
log: function (message, type, wait) {_alertify.log(message, type, wait);return this;},
prompt: function (message, fn, placeholder, cssClass) {_alertify.dialog(message, "prompt", fn, placeholder, cssClass);return this;},
success: function (message, wait) {_alertify.log(message, "success", wait);return this;},
error: function (message, wait) {_alertify.log(message, "error", wait);return this;},
set: function (args) {_alertify.set(args);},
labels: _alertify.labels,
debug: _alertify.handleErrors };
};
// AMD and window support
if (typeof define === "function") {
define([], function () {return new Alertify();});
} else if (typeof global.alertify === "undefined") {
global.alertify = new Alertify();
}
})(this);
$('button.success').click(function () {
alertify.set({ delay: 1700 });
alertify.success("Success notification");
});
$('button.alert').click(function () {
alertify.set({ delay: 1700 });
alertify.error("Error notification");
});
</script>
</body>
</html>