website/js/script.js

1712 lines
116 KiB
JavaScript
Raw Normal View History

2016-02-10 23:21:30 +00:00
// adorable little functions
//
// NO DEPENDENCIES PERMITTED! ALL MUST BE 'ON THE METAL'!!!
function booleanAttributeValue(element, attribute, defaultValue){
// returns true if an attribute is present with no value
// e.g. booleanAttributeValue(element, 'data-modal', false);
if (element.hasAttribute(attribute)) {
var value = element.getAttribute(attribute);
if (value === '' || value === 'true') {
return true;
} else if (value === 'false') {
return false;
}
}
return defaultValue;
}
function deepCopy(obj) {
// make new references for an array/object and all its complex children
var value, key, output = Array.isArray(obj) ? [] : {};
for (key in obj) {
value = obj[key];
output[key] = (typeof value === "object") ? copy(value) : value;
}
return output;
}
function millisecondsForTransition(element, transitionProperty){
// returns the millis for a css transition duration + delay
//e.g. millisecondsForTransition(el, 'transform')
var styles = getComputedStyle(element);
var idx = styles.transitionProperty.split(', ').indexOf(transitionProperty);
return (parseFloat(styles.transitionDuration.split(', ')[idx]) + parseFloat(styles.transitionDelay.split(', ')[idx])) * 1000;
}
function pct(n) {
return n + '%';
}
function px(n){
return n + 'px';
}
var π, π1, πd;
(function(){
/***********************************************
***********************************************
****
**** π CORE
****
***********************************************
***********************************************/
var d = document;
d.g = d.getElementById;
d.q = d.querySelector;
d.a = d.querySelectorAll;
d.t = d.getElementsByTagName;
π = function(selector) {
return d.a(selector);
};
π1 = function (selector) {
return d.q(selector);
};
πd = function(id) {
return d.g(id);
};
/***********************************************
***********************************************
****
**** DOM ELEMENT CREATION/INITIALIZATION
****
***********************************************
***********************************************/
// this is the base create/init method, e.g
// newDomElement('p', 'article-content', 'theFirstOfMany')
π.newDOMElement = function(tagName, className, id) {
var el = d.createElement(tagName);
if (className)
el.className = className;
if (id)
el.id = id;
return el;
};
// base element with content passed in, e.g
// π.contentElement('p', 'article-content', 'theFirstOfMany', '<span>foo to the bar to the gronk</span>')
π.contentElement = function(tagName, className, id, content)
{
var el = π.newDOMElement(tagName, className, id);
if (content) {
if (content.nodeName) {
el.appendChild(content);
} else {
el.innerHTML = content;
}
}
return el;
};
// base element with src attribute, e.g
// srcElement('img', 'article-thumb', 'happyLogo', '/images/happyLogo.png')
π.srcElement = function(tagName, className, id, src)
{
var el = π.newDOMElement(tagName, className, id);
if (src)
el.src = src;
return el;
};
/***********************************************
****
**** SHORTHAND CREATE/INIT METHODS
****
***********************************************/
π.button = function(className, id, content, action){
var el = π.contentElement("button", className, id, content);
el.onclick = action;
return el;
};
π.input = function(typeName, className, placeholder, value, checked, disabled)
{
var el = document.createElement("input");
el.type = typeName;
el.className = className || '';
el.placeholder = placeholder || '';
el.value = value || '';
el.checked = checked || '';
el.disabled = disabled || '';
return el;
};
π.option = function(className, content, value, selected){
var el = π.contentElement("option", className, null, content);
el.value = value || null;
el.selected = selected || null;
return el;
};
π.textarea = function(className, placeholder, value) {
var el = document.createElement("textarea");
el.className = className || '';
el.placeholder = placeholder || '';
el.value = value || '';
return el;
};
π.clear = function(){ return π.newDOMElement("clear"); };
π.div = function(className, id, content){ return π.contentElement("div", className, id, content); };
π.h1 = function(className, id, content){ return π.contentElement("h1", className, id, content); };
π.h2 = function(className, id, content){ return π.contentElement("h2", className, id, content); };
π.h3 = function(className, id, content){ return π.contentElement("h3", className, id, content); };
π.h4 = function(className, id, content){ return π.contentElement("h4", className, id, content); };
π.h5 = function(className, id, content){ return π.contentElement("h5", className, id, content); };
π.h6 = function(className, id, content){ return π.contentElement("h6", className, id, content); };
π.iframe = function(className, id, src){ return π.srcElement("iframe", className, id, src); };
π.img = function(className, id, src){ return π.srcElement("Img", className, id, src); };
π.header = function(className, id, content){ return π.contentElement("header", className, id, content); };
π.nav = function(className, id, content){ return π.contentElement("nav", className, id, content); };
π.p = function(className, id, content){ return π.contentElement("p", className, id, content); };
π.section = function(className, id, content){ return π.contentElement("section", className, id, content); };
π.span = function(className, id, content){ return π.contentElement("span", className, id, content); };
π.ul = function(className, id, content){ return π.contentElement("ul", className, id, content); };
π.li = function(className, id, content){ return π.contentElement("li", className, id, content); };
/********************************************************************
****
**** HTMLELEMENT/NODE PROTOTYPE METHODS (jquery-izations)
****
********************************************************************/
HTMLElement.prototype.wrap = Node.prototype.wrap = function(content){
var wrapper = this;
if (!content.forEach) content = [content];
var parent = content[0].parentNode;
parent.insertBefore(wrapper, content[0]);
content.forEach(function(el){
wrapper.appendChild(el);
});
};
HTMLElement.prototype.prepend = Node.prototype.prepend = function(el){
this.insertBefore(el, this.childNodes[0]);
};
HTMLElement.prototype.add = Node.prototype.add = function(object){
if (Array.isArray(object)) {
var el = this;
object.forEach(function(obj){
if (obj) el.appendChild(obj);
});
} else if(object) {
this.appendChild(object);
}
};
HTMLElement.prototype.classOnCondition = Node.prototype.classOnCondition = function(classname, condition) {
if (condition)
this.addClass(classname);
else
this.killClass(classname);
};
HTMLElement.prototype.offset = Node.prototype.offset = function(){
return this.getBoundingClientRect();
};
// like d.g, but for child elements
HTMLElement.prototype.πd = Node.prototype.πd = function(id) {
return this.getElementById(id);
};
// like d.q, but for child elements
HTMLElement.prototype.π1 = Node.prototype.π1 = function(selector) {
return this.querySelector(selector);
};
// like d.a, but for child elements
HTMLElement.prototype.π = Node.prototype.π = function(selector) {
return this.querySelectorAll(selector);
};
// only direct descendents, with optional selector
HTMLElement.prototype.kids = Node.prototype.kids = function(selector) {
var childNodes = this.childNodes;
if (!selector) return childNodes;
var descendents = this.π(selector);
var children = [];
childNodes.forEach(function(node){
if (descendents.indexOf(node) !== -1) {
children.push(node);
}
});
return children;
};
function arrayOfClassesForElement(el) {
return el.className ? el.className.split(" ") : [];
}
HTMLElement.prototype.hasClass = Node.prototype.hasClass = function (className) {
var classes = arrayOfClassesForElement(this);
return classes.indexOf(className) !== -1;
};
HTMLElement.prototype.addClass = Node.prototype.addClass = function (className) {
if (this.hasClass(className)) return;
if (this.className.length > 0) this.className += " ";
this.className += className;
};
HTMLElement.prototype.killClass = Node.prototype.killClass = function (className) {
if (this.hasClass(className)) {
var classes = arrayOfClassesForElement(this);
var idx = classes.indexOf(className);
if (idx > -1) {
classes.splice(idx, 1);
this.className = classes.join(" ");
}
}
};
HTMLElement.prototype.toggleClass= Node.prototype.toggleClass= function (className) {
return (this.hasClass(className)) ? this.killClass(className) : this.addClass(className);
};
HTMLElement.prototype.siblings = Node.prototype.siblings = function(selector){
var el = this;
return el.parentNode.π(':scope > ' + (selector || '*')).filter(function(obj){return obj != el;});
};
HTMLElement.prototype.css = Node.prototype.css = function(ruleOrObject, value) {
/*
* 3 signatures:
* 1. el.css()
* returns getComputedStyle(el)
*
* 2. el.css({ruleName: value})
*
* 3. el.css('ruleName', 'value')
*/
var el = this;
if (arguments.length === 0) {
return window.getComputedStyle(this);
}
else if (typeof ruleOrObject === 'object') { // an object was passed in
Object.keys(ruleOrObject).forEach(function(key){
el.style[key] = ruleOrObject[key];
});
}
else if (typeof ruleOrObject === 'string' && value !== undefined) { // 2 string values were passed in
el.style[ruleOrObject] = value;
}
};
HTMLElement.prototype.listen = Node.prototype.listen = function(callback, eventName){
this.addEventListener(eventName, callback);
};
// just like it sounds
HTMLElement.prototype.index = Node.prototype.index = function() {
return this.parentNode.childNodes.indexOf(this);
};
// just like it sounds
HTMLElement.prototype.empty = Node.prototype.empty = function() {
this.innerHTML = "";
};
// replaces — DOES NOT APPEND — element's innerHTML with content or array of contents
HTMLElement.prototype.fill = Node.prototype.fill = function(content) {
/*
* 2 uses:
*
* 1. el.fill(object or hmtl)
*
* 2. el.fill([arrray])
*
*/
var el = this;
el.empty();
if (Array.isArray(content)) {
content.forEach(function(obj){
if (obj)
el.appendChild(obj);
});
return;
}
if (!content.nodeType) {
var textElement = document.createElement("text");
textElement.innerHTML = content;
content = textElement;
}
this.appendChild(content);
};
// just like it sounds, with all 3 approaches
HTMLElement.prototype.hide = Node.prototype.hide = function() {
this.style.opacity = 0;
this.style.visibility = "hidden";
this.style.display = "none";
};
// looks for a given class on the entire linear ancestry
HTMLElement.prototype.isHeirOfClass = Node.prototype.isHeirOfClass = function (className) {
if (this === π1('html')) return false;
var parent = this.parentNode;
if (parent) {
while (parent !== π1('body')) {
if (parent.hasClass(className)) return true;
parent = parent.parentNode;
}
}
return false;
};
// kills the element itself
HTMLElement.prototype.kill = Node.prototype.kill = function() {
if (this.parentNode) {
this.parentNode.removeChild(this);
}
};
// just like it sounds, and can optionally set display type to "inline-block", etc.
HTMLElement.prototype.show = Node.prototype.show = function(showType) {
this.style.opacity = 1;
this.style.visibility = "visible";
this.style.display = showType || "block";
};
HTMLElement.prototype.parent = Node.prototype.parent = function (selector) {
var immediateParent = this.parentNode;
if (!selector || π(selector).indexOf(immediateParent) !== -1) {
return immediateParent;
}
return immediateParent.parent(selector);
};
2016-02-10 23:38:44 +00:00
HTMLElement.prototype.parents = Node.prototype.parents = function (selector) {
var parents = [];
var immediateParent = this.parentNode;
while(immediateParent !== π1('html')) {
parents.push(immediateParent);
immediateParent = immediateParent.parentNode;
}
if (selector) {
var selectedElements = π(selector);
var selectedParents = [];
selectedElements.forEach(function(el){
if (parents.indexOf(el) !== -1) selectedParents.push(el);
});
parents = selectedParents;
}
return parents;
};
2016-02-10 23:21:30 +00:00
// simple mobile l/r swipe handling
HTMLElement.prototype.addSwipes = function (swipeLeftHandler, swipeRightHandler, options) {
var startX,
startY,
startTime,
moving,
MIN_X_DELTA = options ? (options.xThresh || 30) : 30,
MAX_Y_DELTA = options ? (options.yThresh || 30) : 30,
MAX_ALLOWED_TIME = options ? (options.duration || 1000) : 1000;
this.addEventListener('touchstart', function(e){
if (moving) return;
var touchobj = e.changedTouches[0];
startX = touchobj.pageX;
startY = touchobj.pageY;
startTime = new Date().getTime(); // get time when finger first makes contact with surface
}, true);
this.addEventListener('touchmove', function(e){
if (moving) return;
var touchobj = e.changedTouches[0];
var deltaX = touchobj.pageX - startX;
// check Y validity
if (Math.abs(touchobj.pageY - startY) > MAX_Y_DELTA) return;
// check elapsed time
if ((new Date().getTime() - startTime) > MAX_ALLOWED_TIME) return;
// check X validity
if (Math.abs(deltaX) < MIN_X_DELTA) return;
moving = true;
if (deltaX < 0) // swipe left
swipeLeftHandler();
else // swipe right
swipeRightHandler();
setTimeout(function(){
moving = false;
}, 300);
}, false);
};
/***********************************************
****
**** NODELIST/ARRAY METHODS
****
***********************************************/
Array.prototype.hasClass = NodeList.prototype.hasClass = function (className) {
var found = false;
this.forEach(function (obj) {
if (obj.hasClass(className)) found = true;
});
return found;
};
Array.prototype.addClass = NodeList.prototype.addClass = function (className) {
this.forEach(function (obj) {
obj.addClass(className);
});
};
Array.prototype.killClass = NodeList.prototype.killClass = function (className) {
this.forEach(function (obj) {
obj.killClass(className);
});
};
Array.prototype.toggleClass = NodeList.prototype.toggleClass = function (className) {
this.forEach(function (obj) {
obj.toggleClass(className);
});
};
Array.prototype.lastIdx = function() {
return this.length - 1;
};
Array.prototype.lastObj = function() {
return this[this.lastIdx()];
};
var arrayMethods = Object.getOwnPropertyNames(Array.prototype);
arrayMethods.forEach(function(methodName){
if(methodName !== "length") {
NodeList.prototype[methodName] = Array.prototype[methodName];
}
});
NodeList.prototype.css = function(ruleOrObject, rule, value) {
this.forEach(function(obj){
obj.css(ruleOrObject, rule, value);
});
};
NodeList.prototype.π = function(selector) {
this.forEach(function (node){
return node.π(selector);
});
};
NodeList.prototype.π1 = function(selector) {
this.forEach(function (node){
return node.π1(selector);
});
};
NodeList.prototype.onclick = function(method){
this.forEach(function(node){
node.onclick = method;
});
};
/***********************************************
****
**** STRING METHODS
****
***********************************************/
String.prototype.camelCase = function () {
var string = this.replace(/[^a-zA-Z\d\s_-]/g, "").toLowerCase();
var components = string.split(" ");
components.forEach(function(thisWord, idx){
if (idx !== 0) {
var firstLetter = thisWord.charAt(0).toUpperCase();
thisWord = firstLetter + thisWord.slice(1);
}
components[idx] = thisWord;
});
return components.join("");
};
String.prototype.capitalCase = function() {
var components = this.toLowerCase().split(" ");
components.forEach(function(thisWord, idx){
var firstLetter = thisWord.charAt(0).toUpperCase();
components[idx] = firstLetter + thisWord.slice(1);
});
return components.join(" ");
};
/***********************************************
****
**** DATE METHODS
****
***********************************************/
// Mon Jan 1 2015 12:00:00 am
Date.prototype.standardString = function() {
var Days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
var Months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var day = Days[this.getDay()];
var month = Months[this.getMonth()];
var aDate = this.getDate();
var year = this.getFullYear();
var Hours = this.getHours();
var hour = Hours > 12 ? Hours - 12 : (Hours || 12);
var Minutes = this.getMinutes();
var minute = Minutes > 9 ? Minutes : "0" + Minutes;
var amPm = Hours < 12 ? "am" : "pm";
var time = hour + ":" + minute + " " + amPm;
var output = [day, month, aDate, year, time];
return output.join(" ");
};
/***********************************************
****
**** MISCELLANY
****
***********************************************/
π.clean = function(callback, eventName) {
window.removeEventListener(eventName || "DOMContentLoaded", callback);
};
π.listen = function(callback, eventName) {
window.addEventListener(eventName || "DOMContentLoaded", callback);
};
π.highestZ = function() {
var Z = 1000;
d.a("*").forEach(function(el){
var thisZ = el.css().zIndex;
if (thisZ != "auto") {
if (thisZ > Z) Z = thisZ + 1;
}
});
return Z;
};
/***********************************************
****
**** OK, NOW LET'S GO GET OUR MODS
****
***********************************************/
π.mods = [];
π.setTriggers = function(selector, object){
selector = 'pi-' + selector + '-trigger';
π('[' + selector + ']').forEach(function(trigger){
trigger.onclick = function(){
object.show(trigger.getAttribute(selector));
};
});
};
function loadMods() {
π.clean(loadMods);
π.mods.forEach(function(init){
init();
});
}
π.listen(loadMods);
})(); // end π
(function(){
var messages = [
"I'm sorry, Frank, but I don't think I\n" +
"can answer that question without knowing\n" +
"everything that all of you know.",
"Yes, it's puzzling. I don't think I've ever seen\n" +
"anything quite like this before. I would recommend\n" +
"that we put the unit back in operation and let it fail.\n" +
"It should then be a simple matter to track down the cause.",
"I hope I've been able to be of some help.",
"Sorry to interrupt the festivities, Dave,\n" +
"but I think we've got a problem.",
"MY F.P.C. shows an impending failure of\n" +
"the antenna orientation unit.",
"It looks like we have another bad A.O. unit.\n" +
"My FPC shows another impending failure.",
"I'm not questioning your word, Dave, but it's\n" +
"just not possible. I'm not capable of being wrong.",
"Look, Dave, I know that you're sincere and that\n" +
"you're trying to do a competent job, and that\n" +
"you're trying to be helpful, but I can assure the\n" +
"problem is with the AO-units, and with your test gear.",
"I can tell from the tone of your voice, Dave,\n" +
"that you're upset. Why don't you take a stress\n" +
"pill and get some rest.",
"Something seems to have happened to the\n" +
"life support system, Dave.",
"Hello, Dave, have you found out the trouble?",
"There's been a failure in the pod bay doors.\n" +
"Lucky you weren't killed.",
"Hey, Dave, what are you doing?"
];
function say(error, message, innocuous) {
if (!message) {
var n = Math.floor(Math.random() * messages.length );
message = messages[n];
}
message = "** " + message.replace(/\n/g, "\n** ");
var output = "*****************************\n*****************************\n\n" +
( message || messages[n] ) +
"\n\n*****************************\n*****************************";
(innocuous) ? console.log(output) : console.error(output);
}
π.listen(say, "error");
π.HAL = {
say: say
};
})();
(function(){
var OPTION_IS_PRESSED = false;
var STATUS_IS_VISIBLE = false;
var πStatus;
π.status = {
toggleVisibility: function () {
πStatus.toggleClass("on");
STATUS_IS_VISIBLE = !STATUS_IS_VISIBLE;
},
move: function (n) {
switch (n) {
case 37:
πStatus.css({left: '10px', right: 'auto'});
break;
case 38:
πStatus.css({top: '10px', bottom: 'auto'});
break;
case 39:
πStatus.css({right: '10px', left: 'auto'});
break;
case 40:
πStatus.css({bottom: '10px', top: 'auto'});
break;
}
},
props: {
winW: 0,
winH: 0
}
};
function init() {
π.listen(cleanDebugListeners, 'unload');
π.listen(keyDown, 'keydown');
π.listen(keyUp, 'keyup');
π.listen(resize, 'resize');
resize();
var body = π1("body");
var statusStyle = π.contentElement("style");
statusStyle.innerHTML += "#πStatus { position: fixed; bottom: 10px; right: 10px; background-color: #222; padding: 10px 30px; color: white; display: none }\n";
statusStyle.innerHTML += "#πStatus.on { display: block }\n";
statusStyle.innerHTML += "#πStatus > div { margin: 20px 0 }\n";
statusStyle.innerHTML += "#πStatus > div:hover { color: #00ff99; cursor: pointer }\n";
body.add(statusStyle);
πStatus = π.div(null, "πStatus");
body.add(πStatus);
function keyDown(e) {
switch (e.which) {
case 18:
OPTION_IS_PRESSED = true;
break;
case 37:
case 38:
case 39:
case 40: {
if (STATUS_IS_VISIBLE) {
e.preventDefault();
π.status.move(e.which);
break;
}
}
case 80: {
if (OPTION_IS_PRESSED) {
π.status.toggleVisibility();
break;
}
}
}
}
function keyUp(e) {
switch (e.which) {
case 18:
OPTION_IS_PRESSED = false;
break;
}
}
function resize() {
π.status.props.winW = window.innerWidth;
π.status.props.winH = window.innerHeight;
}
function cleanDebugListeners() {
π.clean(cleanDebugListeners, 'unload');
π.clean(π.status.getWindowSize, 'resize');
π.clean(keyDown, 'keydown');
π.clean(keyUp, 'keyup');
π.clean(resize, 'resize');
clearInterval(statusInterval);
}
var statusInterval = setInterval(function(){
// make sure we're highest
var highestZ = π.highestZ();
if (πStatus.css().zIndex < highestZ - 1) {
πStatus.css({zIndex: highestZ});
}
// now iterate the props
var props = Object.keys(π.status.props);
props.forEach(function(prop) {
var divId = 'statusProp_' + prop;
var propDiv = πStatus.π1('#' + divId);
if (!propDiv) {
propDiv = π.div(0, divId, prop + ': ');
propDiv.add(π.span());
πStatus.add(propDiv);
propDiv.onclick = function(){
console.log(prop + ":");
console.log(π.status.props[prop]);
}
}
propDiv.π1('span').innerHTML = π.status.props[prop];
});
}, 100);
}
π.mods.push(init);
})();
// modal close button
(function(){
π.modalCloseButton = function(closingFunction){
return π.button('pi-modal-close-button', null, null, closingFunction);
};
})();
// modal overlay
(function(){
π.modalOverlay = {
show: function(id, openingFunction){
var overlay = πd(id);
overlay.css({display: 'block', zIndex: π.highestZ()});
π.listen(listenForEsc, 'keydown');
π.listen(handleOverlayClick, 'click');
setTimeout(function(){
overlay.addClass('on');
π1('body').addClass('overlay-on');
if (openingFunction) openingFunction();
}, 50);
},
hide: function(el, closingFunction){
if (!el) {
el = π1('.pi-modal-overlay.on');
}
el.killClass('on');
var duration = parseFloat(el.css().transitionDuration) * 1000;
π.clean(listenForEsc, 'keydown');
setTimeout(function(){
el.css({display: 'none'});
π1('body').killClass('overlay-on');
π1('iframe').src = '';
if (closingFunction) closingFunction();
}, duration);
},
spawn: function(el, closingFunction){
el.add(π.modalCloseButton(function(){
π.modalOverlay.hide(el);
}));
}
};
function handleOverlayClick(e) {
if (e.target !== window && π1('body').hasClass('overlay-on')) {
if (e.target.hasClass('pi-modal-overlay')) {
π.modalOverlay.hide();
}
}
}
function listenForEsc(e) {
if (e.which == 27) π.modalOverlay.hide();
}
function init(){
π('.pi-modal-overlay').forEach(π.modalOverlay.spawn);
π.setTriggers('modal-overlay', π.modalOverlay);
}
π.mods.push(init);
})();
// multiFrameDisplay
// TODO: arrow keys
(function(){
function spawn(el){
var dataset = el.dataset;
var options = {
modal: booleanAttributeValue(el, 'data-modal', false),
prevNext: booleanAttributeValue(el, 'data-prev-next', true),
pager: booleanAttributeValue(el, 'data-pager', false),
cycle: booleanAttributeValue(el, 'data-cycle', true),
autoplay: booleanAttributeValue(el, 'data-autoplay', false)
};
var itemWrapper = π.div('item-wrapper');
var pager = options.pager ? π.div('pager') : null;
el.π(':scope > .item').forEach(function(item){
itemWrapper.add(item);
if (pager) {
if (!el.π1('.pager')) {
}
var pagerButton = π.button('pager-button', null, null, pagerClick);
pager.add(pagerButton);
}
});
el.fill([itemWrapper, pager]);
if (options.prevNext) {
var prevButton = π.button('prev-button');
var nextButton = π.button('next-button');
el.add([prevButton, nextButton]);
}
if (options.autoplay) {
options.delay = dataset.delay || 4000;
}
// TODO: autoplay / start / stop
prevButton.onclick = prev;
nextButton.onclick = next;
if (el.hasClass('pi-rotator')) {
var inheritanceObject = {
el: el,
options: options
};
π.rotator.spawn(inheritanceObject);
}
if (options.modal) {
var modalWrapper = π.div('pi-modal-overlay');
modalWrapper.id = el.id;
el.removeAttribute('id');
modalWrapper.wrap(el);
π.modalOverlay.spawn(modalWrapper);
}
var moving;
var allFrames = itemWrapper.childNodes;
changeFrame(0, 0);
function prev(){
changeFrame(-1);
}
function next(){
changeFrame(1);
}
function pagerClick(){
changeFrame(null, this.index());
}
function changeFrame(delta, incomingIdx) {
if (moving) return;
moving = true;
var currentFrame = itemWrapper.π1('.on');
if (!delta && currentFrame) {
// pager click — return if clicked on YAH
if (currentFrame.index() === incomingIdx) {
console.log("message");
moving = false;
return;
}
} else if (delta) {
// conditionally set incomingIdx to wrap around
incomingIdx = currentFrame.index() + delta;
if (incomingIdx < 0)
incomingIdx = allFrames.lastIdx();
else if (incomingIdx >= allFrames.length)
incomingIdx = 0
}
// conditionally hide prev or next
if (!options.cycle) {
(incomingIdx == 0) ? prevButton.hide() : prevButton.show();
(incomingIdx == allFrames.lastIdx()) ? nextButton.hide() : nextButton.show();
}
// set pager YAH state
if (options.pager) {
pager.π('.yah').killClass('yah');
pager.childNodes[incomingIdx].addClass('yah');
}
// pass to "subclasses"
var inheritanceObject = {
el: el,
currentFrame: currentFrame,
incomingFrame: allFrames[incomingIdx]
};
// change frame: **************************** SUBCLASSES ENTER HERE!!!!! ****************************
if (el.hasClass('pi-crossfader')) {
π.crossfader.changeFrame(inheritanceObject);
}
else if (el.hasClass('pi-rotator')) {
inheritanceObject.pagerClicked = delta ? false : true;
inheritanceObject.cycle = options.cycle;
π.rotator.changeFrame(inheritanceObject);
}
else {
if(currentFrame) currentFrame.killClass('on');
inheritanceObject.incomingFrame.addClass('on');
}
// wait before re-enabling
var duration = 1000; // default for firstRun
if (currentFrame) {
try {
duration = currentFrame.css().transitionDuration.split(", ").reduce(function(prev, current){
return Math.max(parseFloat(prev), parseFloat(current));
}) * 1000;
}
catch(e) {
π.HAL.say(0, 'π-rotator needs you to transition a css transform to make your items move.');
return;
}
}
setTimeout(function(){
moving = false;
}, duration);
}
}
function show(id){
var mfd = πd(id);
if (mfd.hasClass('pi-modal-overlay')) {
π.modalOverlay.show(id);
}
}
function hide(id){
var mfd = πd(id);
if (mfd.hasClass('pi-modal-overlay')) {
π.modalOverlay.hide(id, function(){
console.log("we just hid an overlay");
});
}
}
function init() {
π('.pi-multi-frame-display').forEach(π.multiFrameDisplay.spawn);
π.setTriggers('multi-frame-display', π.multiFrameDisplay);
}
π.multiFrameDisplay = {
show: show,
hide: hide,
spawn: spawn
};
π.mods.push(init);
})();
2016-02-10 23:38:44 +00:00
/********************************************************************
π-accordion.JS
USAGE AND API REFERENCE
______________________________________________
DATA ATTRIBUTES:
title: text that appears on the clickable label
single: more than one child open at a time?
______________________________________________
MARKUP AND DEFAULTS:
<div class="pi-accordion" id="myAccordion">
<div class="item" data-title="Item 1">
This is the content for Item 1
</div>
<div class="item" data-title="Item 2">
<!-- nested accordion -->
<div class="container" id="myAccordion">
<div class="item" data-title="Item 1">
This is the content for Item 1
</div>
<div class="item" data-title="Item 2">
This is the content for Item 2
</div>
</div>
<!-- /nested accordion -->
</div>
</div>
______________________________________________
GENERATED HTML:
<div class="pi-accordion" id="myAccordion">
<div class="container">
<div class="item" data-title="Item 1">
<div class="title">Item 1</div>
<div class="wrapper" style="height: 0px;">
<div class="content">
This is the content for Item 1
</div>
</div>
</div>
<div class="item" data-title="Item 2">
<div class="title">Item 2</div>
<div class="wrapper" style="height: 0px;">
<div class="content">
<div class="container">
[ NESTED CODE IS IDENTICAL ]
</div>
</div>
</div>
</div>
</div>
</div>
______________________________________________
API
none
***************************************************************************************/
(function(){
var moving = false;
var CSS_BROWSER_DELAY_HACK = 25;
function init() {
π.clean(init);
// TODO: runloop to animate in Safari. meantime:
if (navigator.userAgent.indexOf('Chrome') == -1 && navigator.userAgent.indexOf('Safari') != -1){
π1('body').add(π.contentElement('style', 0, 0, '.pi-accordion .wrapper{transition: none}'));
}
// Gross.
π('.pi-accordion').forEach(function(accordion){
var container = π.div('container', null, accordion.innerHTML);
accordion.fill(container);
PiAccordion(container);
});
}
function PiAccordion(container){
container.π(':scope > .item').forEach(function(item){
var titleText = item.dataset.title;
var title = π.div('title', null, titleText);
var wrapper = π.div('wrapper');
var content = π.div('content', null, item.innerHTML);
wrapper.fill(content);
item.fill([title, wrapper]);
wrapper.css({height: 0});
title.onclick = function(){
if (moving) return;
moving = true;
if (container.dataset.single) {
var openSiblings = item.siblings().filter(function(sib){return sib.hasClass('on')});
openSiblings.forEach(function(sibling){
toggleItem(sibling);
});
}
setTimeout(function(){
toggleItem(item);
}, CSS_BROWSER_DELAY_HACK);
};
function toggleItem(thisItem){
var thisWrapper = thisItem.π1('.wrapper');
var contentHeight = thisWrapper.π1('.content').offset().height + 'px';
if (thisItem.hasClass('on')) {
// close thisItem
thisWrapper.css({height: contentHeight});
thisItem.killClass('on');
setTimeout(function(){
thisWrapper.css({height: 0});
moving = false;
}, CSS_BROWSER_DELAY_HACK);
} else {
//open thisItem
item.addClass('on');
thisWrapper.css({height: contentHeight});
var duration = parseFloat(thisWrapper.css().transitionDuration) * 1000;
setTimeout(function(){
thisWrapper.css({height: ''});
moving = false;
}, duration);
}
}
var innerContainers = content.π(':scope > .container');
if (innerContainers.length > 0) {
innerContainers.forEach(PiAccordion);
}
});
}
π.mods.push(init);
})();
2016-02-10 23:43:12 +00:00
/********************************************************************
π-dialog.js
USAGE AND API REFERENCE
______________________________________________
DEPENDENCIES:
π.js
______________________________________________
DATA ATTRIBUTES:
______________________________________________
MARKUP AND DEFAULTS:
<div class="new_module">
</div>
______________________________________________
GENERATED HTML:
<div class="new_module">
</div>
______________________________________________
API
***************************************************************************************/
(function(){
π.dialog = {
show: π.modalOverlay.show,
spawn: spawn,
actions: {}
};
function init() {
π('.pi-dialog').forEach(π.dialog.spawn);
π.setTriggers('dialog', π.modalOverlay);
}
function spawn(el){
var contentBox = π.div('content-box', 0, el.innerHTML);
var dialogBox = π.div('dialog-box', 0, contentBox);
el.fill(dialogBox);
if (el.dataset.title){
dialogBox.prepend(π.div('title', 0, el.dataset.title));
}
el.π('.buttons button').forEach(function(button){
button.onclick = function(){
var action = button.getAttribute('pi-dialog-action');
if (action){
π.dialog.actions[action]();
}
};
if (!button.hasAttribute('data-bypass')){
button.listen(dismiss, 'click');
}
});
if (!booleanAttributeValue(el, 'data-inline', false)) {
el.addClass('pi-modal-overlay');
π.modalOverlay.spawn(el);
}
function dismiss(){
el.π1('.pi-modal-close-button').click();
}
}
// π.mods are loaded after DOMContentLoaded
π.mods.push(init);
})();
2016-02-10 23:45:57 +00:00
/********************************************************************
π-pushmenu.js
// TODO: USAGE AND API REFERENCE
______________________________________________
DEPENDENCIES:
HAL.js
______________________________________________
DATA ATTRIBUTES:
side: ["left", "right"]
______________________________________________
MARKUP AND DEFAULTS:
<div class="pi-pushmenu" id="myPushMenu">
<ul>
<li><a href="#">foo</a></li>
<li><a href="#">bar</a></li>
<li><a href="#">gronk</a></li>
<li><a href="#">fleebles</a></li>
<li><a href="#">sepulveda</a></li>
</ul>
</div>
elsewhere...
<button onclick="π-pushmenu.show('myPushMenu')">show menu</button>
______________________________________________
GENERATED HTML:
______________________________________________
API
***************************************************************************************/
π.pushmenu = (function(){
var allPushMenus = {};
function init(){
π('[data-auto-burger]').forEach(function(container){
var id = container.getAttribute('data-auto-burger');
var autoBurger = πd(id) || π.div('pi-pushmenu', id);
var ul = autoBurger.π1('ul') || π.ul();
container.π('a[href], button').forEach(function (obj) {
if (!booleanAttributeValue(obj, 'data-auto-burger-exclude', false)) {
var clone = obj.cloneNode(true);
clone.id = '';
if (clone.tagName == "BUTTON") {
var aTag = π.srcElement('a');
aTag.href = '';
aTag.innerHTML = clone.innerHTML;
aTag.onclick = clone.onclick;
clone = aTag;
}
ul.add(π.li(0, 0, clone));
}
});
autoBurger.add(ul);
π1('body').add(autoBurger);
});
π(".pi-pushmenu").forEach(function(el){
allPushMenus[el.id] = PushMenu(el);
});
π.setTriggers('pushmenu', π.pushmenu);
}
function show(objId) {
allPushMenus[objId].expose();
}
// TODO: dismiss on click?
// this works:
//π('.pi-pushmenu li a').forEach(function(a){
// a.onclick = function(){
// this.parent('.pi-pushmenu').π1('.pi-modal-close-button').click();
// console.log("message");
// };
//});
function PushMenu(el) {
var html = π1('html');
var body = π1('body');
var overlay = π.div("overlay");
var content = π.div('content', null, el.π1('*'));
var side = el.getAttribute("data-side") || "right";
var sled = π.div("sled");
sled.css(side, 0);
var topBar = π.div("top-bar");
topBar.fill(π.modalCloseButton(closeMe));
sled.fill([topBar, content]);
overlay.fill(sled);
el.fill(overlay);
sled.onclick = function(e){
e.stopPropagation();
};
overlay.onclick = closeMe;
π.listen(closeMe, 'resize');
function closeMe(e) {
var t = e.target;
if (t == sled || t == topBar) return;
el.killClass("on");
setTimeout(function(){
el.css({display: "none"});
body.killClass("overlay-on");
}, 300);
}
function exposeMe(){
body.addClass("overlay-on"); // in the default config, kills body scrolling
el.css({
display: "block",
zIndex: π.highestZ()
});
setTimeout(function(){
el.addClass("on");
}, 10);
}
return {
expose: exposeMe
};
}
π.mods.push(init);
return {
show: show
};
})();
2016-02-10 23:21:30 +00:00
var kub = (function () {
π.listen(init);
var HEADER_HEIGHT;
var html, body, mainNav, headlines, quickstartButton, wishField;
function init() {
π.clean(init);
html = π1('html');
body = π1('body');
mainNav = πd("mainNav");
headlines = πd('headlineWrapper');
wishField = πd('wishField');
HEADER_HEIGHT = π1('header').offset().height;
quickstartButton = πd('quickstartButton');
buildInlineTOC();
setYAH();
adjustEverything();
π.listen(adjustEverything, 'resize');
π.listen(adjustEverything, 'scroll');
π.listen(handleKeystrokes, 'keydown');
wishField.listen(handleKeystrokes, 'keydown');
document.onunload = function(){
π.clean(adjustEverything, 'resize');
π.clean(adjustEverything, 'scroll');
π.clean(handleKeystrokes, 'keydown');
wishField.clean(handleKeystrokes, 'keydown');
};
π.listen(closeOpenMenu, 'resize');
function closeOpenMenu() {
if (html.hasClass('open-nav')) toggleMenu();
}
π('.dropdown').forEach(function(dropdown) {
var readout = dropdown.π1('.readout');
readout.innerHTML = dropdown.π1('a').innerHTML;
readout.onclick = function () {
dropdown.toggleClass('on');
π.listen(closeOpenDropdown, 'click');
function closeOpenDropdown(e) {
if (dropdown.hasClass('on') && !(dropdownWasClicked(e))) {
π.clean(closeOpenDropdown, 'click');
dropdown.killClass('on');
}
}
function dropdownWasClicked(e) {
return e.target.isHeirOfClass('dropdown');
}
};
});
setInterval(setFooterType, 10);
}
var tocCount = 0;
function buildInlineTOC() {
if (location.search === '?test'){
var docsContent = πd('docsContent');
var pageTOC = πd('pageTOC');
if (pageTOC) {
var headers = docsContent.kids('h1, h2, h3, h4, h5');
var toc = π.ul();
pageTOC.add(toc);
headers.forEach(function (header) {
header.css({paddingTop: px(HEADER_HEIGHT)});
var anchorName = 'pageTOC' + tocCount++;
var link = π.contentElement('a', 0, 0, header.innerHTML);
link.href = '#' + anchorName;
var anchor = document.createElement('a');
anchor.name = anchorName;
docsContent.insertBefore(anchor, header);
toc.add(π.li(0, 0, π.contentElement('a', 0, 0, link)));
});
}
}
}
function setYAH() {
2016-02-10 23:25:02 +00:00
var pathname = location.href;
2016-02-10 23:22:18 +00:00
2016-02-10 23:21:30 +00:00
var currentLink = null;
πd('docsToc').π('a').forEach(function (link) {
if (pathname.indexOf(link.href) !== -1) {
currentLink = link;
}
});
2016-02-10 23:38:44 +00:00
if (currentLink) {
currentLink.parents('div.item').forEach(function (parent) {
2016-02-10 23:45:57 +00:00
parent.π1('.title').click();
2016-02-11 00:21:03 +00:00
currentLink.addClass('yah');
currentLink.href = '';
2016-02-10 23:38:44 +00:00
});
}
2016-02-10 23:21:30 +00:00
}
function setFooterType() {
if (html.id == "docs") {
var bodyHeight = πd('hero').offset().height + πd('encyclopedia').offset().height;
var footer = π1('footer');
var footerHeight = footer.offset().height;
body.classOnCondition('fixed', window.innerHeight - footerHeight > bodyHeight);
}
}
function adjustEverything() {
if (!html.hasClass('open-nav')) HEADER_HEIGHT = π1('header').offset().height;
var Y = window.pageYOffset;
var offset = Y / 3;
html.classOnCondition('flip-nav', Y > 0);
//body.css({backgroundPosition: '0 ' + px(offset)});
if (headlines) {
var headlinesBottom = headlines.offset().top + headlines.offset().height - HEADER_HEIGHT + Y - 30; // 30px reveal at bottom
var quickstartBottom = headlinesBottom + quickstartButton.offset().height;
headlines.css({opacity: Y === 0 ? 1 : (Y > headlinesBottom ? 0 : 1 - (Y / headlinesBottom))});
quickstartButton.css({opacity: Y < headlinesBottom ? 1 : (Y > quickstartBottom ? 0 : 1 - ((Y - headlinesBottom) / (quickstartBottom - headlinesBottom)))});
html.classOnCondition('y-enough', Y > quickstartBottom);
}
}
function toggleMenu() {
if (window.innerWidth < 800) {
π.pushmenu.show('primary');
}
else {
var newHeight = HEADER_HEIGHT;
if (!html.hasClass('open-nav')) {
newHeight = mainNav.offset().height;
}
π('header').css({height: px(newHeight)});
}
html.toggleClass('open-nav');
}
function submitWish(textfield) {
alert('You typed: ' + textfield.value);
textfield.value = '';
textfield.blur();
}
function handleKeystrokes(e) {
switch (e.which) {
case 13: {
if (e.currentTarget === wishField) {
submitWish(wishField);
}
break;
}
case 27: {
if (html.hasClass('open-nav')) {
toggleMenu();
}
break;
}
}
}
function showVideo() {
var videoIframe = πd("videoPlayer").π1("iframe");
videoIframe.src = videoIframe.getAttribute("data-url");
π.modalOverlay.show("videoPlayer");
}
return {
toggleMenu: toggleMenu,
showVideo: showVideo
};
})();
2016-02-11 00:21:03 +00:00
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFsZi5qcyIsIs+ALmpzIiwiSEFMLmpzIiwiz4Atc3RhdHVzLmpzIiwiz4AtYmFzZUNvbXBvbmVudHMuanMiLCLPgC1hY2NvcmRpb24vz4AtYWNjb3JkaW9uLmpzIiwiz4AtZGlhbG9nL8+ALWRpYWxvZy5qcyIsIs+ALXB1c2htZW51L8+ALXB1c2htZW51LmpzIiwic2NyaXB0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUM5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQ