Skip to content

Instantly share code, notes, and snippets.

@AlexBezuska
Created March 17, 2014 00:42
Show Gist options
  • Save AlexBezuska/9592033 to your computer and use it in GitHub Desktop.
Save AlexBezuska/9592033 to your computer and use it in GitHub Desktop.
!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Splat=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
var Entity = _dereq_("./entity");
function AnimatedEntity(x, y, width, height, sprite, spriteOffsetX, spriteOffsetY) {
this.sprite = sprite;
this.spriteOffsetX = spriteOffsetX;
this.spriteOffsetY = spriteOffsetY;
Entity.call(this, x, y, width, height);
}
AnimatedEntity.prototype = Object.create(Entity.prototype);
AnimatedEntity.prototype.move = function(elapsedMillis) {
Entity.prototype.move.call(this, elapsedMillis);
if (typeof this.sprite.move === "function") {
this.sprite.move(elapsedMillis);
}
};
AnimatedEntity.prototype.draw = function(context) {
if (typeof this.sprite.draw === "function") {
this.sprite.draw(context, this.x + this.spriteOffsetX, this.y + this.spriteOffsetY);
} else {
context.drawImage(this.sprite, this.x + this.spriteOffsetX, this.y + this.spriteOffsetY);
}
// draw bounding boxes
// context.strokeStyle = "#ff0000";
// context.strokeRect(this.x, this.y, this.width, this.height);
};
AnimatedEntity.prototype.copy = function() {
return new AnimatedEntity(this.x, this.y, this.width, this.height, this.sprite, this.spriteOffsetX, this.spriteOffsetY);
};
module.exports = AnimatedEntity;
},{"./entity":7}],2:[function(_dereq_,module,exports){
var buffer = _dereq_("./buffer");
function Animation() {
this.frames = [];
this.frame = 0;
this.elapsedMillis = 0;
this.repeatAt = 0;
this.width = 0;
this.height = 0;
}
Animation.prototype.add = function(img, time) {
this.frames.push({img: img, time: time});
if (this.frames.length === 1) {
this.width = img.width;
this.height = img.height;
}
};
Animation.prototype.step = function() {
this.frame++;
if (this.frame >= this.frames.length) {
this.frame = this.repeatAt;
}
};
Animation.prototype.move = function(elapsedMillis) {
this.elapsedMillis += elapsedMillis;
while (this.elapsedMillis > this.frames[this.frame].time) {
this.elapsedMillis -= this.frames[this.frame].time;
this.step();
}
};
Animation.prototype.draw = function(context, x, y) {
var img = this.frames[this.frame].img;
context.drawImage(img, x, y);
};
Animation.prototype.reset = function() {
this.frame = 0;
this.elapsedMillis = 0;
};
Animation.prototype.flipHorizontally = function() {
for (var i = 0; i < this.frames.length; i++) {
this.frames[i].img = buffer.flipBufferHorizontally(this.frames[i].img);
}
};
Animation.prototype.flipVertically = function() {
for (var i = 0; i < this.frames.length; i++) {
this.frames[i].img = buffer.flipBufferVertically(this.frames[i].img);
}
};
module.exports = Animation;
},{"./buffer":4}],3:[function(_dereq_,module,exports){
var buffer = _dereq_("./buffer");
var Animation = _dereq_("./animation");
function makeFrame(img, frameWidth, f) {
return buffer.makeBuffer(frameWidth, img.height, function(ctx) {
var sx = f * frameWidth;
ctx.drawImage(img, sx, 0, frameWidth, img.height, 0, 0, frameWidth, img.height);
});
}
function makeAnimation(img, numFrames, time) {
var a = new Animation();
var frameWidth = img.width / numFrames |0;
for (var f = 0; f < numFrames; f++) {
a.add(makeFrame(img, frameWidth, f), time);
}
return a;
}
function loadImageFromManifest(imageLoader, name, info) {
if (info.strip !== undefined) {
imageLoader.load(name, info.strip);
} else if (info.prefix !== undefined) {
for (var i = 1; i <= info.frames; i++) {
var number = "" + i;
if (info.padNumberTo > 1) {
while (number.length < info.padNumberTo) {
number = "0" + number;
}
}
name = info.prefix + number + info.suffix;
imageLoader.load(name + i, name);
}
}
}
function loadImagesFromManifest(imageLoader, manifest) {
for (var key in manifest) {
if (manifest.hasOwnProperty(key)) {
var info = manifest[key];
loadImageFromManifest(imageLoader, key, info);
}
}
}
function makeAnimationFromManifest(images, key, manifestEntry) {
var animation;
if (manifestEntry.strip !== undefined) {
var strip = images.get(key);
animation = makeAnimation(strip, manifestEntry.frames, manifestEntry.msPerFrame);
} else if (manifestEntry.prefix !== undefined) {
animation = new Animation();
for (var i = 1; i <= manifestEntry.frames; i++) {
var frame = images.get(key + i);
animation.add(frame, manifestEntry.msPerFrame);
}
}
if (manifestEntry.repeatAt !== undefined) {
animation.repeatAt = manifestEntry.repeatAt;
}
if (manifestEntry.flip === "horizontal") {
animation.flipHorizontally();
}
if (manifestEntry.flip === "vertical") {
animation.flipVertically();
}
animation.name = key;
return animation;
}
function generateAnimationsFromManifest(images, manifest) {
var animations = {};
for (var key in manifest) {
if (manifest.hasOwnProperty(key)) {
var info = manifest[key];
animations[key] = makeAnimationFromManifest(images, key, info);
}
}
return animations;
}
function AnimationLoader(imageLoader, manifest) {
this.imageLoader = imageLoader;
this.manifest = manifest;
loadImagesFromManifest(imageLoader, manifest);
}
AnimationLoader.prototype.allLoaded = function() {
if (this.loaded) {
return true;
}
var loaded = this.imageLoader.allLoaded();
if (loaded) {
this.animations = generateAnimationsFromManifest(this.imageLoader, this.manifest);
this.loaded = true;
}
return loaded;
};
AnimationLoader.prototype.load = function(name, info) {
this.manifest[name] = info;
this.loaded = false;
loadImageFromManifest(this.imageLoader, name, info);
};
AnimationLoader.prototype.get = function(name) {
var anim = this.animations[name];
if (anim === undefined) {
console.error("Unknown animation: " + name);
}
return anim;
};
module.exports = AnimationLoader;
},{"./animation":2,"./buffer":4}],4:[function(_dereq_,module,exports){
function makeCanvas(width, height) {
var c = document.createElement("canvas");
c.width = width;
c.height = height;
return c;
}
function makeBuffer(width, height, drawFun) {
var canvas = makeCanvas(width, height);
var ctx = canvas.getContext("2d");
drawFun(ctx);
return canvas;
}
function flipBufferHorizontally(buffer) {
return makeBuffer(buffer.width, buffer.height, function(context) {
context.scale(-1, 1);
context.drawImage(buffer, -buffer.width, 0);
});
}
function flipBufferVertically(buffer) {
return makeBuffer(buffer.width, buffer.height, function(context) {
context.scale(1, -1);
context.drawImage(buffer, 0, -buffer.height);
});
}
module.exports = {
makeBuffer: makeBuffer,
flipBufferHorizontally: flipBufferHorizontally,
flipBufferVertically: flipBufferVertically
};
},{}],5:[function(_dereq_,module,exports){
var Entity = _dereq_("./entity");
function Camera(x, y, width, height) {
Entity.call(this, x, y, width, height);
}
Camera.prototype = Object.create(Entity.prototype);
Camera.prototype.draw = function(context) {
context.translate(-(this.x|0), -(this.y|0));
};
Camera.prototype.drawAbsolute = function(context, drawFunc) {
context.save();
context.translate(this.x|0, this.y|0);
drawFunc();
context.restore();
};
module.exports = Camera;
},{"./entity":7}],6:[function(_dereq_,module,exports){
function get(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) {
return parts.pop().split(";").shift();
}
}
function set(name, value) {
var expire = new Date();
expire.setTime(expire.getTime() + 1000 * 60 * 60 * 24 * 365);
var cookie = name + "=" + value + "; expires=" + expire.toUTCString() + ";";
document.cookie = cookie;
}
module.exports = {
"get": get,
"set": set
};
},{}],7:[function(_dereq_,module,exports){
function Entity(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.vx = 0;
this.vy = 0;
this.lastX = x;
this.lastY = y;
this.frictionX = 1;
this.frictionY = 1;
}
Entity.prototype.move = function(elapsedMillis) {
this.lastX = this.x;
this.lastY = this.y;
this.x += elapsedMillis * this.vx;
this.y += elapsedMillis * this.vy;
this.vx *= this.frictionX;
this.vy *= this.frictionY;
};
Entity.prototype.overlapsHoriz = function(other) {
return this.x + this.width >= other.x && this.x <= other.x + other.width;
};
Entity.prototype.overlapsVert = function(other) {
return this.y + this.height >= other.y && this.y <= other.y + other.height;
};
Entity.prototype.collides = function(other) {
return this.overlapsHoriz(other) && this.overlapsVert(other);
};
Entity.prototype.didOverlapHoriz = function(other) {
return this.lastX + this.width >= other.lastX && this.lastX <= other.lastX + other.width;
};
Entity.prototype.didOverlapVert = function(other) {
return this.lastY + this.height >= other.lastY && this.lastY <= other.lastY + other.height;
};
Entity.prototype.wasAbove = function(other) {
return this.lastY + this.height <= other.lastY;
};
Entity.prototype.wasBelow = function(other) {
return this.lastY >= other.lastY + other.height;
};
Entity.prototype.wasLeft = function(other) {
return this.lastX + this.width <= other.lastX;
};
Entity.prototype.wasRight = function(other) {
return this.lastX >= other.lastX + other.width;
};
Entity.prototype.moved = function() {
var x = this.x|0;
var lastX = this.lastX|0;
var y = this.y|0;
var lastY = this.lastY|0;
return (x != lastX) || (y != lastY);
};
Entity.prototype.draw = function(context) {
// draw bounding boxes
// context.strokeStyle = "#ff0000";
// context.strokeRect(this.x, this.y, this.width, this.height);
};
Entity.prototype.resolveBottomCollisionWith = function(other) {
if (this.didOverlapHoriz(other) && this.wasAbove(other)) {
this.y = other.y - this.height;
this.vy = 0;
}
};
Entity.prototype.resolveTopCollisionWith = function(other) {
if (this.didOverlapHoriz(other) && this.wasBelow(other)) {
this.y = other.y + other.height;
this.vy = 0;
}
};
Entity.prototype.resolveRightCollisionWith = function(other) {
if (this.didOverlapVert(other) && this.wasLeft(other)) {
this.x = other.x - this.width;
this.vx = 0;
}
};
Entity.prototype.resolveLeftCollisionWith = function(other) {
if (this.didOverlapVert(other) && this.wasRight(other)) {
this.x = other.x + other.width;
this.vx = 0;
}
};
Entity.prototype.resolveCollisionWith = function(other) {
this.resolveBottomCollisionWith(other);
this.resolveTopCollisionWith(other);
this.resolveRightCollisionWith(other);
this.resolveLeftCollisionWith(other);
};
module.exports = Entity;
},{}],8:[function(_dereq_,module,exports){
var Camera = _dereq_("./camera");
function EntityBoxCamera(entity, width, height, screenCenterX, screenCenterY) {
this.entity = entity;
this.screenCenterX = screenCenterX;
this.screenCenterY = screenCenterY;
var x = keepPositionInBox(entity.x, entity.width, 0, width, screenCenterX);
var y = keepPositionInBox(entity.y, entity.height, 0, height, screenCenterY);
Camera.call(this, x, y, width, height);
}
EntityBoxCamera.prototype = Object.create(Camera.prototype);
EntityBoxCamera.prototype.move = function(elapsedMillis) {
this.x = keepPositionInBox(this.entity.x, this.entity.width, this.x, this.width, this.screenCenterX);
this.y = keepPositionInBox(this.entity.y, this.entity.height, this.y, this.height, this.screenCenterY);
};
function keepPositionInBox(entityPos, entitySize, thisPos, thisSize, offset) {
var boundsFromCenter = thisSize / 2;
if (entityPos < thisPos + offset - boundsFromCenter) {
thisPos = entityPos - offset + boundsFromCenter;
}
if (entityPos + entitySize > thisPos + offset + boundsFromCenter) {
thisPos = entityPos + entitySize - offset - boundsFromCenter;
}
return thisPos;
}
module.exports = EntityBoxCamera;
},{"./camera":5}],9:[function(_dereq_,module,exports){
_dereq_("../vendor/FontLoader.js");
function FontLoader() {
this.totalFonts = 0;
this.loadedFonts = 0;
}
FontLoader.prototype.load = function(fontFamilies) {
this.totalFonts += fontFamilies.length;
var that = this;
var loader = new window.FontLoader(fontFamilies, {
"fontLoaded": function(fontFamily) {
that.loadedFonts++;
}
});
loader.loadFonts();
};
FontLoader.prototype.allLoaded = function() {
return this.totalFonts == this.loadedFonts;
};
module.exports = FontLoader;
},{"../vendor/FontLoader.js":22}],10:[function(_dereq_,module,exports){
var Scene = _dereq_("./scene");
var Mouse = _dereq_("./mouse");
var Keyboard = _dereq_("./keyboard");
var keyMap = _dereq_("./key_map");
var ImageLoader = _dereq_("./image_loader");
var SoundLoader = _dereq_("./sound_loader");
var FontLoader = _dereq_("./font_loader");
var AnimationLoader = _dereq_("./animation_loader");
var SceneManager = _dereq_("./scene_manager");
function loadAssets(assetLoader, assets) {
for (var key in assets) {
if (assets.hasOwnProperty(key)) {
assetLoader.load(key, assets[key]);
}
}
}
function makeLoadingScene(game, canvas, nextScene) {
return new Scene(canvas, function() {
}, function(elapsedMillis) {
if (game.isLoaded()) {
game.scenes.switchTo(nextScene);
}
}, function(context) {
context.fillStyle = "#000000";
context.fillRect(0, 0, canvas.width, canvas.height);
var quarterWidth = (canvas.width / 4) |0;
var halfWidth = (canvas.width / 2) |0;
var halfHeight = (canvas.height / 2) |0;
context.fillStyle = "#ffffff";
context.fillRect(quarterWidth, halfHeight - 15, halfWidth, 30);
context.fillStyle = "#000000";
context.fillRect(quarterWidth + 3, halfHeight - 12, halfWidth - 6, 24);
context.fillStyle = "#ffffff";
var barWidth = (halfWidth - 6) * game.percentLoaded();
context.fillRect(quarterWidth + 3, halfHeight - 12, barWidth, 24);
});
}
function setCanvasSize(canvas) {
var ww = window.innerWidth;
var wh = window.innerHeight;
var cw = canvas.width;
var ch = canvas.height;
if (ww >= cw && wh >= ch) {
return;
} else if (ww < cw && wh >= ch) {
wh = ((ww / cw) * ch) | 0;
canvas.style.width = ww + "px";
canvas.style.height = wh + "px";
} else if (ww >= cw && wh < ch) {
ww = ((wh / ch) * cw) | 0;
canvas.style.width = ww + "px";
canvas.style.height = wh + "px";
} else if (ww < cw && wh < ch) {
if ((ww / cw) * ch > wh) {
ww = ((wh / ch) * cw) | 0;
} else {
wh = ((ww / cw) * ch) | 0;
}
canvas.style.width = ww + "px";
canvas.style.height = wh + "px";
}
}
function Game(canvas, manifest) {
//window.addEventListener("resize", function() { setCanvasSize(canvas); });
//setCanvasSize(canvas);
ejecta.loadFont("pixelade/pixelade.ttf");
console.debug("canvas.width: " + canvas.width
+" canvas.height: " + canvas.height
+" window.innerWidth: " + window.innerWidth
+" window.innerheight: "+ window.innerHeight
+" canvas.style.height: " + canvas.style.height
+" canvas.style.width: " + canvas.style.width
+" devicePixelRatio: " + devicePixelRatio);
canvas.width = window.innerWidth * window.devicePixelRatio;
canvas.height = window.innerHeight * window.devicePixelRatio;
canvas.style.width = window.innerWidth + "px";
canvas.style.height = window.innerHeight + "px";
console.debug("canvas.width: " + canvas.width
+" canvas.height: " + canvas.height
+" window.innerWidth: " + window.innerWidth
+" window.innerheight: "+ window.innerHeight
+" canvas.style.height: " + canvas.style.height
+" canvas.style.width: " + canvas.style.width
+" devicePixelRatio: " + devicePixelRatio);
this.mouse = new Mouse(canvas);
this.keyboard = new Keyboard(keyMap.US);
this.images = new ImageLoader();
loadAssets(this.images, manifest.images);
this.sounds = new SoundLoader();
loadAssets(this.sounds, manifest.sounds);
//this.fonts = new FontLoader();
//this.fonts.load(manifest.fonts);
this.animations = new AnimationLoader(this.images, manifest.animations);
this.scenes = new SceneManager();
this.scenes.add("loading", makeLoadingScene(this, canvas, "title"));
}
Game.prototype.isLoaded = function() {
return this.images.allLoaded() &&
this.sounds.allLoaded() &&
//this.fonts.allLoaded() &&
this.animations.allLoaded();
};
Game.prototype.percentLoaded = function() {
var totalAssets =
this.images.totalImages +
this.sounds.totalSounds;
//this.fonts.totalFonts;
var loadedAssets =
this.images.loadedImages +
this.sounds.loadedSounds;
//this.fonts.loadedFonts;
return loadedAssets / totalAssets;
};
module.exports = Game;
},{"./animation_loader":3,"./font_loader":9,"./image_loader":11,"./key_map":12,"./keyboard":13,"./mouse":16,"./scene":18,"./scene_manager":19,"./sound_loader":20}],11:[function(_dereq_,module,exports){
function ImageLoader() {
this.images = {};
this.totalImages = 0;
this.loadedImages = 0;
this.names = [];
}
ImageLoader.prototype.load = function(name, path) {
// only load an image once
if (this.names.indexOf(name) > -1) {
return;
}
this.names.push(name);
this.totalImages++;
var img = new Image();
var that = this;
img.addEventListener("load", function() {
that.loadedImages++;
that.images[name] = img;
});
img.addEventListener("error", function() {
console.error("Error loading image " + path);
});
img.src = path;
};
ImageLoader.prototype.allLoaded = function() {
return this.totalImages == this.loadedImages;
};
ImageLoader.prototype.get = function(name) {
var img = this.images[name];
if (img === undefined) {
console.error("Unknown image: " + name);
}
return img;
};
module.exports = ImageLoader;
},{}],12:[function(_dereq_,module,exports){
module.exports = {
"US": {
8: "backspace",
9: "tab",
13: "enter",
16: "shift",
17: "ctrl",
18: "alt",
19: "pause/break",
20: "capslock",
27: "escape",
32: "space",
33: "pageup",
34: "pagedown",
35: "end",
36: "home",
37: "left",
38: "up",
39: "right",
40: "down",
45: "insert",
46: "delete",
48: "0",
49: "1",
50: "2",
51: "3",
52: "4",
53: "5",
54: "6",
55: "7",
56: "8",
57: "9",
65: "a",
66: "b",
67: "c",
68: "d",
69: "e",
70: "f",
71: "g",
72: "h",
73: "i",
74: "j",
75: "k",
76: "l",
77: "m",
78: "n",
79: "o",
80: "p",
81: "q",
82: "r",
83: "s",
84: "t",
85: "u",
86: "v",
87: "w",
88: "x",
89: "y",
90: "z",
91: "leftwindow",
92: "rightwindow",
93: "select",
96: "numpad-0",
97: "numpad-1",
98: "numpad-2",
99: "numpad-3",
100: "numpad-4",
101: "numpad-5",
102: "numpad-6",
103: "numpad-7",
104: "numpad-8",
105: "numpad-9",
106: "multiply",
107: "add",
109: "subtract",
110: "decimalpoint",
111: "divide",
112: "f1",
113: "f2",
114: "f3",
115: "f4",
116: "f5",
117: "f6",
118: "f7",
119: "f8",
120: "f9",
121: "f10",
122: "f11",
123: "f12",
144: "numlock",
145: "scrolllock",
186: "semicolon",
187: "equals",
188: "comma",
189: "dash",
190: "period",
191: "forwardslash",
192: "graveaccent",
219: "openbracket",
220: "backslash",
221: "closebraket",
222: "singlequote"
}
};
},{}],13:[function(_dereq_,module,exports){
function Keyboard(keyMap) {
this.keys = {};
var that = this;
for (var kc in keyMap) {
this.keys[keyMap[kc]] = 0;
}
window.addEventListener("keydown", function(event) {
if (keyMap.hasOwnProperty(event.keyCode)) {
if (that.keys[keyMap[event.keyCode]] === 0) {
that.keys[keyMap[event.keyCode]] = 2;
}
return false;
}
});
window.addEventListener("keyup", function(event) {
if (keyMap.hasOwnProperty(event.keyCode)) {
that.keys[keyMap[event.keyCode]] = 0;
return false;
}
});
}
Keyboard.prototype.isPressed = function(name) {
return this.keys[name] >= 1;
};
Keyboard.prototype.consumePressed = function(name) {
var p = this.keys[name] === 2;
if (p) {
this.keys[name] = 1;
}
return p;
};
module.exports = Keyboard;
},{}],14:[function(_dereq_,module,exports){
var buffer = _dereq_("./buffer");
module.exports = {
makeBuffer: buffer.makeBuffer,
flipBufferHorizontally: buffer.flipBufferHorizontally,
flipBufferVertically: buffer.flipBufferVertically,
AnimatedEntity: _dereq_("./animated_entity"),
Camera: _dereq_("./camera"),
cookie: _dereq_("./cookie"),
Entity: _dereq_("./entity"),
EntityBoxCamera: _dereq_("./entity_box_camera"),
Game: _dereq_("./game"),
math: _dereq_("./math"),
NinePatch: _dereq_("./ninepatch"),
Scene: _dereq_("./scene"),
Timer: _dereq_("./timer"),
};
},{"./animated_entity":1,"./buffer":4,"./camera":5,"./cookie":6,"./entity":7,"./entity_box_camera":8,"./game":10,"./math":15,"./ninepatch":17,"./scene":18,"./timer":21}],15:[function(_dereq_,module,exports){
module.exports = {
"oscillate": function(current, period) {
return Math.sin(current / period * Math.PI);
}
};
},{}],16:[function(_dereq_,module,exports){
// prevent springy scrolling on ios
document.ontouchmove = function(e) {
e.preventDefault();
};
// prevent right-click on desktop
window.oncontextmenu = function() {
return false;
};
function relMouseCoords(canvas, event) {
var x = event.pageX - canvas.offsetLeft + document.body.scrollLeft;
var y = event.pageY - canvas.offsetTop + document.body.scrollTop;
// scale based on ratio of canvas internal dimentions to css dimensions
if (canvas.style.width.length) {
x *= canvas.width / canvas.style.width.substring(0, canvas.style.width.indexOf("p"));
}
if (canvas.style.height.length) {
y *= canvas.height / canvas.style.height.substring(0, canvas.style.height.indexOf("p"));
}
//return {x:x, y:y};
return {x:event.pageX * window.devicePixelRatio, y:event.pageY * window.devicePixelRatio};
}
function Mouse(canvas) {
this.x = 0;
this.y = 0;
this.buttons = [0, 0, 0];
var that = this;
canvas.addEventListener("mousedown", function(event) {
var m = relMouseCoords(canvas, event);
that.x = m.x;
that.y = m.y;
that.buttons[event.button] = 2;
});
canvas.addEventListener("mouseup", function(event) {
var m = relMouseCoords(canvas, event);
that.x = m.x;
that.y = m.y;
that.buttons[event.button] = 0;
});
canvas.addEventListener("touchstart", function(event) {
var touch = event.touches[0];
var m = relMouseCoords(canvas, touch);
console.debug("m.x = "+ m.x + "m.y = " + m.y);
console.debug("touch.pageX = " + touch.pageX + " touch.pageY = " + touch.pageY );
that.x = m.x;
that.y = m.y;
that.buttons[0] = 2;
});
canvas.addEventListener("touchend", function(event) {
that.buttons[0] = 0;
});
}
Mouse.prototype.supportsTouch = function() {
return "ontouchstart" in window || navigator.msMaxTouchPoints;
};
Mouse.prototype.isPressed = function(button) {
return this.buttons[button] >= 1;
};
Mouse.prototype.consumePressed = function(button, x, y, width, height) {
var b = this.buttons[button] === 2;
if (arguments.length > 1 && (this.x < x || this.x > x + width || this.y < y || this.y > y + height)) {
b = false;
}
if (b) {
this.buttons[button] = 1;
}
return b;
};
module.exports = Mouse;
},{}],17:[function(_dereq_,module,exports){
var buffer = _dereq_("./buffer");
function getContextForImage(image) {
var ctx;
var canvas = buffer.makeBuffer(image.width, image.height, function(context) {
context.drawImage(image, 0, 0, image.width, image.height);
ctx = context;
});
return ctx;
}
function NinePatch(image) {
this.img = image;
var imgw = image.width - 1;
var imgh = image.height - 1;
var context = getContextForImage(image);
var firstDiv = imgw;
var secondDiv = imgw;
var pixel;
var alpha;
for (var x = 0; x < imgw; x++) {
pixel = context.getImageData(x, imgh, 1, 1).data;
alpha = pixel[3];
if (firstDiv == imgw && alpha > 0) {
firstDiv = x;
}
if (firstDiv < imgw && alpha === 0) {
secondDiv = x;
break;
}
}
this.w1 = firstDiv;
this.w2 = secondDiv - firstDiv;
this.w3 = imgw - secondDiv;
firstDiv = secondDiv = imgh;
for (var y = 0; y < imgh; y++) {
pixel = context.getImageData(imgw, y, 1, 1).data;
alpha = pixel[3];
if (firstDiv == imgh && alpha > 0) {
firstDiv = y;
}
if (firstDiv < imgh && alpha === 0) {
secondDiv = y;
break;
}
}
this.h1 = firstDiv;
this.h2 = secondDiv - firstDiv;
this.h3 = imgh - secondDiv;
}
NinePatch.prototype.draw = function(context, x, y, width, height) {
x = x|0;
y = y|0;
width = width |0;
height = height |0;
var cx, cy, w, h;
for (cy = y + this.h1; cy < y + height - this.h3; cy += this.h2) {
for (cx = x + this.w1; cx < x + width - this.w3; cx += this.w2) {
w = Math.min(this.w2, x + width - this.w3 - cx);
h = Math.min(this.h2, y + height - this.h3 - cy);
context.drawImage(this.img, this.w1, this.h1, w, h, cx, cy, w, h);
}
}
for (cy = y + this.h1; cy < y + height - this.h3; cy += this.h2) {
h = Math.min(this.h2, y + height - this.h3 - cy);
if (this.w1 > 0) {
context.drawImage(this.img, 0, this.h1, this.w1, h, x, cy, this.w1, h);
}
if (this.w3 > 0) {
context.drawImage(this.img, this.w1 + this.w2, this.h1, this.w3, h, x + width - this.w3, cy, this.w3, h);
}
}
for (cx = x + this.w1; cx < x + width - this.w3; cx += this.w2) {
w = Math.min(this.w2, x + width - this.w3 - cx);
if (this.h1 > 0) {
context.drawImage(this.img, this.w1, 0, w, this.h1, cx, y, w, this.h1);
}
if (this.h3 > 0) {
context.drawImage(this.img, this.w1, this.w1 + this.w2, w, this.h3, cx, y + height - this.h3, w, this.h3);
}
}
if (this.w1 > 0 && this.h1 > 0) {
context.drawImage(this.img, 0, 0, this.w1, this.h1, x, y, this.w1, this.h1);
}
if (this.w3 > 0 && this.h1 > 0) {
context.drawImage(this.img, this.w1 + this.w2, 0, this.w3, this.h1, x + width - this.w3, y, this.w3, this.h1);
}
if (this.w1 > 0 && this.h3 > 0) {
context.drawImage(this.img, 0, this.h1 + this.h2, this.w1, this.h3, x, y + height - this.h3, this.w1, this.h3);
}
if (this.w3 > 0 && this.h3 > 0) {
context.drawImage(this.img, this.w1 + this.w2, this.h1 + this.h2, this.w3, this.h3, x + width - this.w3, y + height - this.h3, this.w3, this.h3);
}
};
module.exports = NinePatch;
},{"./buffer":4}],18:[function(_dereq_,module,exports){
var Camera = _dereq_("./camera");
function Scene(canvas, initFunc, simulationFunc, drawFunc) {
this.canvas = canvas;
this.initFunc = initFunc;
this.simulationFunc = simulationFunc;
this.drawFunc = drawFunc;
this.context = canvas.getContext("2d");
this.lastTimestamp = -1;
this.running = false;
this.timers = {};
this.camera = new Camera(0, 0, canvas.width, canvas.height);
this.showFrameRate = false;
}
Scene.prototype.start = function() {
this.lastTimestamp = -1;
this.running = true;
this.initFunc.call(this);
var scene = this;
window.requestAnimationFrame(function(t) { mainLoop(scene, t); });
};
Scene.prototype.stop = function() {
this.running = false;
};
Scene.prototype.reset = function() {
this.initFunc.call(this);
};
function mainLoop(scene, timestamp) {
if (!scene.running) {
return;
}
if (scene.lastTimestamp === -1) {
scene.lastTimestamp = timestamp;
}
var elapsedMillis = timestamp - scene.lastTimestamp;
scene.lastTimestamp = timestamp;
incrementTimers(scene.timers, elapsedMillis);
if (!scene.running) {
return;
}
scene.simulationFunc.call(scene, elapsedMillis);
scene.camera.move(elapsedMillis);
scene.context.save();
scene.camera.draw(scene.context);
scene.drawFunc.call(scene, scene.context);
if (scene.showFrameRate) {
drawFrameRate(scene, elapsedMillis);
}
scene.context.restore();
if (scene.running) {
window.requestAnimationFrame(function(t) { mainLoop(scene, t); });
}
};
function incrementTimers(timers, elapsedMillis) {
for (var i in timers) {
if (timers.hasOwnProperty(i)) {
timers[i].tick(elapsedMillis);
}
}
};
function drawFrameRate(scene, elapsedMillis) {
var fps = (1000 / elapsedMillis) |0;
scene.context.font = "24px mono";
if (fps < 30) {
scene.context.fillStyle = "#ff0000";
} else if (fps < 50) {
scene.context.fillStyle = "#ffff00";
} else {
scene.context.fillStyle = "#00ff00";
}
var msg = fps + " FPS";
var w = scene.context.measureText(msg).width;
scene.camera.drawAbsolute(scene.context, function() {
scene.context.fillText(msg, scene.canvas.width - w - 50, 50);
});
}
module.exports = Scene;
},{"./camera":5}],19:[function(_dereq_,module,exports){
function SceneManager() {
this.scenes = {};
}
SceneManager.prototype.add = function(name, scene) {
this.scenes[name] = scene;
};
SceneManager.prototype.get = function(name) {
return this.scenes[name];
};
SceneManager.prototype.switchTo = function(name) {
if (this.currentScene === this.scenes[name]) {
this.currentScene.reset();
return;
}
if (this.currentScene !== undefined) {
this.currentScene.stop();
}
this.currentScene = this.scenes[name];
this.currentScene.start();
};
module.exports = SceneManager;
},{}],20:[function(_dereq_,module,exports){
window.AudioContext = window.AudioContext || window.webkitAudioContext;
function SoundLoader() {
this.sounds = {};
this.totalSounds = 0;
this.loadedSounds = 0;
this.muted = false;
this.looping = {};
this.context = new AudioContext();
}
SoundLoader.prototype.load = function(name, path) {
var that = this;
if (this.totalSounds === 0) {
// safari on iOS mutes sounds until they're played in response to user input
// play a dummy sound on first touch
var firstTouchHandler = function(event) {
window.removeEventListener("click", firstTouchHandler);
window.removeEventListener("keydown", firstTouchHandler);
window.removeEventListener("touchstart", firstTouchHandler);
var source = that.context.createOscillator();
source.connect(that.context.destination);
source.start(0);
source.stop(0);
if (that.firstPlay) {
that.play(that.firstPlay, that.firstPlayLoop);
} else {
that.firstPlay = "workaround";
}
};
window.addEventListener("click", firstTouchHandler);
window.addEventListener("keydown", firstTouchHandler);
window.addEventListener("touchstart", firstTouchHandler);
}
this.totalSounds++;
var request = new XMLHttpRequest();
request.open("GET", path, true);
request.responseType = "arraybuffer";
request.addEventListener("readystatechange", function() {
if (request.readyState != 4) {
return;
}
if (request.status !== 200 && request.status !== 0) {
console.error("Error loading sound " + path);
return;
}
that.context.decodeAudioData(request.response, function(buffer) {
that.sounds[name] = buffer;
that.loadedSounds++;
});
});
request.addEventListener("error", function() {
console.error("Error loading sound " + path);
});
request.send();
};
SoundLoader.prototype.allLoaded = function() {
return this.totalSounds == this.loadedSounds;
};
SoundLoader.prototype.play = function(name, loop) {
if (loop && this.looping[name]) {
return;
}
if (!this.firstPlay) {
// let the iOS user input workaround handle it
this.firstPlay = name;
this.firstPlayLoop = loop;
return;
}
if (this.muted) {
return;
}
var snd = this.sounds[name];
if (snd === undefined) {
console.error("Unknown sound: " + name);
}
var source = this.context.createBufferSource();
source.buffer = snd;
source.connect(this.context.destination);
if (loop) {
source.loop = true;
this.looping[name] = source;
}
source.start(0);
};
SoundLoader.prototype.stop = function(name) {
if (!this.looping[name]) {
return;
}
this.looping[name].stop();
delete this.looping[name];
}
if (window.AudioContext) {
module.exports = SoundLoader;
} else {
console.log("This browser doesn't support the Web Audio API");
var fakeSoundLoader = function() {};
fakeSoundLoader.prototype.load = function() {};
fakeSoundLoader.prototype.allLoaded = function() { return true; };
fakeSoundLoader.prototype.play = function() {};
module.exports = fakeSoundLoader;
}
},{}],21:[function(_dereq_,module,exports){
function Timer(onTick, expireMillis, onExpire) {
this.onTick = onTick;
this.expireMillis = expireMillis;
this.onExpire = onExpire;
this.running = false;
this.time = 0;
}
Timer.prototype.start = function() {
this.running = true;
};
Timer.prototype.stop = function() {
this.running = false;
};
Timer.prototype.reset = function() {
this.time = 0;
};
Timer.prototype.tick = function(elapsedMillis) {
if (!this.running) {
return;
}
this.time += elapsedMillis;
if (this.expired()) {
this.stop();
if (typeof this.onExpire === "function") {
this.onExpire.call(this);
}
return;
}
if (typeof this.onTick === "function") {
this.onTick.call(this, elapsedMillis);
}
};
Timer.prototype.expired = function() {
return typeof this.expireMillis !== "undefined" && this.time >= this.expireMillis;
};
module.exports = Timer;
},{}],22:[function(_dereq_,module,exports){
(function(namespace) {
var isIE = /MSIE/i.test(navigator.userAgent),
ieVer = null;
// Get Internet Explorer version
if (isIE) {
var re, result;
re = new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})");
result = re.exec(navigator.userAgent);
if (result !== null) {
ieVer = parseFloat(result[1]);
}
}
/**
* FontLoader detects when web fonts specified in the "fontFamiliesArray" array were loaded and rendered. Then it
* notifies the specified delegate object via "fontLoaded" and "fontsLoaded" methods when specific or all fonts were
* loaded respectively. The use of this functions implies that the insertion of specified web fonts into the
* document is done elsewhere.
*
* If timeout (default 3000ms) is reached before all fonts were loaded and rendered, then "fontsLoaded" delegate
* method is invoked with an error object as its single parameter. The error object has two fields: the "message"
* field holding the error description and the "notLoadedFontFamilies" field holding an array with all the
* font-families that weren't loaded. Otherwise the parameter is null.
*
* @param {Array} fontFamiliesArray Array of font-family strings.
* @param {Object} delegate Delegate object whose delegate methods will be invoked in its own context.
* @param {Function} [delegate.fontsLoaded] Delegate method invoked after all fonts are loaded or timeout is reached.
* @param {Function} [delegate.fontLoaded] Delegate method invoked for each loaded font with its font-family string as its single parameter.
* @param {Number} [timeout=3000] Timeout in milliseconds. Pass "null" to disable timeout.
* @constructor
*/
function FontLoader(fontFamiliesArray, delegate, timeout) {
// Public
this.delegate = delegate;
this.timeout = (typeof timeout !== "undefined") ? timeout : 3000;
// Private
this._fontFamiliesArray = fontFamiliesArray.slice(0);
this._testContainer = null;
this._adobeBlankSizeWatcher = null;
this._timeoutId = null;
this._intervalId = null;
this._intervalDelay = 50;
this._numberOfLoadedFonts = 0;
this._numberOfFontFamilies = this._fontFamiliesArray.length;
this._fontsMap = {};
this._finished = false;
}
namespace.FontLoader = FontLoader;
FontLoader.testDiv = null;
FontLoader.useAdobeBlank = !isIE || ieVer >= 11.0;
FontLoader.useResizeEvent = isIE && ieVer < 11.0 && typeof document.attachEvent !== "undefined";
FontLoader.useIntervalChecking = window.opera || (isIE && ieVer < 11.0 && !FontLoader.useResizeEvent);
FontLoader.referenceText = " !\"\\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~";
FontLoader.referenceFontFamilies = FontLoader.useAdobeBlank ? ["AdobeBlank"] : ["serif", "cursive"];
FontLoader.referenceFontFamiliesSizes = [];
FontLoader.adobeBlankFontFaceRule = "@font-face{ font-family:AdobeBlank; src:url('data:font/opentype;base64,T1RUTwAKAIAAAwAgQ0ZGIM6ZbkwAAEPEAAAZM0RTSUcAAAABAABtAAAAAAhPUy8yAR6vMwAAARAAAABgY21hcDqI98oAACjEAAAa4GhlYWT+BQILAAAArAAAADZoaGVhCCID7wAAAOQAAAAkaG10eAPoAHwAAFz4AAAQBm1heHAIAVAAAAABCAAAAAZuYW1lD/tWxwAAAXAAACdScG9zdP+4ADIAAEOkAAAAIAABAAAAAQj1Snw1O18PPPUAAwPoAAAAAM2C2p8AAAAAzYLanwB8/4gDbANwAAAAAwACAAAAAAAAAAEAAANw/4gAyAPoAHwAfANsAAEAAAAAAAAAAAAAAAAAAAACAABQAAgBAAAABAAAAZAABQAAAooCWAAAAEsCigJYAAABXgAyANwAAAAAAAAAAAAAAAD3/67/+9///w/gAD8AAAAAQURCRQHAAAD//wNw/4gAyANwAHhgLwH/AAAAAAAAAAAAAAAgAAAAAAARANIAAQAAAAAAAQALAAAAAQAAAAAAAgAHAAsAAQAAAAAAAwAbABIAAQAAAAAABAALAAAAAQAAAAAABQA5AC0AAQAAAAAABgAKAGYAAwABBAkAAABuAHAAAwABBAkAAQAWAN4AAwABBAkAAgAOAPQAAwABBAkAAwA2AQIAAwABBAkABAAWAN4AAwABBAkABQByATgAAwABBAkABgAUAaoAAwABBAkACAA0Ab4AAwABBAkACwA0AfIAAwABBAkADSQSAiYAAwABBAkADgBIJjhBZG9iZSBCbGFua1JlZ3VsYXIxLjAzNTtBREJFO0Fkb2JlQmxhbms7QURPQkVWZXJzaW9uIDEuMDM1O1BTIDEuMDAzO2hvdGNvbnYgMS4wLjcwO21ha2VvdGYubGliMi41LjU5MDBBZG9iZUJsYW5rAKkAIAAyADAAMQAzACAAQQBkAG8AYgBlACAAUwB5AHMAdABlAG0AcwAgAEkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkAC4AIABBAGwAbAAgAFIAaQBnAGgAdABzACAAUgBlAHMAZQByAHYAZQBkAC4AQQBkAG8AYgBlACAAQgBsAGEAbgBrAFIAZQBnAHUAbABhAHIAMQAuADAAMwA1ADsAQQBEAEIARQA7AEEAZABvAGIAZQBCAGwAYQBuAGsAOwBBAEQATwBCAEUAVgBlAHIAcwBpAG8AbgAgADEALgAwADMANQA7AFAAUwAgADEALgAwADAAMwA7AGgAbwB0AGMAbwBuAHYAIAAxAC4AMAAuADcAMAA7AG0AYQBrAGUAbwB0AGYALgBsAGkAYgAyAC4ANQAuADUAOQAwADAAQQBkAG8AYgBlAEIAbABhAG4AawBBAGQAbwBiAGUAIABTAHkAcwB0AGUAbQBzACAASQBuAGMAbwByAHAAbwByAGEAdABlAGQAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGEAZABvAGIAZQAuAGMAbwBtAC8AdAB5AHAAZQAvAEEAZABvAGIAZQAgAEIAbABhAG4AawAgAGkAcwAgAHIAZQBsAGUAYQBzAGUAZAAgAHUAbgBkAGUAcgAgAHQAaABlACAAUwBJAEwAIABPAHAAZQBuACAARgBvAG4AdAAgAEwAaQBjAGUAbgBzAGUAIAAtACAAcABsAGUAYQBzAGUAIAByAGUAYQBkACAAaQB0ACAAYwBhAHIAZQBmAHUAbABsAHkAIABhAG4AZAAgAGQAbwAgAG4AbwB0ACAAZABvAHcAbgBsAG8AYQBkACAAdABoAGUAIABmAG8AbgB0AHMAIAB1AG4AbABlAHMAcwAgAHkAbwB1ACAAYQBnAHIAZQBlACAAdABvACAAdABoAGUAIAB0AGgAZQAgAHQAZQByAG0AcwAgAG8AZgAgAHQAaABlACAAbABpAGMAZQBuAHMAZQA6AA0ACgANAAoAQwBvAHAAeQByAGkAZwBoAHQAIACpACAAMgAwADEAMwAgAEEAZABvAGIAZQAgAFMAeQBzAHQAZQBtAHMAIABJAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgACgAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGEAZABvAGIAZQAuAGMAbwBtAC8AKQAsACAAdwBpAHQAaAAgAFIAZQBzAGUAcgB2AGUAZAAgAEYAbwBuAHQAIABOAGEAbQBlACAAQQBkAG8AYgBlACAAQgBsAGEAbgBrAA0ACgANAAoAVABoAGkAcwAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUAIABpAHMAIABsAGkAYwBlAG4AcwBlAGQAIAB1AG4AZABlAHIAIAB0AGgAZQAgAFMASQBMACAATwBwAGUAbgAgAEYAbwBuAHQAIABMAGkAYwBlAG4AcwBlACwAIABWAGUAcgBzAGkAbwBuACAAMQAuADEALgANAAoADQAKAFQAaABpAHMAIABsAGkAYwBlAG4AcwBlACAAaQBzACAAYwBvAHAAaQBlAGQAIABiAGUAbABvAHcALAAgAGEAbgBkACAAaQBzACAAYQBsAHMAbwAgAGEAdgBhAGkAbABhAGIAbABlACAAdwBpAHQAaAAgAGEAIABGAEEAUQAgAGEAdAA6ACAAaAB0AHQAcAA6AC8ALwBzAGMAcgBpAHAAdABzAC4AcwBpAGwALgBvAHIAZwAvAE8ARgBMAA0ACgANAAoALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAA0ACgBTAEkATAAgAE8AUABFAE4AIABGAE8ATgBUACAATABJAEMARQBOAFMARQAgAFYAZQByAHMAaQBvAG4AIAAxAC4AMQAgAC0AIAAyADYAIABGAGUAYgByAHUAYQByAHkAIAAyADAAMAA3AA0ACgAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ADQAKAA0ACgBQAFIARQBBAE0AQgBMAEUADQAKAFQAaABlACAAZwBvAGEAbABzACAAbwBmACAAdABoAGUAIABPAHAAZQBuACAARgBvAG4AdAAgAEwAaQBjAGUAbgBzAGUAIAAoAE8ARgBMACkAIABhAHIAZQAgAHQAbwAgAHMAdABpAG0AdQBsAGEAdABlACAAdwBvAHIAbABkAHcAaQBkAGUAIABkAGUAdgBlAGwAbwBwAG0AZQBuAHQAIABvAGYAIABjAG8AbABsAGEAYgBvAHIAYQB0AGkAdgBlACAAZgBvAG4AdAAgAHAAcgBvAGoAZQBjAHQAcwAsACAAdABvACAAcwB1AHAAcABvAHIAdAAgAHQAaABlACAAZgBvAG4AdAAgAGMAcgBlAGEAdABpAG8AbgAgAGUAZgBmAG8AcgB0AHMAIABvAGYAIABhAGMAYQBkAGUAbQBpAGMAIABhAG4AZAAgAGwAaQBuAGcAdQBpAHMAdABpAGMAIABjAG8AbQBtAHUAbgBpAHQAaQBlAHMALAAgAGEAbgBkACAAdABvACAAcAByAG8AdgBpAGQAZQAgAGEAIABmAHIAZQBlACAAYQBuAGQAIABvAHAAZQBuACAAZgByAGEAbQBlAHcAbwByAGsAIABpAG4AIAB3AGgAaQBjAGgAIABmAG8AbgB0AHMAIABtAGEAeQAgAGIAZQAgAHMAaABhAHIAZQBkACAAYQBuAGQAIABpAG0AcAByAG8AdgBlAGQAIABpAG4AIABwAGEAcgB0AG4AZQByAHMAaABpAHAAIAB3AGkAdABoACAAbwB0AGgAZQByAHMALgANAAoADQAKAFQAaABlACAATwBGAEwAIABhAGwAbABvAHcAcwAgAHQAaABlACAAbABpAGMAZQBuAHMAZQBkACAAZgBvAG4AdABzACAAdABvACAAYgBlACAAdQBzAGUAZAAsACAAcwB0AHUAZABpAGUAZAAsACAAbQBvAGQAaQBmAGkAZQBkACAAYQBuAGQAIAByAGUAZABpAHMAdAByAGkAYgB1AHQAZQBkACAAZgByAGUAZQBsAHkAIABhAHMAIABsAG8AbgBnACAAYQBzACAAdABoAGUAeQAgAGEAcgBlACAAbgBvAHQAIABzAG8AbABkACAAYgB5ACAAdABoAGUAbQBzAGUAbAB2AGUAcwAuACAAVABoAGUAIABmAG8AbgB0AHMALAAgAGkAbgBjAGwAdQBkAGkAbgBnACAAYQBuAHkAIABkAGUAcgBpAHYAYQB0AGkAdgBlACAAdwBvAHIAawBzACwAIABjAGEAbgAgAGIAZQAgAGIAdQBuAGQAbABlAGQALAAgAGUAbQBiAGUAZABkAGUAZAAsACAAcgBlAGQAaQBzAHQAcgBpAGIAdQB0AGUAZAAgAGEAbgBkAC8AbwByACAAcwBvAGwAZAAgAHcAaQB0AGgAIABhAG4AeQAgAHMAbwBmAHQAdwBhAHIAZQAgAHAAcgBvAHYAaQBkAGUAZAAgAHQAaABhAHQAIABhAG4AeQAgAHIAZQBzAGUAcgB2AGUAZAAgAG4AYQBtAGUAcwAgAGEAcgBlACAAbgBvAHQAIAB1AHMAZQBkACAAYgB5ACAAZABlAHIAaQB2AGEAdABpAHYAZQAgAHcAbwByAGsAcwAuACAAVABoAGUAIABmAG8AbgB0AHMAIABhAG4AZAAgAGQAZQByAGkAdgBhAHQAaQB2AGUAcwAsACAAaABvAHcAZQB2AGUAcgAsACAAYwBhAG4AbgBvAHQAIABiAGUAIAByAGUAbABlAGEAcwBlAGQAIAB1AG4AZABlAHIAIABhAG4AeQAgAG8AdABoAGUAcgAgAHQAeQBwAGUAIABvAGYAIABsAGkAYwBlAG4AcwBlAC4AIABUAGgAZQAgAHIAZQBxAHUAaQByAGUAbQBlAG4AdAAgAGYAbwByACAAZgBvAG4AdABzACAAdABvACAAcgBlAG0AYQBpAG4AIAB1AG4AZABlAHIAIAB0AGgAaQBzACAAbABpAGMAZQBuAHMAZQAgAGQAbwBlAHMAIABuAG8AdAAgAGEAcABwAGwAeQAgAHQAbwAgAGEAbgB5ACAAZABvAGMAdQBtAGUAbgB0ACAAYwByAGUAYQB0AGUAZAAgAHUAcwBpAG4AZwAgAHQAaABlACAAZgBvAG4AdABzACAAbwByACAAdABoAGUAaQByACAAZABlAHIAaQB2AGEAdABpAHYAZQBzAC4ADQAKAA0ACgBEAEUARgBJAE4ASQBUAEkATwBOAFMADQAKACIARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAiACAAcgBlAGYAZQByAHMAIAB0AG8AIAB0AGgAZQAgAHMAZQB0ACAAbwBmACAAZgBpAGwAZQBzACAAcgBlAGwAZQBhAHMAZQBkACAAYgB5ACAAdABoAGUAIABDAG8AcAB5AHIAaQBnAGgAdAAgAEgAbwBsAGQAZQByACgAcwApACAAdQBuAGQAZQByACAAdABoAGkAcwAgAGwAaQBjAGUAbgBzAGUAIABhAG4AZAAgAGMAbABlAGEAcgBsAHkAIABtAGEAcgBrAGUAZAAgAGEAcwAgAHMAdQBjAGgALgAgAFQAaABpAHMAIABtAGEAeQAgAGkAbgBjAGwAdQBkAGUAIABzAG8AdQByAGMAZQAgAGYAaQBsAGUAcwAsACAAYgB1AGkAbABkACAAcwBjAHIAaQBwAHQAcwAgAGEAbgBkACAAZABvAGMAdQBtAGUAbgB0AGEAdABpAG8AbgAuAA0ACgANAAoAIgBSAGUAcwBlAHIAdgBlAGQAIABGAG8AbgB0ACAATgBhAG0AZQAiACAAcgBlAGYAZQByAHMAIAB0AG8AIABhAG4AeQAgAG4AYQBtAGUAcwAgAHMAcABlAGMAaQBmAGkAZQBkACAAYQBzACAAcwB1AGMAaAAgAGEAZgB0AGUAcgAgAHQAaABlACAAYwBvAHAAeQByAGkAZwBoAHQAIABzAHQAYQB0AGUAbQBlAG4AdAAoAHMAKQAuAA0ACgANAAoAIgBPAHIAaQBnAGkAbgBhAGwAIABWAGUAcgBzAGkAbwBuACIAIAByAGUAZgBlAHIAcwAgAHQAbwAgAHQAaABlACAAYwBvAGwAbABlAGMAdABpAG8AbgAgAG8AZgAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUAIABjAG8AbQBwAG8AbgBlAG4AdABzACAAYQBzACAAZABpAHMAdAByAGkAYgB1AHQAZQBkACAAYgB5ACAAdABoAGUAIABDAG8AcAB5AHIAaQBnAGgAdAAgAEgAbwBsAGQAZQByACgAcwApAC4ADQAKAA0ACgAiAE0AbwBkAGkAZgBpAGUAZAAgAFYAZQByAHMAaQBvAG4AIgAgAHIAZQBmAGUAcgBzACAAdABvACAAYQBuAHkAIABkAGUAcgBpAHYAYQB0AGkAdgBlACAAbQBhAGQAZQAgAGIAeQAgAGEAZABkAGkAbgBnACAAdABvACwAIABkAGUAbABlAHQAaQBuAGcALAAgAG8AcgAgAHMAdQBiAHMAdABpAHQAdQB0AGkAbgBnACAALQAtACAAaQBuACAAcABhAHIAdAAgAG8AcgAgAGkAbgAgAHcAaABvAGwAZQAgAC0ALQAgAGEAbgB5ACAAbwBmACAAdABoAGUAIABjAG8AbQBwAG8AbgBlAG4AdABzACAAbwBmACAAdABoAGUAIABPAHIAaQBnAGkAbgBhAGwAIABWAGUAcgBzAGkAbwBuACwAIABiAHkAIABjAGgAYQBuAGcAaQBuAGcAIABmAG8AcgBtAGEAdABzACAAbwByACAAYgB5ACAAcABvAHIAdABpAG4AZwAgAHQAaABlACAARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAgAHQAbwAgAGEAIABuAGUAdwAgAGUAbgB2AGkAcgBvAG4AbQBlAG4AdAAuAA0ACgANAAoAIgBBAHUAdABoAG8AcgAiACAAcgBlAGYAZQByAHMAIAB0AG8AIABhAG4AeQAgAGQAZQBzAGkAZwBuAGUAcgAsACAAZQBuAGcAaQBuAGUAZQByACwAIABwAHIAbwBnAHIAYQBtAG0AZQByACwAIAB0AGUAYwBoAG4AaQBjAGEAbAAgAHcAcgBpAHQAZQByACAAbwByACAAbwB0AGgAZQByACAAcABlAHIAcwBvAG4AIAB3AGgAbwAgAGMAbwBuAHQAcgBpAGIAdQB0AGUAZAAgAHQAbwAgAHQAaABlACAARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAuAA0ACgANAAoAUABFAFIATQBJAFMAUwBJAE8ATgAgACYAIABDAE8ATgBEAEkAVABJAE8ATgBTAA0ACgBQAGUAcgBtAGkAcwBzAGkAbwBuACAAaQBzACAAaABlAHIAZQBiAHkAIABnAHIAYQBuAHQAZQBkACwAIABmAHIAZQBlACAAbwBmACAAYwBoAGEAcgBnAGUALAAgAHQAbwAgAGEAbgB5ACAAcABlAHIAcwBvAG4AIABvAGIAdABhAGkAbgBpAG4AZwAgAGEAIABjAG8AcAB5ACAAbwBmACAAdABoAGUAIABGAG8AbgB0ACAAUwBvAGYAdAB3AGEAcgBlACwAIAB0AG8AIAB1AHMAZQAsACAAcwB0AHUAZAB5ACwAIABjAG8AcAB5ACwAIABtAGUAcgBnAGUALAAgAGUAbQBiAGUAZAAsACAAbQBvAGQAaQBmAHkALAAgAHIAZQBkAGkAcwB0AHIAaQBiAHUAdABlACwAIABhAG4AZAAgAHMAZQBsAGwAIABtAG8AZABpAGYAaQBlAGQAIABhAG4AZAAgAHUAbgBtAG8AZABpAGYAaQBlAGQAIABjAG8AcABpAGUAcwAgAG8AZgAgAHQAaABlACAARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAsACAAcwB1AGIAagBlAGMAdAAgAHQAbwAgAHQAaABlACAAZgBvAGwAbABvAHcAaQBuAGcAIABjAG8AbgBkAGkAdABpAG8AbgBzADoADQAKAA0ACgAxACkAIABOAGUAaQB0AGgAZQByACAAdABoAGUAIABGAG8AbgB0ACAAUwBvAGYAdAB3AGEAcgBlACAAbgBvAHIAIABhAG4AeQAgAG8AZgAgAGkAdABzACAAaQBuAGQAaQB2AGkAZAB1AGEAbAAgAGMAbwBtAHAAbwBuAGUAbgB0AHMALAAgAGkAbgAgAE8AcgBpAGcAaQBuAGEAbAAgAG8AcgAgAE0AbwBkAGkAZgBpAGUAZAAgAFYAZQByAHMAaQBvAG4AcwAsACAAbQBhAHkAIABiAGUAIABzAG8AbABkACAAYgB5ACAAaQB0AHMAZQBsAGYALgANAAoADQAKADIAKQAgAE8AcgBpAGcAaQBuAGEAbAAgAG8AcgAgAE0AbwBkAGkAZgBpAGUAZAAgAFYAZQByAHMAaQBvAG4AcwAgAG8AZgAgAHQAaABlACAARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAgAG0AYQB5ACAAYgBlACAAYgB1AG4AZABsAGUAZAAsACAAcgBlAGQAaQBzAHQAcgBpAGIAdQB0AGUAZAAgAGEAbgBkAC8AbwByACAAcwBvAGwAZAAgAHcAaQB0AGgAIABhAG4AeQAgAHMAbwBmAHQAdwBhAHIAZQAsACAAcAByAG8AdgBpAGQAZQBkACAAdABoAGEAdAAgAGUAYQBjAGgAIABjAG8AcAB5ACAAYwBvAG4AdABhAGkAbgBzACAAdABoAGUAIABhAGIAbwB2AGUAIABjAG8AcAB5AHIAaQBnAGgAdAAgAG4AbwB0AGkAYwBlACAAYQBuAGQAIAB0AGgAaQBzACAAbABpAGMAZQBuAHMAZQAuACAAVABoAGUAcwBlACAAYwBhAG4AIABiAGUAIABpAG4AYwBsAHUAZABlAGQAIABlAGkAdABoAGUAcgAgAGEAcwAgAHMAdABhAG4AZAAtAGEAbABvAG4AZQAgAHQAZQB4AHQAIABmAGkAbABlAHMALAAgAGgAdQBtAGEAbgAtAHIAZQBhAGQAYQBiAGwAZQAgAGgAZQBhAGQAZQByAHMAIABvAHIAIABpAG4AIAB0AGgAZQAgAGEAcABwAHIAbwBwAHIAaQBhAHQAZQAgAG0AYQBjAGgAaQBuAGUALQByAGUAYQBkAGEAYgBsAGUAIABtAGUAdABhAGQAYQB0AGEAIABmAGkAZQBsAGQAcwAgAHcAaQB0AGgAaQBuACAAdABlAHgAdAAgAG8AcgAgAGIAaQBuAGEAcgB5ACAAZgBpAGwAZQBzACAAYQBzACAAbABvAG4AZwAgAGEAcwAgAHQAaABvAHMAZQAgAGYAaQBlAGwAZABzACAAYwBhAG4AIABiAGUAIABlAGEAcwBpAGwAeQAgAHYAaQBlAHcAZQBkACAAYgB5ACAAdABoAGUAIAB1AHMAZQByAC4ADQAKAA0ACgAzACkAIABOAG8AIABNAG8AZABpAGYAaQBlAGQAIABWAGUAcgBzAGkAbwBuACAAbwBmACAAdABoAGUAIABGAG8AbgB0ACAAUwBvAGYAdAB3AGEAcgBlACAAbQBhAHkAIAB1AHMAZQAgAHQAaABlACAAUgBlAHMAZQByAHYAZQBkACAARgBvAG4AdAAgAE4AYQBtAGUAKABzACkAIAB1AG4AbABlAHMAcwAgAGUAeABwAGwAaQBjAGkAdAAgAHcAcgBpAHQAdABlAG4AIABwAGUAcgBtAGkAcwBzAGkAbwBuACAAaQBzACAAZwByAGEAbgB0AGUAZAAgAGIAeQAgAHQAaABlACAAYwBvAHIAcgBlAHMAcABvAG4AZABpAG4AZwAgAEMAbwBwAHkAcgBpAGcAaAB0ACAASABvAGwAZABlAHIALgAgAFQAaABpAHMAIAByAGUAcwB0AHIAaQBjAHQAaQBvAG4AIABvAG4AbAB5ACAAYQBwAHAAbABpAGUAcwAgAHQAbwAgAHQAaABlACAAcAByAGkAbQBhAHIAeQAgAGYAbwBuAHQAIABuAGEAbQBlACAAYQBzACAAcAByAGUAcwBlAG4AdABlAGQAIAB0AG8AIAB0AGgAZQAgAHUAcwBlAHIAcwAuAA0ACgANAAoANAApACAAVABoAGUAIABuAGEAbQBlACgAcwApACAAbwBmACAAdABoAGUAIABDAG8AcAB5AHIAaQBnAGgAdAAgAEgAbwBsAGQAZQByACgAcwApACAAbwByACAAdABoAGUAIABBAHUAdABoAG8AcgAoAHMAKQAgAG8AZgAgAHQAaABlACAARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAgAHMAaABhAGwAbAAgAG4AbwB0ACAAYgBlACAAdQBzAGUAZAAgAHQAbwAgAHAAcgBvAG0AbwB0AGUALAAgAGUAbgBkAG8AcgBzAGUAIABvAHIAIABhAGQAdgBlAHIAdABpAHMAZQAgAGEAbgB5ACAATQBvAGQAaQBmAGkAZQBkACAAVgBlAHIAcwBpAG8AbgAsACAAZQB4AGMAZQBwAHQAIAB0AG8AIABhAGMAawBuAG8AdwBsAGUAZABnAGUAIAB0AGgAZQAgAGMAbwBuAHQAcgBpAGIAdQB0AGkAbwBuACgAcwApACAAbwBmACAAdABoAGUAIABDAG8AcAB5AHIAaQBnAGgAdAAgAEgAbwBsAGQAZQByACgAcwApACAAYQBuAGQAIAB0AGgAZQAgAEEAdQB0AGgAbwByACgAcwApACAAbwByACAAdwBpAHQAaAAgAHQAaABlAGkAcgAgAGUAeABwAGwAaQBjAGkAdAAgAHcAcgBpAHQAdABlAG4AIABwAGUAcgBtAGkAcwBzAGkAbwBuAC4ADQAKAA0ACgA1ACkAIABUAGgAZQAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUALAAgAG0AbwBkAGkAZgBpAGUAZAAgAG8AcgAgAHUAbgBtAG8AZABpAGYAaQBlAGQALAAgAGkAbgAgAHAAYQByAHQAIABvAHIAIABpAG4AIAB3AGgAbwBsAGUALAAgAG0AdQBzAHQAIABiAGUAIABkAGkAcwB0AHIAaQBiAHUAdABlAGQAIABlAG4AdABpAHIAZQBsAHkAIAB1AG4AZABlAHIAIAB0AGgAaQBzACAAbABpAGMAZQBuAHMAZQAsACAAYQBuAGQAIABtAHUAcwB0ACAAbgBvAHQAIABiAGUAIABkAGkAcwB0AHIAaQBiAHUAdABlAGQAIAB1AG4AZABlAHIAIABhAG4AeQAgAG8AdABoAGUAcgAgAGwAaQBjAGUAbgBzAGUALgAgAFQAaABlACAAcgBlAHEAdQBpAHIAZQBtAGUAbgB0ACAAZgBvAHIAIABmAG8AbgB0AHMAIAB0AG8AIAByAGUAbQBhAGkAbgAgAHUAbgBkAGUAcgAgAHQAaABpAHMAIABsAGkAYwBlAG4AcwBlACAAZABvAGUAcwAgAG4AbwB0ACAAYQBwAHAAbAB5ACAAdABvACAAYQBuAHkAIABkAG8AYwB1AG0AZQBuAHQAIABjAHIAZQBhAHQAZQBkACAAdQBzAGkAbgBnACAAdABoAGUAIABGAG8AbgB0ACAAUwBvAGYAdAB3AGEAcgBlAC4ADQAKAA0ACgBUAEUAUgBNAEkATgBBAFQASQBPAE4ADQAKAFQAaABpAHMAIABsAGkAYwBlAG4AcwBlACAAYgBlAGMAbwBtAGUAcwAgAG4AdQBsAGwAIABhAG4AZAAgAHYAbwBpAGQAIABpAGYAIABhAG4AeQAgAG8AZgAgAHQAaABlACAAYQBiAG8AdgBlACAAYwBvAG4AZABpAHQAaQBvAG4AcwAgAGEAcgBlACAAbgBvAHQAIABtAGUAdAAuAA0ACgANAAoARABJAFMAQwBMAEEASQBNAEUAUgANAAoAVABIAEUAIABGAE8ATgBUACAAUwBPAEYAVABXAEEAUgBFACAASQBTACAAUABSAE8AVgBJAEQARQBEACAAIgBBAFMAIABJAFMAIgAsACAAVwBJAFQASABPAFUAVAAgAFcAQQBSAFIAQQBOAFQAWQAgAE8ARgAgAEEATgBZACAASwBJAE4ARAAsACAARQBYAFAAUgBFAFMAUwAgAE8AUgAgAEkATQBQAEwASQBFAEQALAAgAEkATgBDAEwAVQBEAEkATgBHACAAQgBVAFQAIABOAE8AVAAgAEwASQBNAEkAVABFAEQAIABUAE8AIABBAE4AWQAgAFcAQQBSAFIAQQBOAFQASQBFAFMAIABPAEYAIABNAEUAUgBDAEgAQQBOAFQAQQBCAEkATABJAFQAWQAsACAARgBJAFQATgBFAFMAUwAgAEYATwBSACAAQQAgAFAAQQBSAFQASQBDAFUATABBAFIAIABQAFUAUgBQAE8AUwBFACAAQQBOAEQAIABOAE8ATgBJAE4ARgBSAEkATgBHAEUATQBFAE4AVAAgAE8ARgAgAEMATwBQAFkAUgBJAEcASABUACwAIABQAEEAVABFAE4AVAAsACAAVABSAEEARABFAE0AQQBSAEsALAAgAE8AUgAgAE8AVABIAEUAUgAgAFIASQBHAEgAVAAuACAASQBOACAATgBPACAARQBWAEUATgBUACAAUwBIAEEATABMACAAVABIAEUAIABDAE8AUABZAFIASQBHAEgAVAAgAEgATwBMAEQARQBSACAAQgBFACAATABJAEEAQgBMAEUAIABGAE8AUgAgAEEATgBZACAAQwBMAEEASQBNACwAIABEAEEATQBBAEcARQBTACAATwBSACAATwBUAEgARQBSACAATABJAEEAQgBJAEwASQBUAFkALAAgAEkATgBDAEwAVQBEAEkATgBHACAAQQBOAFkAIABHAEUATgBFAFIAQQBMACwAIABTAFAARQBDAEkAQQBMACwAIABJAE4ARABJAFIARQBDAFQALAAgAEkATgBDAEkARABFAE4AVABBAEwALAAgAE8AUgAgAEMATwBOAFMARQBRAFUARQBOAFQASQBBAEwAIABEAEEATQBBAEcARQBTACwAIABXAEgARQBUAEgARQBSACAASQBOACAAQQBOACAAQQBDAFQASQBPAE4AIABPAEYAIABDAE8ATgBUAFIAQQBDAFQALAAgAFQATwBSAFQAIABPAFIAIABPAFQASABFAFIAVwBJAFMARQAsACAAQQBSAEkAUwBJAE4ARwAgAEYAUgBPAE0ALAAgAE8AVQBUACAATwBGACAAVABIAEUAIABVAFMARQAgAE8AUgAgAEkATgBBAEIASQBMAEkAVABZACAAVABPACAAVQBTAEUAIABUAEgARQAgAEYATwBOAFQAIABTAE8ARgBUAFcAQQBSAEUAIABPAFIAIABGAFIATwBNACAATwBUAEgARQBSACAARABFAEEATABJAE4ARwBTACAASQBOACAAVABIAEUAIABGAE8ATgBUACAAUwBPAEYAVABXAEEAUgBFAC4ADQAKAGgAdAB0AHAAOgAvAC8AdwB3AHcALgBhAGQAbwBiAGUALgBjAG8AbQAvAHQAeQBwAGUALwBsAGUAZwBhAGwALgBoAHQAbQBsAAAAAAAFAAAAAwAAADgAAAAEAAABUAABAAAAAAAsAAMAAQAAADgAAwAKAAABUAAGAAwAAAAAAAEAAAAEARgAAABCAEAABQACB/8P/xf/H/8n/y//N/8//0f/T/9X/1//Z/9v/3f/f/+H/4//l/+f/6f/r/+3/7//x//P/9f/5//v//f//c///f//AAAAAAgAEAAYACAAKAAwADgAQABIAFAAWABgAGgAcAB4AIAAiACQAJgAoACoALAAuADAAMgA0ADgAOgA8AD4AP3w//8AAfgB8AHoAeAB2AHQAcgBwAG4AbABqAGgAZgBkAGIAYABeAFwAWgBYAFYAVABSAFAATgBMAEgARgBEAEIAQgBAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAZkAAAAAAAAAIgAAAAAAAAB/8AAAABAAAIAAAAD/8AAAABAAAQAAAAF/8AAAABAAAYAAAAH/8AAAABAAAgAAAAJ/8AAAABAAAoAAAAL/8AAAABAAAwAAAAN/8AAAABAAA4AAAAP/8AAAABAABAAAAAR/8AAAABAABIAAAAT/8AAAABAABQAAAAV/8AAAABAABYAAAAX/8AAAABAABgAAAAZ/8AAAABAABoAAAAb/8AAAABAABwAAAAd/8AAAABAAB4AAAAf/8AAAABAACAAAAAh/8AAAABAACIAAAAj/8AAAABAACQAAAAl/8AAAABAACYAAAAn/8AAAABAACgAAAAp/8AAAABAACoAAAAr/8AAAABAACwAAAAt/8AAAABAAC4AAAAv/8AAAABAADAAAAAx/8AAAABAADIAAAAz/8AAAABAADQAAAA1/8AAAABAADgAAAA5/8AAAABAADoAAAA7/8AAAABAADwAAAA9/8AAAABAAD4AAAA/c8AAAABAAD98AAA//0AAAXxAAEAAAABB/8AAAABAAEIAAABD/8AAAABAAEQAAABF/8AAAABAAEYAAABH/8AAAABAAEgAAABJ/8AAAABAAEoAAABL/8AAAABAAEwAAABN/8AAAABAAE4AAABP/8AAAABAAFAAAABR/8AAAABAAFIAAABT/8AAAABAAFQAAABV/8AAAABAAFYAAABX/8AAAABAAFgAAABZ/8AAAABAAFoAAABb/8AAAABAAFwAAABd/8AAAABAAF4AAABf/8AAAABAAGAAAABh/8AAAABAAGIAAABj/8AAAABAAGQAAABl/8AAAABAAGYAAABn/8AAAABAAGgAAABp/8AAAABAAGoAAABr/8AAAABAAGwAAABt/8AAAABAAG4AAABv/8AAAABAAHAAAABx/8AAAABAAHIAAABz/8AAAABAAHQAAAB1/8AAAABAAHYAAAB3/8AAAABAAHgAAAB5/8AAAABAAHoAAAB7/8AAAABAAHwAAAB9/8AAAABAAH4AAAB//0AAAABAAIAAAACB/8AAAABAAIIAAACD/8AAAABAAIQAAACF/8AAAABAAIYAAACH/8AAAABAAIgAAACJ/8AAAABAAIoAAACL/8AAAABAAIwAAACN/8AAAABAAI4AAACP/8AAAABAAJAAAACR/8AAAABAAJIAAACT/8AAAABAAJQAAACV/8AAAABAAJYAAACX/8AAAABAAJgAAACZ/8AAAABAAJoAAACb/8AAAABAAJwAAACd/8AAAABAAJ4AAACf/8AAAABAAKAAAACh/8AAAABAAKIAAACj/8AAAABAAKQAAACl/8AAAABAAKYAAACn/8AAAABAAKgAAACp/8AAAABAAKoAAACr/8AAAABAAKwAAACt/8AAAABAAK4AAACv/8AAAABAALAAAACx/8AAAABAALIAAACz/8AAAABAALQAAAC1/8AAAABAALYAAAC3/8AAAABAALgAAAC5/8AAAABAALoAAAC7/8AAAABAALwAAAC9/8AAAABAAL4AAAC//0AAAABAAMAAAADB/8AAAABAAMIAAADD/8AAAABAAMQAAADF/8AAAABAAMYAAADH/8AAAABAAMgAAADJ/8AAAABAAMoAAADL/8AAAABAAMwAAADN/8AAAABAAM4AAADP/8AAAABAANAAAADR/8AAAABAANIAAADT/8AAAABAANQAAADV/8AAAABAANYAAADX/8AAAABAANgAAADZ/8AAAABAANoAAADb/8AAAABAANwAAADd/8AAAABAAN4AAADf/8AAAABAAOAAAADh/8AAAABAAOIAAADj/8AAAABAAOQAAADl/8AAAABAAOYAAADn/8AAAABAAOgAAADp/8AAAABAAOoAAADr/8AAAABAAOwAAADt/8AAAABAAO4AAADv/8AAAABAAPAAAADx/8AAAABAAPIAAADz/8AAAABAAPQAAAD1/8AAAABAAPYAAAD3/8AAAABAAPgAAAD5/8AAAABAAPoAAAD7/8AAAABAAPwAAAD9/8AAAABAAP4AAAD//0AAAABAAQAAAAEB/8AAAABAAQIAAAED/8AAAABAAQQAAAEF/8AAAABAAQYAAAEH/8AAAABAAQgAAAEJ/8AAAABAAQoAAAEL/8AAAABAAQwAAAEN/8AAAABAAQ4AAAEP/8AAAABAARAAAAER/8AAAABAARIAAAET/8AAAABAARQAAAEV/8AAAABAARYAAAEX/8AAAABAARgAAAEZ/8AAAABAARoAAAEb/8AAAABAARwAAAEd/8AAAABAAR4AAAEf/8AAAABAASAAAAEh/8AAAABAASIAAAEj/8AAAABAASQAAAEl/8AAAABAASYAAAEn/8AAAABAASgAAAEp/8AAAABAASoAAAEr/8AAAABAASwAAAEt/8AAAAB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AAloAAAJb/8AAAABAAlwAAAJd/8AAAABAAl4AAAJf/8AAAABAAmAAAAJh/8AAAABAAmIAAAJj/8AAAABAAmQAAAJl/8AAAABAAmYAAAJn/8AAAABAAmgAAAJp/8AAAABAAmoAAAJr/8AAAABAAmwAAAJt/8AAAABAAm4AAAJv/8AAAABAAnAAAAJx/8AAAABAAnIAAAJz/8AAAABAAnQAAAJ1/8AAAABAAnYAAAJ3/8AAAABAAngAAAJ5/8AAAABAAnoAAAJ7/8AAAABAAnwAAAJ9/8AAAABAAn4AAAJ//0AAAABAAoAAAAKB/8AAAABAAoIAAAKD/8AAAABAAoQAAAKF/8AAAABAAoYAAAKH/8AAAABAAogAAAKJ/8AAAABAAooAAAKL/8AAAABAAowAAAKN/8AAAABAAo4AAAKP/8AAAABAApAAAAKR/8AAAABAApIAAAKT/8AAAABAApQAAAKV/8AAAABAApYAAAKX/8AAAABAApgAAAKZ/8AAAABAApoAAAKb/8AAAABAApwAAAKd/8AAAABAAp4AAAKf/8AAAABAAqAAAAKh/8AAAABAAqIAAAKj/8AAAABAAqQAAAKl/8AAAABAAqYAAAKn/8AAAABAAqgAAAKp/8AAAABAAqoAAAKr/8AAAABAAqwAAAKt/8AAAABAAq4AAAKv/8AAAABAArAAAAKx/8AAAABAArIAAAKz/8AAAABAArQAAAK1/8AAAABAArYAAAK3/8AAAABAArgAAAK5/8AAAABAAroAAAK7/8AAAABAArwAAAK9/8AAAABAAr4AAAK//0AAAABAAsAAAALB/8AAAABAAsIAAALD/8AAAABAAsQAAALF/8AAAABAAsYAAALH/8AAAABAAsgAAALJ/8AAAABAAsoAAALL/8AAAABAAswAAALN/8AAAABAAs4AAALP/8AAAABAAtAAAALR/8AAAABAAtIAAALT/8AAAABAAtQAAALV/8AAAABAAtYAAALX/8AAAABAAtgAAALZ/8AAAABAAtoAAALb/8AAAABAAtwAAALd/8AAAABAAt4AAALf/8AAAABAAuAAAALh/8AAAABAAuIAAALj/8AAAABAAuQAAALl/8AAAABAAuYAAALn/8AAAABAAugAAALp/8AAAABAAuoAAALr/8AAAABAAuwAAALt/8AAAABAAu4AAALv/8AAAAB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ASwBLQEuAS8BMAExATIBMwE0ATUBNgE3ATgBOQE6ATsBPAE9AT4BPwFAAUEBQgFDAUQBRQFGAUcBSAFJAUoBSwFMAU0BTgFPAVABUQFSAVMBVAFVAVYBVwFYAVkBWgFbAVwBXQFeAV8BYAFhAWIBYwFkAWUBZgFnAWgBaQFqAWsBbAFtAW4BbwFwAXEBcgFzAXQBdQF2AXcBeAF5AXoBewF8AX0BfgF/AYABgQGCAYMBhAGFAYYBhwGIAYkBigGLAYwBjQGOAY8BkAGRAZIBkwGUAZUBlgGXAZgBmQGaAZsBnAGdAZ4BnwGgAaEBogGjAaQBpQGmAacBqAGpAaoBqwGsAa0BrgGvAbABsQGyAbMBtAG1AbYBtwG4AbkBugG7AbwBvQG+Ab8BwAHBAcIBwwHEAcUBxgHHAcgByQHKAcsBzAHNAc4BzwHQAdEB0gHTAdQB1QHWAdcB2AHZAdoB2wHcAd0B3gHfAeAB4QHiAeMB5AHlAeYB5wHoAekB6gHrAewB7QHuAe8B8AHxAfIB8wH0AfUB9gH3AfgB+QH6AfsB/AH9Af4B/wIAAgECAgIDAgQCBQIGAgcCCAIJAgoCCwIMAg0CDgIPAhACEQISAhMCFAIVAhYCFwIYAhkCGgIbAhwCHQIeAh8CIAIhAiICIwIkAiUCJgInAigCKQIqAisCLAItAi4CLwIwAjECMgIzAjQCNQI2AjcCOAI5AjoCOwI8Aj0CPgI/AkACQQJCAkMCRAJFAkYCRwJIAkkCSgJLAkwCTQJOAk8CUAJRAlICUwJUAlUCVgJXAlgCWQJaAlsCXAJdAl4CXwJgAmECYgJjAmQCZQJmAmcCaAJpAmoCawJsAm0CbgJvAnACcQJyAnMCdAJ1AnYCdwJ4AnkCegJ7AnwCfQJ+An8CgAKBAoICgwKEAoUChgKHAogCiQKKAosCjAKNAo4CjwKQApECkgKTApQClQKWApcCmAKZApoCmwKcAp0CngKfAqACoQKiAqMCpAKlAqYCpwKoAqkCqgKrAqwCrQKuAq8CsAKxArICswK0ArUCtgK3ArgCuQK6ArsCvAK9Ar4CvwLAAsECwgLDAsQCxQLGAscCyALJAsoCywLMAs0CzgLPAtAC0QLSAtMC1ALVAtYC1wLYAtkC2gLbAtwC3QLeAt8C4ALhAuIC4wLkAuUC5gLnAugC6QLqAusC7ALtAu4C7wLwAvEC8gLzAvQC9QL2AvcC+AL5AvoC+wL8Av0C/gL/AwADAQMCAwMDBAMFAwYDBwMIAwkDCgMLAwwDDQMOAw8DEAMRAxIDEwMUAxUDFgMXAxgDGQMaAxsDHAMdAx4DHwMgAyEDIgMjAyQDJQMmAycDKAMpAyoDKwMsAy0DLgMvAzADMQMyAzMDNAM1AzYDNwM4AzkDOgM7AzwDPQM+Az8DQANBA0IDQwNEA0UDRgNHA0gDSQNKA0sDTANNA04DTwNQA1EDUgNTA1QDVQNWA1cDWANZA1oDWwNcA10DXgNfA2ADYQNiA2MDZANlA2YDZwNoA2kDagNrA2wDbQNuA28DcANxA3IDcwN0A3UDdgN3A3gDeQN6A3sDfAN9A34DfwOAA4EDggODA4QDhQOGA4cDiAOJA4oDiwOMA40DjgOPA5ADkQOSA5MDlAOVA5YDlwOYA5kDmgObA5wDnQOeA58DoAOhA6IDowOkA6UDpgOnA6gDqQOqA6sDrAOtA64DrwOwA7EDsgOzA7QDtQO2A7cDuAO5A7oDuwO8A70DvgO/A8ADwQPCA8MDxAPFA8YDxwPIA8kDygPLA8wDzQPOA88D0APRA9ID0wPUA9UD1gPXA9gD2QPaA9sD3APdA94D3wPgA+ED4gPjA+QD5QPmA+cD6APpA+oD6wPsA+0D7gPvA/AD8QPyA/MD9AP1A/YD9wP4A/kD+gP7A/wD/QP+A/8EAAQBBAIEAwQEBAUEBgQHBAgECQQKBAsEDAQNBA4EDwQQBBEEEgQTBBQEFQQWBBcEGAQZBBoEGwQcBB0EHgQfBCAEIQQiBCMEJAQlBCYEJwQoBCkEKgQrBCwELQQuBC8EMAQxBDIEMwQ0BDUENgQ3BDgEOQQ6BDsEPAQ9BD4EPwRABEEEQgRDBEQERQRGBEcESARJBEoESwRMBE0ETgRPBFAEUQRSBFMEVARVBFYEVwRYBFkEWgRbBFwEXQReBF8EYARhBGIEYwRkBGUEZgRnBGgEaQRqBGsEbARtBG4EbwRwBHEEcgRzBHQEdQR2BHcEeAR5BHoEewR8BH0EfgR/BIAEgQSCBIMEhASFBIYEhwSIBIkEigSLBIwEjQSOBI8EkASRBJIEkwSUBJUElgSXBJgEmQSaBJsEnASdBJ4EnwSgBKEEogSjBKQEpQSmBKcEqASpBKoEqwSsBK0ErgSvBLAEsQSyBLMEtAS1BLYEtwS4BLkEugS7BLwEvQS+BL8EwATBBMIEwwTEBMUExgTHBMgEyQTKBMsEzATNBM4EzwTQBNEE0gTTBNQE1QTWBNcE2ATZBNoE2wTcBN0E3gTfBOAE4QTiBOME5ATlBOYE5wToBOkE6gTrBOwE7QTuBO8E8ATxBPIE8wT0BPUE9gT3BPgE+QT6BPsE/AT9BP4E/wUABQEFAgUDBQQFBQUGBQcFCAUJBQoFCwUMBQ0FDgUPBRAFEQUSBRMFFAUVBRYFFwUYBRkFGgUbBRwFHQUeBR8FIAUhBSIFIwUkBSUFJgUnBSgFKQUqBSsFLAUtBS4FLwUwBTEFMgUzBTQFNQU2BTcFOAU5BToFOwU8BT0FPgU/BUAFQQVCBUMFRAVFBUYFRwVIBUkFSgVLBUwFTQVOBU8FUAVRBVIFUwVUBVUFVgVXBVgFWQVaBVsFXAVdBV4FXwVgBWEFYgVjBWQFZQVmBWcFaAVpBWoFawVsBW0FbgVvBXAFcQVyBXMFdAV1BXYFdwV4BXkFegV7BXwFfQV+BX8FgAWBBYIFgwWEBYUFhgWHBYgFiQWKBYsFjAWNBY4FjwWQBZEFkgWTBZQFlQWWBZcFmAWZBZoFmwWcBZ0FngWfBaAFoQWiBaMFpAWlBaYFpwWoBakFqgWrBawFrQWuBa8FsAWxBbIFswW0BbUFtgW3BbgFuQW6BbsFvAW9Bb4FvwXABcEFwgXDBcQFxQXGBccFyAXJBcoFywXMBc0FzgXPBdAF0QXSBdMF1AXVBdYF1wXYBdkF2gXbBdwF3QXeBd8F4AXhBeIF4wXkBeUF5gXnBegF6QXqBesF7AXtBe4F7wXwBfEF8gXzBfQF9QX2BfcF+AX5BfoF+wX8Bf0F/gX/BgAGAQYCBgMGBAYFBgYGBwYIBgkGCgYLBgwGDQYOBg8GEAYRBhIGEwYUBhUGFgYXBhgGGQYaBhsGHAYdBh4GHwYgBiEGIgYjBiQGJQYmBicGKAYpBioGKwYsBi0GLgYvBjAGMQYyBjMGNAY1BjYGNwY4BjkGOgY7BjwGPQY+Bj8GQAZBBkIGQwZEBkUGRgZHBkgGSQZKBksGTAZNBk4GTwZQBlEGUgZTBlQGVQZWBlcGWAZZBloGWwZcBl0GXgZfBmAGYQZiBmMGZAZlBmYGZwZoBmkGagZrBmwGbQZuBm8GcAZxBnIGcwZ0BnUGdgZ3BngGeQZ6BnsGfAZ9Bn4GfwaABoEGggaDBoQGhQaGBocGiAaJBooGiwaMBo0GjgaPBpAGkQaSBpMGlAaVBpYGlwaYBpkGmgabBpwGnQaeBp8GoAahBqIGowakBqUGpganBqgGqQaqBqsGrAatBq4GrwawBrEGsgazBrQGtQa2BrcGuAa5BroGuwa8Br0Gvga/BsAGwQbCBsMGxAbFBsYGxwbIBskGygbLBswGzQbOBs8G0AbRBtIG0wbUBtUG1gbXBtgG2QbaBtsG3AbdBt4G3wbgBuEG4gbjBuQG5QbmBucG6AbpBuoG6wbsBu0G7gbvBvAG8QbyBvMG9Ab1BvYG9wb4BvkG+gb7BvwG/Qb+Bv8HAAcBBwIHAwcEBwUHBgcHBwgHCQcKBwsHDAcNBw4HDwcQBxEHEgcTBxQHFQcWBxcHGAcZBxoHGwccBx0HHgcfByAHIQciByMHJAclByYHJwcoBykHKgcrBywHLQcuBy8HMAcxBzIHMwc0BzUHNgc3BzgHOQc6BzsHPAc9Bz4HPwdAB0EHQgdDB0QHRQdGB0cHSAdJB0oHSwdMB00HTgdPB1AHUQdSB1MHVAdVB1YHVwdYB1kHWgdbB1wHXQdeB18HYAdhB2IHYwdkB2UHZgdnB2gHaQdqB2sHbAdtB24HbwdwB3EHcgdzB3QHdQd2B3cHeAd5B3oHewd8B30Hfgd/B4AHgQeCB4MHhAeFB4YHhweIB4kHigeLB4wHjQeOB48HkAeRB5IHkweUB5UHlgeXB5gHmQeaB5sHnAedB54HnwegB6EHogejB6QHpQemB6cHqAepB6oHqwesB60HrgevB7AHsQeyB7MHtAe1B7YHtwe4B7kHuge7B7wHvQe+B78HwAfBB8IHwwfEB8UHxgfHB8gHyQfKB8sHzAfNB84HzwfQB9EH0gfTB9QH1QfWB9cH2AfZB9oH2wfcB90H3gffB+AH4QfiB+MH5AflB+YH5wfoB+kH6gfrB+wH7QfuB+8H8AfxB/IH8wf0B/UH9gf3B/gH+Qf6B/sH/Af9B/4H/wgACAEIAggDCAQIBQgGCAcICAgJCAoICwgMCA0IDggPCBAIEQgSCBMIFAgVCBYIFwgYCBkIGggbCBwIHQgeCB8IIAghCCIIIwgkCCUIJggnCCgIKQgqCCsILAgtCC4ILwgwCDEIMggzCDQINQg2CDcIOAg5CDoIOwg8CD0IPgg/CEAIQQhCCEMIRAhFCEYIRwhICEkISghLIPsMt/oktwH3ELf5LLcD9xD6BBX+fPmE+nwH/Vj+JxX50gf3xfwzBaawFfvF+DcF+PYGpmIV/dIH+8X4MwVwZhX3xfw3Bfz2Bg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODgABAQEK+B8MJpocGSQS+46LHAVGiwa9Cr0L+ucVAAPoAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAA') format('truetype'); }";
FontLoader.prototype = {
constructor: FontLoader,
loadFonts: function() {
var self = this;
if (this._numberOfFontFamilies === 0) {
this._finish();
return;
}
if (this.timeout !== null) {
this._timeoutId = window.setTimeout(function timeoutFire() {
self._finish();
}, this.timeout);
}
// Use constant line-height so there won't be changes in height because Adobe Blank uses zero width but not zero height.
this._testContainer = document.createElement("div");
this._testContainer.style.cssText = "position:absolute; left:-10000px; top:-10000px; white-space:nowrap; font-size:20px; line-height:20px; visibility:hidden;";
if (FontLoader.testDiv === null) {
this._runOnce();
} else {
this._loadFonts();
}
},
_runOnce: function() {
var self = this,
clonedDiv, j,
adobeBlankFontFaceStyle, adobeBlankDiv,
adobeBlankFallbackFont = "serif";
// Create testFiv template that will be cloned for each font
FontLoader.testDiv = document.createElement("div");
FontLoader.testDiv.style.position = "absolute";
FontLoader.testDiv.appendChild(document.createTextNode(FontLoader.referenceText));
if (!FontLoader.useAdobeBlank) {
// Get default dimensions
clonedDiv = FontLoader.testDiv.cloneNode(true);
this._testContainer.appendChild(clonedDiv);
document.body.appendChild(this._testContainer);
for (j = 0; j < FontLoader.referenceFontFamilies.length; j++) {
clonedDiv.style.fontFamily = FontLoader.referenceFontFamilies[j];
FontLoader.referenceFontFamiliesSizes.push(new Size(clonedDiv.offsetWidth, clonedDiv.offsetHeight));
}
this._testContainer.parentNode.removeChild(this._testContainer);
clonedDiv.parentNode.removeChild(clonedDiv);
this._loadFonts();
} else {
// Add AdobeBlank @font-face
adobeBlankFontFaceStyle = document.createElement("style");
adobeBlankFontFaceStyle.setAttribute("type", "text/css");
adobeBlankFontFaceStyle.appendChild(document.createTextNode(FontLoader.adobeBlankFontFaceRule));
document.getElementsByTagName("head")[0].appendChild(adobeBlankFontFaceStyle);
// Get default dimensions
adobeBlankDiv = /** @type HTMLElement */FontLoader.testDiv.cloneNode(true);
this._testContainer.appendChild(adobeBlankDiv);
document.body.appendChild(this._testContainer);
adobeBlankDiv.style.fontFamily = adobeBlankFallbackFont;
if (FontLoader.useIntervalChecking) {
this._testContainer.appendChild(adobeBlankDiv);
// Start polling element sizes but also do first synchronous check in case all fonts where already loaded.
this._intervalId = window.setInterval(function intervalFire() {
self._checkAdobeBlankSize();
}, this._intervalDelay);
this._checkAdobeBlankSize();
} else {
this._adobeBlankSizeWatcher = new SizeWatcher(adobeBlankDiv, {
container: this._testContainer,
delegate: this,
continuous: true,
direction: SizeWatcher.directions.decrease,
dimension: SizeWatcher.dimensions.horizontal
});
this._adobeBlankSizeWatcher.prepareForWatch();
this._adobeBlankSizeWatcher.beginWatching();
}
adobeBlankDiv.style.fontFamily = FontLoader.referenceFontFamilies[0] + ", " + adobeBlankFallbackFont;
}
},
_checkAdobeBlankSize: function() {
var adobeBlankDiv = this._testContainer.firstChild;
this._adobeBlankLoaded(adobeBlankDiv);
},
_adobeBlankLoaded: function(adobeBlankDiv) {
// Prevent false size change, for example if AdobeBlank height is higher than fallback font.
if (adobeBlankDiv.offsetWidth !== 0) {
return;
}
FontLoader.referenceFontFamiliesSizes.push(new Size(adobeBlankDiv.offsetWidth, adobeBlankDiv.offsetHeight));
if (this._adobeBlankSizeWatcher !== null) {
// SizeWatcher method
this._adobeBlankSizeWatcher.endWatching();
this._adobeBlankSizeWatcher.removeScrollWatchers();
this._adobeBlankSizeWatcher = null;
} else {
// Polling method (IE)
window.clearInterval(this._intervalId);
adobeBlankDiv.parentNode.removeChild(adobeBlankDiv);
}
this._testContainer.parentNode.removeChild(this._testContainer);
this._loadFonts();
},
_loadFonts: function() {
var i, j, clonedDiv, sizeWatcher, sizeWatchers = [],
self = this;
// Add div for each font-family
for (i = 0; i < this._numberOfFontFamilies; i++) {
this._fontsMap[this._fontFamiliesArray[i]] = true;
if (FontLoader.useResizeEvent) {
for (j = 0; j < FontLoader.referenceFontFamilies.length; j++) {
clonedDiv = FontLoader.testDiv.cloneNode(true);
clonedDiv.setAttribute("data-font-family", this._fontFamiliesArray[i]);
clonedDiv.setAttribute("data-ref-font-family-index", String(j));
clonedDiv.style.fontFamily = FontLoader.referenceFontFamilies[j];
this._testContainer.appendChild(clonedDiv);
}
} else if (FontLoader.useIntervalChecking) {
for (j = 0; j < FontLoader.referenceFontFamilies.length; j++) {
clonedDiv = FontLoader.testDiv.cloneNode(true);
clonedDiv.setAttribute("data-font-family", this._fontFamiliesArray[i]);
clonedDiv.setAttribute("data-ref-font-family-index", String(j));
clonedDiv.style.fontFamily = "'" + this._fontFamiliesArray[i] + "', " + FontLoader.referenceFontFamilies[j];
this._testContainer.appendChild(clonedDiv);
}
} else {
for (j = 0; j < FontLoader.referenceFontFamilies.length; j++) {
clonedDiv = FontLoader.testDiv.cloneNode(true);
clonedDiv.setAttribute("data-font-family", this._fontFamiliesArray[i]);
clonedDiv.setAttribute("data-ref-font-family-index", String(j));
clonedDiv.style.fontFamily = FontLoader.referenceFontFamilies[j];
sizeWatcher = new SizeWatcher(/** @type HTMLElement */clonedDiv, {
container: this._testContainer,
delegate: this,
size: FontLoader.referenceFontFamiliesSizes[j],
direction: SizeWatcher.directions.increase,
dimension: SizeWatcher.dimensions.horizontal
});
// The prepareForWatch() and beginWatching() methods will be invoked in separate iterations to
// reduce number of browser's CSS recalculations.
sizeWatchers.push(sizeWatcher);
}
}
}
// Append the testContainer after all test elements to minimize DOM insertions
document.body.appendChild(this._testContainer);
if (FontLoader.useResizeEvent) {
for (j = 0; j < this._testContainer.childNodes.length; j++) {
clonedDiv = this._testContainer.childNodes[j];
// "resize" event works only with attachEvent
clonedDiv.attachEvent("onresize", (function(self, clonedDiv) {
return function() {
self._elementSizeChanged(clonedDiv);
}
})(this, clonedDiv));
}
window.setTimeout(function() {
for (j = 0; j < self._testContainer.childNodes.length; j++) {
clonedDiv = self._testContainer.childNodes[j];
clonedDiv.style.fontFamily = "'" + clonedDiv.getAttribute("data-font-family") + "', " + FontLoader.referenceFontFamilies[clonedDiv.getAttribute("data-ref-font-family-index")];
}
}, 0);
} else if (FontLoader.useIntervalChecking) {
// Start polling element sizes but also do first synchronous check in case all fonts where already loaded.
this._intervalId = window.setInterval(function intervalFire() {
self._checkSizes();
}, this._intervalDelay);
this._checkSizes();
} else {
// We are dividing the prepareForWatch() and beginWatching() methods to optimize browser performance by
// removing CSS recalculation from each iteration to the end of iterations.
for (i = 0; i < this._numberOfFontFamilies * FontLoader.referenceFontFamilies.length; i++) {
sizeWatcher = sizeWatchers[i];
sizeWatcher.prepareForWatch();
}
for (i = 0; i < this._numberOfFontFamilies * FontLoader.referenceFontFamilies.length; i++) {
sizeWatcher = sizeWatchers[i];
sizeWatcher.beginWatching();
// Apply tested font-family
clonedDiv = sizeWatcher.getWatchedElement();
clonedDiv.style.fontFamily = "'" + clonedDiv.getAttribute("data-font-family") + "', " + FontLoader.referenceFontFamilies[clonedDiv.getAttribute("data-ref-font-family-index")];
}
}
},
_checkSizes: function() {
var i, testDiv, currSize, refSize;
for (i = this._testContainer.childNodes.length - 1; i >= 0; i--) {
testDiv = this._testContainer.childNodes[i];
currSize = new Size(testDiv.offsetWidth, testDiv.offsetHeight);
refSize = FontLoader.referenceFontFamiliesSizes[testDiv.getAttribute("data-ref-font-family-index")];
if (!refSize.isEqual(currSize)) {
// Element dimensions changed, this means its font loaded, remove it from testContainer div
testDiv.parentNode.removeChild(testDiv);
this._elementSizeChanged(testDiv);
}
}
},
_elementSizeChanged: function(element) {
var fontFamily = element.getAttribute("data-font-family");
if (this._finished) {
return;
}
// Check that the font of this element wasn't already marked as loaded by an element with different reference font family.
if (typeof this._fontsMap[fontFamily] === "undefined") {
return;
}
this._numberOfLoadedFonts++;
delete this._fontsMap[fontFamily];
if (this.delegate && typeof this.delegate.fontLoaded === "function") {
this.delegate.fontLoaded(fontFamily);
}
if (this._numberOfLoadedFonts === this._numberOfFontFamilies) {
this._finish();
}
},
_finish: function() {
var callbackParameter,
fontFamily,
notLoadedFontFamilies = [];
if (this._finished) {
return;
}
this._finished = true;
if (this._adobeBlankSizeWatcher !== null) {
this._adobeBlankSizeWatcher = null;
}
if (this._testContainer !== null) {
this._testContainer.parentNode.removeChild(this._testContainer);
}
if (this._timeoutId !== null) {
window.clearTimeout(this._timeoutId);
}
if (this._intervalId !== null) {
window.clearInterval(this._intervalId);
}
if (this._numberOfLoadedFonts < this._numberOfFontFamilies) {
for (fontFamily in this._fontsMap) {
if (this._fontsMap.hasOwnProperty(fontFamily)) {
notLoadedFontFamilies.push(fontFamily);
}
}
callbackParameter = {
message: "Not all fonts were loaded",
notLoadedFontFamilies: notLoadedFontFamilies
};
} else {
callbackParameter = null;
}
if (this.delegate && typeof this.delegate.fontsLoaded === "function") {
this.delegate.fontsLoaded(callbackParameter);
}
},
/**
* SizeWatcher delegate method
* @param {SizeWatcher} sizeWatcher
*/
sizeWatcherChangedSize: function(sizeWatcher) {
var watchedElement = sizeWatcher.getWatchedElement();
if (sizeWatcher === this._adobeBlankSizeWatcher) {
this._adobeBlankLoaded(watchedElement);
} else {
this._elementSizeChanged(watchedElement);
}
}
};
/**
* Size object
*
* @param width
* @param height
* @constructor
*/
function Size(width, height) {
this.width = width;
this.height = height;
}
/**
* Compares receiver object to passed in size object.
*
* @param otherSize
* @returns {boolean}
*/
Size.prototype.isEqual = function(otherSize) {
return (this.width === otherSize.width && this.height === otherSize.height);
};
/**
* SizeWatcher observes size of an element and notifies when its size is changed. It doesn't use any timeouts
* to check the element size, when change in size occurs a callback method immediately invoked.
*
* To watch for element's size changes the element, and other required elements are appended to a container element
* you specify, and which must be added to the DOM tree before invoking prepareForWatch() method. Your container
* element should be positioned outside of client's visible area. Therefore you shouldn't use SizeWatcher to watch
* for size changes of elements used for UI.
* Such container element could be a simple <div> that is a child of the <body> element:
* <div style="position:absolute; left:-10000px; top:-10000px;"></div>
*
* You must invoke SizeWatcher's methods in a specific order to establish size change listeners:
*
* 1. Create SizeWatcher instance by invoke SizeWatcher constructor passing the element (size of which you want to
* observe), the container element, the delegate object and optional size parameter of type Size which should be
* the pre-calculated initial size of your element.
* 4. Invoke prepareForWatch() method. This method will calculate element size if you didn't passed it to the constructor.
* 5. Invoke beginWatching() method. This method will set event listeners and invoke your delegate's method once
* element size changes.
*
* Failing to invoke above methods in their predefined order will throw an exception.
*
* @param {HTMLElement} element An element, size of which will be observed for changes.
* @param {Object} options
* @param {HTMLElement} options.container An element to which special observing elements will be added. Must be in DOM tree
* when prepareForWatch() method is called.
* @param {Object} options.delegate A delegate object with a sizeWatcherChangedSize method which will be invoked, in
* context of the delegate object, when change in size occurs. This method is invoked with single
* parameter which is the current SizeWatcher instance.
* @param {Size} [options.size] The pre-calculated initial size of your element. When passed, the element is not
* asked for offsetWidth and offsetHeight, which may be useful to reduce browser's CSS
* recalculations. If you will not pass the size parameter then its size calculation will be
* deferred to prepareForWatch() method.
* @param {Boolean} [options.continuous=false] A boolean flag indicating if the SizeWatcher will watch only for
* the first size change (default) or will continuously watch for size changes.
* @param {Number} [options.direction=SizeWatcher.directions.both] The direction of size change that should be
* watched: SizeWatcher.directions.increase, SizeWatcher.directions.decrease or
* SizeWatcher.directions.both
* @param {Number} [options.dimension=SizeWatcher.dimensions.both] The dimension of size change that should be
* watched: SizeWatcher.dimensions.horizontal, SizeWatcher.dimensions.vertical or
* SizeWatcher.dimensions.both
* @constructor
*/
function SizeWatcher(element, options) {
this._element = element;
this._delegate = options.delegate;
this._size = null;
this._continuous = !!options.continuous;
this._direction = options.direction ? options.direction : SizeWatcher.directions.both;
this._dimension = options.dimension ? options.dimension : SizeWatcher.dimensions.both;
this._sizeIncreaseWatcherContentElm = null;
this._sizeDecreaseWatcherElm = null;
this._sizeIncreaseWatcherElm = null;
this._state = SizeWatcher.states.initialized;
this._generateScrollWatchers(options.size);
this._appendScrollWatchersToElement(options.container);
}
SizeWatcher.states = {
initialized: 0,
generatedScrollWatchers: 1,
appendedScrollWatchers: 2,
preparedScrollWatchers: 3,
watchingForSizeChange: 4
};
SizeWatcher.directions = {
decrease: 1,
increase: 2,
both: 3
};
SizeWatcher.dimensions = {
horizontal: 1,
vertical: 2,
both: 3
};
//noinspection JSUnusedLocalSymbols
SizeWatcher.prototype = {
constructor: SizeWatcher,
getWatchedElement: function() {
return this._element;
},
setSize: function(size) {
this._size = size;
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.increase) {
this._sizeIncreaseWatcherContentElm.style.cssText = "width: " + (size.width + 1) + "px; height: " + (size.height + 1) + "px;";
}
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.decrease) {
this._sizeDecreaseWatcherElm.style.cssText = "position:absolute; left: 0px; top: 0px; overflow: hidden; width: " + (size.width - 1) + "px; height: " + (size.height - 1) + "px;";
}
},
_generateScrollWatchers: function(size) {
this._element.style.position = "absolute";
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.increase) {
this._sizeIncreaseWatcherContentElm = document.createElement("div");
this._sizeIncreaseWatcherElm = document.createElement("div");
this._sizeIncreaseWatcherElm.style.cssText = "position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: hidden;";
this._sizeIncreaseWatcherElm.appendChild(this._sizeIncreaseWatcherContentElm);
this._element.appendChild(this._sizeIncreaseWatcherElm);
}
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.decrease) {
this._sizeDecreaseWatcherElm = document.createElement("div");
this._sizeDecreaseWatcherElm.appendChild(this._element);
}
if (size) {
this.setSize(size);
}
this._state = SizeWatcher.states.generatedScrollWatchers;
},
_appendScrollWatchersToElement: function(container) {
if (this._state !== SizeWatcher.states.generatedScrollWatchers) {
throw new Error("SizeWatcher._appendScrollWatchersToElement() was invoked before SizeWatcher._generateScrollWatchers()");
}
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.decrease) {
container.appendChild(this._sizeDecreaseWatcherElm);
} else {
container.appendChild(this._element);
}
this._state = SizeWatcher.states.appendedScrollWatchers;
},
removeScrollWatchers: function() {
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.decrease) {
if (this._sizeDecreaseWatcherElm.parentNode) {
this._sizeDecreaseWatcherElm.parentNode.removeChild(this._sizeDecreaseWatcherElm);
}
} else if (this._element.parentNode) {
this._element.parentNode.removeChild(this._element);
}
},
prepareForWatch: function() {
var parentNode,
sizeDecreaseWatcherElmScrolled = true,
sizeIncreaseWatcherElmScrolled = true;
if (this._state !== SizeWatcher.states.appendedScrollWatchers) {
throw new Error("SizeWatcher.prepareForWatch() invoked before SizeWatcher._appendScrollWatchersToElement()");
}
if (this._size === null) {
this.setSize(new Size(this._element.offsetWidth, this._element.offsetHeight));
}
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.decrease) {
sizeDecreaseWatcherElmScrolled = this._scrollElementToBottomRight(this._sizeDecreaseWatcherElm);
}
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.increase) {
sizeIncreaseWatcherElmScrolled = this._scrollElementToBottomRight(this._sizeIncreaseWatcherElm);
}
// Check if scroll positions updated.
if (!sizeDecreaseWatcherElmScrolled || !sizeIncreaseWatcherElmScrolled) {
// Traverse tree to the top node to see if element is in the DOM tree.
parentNode = this._element.parentNode;
while (parentNode !== window.document && parentNode !== null) {
parentNode = parentNode.parentNode;
}
if (parentNode === null) {
throw new Error("Can't set scroll position of scroll watchers. SizeWatcher is not in the DOM tree.");
} else if (console && typeof console.warn === "function") {
console.warn("SizeWatcher can't set scroll position of scroll watchers.");
}
}
this._state = SizeWatcher.states.preparedScrollWatchers;
},
_scrollElementToBottomRight: function(element) {
var elementScrolled = true;
//noinspection JSBitwiseOperatorUsage
if (this._dimension & SizeWatcher.dimensions.vertical) {
element.scrollTop = 1;
elementScrolled = elementScrolled && element.scrollTop === 1;
}
//noinspection JSBitwiseOperatorUsage
if (this._dimension & SizeWatcher.dimensions.horizontal) {
element.scrollLeft = 1;
elementScrolled = elementScrolled && element.scrollLeft === 1;
}
return elementScrolled;
},
beginWatching: function() {
if (this._state !== SizeWatcher.states.preparedScrollWatchers) {
throw new Error("SizeWatcher.beginWatching() invoked before SizeWatcher.prepareForWatch()");
}
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.decrease) {
//noinspection JSValidateTypes
this._sizeDecreaseWatcherElm.addEventListener("scroll", this, false);
}
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.increase) {
//noinspection JSValidateTypes
this._sizeIncreaseWatcherElm.addEventListener("scroll", this, false);
}
this._state = SizeWatcher.states.watchingForSizeChange;
},
endWatching: function() {
if (this._state !== SizeWatcher.states.watchingForSizeChange) {
throw new Error("SizeWatcher.endWatching() invoked before SizeWatcher.beginWatching()");
}
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.decrease) {
//noinspection JSValidateTypes
this._sizeDecreaseWatcherElm.removeEventListener("scroll", this, false);
}
//noinspection JSBitwiseOperatorUsage
if (this._direction & SizeWatcher.directions.increase) {
//noinspection JSValidateTypes
this._sizeIncreaseWatcherElm.removeEventListener("scroll", this, false);
}
this._state = SizeWatcher.states.appendedScrollWatchers;
},
/**
* @private
*/
handleEvent: function(event) {
var newSize, oldSize;
// This is not suppose to happen because when we run endWatching() we remove scroll listeners.
// But some browsers will fire second scroll event which was pushed into event stack before listener was
// removed so do this check anyway.
if (this._state !== SizeWatcher.states.watchingForSizeChange) {
return;
}
newSize = new Size(this._element.offsetWidth, this._element.offsetHeight);
oldSize = this._size;
// Check if element size is changed. How come that element size isn't changed but scroll event fired?
// This can happen in two cases: when double scroll occurs or immediately after calling prepareForWatch()
// (event if scroll event listeners attached after it).
// The double scroll event happens when one size dimension (e.g.:width) is increased and another
// (e.g.:height) is decreased.
if (oldSize.isEqual(newSize)) {
return;
}
if (this._delegate && typeof this._delegate.sizeWatcherChangedSize === "function") {
this._delegate.sizeWatcherChangedSize(this);
// Check that endWatching() wasn't invoked from within the delegate.
if (this._state !== SizeWatcher.states.watchingForSizeChange) {
return;
}
}
if (!this._continuous) {
this.endWatching();
} else {
// Set the new size so in case of double scroll event we won't cause the delegate method to be executed twice
// and also to update to the new watched size.
this.setSize(newSize);
// change state so prepareFowWatch() won't throw exception about wrong order invocation.
this._state = SizeWatcher.states.appendedScrollWatchers;
// Run prepareForWatch to reset the scroll watchers, we have already set the size
this.prepareForWatch();
// Set state to listeningForSizeChange, there is no need to invoke beginWatching() method as scroll event
// listeners and callback are already set.
this._state = SizeWatcher.states.watchingForSizeChange;
}
}
};
}(window));
},{}]},{},[14])
(14)
});
var canvas = document.getElementById("canvas");
var musictest = new Audio("audio/Rolemusic_-_01_-_A_ninja_among_culturachippers-mono-loop.mp3");
var jumpsoundJS = new Audio("audio/jump1.wav");
var manifest = {
"images": {
"bg": "images/bg.png",
"logo": "images/kickbot-logo.png",
},
"sounds": {
"jump1": "audio/jump1.wav",
"jump2": "audio/jump2.wav",
"jump3": "audio/jump3.wav",
"jump4": "audio/jump4.wav",
"jump5": "audio/jump5.wav",
"laser": "audio/laser.wav",
"spikes": "audio/spikes.wav",
"point": "audio/point.wav",
"music": "audio/Rolemusic_-_01_-_A_ninja_among_culturachippers-mono-loop.mp3",
},
"fonts": [
"pixelade"
],
"animations": {
"two-scoop": {
"strip": "images/two-scoop-pixel-anim.png",
"frames": 16,
"msPerFrame": 100,
"repeatAt": 15
},
"arrow-left": {
"strip": "images/arrow-key-sprite.png",
"frames": 2,
"msPerFrame": 500
},
"arrow-right": {
"strip": "images/arrow-key-sprite.png",
"frames": 2,
"msPerFrame": 500,
"flip": "horizontal"
},
"tap-left": {
"strip": "images/tap-icons-sprite.png",
"frames": 2,
"msPerFrame": 500
},
"tap-right": {
"strip": "images/tap-icons-sprite.png",
"frames": 2,
"msPerFrame": 500,
"flip": "horizontal"
},
"laser-left": {
"strip": "images/laser-anim.png",
"frames": 12,
"msPerFrame": 70
},
"laser-right": {
"strip": "images/laser-anim.png",
"frames": 12,
"msPerFrame": 70,
"flip": "horizontal"
},
"spikes-left": {
"strip": "images/spikes.png",
"frames": 1,
"msPerFrame": 70
},
"spikes-right": {
"strip": "images/spikes.png",
"frames": 1,
"msPerFrame": 70,
"flip": "horizontal"
},
"player-left": {
"strip": "images/player.png",
"frames": 1,
"msPerFrame": 70
},
"player-right": {
"strip": "images/player.png",
"frames": 1,
"msPerFrame": 70,
"flip": "horizontal"
},
"wall-1-left": {
"strip": "images/wall1.png",
"frames": 1,
"msPerFrame": 300
},
"wall-1-right": {
"strip": "images/wall1.png",
"frames": 1,
"msPerFrame": 300,
"flip": "horizontal"
},
"wall-2-left": {
"strip": "images/wall2.png",
"frames": 1,
"msPerFrame": 300
},
"wall-2-right": {
"strip": "images/wall2.png",
"frames": 1,
"msPerFrame": 300,
"flip": "horizontal"
},
"player-slide-left": {
"strip": "images/player-slide-anim.png",
"frames": 8,
"msPerFrame": 100
},
"player-slide-right": {
"strip": "images/player-slide-anim.png",
"frames": 8,
"msPerFrame": 100,
"flip": "horizontal"
},
"player-explode-left": {
"strip": "images/explode.png",
"frames": 8,
"msPerFrame": 70,
"repeatAt": 7
},
"player-explode-right": {
"strip": "images/explode.png",
"frames": 8,
"msPerFrame": 70,
"repeatAt": 7,
"flip": "horizontal"
},
"window-1-left": {
"strip": "images/wall-grate.png",
"frames": 1,
"msPerFrame": 300
},
"window-1-right": {
"strip": "images/wall-grate.png",
"frames": 1,
"msPerFrame": 300,
"flip": "horizontal"
},
"window-2-left": {
"strip": "images/window-robot-2f.png",
"frames": 2,
"msPerFrame": 300
},
"window-2-right": {
"strip": "images/window-robot-2f.png",
"frames": 2,
"msPerFrame": 300,
"flip": "horizontal"
},
"window-3-left": {
"strip": "images/window-scientist1.png",
"frames": 2,
"msPerFrame": 300
},
"window-3-right": {
"strip": "images/window-scientist1.png",
"frames": 2,
"msPerFrame": 300,
"flip": "horizontal"
},
"window-4-left": {
"strip": "images/window-scientist2.png",
"frames": 2,
"msPerFrame": 300
},
"window-4-right": {
"strip": "images/window-scientist2.png",
"frames": 2,
"msPerFrame": 300,
"flip": "horizontal"
},
"window-5-left": {
"strip": "images/window-scientist3.png",
"frames": 2,
"msPerFrame": 300
},
"window-5-right": {
"strip": "images/window-scientist3.png",
"frames": 2,
"msPerFrame": 300,
"flip": "horizontal"
},
}
};
var game = new Splat.Game(canvas, manifest);
game.scenes.add("title", new Splat.Scene(canvas, function() {
this.timers.running = new Splat.Timer(null, 2000, function() {
game.scenes.switchTo("main");
});
this.timers.running.start();
}, function(elapsedMillis) {
game.animations.get("two-scoop").move(elapsedMillis);
}, function(context) {
context.fillStyle = "#93cbcd";
context.fillRect(0, 0, canvas.width, canvas.height);
var anim = game.animations.get("two-scoop");
context.fillStyle = "#ffffff";
context.font = "50px pixelade";
centerText(context, "TWO SCOOP GAMES", 0, (canvas.height / 2) + (anim.height / 2) + 30);
anim.draw(context, (canvas.width / 2) - (anim.width / 2), (canvas.height / 2) - (anim.height / 2));
}));
function getBest() {
var b = parseInt(Splat.cookie.get("bestScore"));
if (isNaN(b) || b < 0 || !b) {
b = 0;
}
return b;
}
function setBest(b) {
best = b;
Splat.cookie.set("bestScore", best);
}
var player;
var walls = [];
var obstacles = [];
var onWall;
var dead = false;
var waitingToStart = true;
var wallImages = ["wall-1", "wall-2"];
var windowImages = ["window-1", "window-2", "window-3", "window-4", "window-5"];
var jumpSounds = ["jump1", "jump2", "jump3", "jump4", "jump5"];
var bgY = 0;
var score = 0;
var best = getBest();
var newBest = false;
var ad = new Ejecta.AdBanner();
ad.onload = function(){ console.debug("AD LOAD"); };
ad.onerror = function(){ console.debug("AD ERROR"); };
function jumpSound() {
var i = Math.random() * jumpSounds.length |0;
game.sounds.play(jumpSounds[i]);
}
function chooseWall(y, possibleWalls, isLeft) {
var i = Math.random() * possibleWalls.length |0;
var name = isLeft ? "-left" : "-right";
var anim = game.animations.get(possibleWalls[i] + name);
var x = 0;
if (!isLeft) {
x = canvas.width - anim.width;
}
var wall = new Splat.AnimatedEntity(x, y, anim.width, anim.height, anim, 0, 0);
walls.push(wall);
}
function isWindow(entity) {
if (!entity) {
return false;
}
return entity.sprite.name.indexOf("window") > -1;
}
function wallIsBelowScreen(y) {
return y > walls[0].y && y > walls[walls.length - 2].y;
}
function getLastLeftWall(y) {
if (walls.length > 1) {
return wallIsBelowScreen(y) ? walls[0] : walls[walls.length - 2];
}
}
function getLastRightWall(y) {
if (walls.length > 1) {
return wallIsBelowScreen(y) ? walls[1] : walls[walls.length - 1];
}
}
function makeObstacle(onRight, y, getWindowImages) {
var img;
var obstacle;
var wallImg = game.animations.get("wall-1-left");
var x = wallImg.width - 8;
if (Math.random() > 0.5) {
img = game.animations.get(onRight ? "laser-right" : "laser-left");
if (onRight) {
obstacle = new Splat.AnimatedEntity(canvas.width - wallImg.width - img.width + 8 + 4, y + 10, 8, 211, img, -4, -10);
} else {
obstacle = new Splat.AnimatedEntity(x + 29, y + 10, 8, 211, img, -29, -10);
}
} else {
img = game.animations.get(onRight ? "spikes-right" : "spikes-left");
obstacle = new Splat.AnimatedEntity(x, y, img.width, img.height, img, 0, 0);
if (onRight) {
obstacle.x = canvas.width - wallImg.width - img.width + 8;
}
}
obstacles.push(obstacle);
}
var lastObstacle = false;
var pita = 0;
function makeWall(y) {
var hasObstacle = !lastObstacle;
if (!hasObstacle) {
pita++;
}
if (pita == 2) {
hasObstacle = true;
pita = 0;
}
lastObstacle = hasObstacle;
var lastLeftWallIsWindow = isWindow(getLastLeftWall(y));
var lastRightWallIsWindow = isWindow(getLastRightWall(y));
function getWindowImages(isLeft) {
if ((isLeft && lastLeftWallIsWindow) || (!isLeft && lastRightWallIsWindow)) {
return wallImages;
}
return Math.random() > 0.9 ? windowImages : wallImages;
}
if (hasObstacle) {
var onRight = Math.random() > 0.5;
chooseWall(y, onRight ? getWindowImages(true) : wallImages, true);
chooseWall(y, onRight ? wallImages : getWindowImages(false), false);
makeObstacle(onRight, y, getWindowImages);
} else {
chooseWall(y, getWindowImages(true), true);
chooseWall(y, getWindowImages(false), false);
}
}
function populateWallsUp(scene) {
var wallH = game.animations.get("wall-1-left").height;
var first = false;
if (walls.length == 0) {
makeWall(scene.camera.y + scene.camera.height - wallH);
first = true;
}
while (walls[walls.length - 1].y + walls[walls.length - 1].height > scene.camera.y) {
makeWall(walls[walls.length - 1].y - wallH);
}
if (first) {
obstacles = [];
}
while (walls[0].y > scene.camera.y + scene.camera.height) {
walls.shift();
}
while (obstacles.length > 0 && obstacles[0].y > scene.camera.y + scene.camera.height) {
obstacles.shift();
}
}
function populateWallsDown(scene) {
var wallH = game.animations.get("wall-1-left").height;
if (walls.length == 0) {
makeWall(scene.camera.y);
}
while (walls[0].y < scene.camera.y + scene.camera.height) {
makeWall(walls[0].y + wallH);
walls.unshift(walls.pop());
walls.unshift(walls.pop());
}
while (walls[walls.length - 1].y + walls[walls.length - 1].height < scene.camera.y) {
walls.pop();
}
obstacles = [];
}
function centerText(context, text, offsetX, offsetY) {
var w = context.measureText(text).width;
var x = offsetX + (canvas.width / 2) - (w / 2) |0;
var y = offsetY |0;
context.fillText(text, x, y);
}
function anythingWasPressed() {
return game.keyboard.isPressed("left") || game.keyboard.isPressed("right") || game.mouse.isPressed(0);
}
function drawScoreScreen(context, scene) {
var ftb = scene.timers.fadeToBlack.time;
scene.camera.drawAbsolute(context, function() {
var opacity = Math.min(ftb / 300, 0.7);
context.fillStyle = "rgba(0, 0, 0, " + opacity + ")";
context.fillRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "#ffffff";
context.font = "50px pixelade";
centerText(context, "SCORE", 0, 300);
context.font = "100px pixelade";
centerText(context, score, 0, 400);
context.font = "50px pixelade";
if (newBest) {
context.fillStyle = "#be4682";
centerText(context, "NEW BEST!", 0, 600);
} else {
centerText(context, "BEST", 0, 600);
}
context.font = "100px pixelade";
centerText(context, best, 0, 700);
});
}
function drawIntroOverlay(context, scene) {
scene.camera.drawAbsolute(context, function() {
var logo = game.images.get("logo");
context.drawImage(logo, (canvas.width / 2) - (logo.width / 2)|0, 200);
var isTouch = game.mouse.supportsTouch();
var arrow = game.animations.get(isTouch ? "tap-left" : "arrow-left");
var x = (canvas.width / 4);
arrow.draw(context, x, canvas.height * 3 / 4);
x = canvas.width - (canvas.width / 4) - arrow.width;
game.animations.get(isTouch ? "tap-right" : "arrow-right").draw(context, x, canvas.height * 3 / 4);
});
}
function drawFlash(context, scene) {
var flashTime = scene.timers.flash.time;
var flashLen = scene.timers.flash.expireMillis;
if (flashTime > 0) {
var opacity = Splat.math.oscillate(flashTime, flashLen);
context.fillStyle = "rgba(255, 255, 255, " + opacity + ")";
context.fillRect(scene.camera.x, scene.camera.y, canvas.width, canvas.height);
}
}
game.scenes.add("main", new Splat.Scene(canvas, function() {
walls = [];
obstacles = [];
waitingToStart = true;
dead = false;
this.camera.y = 0;
score = 0;
newBest = false;
var wallW = game.animations.get("wall-1-left").width;
var playerImg = game.animations.get("player-slide-left");
player = new Splat.AnimatedEntity(wallW, canvas.height / 2, 30, 100, playerImg, -35, -13);
this.timers.flash = new Splat.Timer(null, 150, function() {
this.reset();
});
this.timers.fadeToBlack = new Splat.Timer(null, 800, function() {
game.scenes.switchTo("main");
});
this.timers.leftJumpUp = new Splat.Timer(function(elapsedMillis) {
player.vx = Splat.math.oscillate(this.time + 100, 200);
}, 200, function() {
this.reset();
});
this.timers.rightJumpUp = new Splat.Timer(function(elapsedMillis) {
player.vx = -Splat.math.oscillate(this.time + 100, 200);
}, 200, function() {
this.reset();
});
game.animations.get("arrow-left").reset();
game.animations.get("arrow-right").reset();
game.animations.get("arrow-right").frame = 1;
game.animations.get("tap-left").reset();
game.animations.get("tap-right").reset();
game.animations.get("tap-right").frame = 1;
ad.show();
},
function(elapsedMillis) {
if (waitingToStart) {
this.camera.vy = 0.6;
player.vy = this.camera.vy;
if (anythingWasPressed()) {
musictest.loop = true;
musictest.play();
game.sounds.play("music", true);
waitingToStart = false;
this.camera.vy = -0.6;
//console.debug("AD HIDE");
ad.hide();
}
game.animations.get("arrow-left").move(elapsedMillis);
game.animations.get("arrow-right").move(elapsedMillis);
game.animations.get("tap-left").move(elapsedMillis);
game.animations.get("tap-right").move(elapsedMillis);
}
bgY -= this.camera.vy / 1.5 * elapsedMillis;
var bgH = game.images.get("bg").height;
if (bgY > bgH) {
bgY -= bgH;
}
if (player.y > this.camera.y + this.camera.height) {
if (!dead) {
game.sounds.play("spikes");
}
dead = true;
this.timers.fadeToBlack.start();
}
for (var i = 0; i < walls.length; i++) {
walls[i].move(elapsedMillis);
}
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].move(elapsedMillis);
}
if (this.camera.vy > 0) {
populateWallsDown(this);
} else {
populateWallsUp(this);
}
// gravity
if (!waitingToStart) {
player.vy += elapsedMillis * 0.003;
}
if (onWall && !dead && !waitingToStart && player.vy > 0.5) {
player.vy = 0.5;
}
player.move(elapsedMillis);
onWall = undefined;
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
if (player.collides(wall)) {
player.resolveLeftCollisionWith(wall);
player.resolveRightCollisionWith(wall);
player.resolveTopCollisionWith(wall);
this.timers.leftJumpUp.stop();
this.timers.leftJumpUp.reset();
this.timers.rightJumpUp.stop();
this.timers.rightJumpUp.reset();
if (player.overlapsVert(wall)) {
onWall = wall;
}
}
}
if (dead) {
return;
}
if (onWall) {
var wallIsOnLeft = player.x > onWall.x;
if (wallIsOnLeft) {
player.sprite = game.animations.get("player-slide-left");
} else {
player.sprite = game.animations.get("player-slide-right");
}
} else {
if (player.vx > 0) {
player.sprite = game.animations.get("player-left");
} else if (player.vx < 0) {
player.sprite = game.animations.get("player-right");
}
}
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (!obstacle.counted && obstacle.y > player.y + player.height) {
score++;
game.sounds.play("point");
if (score > best) {
setBest(score);
newBest = true;
}
obstacle.counted = true;
}
if (player.collides(obstacle)) {
if (!this.timers.flash.running) {
var explode;
if (player.sprite.name.indexOf("left") > -1) {
explode = game.animations.get("player-explode-left");
} else {
explode = game.animations.get("player-explode-right");
}
explode.reset();
player.sprite = explode;
if (obstacle.sprite == game.animations.get("laser-left") || obstacle.sprite == game.animations.get("laser-right")) {
game.sounds.play("laser");
} else if (obstacle.sprite.name.indexOf("spikes") > -1) {
game.sounds.play("spikes");
}
}
this.timers.flash.start();
dead = true;
return;
}
}
if (onWall) {
var wallIsOnLeft = player.x > onWall.x;
var left = false;
var right = false;
if (game.mouse.consumePressed(0)) {
if (game.mouse.x < canvas.width / 2) {
left = true;
} else {
right = true;
}
} else if (game.keyboard.consumePressed("left")) {
left = true;
} else if (game.keyboard.consumePressed("right")) {
right = true;
}
if (left) {
if (wallIsOnLeft) {
this.timers.leftJumpUp.start();
} else {
player.vx = -1.0;
}
player.vy = -1.5;
onWall = undefined;
jumpsoundJS.play();
jumpSound();
} else if (right) {
if (wallIsOnLeft) {
player.vx = 1.0;
} else {
this.timers.rightJumpUp.start();
}
player.vy = -1.5;
onWall = undefined;
jumpSound();
jumpsoundJS.play();
}
}
},
function(context) {
this.camera.drawAbsolute(context, function() {
var bg = game.images.get("bg");
for (var y = bgY - bg.height; y <= canvas.height; y += bg.height) {
y = y |0;
context.drawImage(bg, 0, y);
}
});
for (var i = 0; i < walls.length; i++) {
walls[i].draw(context);
}
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].draw(context);
}
player.draw(context);
drawFlash(context, this);
if (this.timers.fadeToBlack.running) {
drawScoreScreen(context, this);
return;
}
if (waitingToStart) {
drawIntroOverlay(context, this);
}
this.camera.drawAbsolute(context, function() {
context.fillStyle = "#ffffff";
context.font = "100px pixelade";
centerText(context, score, 0, 100);
});
}));
game.scenes.switchTo("loading");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment