2022-05-28 17:53:00 +00:00
|
|
|
// Brian Kumanchik
|
2022-05-27 19:28:06 +00:00
|
|
|
// Started 05-25-22
|
|
|
|
// My Invader Demo, for Bangle.js 2, written JavaScript - using Espruino Web IDE
|
|
|
|
|
|
|
|
|
2022-05-27 23:42:20 +00:00
|
|
|
// resolution 176x176
|
|
|
|
|
|
|
|
|
2022-05-27 19:28:06 +00:00
|
|
|
// - variables -----------------------------------------
|
|
|
|
// invader variables
|
2022-05-27 23:42:20 +00:00
|
|
|
var inv_x = 77;
|
|
|
|
var inv_y = 20;
|
|
|
|
var i_anim_delay = 10; // invader animation (and move) delay
|
|
|
|
var inv_frame = 1; // invader start animation frame
|
|
|
|
var ix_speed = 6; // march speed
|
|
|
|
var i_dir = 1; // 1 = right, 0 = left
|
|
|
|
var been_hit = false; // invader hit state
|
2022-05-28 17:53:00 +00:00
|
|
|
// - shoot variables
|
2022-05-28 20:22:44 +00:00
|
|
|
var inv_shot_x = -32;
|
|
|
|
var inv_shot_y = -32;
|
2022-05-27 23:42:20 +00:00
|
|
|
var inv_fire_pause = 30;
|
2022-05-28 20:22:44 +00:00
|
|
|
var inv_fired = false; // invader fired state
|
2022-05-28 17:53:00 +00:00
|
|
|
// - explode variables
|
2022-05-27 23:42:20 +00:00
|
|
|
var been_hit = false; // invader hit state
|
|
|
|
var bx = -32; // blast x
|
|
|
|
var by = -32; // blast y
|
2022-05-28 17:53:00 +00:00
|
|
|
var blast_delay = 15; // invader blast delay - pause after explosion
|
|
|
|
var boom_play = false;
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
// turret variables
|
2022-05-28 17:53:00 +00:00
|
|
|
var tur_x = 77;
|
|
|
|
var tur_y = 148;
|
|
|
|
var shot_fired = false; // turret fired state
|
|
|
|
var sx = -20; // turret shot starting x - off screen
|
|
|
|
var sy = -20; // turret shot starting y - off screen
|
|
|
|
var turret_been_hit = false;
|
|
|
|
var turret_blast_delay = 21; // keep blast active on screen for 60 frames
|
|
|
|
var turret_exp_frame = 1; // turret explode start animation frame
|
2022-05-28 20:22:44 +00:00
|
|
|
var turret_anim_delay = 3; // turret explode animation delay
|
2022-05-28 17:53:00 +00:00
|
|
|
var explosion_play = false;
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
// misc variables
|
2022-05-28 20:22:44 +00:00
|
|
|
var score = 0; // starting score
|
|
|
|
var lives = 3; // starting lives
|
|
|
|
var game_state = 0; // game state - 0 = game not started, 1 = game running, 3 = game over
|
|
|
|
var ang = 0.1;
|
|
|
|
var start_been_pressed = false; // stops double press on restart
|
|
|
|
var fire_been_pressed = false; // stops auto fire
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
// input(screen controller) variables
|
2022-05-28 17:53:00 +00:00
|
|
|
var BTNL, BTNR, BTNF, BTNS; // button - left, right, fire, start
|
2022-05-27 19:28:06 +00:00
|
|
|
var tap = {};
|
|
|
|
// use tapping on screen for left and right
|
|
|
|
Bangle.on('drag',e=>tap=e);
|
|
|
|
BTNL = { read : _=>tap.b && tap.x < 88 && tap.y > 88};
|
|
|
|
BTNR = { read : _=>tap.b && tap.x > 88 && tap.y > 88};
|
|
|
|
BTNF = { read : _=>tap.b && tap.x > 88 && tap.y < 88};
|
2022-05-28 17:53:00 +00:00
|
|
|
BTNS = { read : _=>tap.b && tap.x < 88 && tap.y < 88};
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
// - sprites -------------------------------------------
|
|
|
|
// invader sprites
|
2022-05-28 17:53:00 +00:00
|
|
|
var invader_a =
|
|
|
|
require("heatshrink").decompress(atob("hcIwkBiIBBAQoECCQQFBgEQAIMBEhUBDoYWDAYI="));
|
|
|
|
var invader_b =
|
2022-05-27 23:42:20 +00:00
|
|
|
require("heatshrink").decompress(atob("hcIwkBiIBBAQMQAoQEBgISCAYUQAIQAEB4YEBEAgEDAYIA=="));
|
2022-05-27 19:28:06 +00:00
|
|
|
var boom =
|
2022-05-27 23:42:20 +00:00
|
|
|
require("heatshrink").decompress(atob("hcJwkBiMQAIURgMQAgIKBAIICFAIMAAwIWBBAYSIEAgrDiA="));
|
2022-05-27 19:28:06 +00:00
|
|
|
var inv_shot =
|
2022-05-27 23:42:20 +00:00
|
|
|
require("heatshrink").decompress(atob("gcFwkBiERiAABAYQ"));
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
// turret sprites
|
2022-05-28 17:53:00 +00:00
|
|
|
var turret =
|
2022-05-27 23:42:20 +00:00
|
|
|
require("heatshrink").decompress(atob("h8IwkBiIABAYYACgAHFiEABggADCAInFgITBAAgOPA=="));
|
2022-05-28 17:53:00 +00:00
|
|
|
var tur_exp_a =
|
2022-05-27 23:42:20 +00:00
|
|
|
require("heatshrink").decompress(atob("h8IwkBiMRiACBAAwJEiAABBQgZCAAkAiAJBBoIUBgIABBgQACDIQ9ECQIA=="));
|
2022-05-28 17:53:00 +00:00
|
|
|
var tur_exp_b =
|
2022-05-27 23:42:20 +00:00
|
|
|
require("heatshrink").decompress(atob("h8IwkBiIBBAAUBiADCiMQAwQFDCIYXEB4IABgMAEYQXBiEAAQIQBAoIABDAQUCAAIVBA"));
|
2022-05-27 19:28:06 +00:00
|
|
|
var shot =
|
2022-05-27 23:42:20 +00:00
|
|
|
require("heatshrink").decompress(atob("gMDwkBAoIA=="));
|
|
|
|
|
|
|
|
|
|
|
|
// function to move and animate invader
|
2022-05-28 17:53:00 +00:00
|
|
|
function move_anim_inv() {
|
|
|
|
// invader anim code
|
|
|
|
i_anim_delay -= 1;
|
|
|
|
if ((i_anim_delay < 0) && !(been_hit)) {
|
|
|
|
i_anim_delay = 10;
|
|
|
|
|
|
|
|
inv_frame += 1;
|
|
|
|
if (inv_frame > 2) {
|
|
|
|
inv_frame = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// move right
|
|
|
|
if (i_dir == 1){
|
|
|
|
inv_x += ix_speed;
|
|
|
|
if (inv_x >= 142) {
|
|
|
|
inv_y += 8; // step down
|
|
|
|
i_dir = -1;
|
|
|
|
}
|
2022-05-27 23:42:20 +00:00
|
|
|
}
|
|
|
|
|
2022-05-28 17:53:00 +00:00
|
|
|
// move left
|
|
|
|
if (i_dir < 1){
|
|
|
|
inv_x -= ix_speed;
|
|
|
|
if (inv_x <= 10) {
|
|
|
|
inv_y += 8; // step down
|
|
|
|
i_dir = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-27 23:42:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
// function to make invader fire
|
2022-05-28 17:53:00 +00:00
|
|
|
function invader_fire() {
|
|
|
|
inv_fire_pause -= 1;
|
2022-05-27 23:42:20 +00:00
|
|
|
|
2022-05-28 17:53:00 +00:00
|
|
|
if (!(inv_fired)) { // so once invader shot is fired it doesn't follow the invader still
|
|
|
|
inv_shot_x = inv_x + 8;
|
|
|
|
inv_shot_y = inv_y + 18;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inv_fire_pause < 0) {
|
|
|
|
inv_fired = true;
|
|
|
|
inv_shot_y += 8;
|
|
|
|
}
|
2022-05-27 23:42:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-05-28 17:53:00 +00:00
|
|
|
// function to make turret explode (when hit) then start back in center
|
|
|
|
function turret_hit() {
|
|
|
|
if (turret_been_hit) {
|
|
|
|
if (!(explosion_play)) {
|
|
|
|
Bangle.buzz();
|
|
|
|
//Bangle.beep();
|
|
|
|
}
|
2022-05-27 23:42:20 +00:00
|
|
|
|
2022-05-28 17:53:00 +00:00
|
|
|
explosion_play = true;
|
|
|
|
turret_anim_delay -= 1;
|
|
|
|
turret_blast_delay -= 1;
|
2022-05-27 23:42:20 +00:00
|
|
|
|
2022-05-28 17:53:00 +00:00
|
|
|
if (turret_anim_delay < 0) {
|
|
|
|
turret_exp_frame += 1;
|
|
|
|
if (turret_exp_frame > 2) {
|
|
|
|
turret_exp_frame = 1;
|
|
|
|
}
|
|
|
|
turret_anim_delay = 3;
|
|
|
|
}
|
2022-05-27 23:42:20 +00:00
|
|
|
|
2022-05-28 17:53:00 +00:00
|
|
|
if (turret_blast_delay < 0) {
|
|
|
|
turret_blast_delay = 21;
|
|
|
|
turret_been_hit = false;
|
|
|
|
explosion_play = false;
|
|
|
|
tur_x = 77; // reset turret x
|
|
|
|
tur_y = 148; // reset turret y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// function to make invader explode (when hit) then randomly start somewhere else
|
|
|
|
function invader_hit() {
|
|
|
|
if (been_hit) {
|
|
|
|
if (!(boom_play)) {
|
|
|
|
Bangle.buzz();
|
|
|
|
//Bangle.beep();
|
|
|
|
}
|
2022-05-27 19:28:06 +00:00
|
|
|
|
2022-05-28 17:53:00 +00:00
|
|
|
inv_shot_x = -32; // hide shot
|
|
|
|
inv_shot_y = -32; // hide shot
|
|
|
|
inv_fire_pause = 30; // and reset pause
|
|
|
|
|
|
|
|
boom_play = true;
|
|
|
|
blast_delay -= 1;
|
|
|
|
|
|
|
|
if (blast_delay < 0) {
|
|
|
|
blast_delay = 15;
|
|
|
|
boom_play = false;
|
|
|
|
been_hit = false;
|
|
|
|
bx = -32; // move boom off screen (following invader)
|
|
|
|
by = -32;
|
2022-05-28 20:22:44 +00:00
|
|
|
// to gerate a random rounded number between 10 and 142;
|
|
|
|
inv_x = Math.floor(Math.random() * 142) + 10;
|
|
|
|
//inv_x = 77; // move invader back up after being hit
|
2022-05-28 17:53:00 +00:00
|
|
|
inv_y = 20; // move invader back up after being hit
|
|
|
|
i_dir = 1; // reset invader direction
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
// - setup stuff ---------------------------------------
|
|
|
|
function gameStart() {
|
2022-05-28 17:53:00 +00:00
|
|
|
setInterval(onFrame, 50);
|
2022-05-27 19:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-05-28 20:22:44 +00:00
|
|
|
// - main loop -------------------------------------------------------------
|
2022-05-27 19:28:06 +00:00
|
|
|
function onFrame() {
|
2022-05-28 17:53:00 +00:00
|
|
|
|
2022-05-28 20:22:44 +00:00
|
|
|
// game not started state (title screen)
|
|
|
|
if(game_state == 0) {
|
|
|
|
g.clear();
|
|
|
|
|
|
|
|
|
|
|
|
if (!(BTNS.read())) {
|
|
|
|
start_been_pressed = false; // stops double press on restart
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// draw text during game over state
|
|
|
|
g.setFont("4x6", 4); // set font and size x 2
|
|
|
|
g.setColor(0,1,0); // set color (black)
|
|
|
|
g.drawString("INVADER", 33, 55);
|
|
|
|
|
|
|
|
|
|
|
|
// just animate invader
|
|
|
|
// invader anim code
|
|
|
|
i_anim_delay -= 1;
|
|
|
|
if(i_anim_delay < 0) {
|
|
|
|
i_anim_delay = 25;
|
|
|
|
|
|
|
|
inv_frame += 1;
|
|
|
|
if (inv_frame > 2) {
|
|
|
|
inv_frame = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// draw sprites during game over state
|
|
|
|
//ang += 0.1;
|
|
|
|
//g.drawImage(invader_a, 88, 98, {scale:4, rotate:ang});
|
|
|
|
if(inv_frame == 1) {
|
|
|
|
g.drawImage(invader_a, 88-22, 85, {scale:4});
|
|
|
|
}
|
|
|
|
else if(inv_frame == 2) {
|
|
|
|
g.drawImage(invader_b, 88-22, 85, {scale:4});
|
|
|
|
}
|
|
|
|
|
|
|
|
// reset stuff
|
|
|
|
if(BTNS.read() && !(start_been_pressed)) {
|
|
|
|
turret_been_hit = false;
|
|
|
|
tur_x = 77; // reset turret to center of screen
|
|
|
|
tur_y = 148; // reset turret y
|
|
|
|
inv_x = 77; // reset invader to center of screen
|
|
|
|
inv_y = 20; // reset invader back to top
|
|
|
|
i_dir = 1; // reset invader direction
|
|
|
|
lives = 3; // reset lives
|
|
|
|
score = 0; // reset score
|
|
|
|
explosion_play = false;
|
|
|
|
game_state = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
g.flip();
|
|
|
|
}
|
|
|
|
|
2022-05-28 17:53:00 +00:00
|
|
|
// game over state
|
2022-05-28 20:22:44 +00:00
|
|
|
if(game_state == 3) {
|
2022-05-27 19:28:06 +00:00
|
|
|
g.clear();
|
2022-05-28 17:53:00 +00:00
|
|
|
|
|
|
|
// draw text during game over state
|
|
|
|
g.setFont("4x6", 2); // set font and size x 2
|
|
|
|
g.setColor(0,0,0); // set color (black)
|
|
|
|
g.drawString("SCORE:" + score ,5, 5);
|
|
|
|
g.drawString("LIVES:" + lives ,117, 5);
|
|
|
|
g.drawString("GAME OVER", 52, 80);
|
|
|
|
|
|
|
|
|
|
|
|
// draw sprites during game over state
|
|
|
|
// - invader frame 2
|
|
|
|
g.drawImage(invader_b, inv_x, inv_y, {scale:2});
|
|
|
|
g.drawImage(tur_exp_b, tur_x, tur_y, {scale:2});
|
|
|
|
g.drawImage(inv_shot, inv_shot_x, inv_shot_y, {scale:2});
|
|
|
|
|
|
|
|
|
|
|
|
// reset stuff
|
|
|
|
if(BTNS.read()) {
|
|
|
|
turret_been_hit = false;
|
|
|
|
tur_x = 77; // reset turret to center of screen
|
|
|
|
tur_y = 148; // reset turret y
|
|
|
|
inv_x = 77; // reset invader to center of screen
|
|
|
|
inv_y = 20; // reset invader back to top
|
|
|
|
i_dir = 1; // reset invader direction
|
|
|
|
lives = 3; // reset lives
|
|
|
|
score = 0; // reset score
|
|
|
|
explosion_play = false;
|
2022-05-28 20:22:44 +00:00
|
|
|
game_state = 0;
|
|
|
|
start_been_pressed = true;
|
2022-05-28 17:53:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
g.flip();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// not game over state (game running)
|
2022-05-28 20:22:44 +00:00
|
|
|
if(game_state == 1) {
|
2022-05-28 17:53:00 +00:00
|
|
|
g.clear();
|
|
|
|
|
2022-05-28 20:22:44 +00:00
|
|
|
|
|
|
|
if (!(BTNF.read())) {
|
|
|
|
fire_been_pressed = false; // stops auto fire
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-05-27 23:42:20 +00:00
|
|
|
// call function to move and animate invader
|
|
|
|
move_anim_inv();
|
2022-05-28 17:53:00 +00:00
|
|
|
|
2022-05-27 23:42:20 +00:00
|
|
|
// call function to make invader fire
|
|
|
|
invader_fire();
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
// check input (screen presses)
|
2022-05-28 17:53:00 +00:00
|
|
|
if(BTNL.read() && tur_x >= 12 && !(turret_been_hit)) {
|
2022-05-27 23:42:20 +00:00
|
|
|
tur_x -= 6;
|
2022-05-27 19:28:06 +00:00
|
|
|
}
|
2022-05-28 17:53:00 +00:00
|
|
|
else if(BTNR.read() && tur_x <= 140 && !(turret_been_hit)) {
|
2022-05-27 23:42:20 +00:00
|
|
|
tur_x += 6;
|
2022-05-27 19:28:06 +00:00
|
|
|
}
|
2022-05-28 20:22:44 +00:00
|
|
|
else if(BTNF.read() && !(turret_been_hit) && !(fire_been_pressed) && !(shot_fired)) {
|
2022-05-28 17:53:00 +00:00
|
|
|
shot_fired = true;
|
2022-05-28 20:22:44 +00:00
|
|
|
fire_been_pressed = true; // stops auto fire
|
2022-05-28 17:53:00 +00:00
|
|
|
sx=tur_x + 12;
|
|
|
|
sy=tur_y - 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// check for turret shot going off screen before allowing to fire again
|
|
|
|
if (shot_fired) {
|
|
|
|
sy -= 8;
|
|
|
|
if (sy < 22) {
|
|
|
|
shot_fired = false;
|
|
|
|
sx = -32;
|
|
|
|
sy = -32;
|
|
|
|
}
|
2022-05-27 19:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-05-27 23:42:20 +00:00
|
|
|
// check for invader shot going off screen before allowing to fire again
|
|
|
|
if (inv_shot_y > 150
|
|
|
|
) {
|
2022-05-28 17:53:00 +00:00
|
|
|
inv_fired = false;
|
|
|
|
inv_shot_x = inv_x - 1;
|
|
|
|
inv_shot_y = inv_y + 7;
|
|
|
|
inv_fire_pause = 30;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// check for turret shot and invader collision
|
|
|
|
if ((sx >= inv_x) && (sx <= inv_x + 20) && (sy <= inv_y + 14)) {
|
|
|
|
sx = -32;
|
|
|
|
sy = -32;
|
|
|
|
been_hit = true;
|
|
|
|
score += 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// check for invader shot and turret collision
|
|
|
|
if ((inv_shot_x + 4) >= (tur_x) && (inv_shot_x) <= (tur_x + 24) && (inv_shot_y + 8) >= (tur_y + 6)) {
|
|
|
|
if (!(turret_been_hit)) {
|
|
|
|
lives -= 1;
|
|
|
|
|
|
|
|
if (lives == 0) {
|
2022-05-28 20:22:44 +00:00
|
|
|
game_state = 3;
|
2022-05-28 17:53:00 +00:00
|
|
|
}
|
|
|
|
turret_been_hit = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-05-27 19:28:06 +00:00
|
|
|
// - draw sprites ----------------------------------
|
2022-05-28 17:53:00 +00:00
|
|
|
// invader sprites
|
|
|
|
if(!(been_hit)) {
|
|
|
|
if(inv_frame == 1) {
|
|
|
|
// - invader frame 1
|
|
|
|
g.drawImage(invader_a, inv_x, inv_y, {scale:2});
|
|
|
|
}
|
|
|
|
else if(inv_frame == 2) {
|
|
|
|
// - invader frame 2
|
|
|
|
g.drawImage(invader_b, inv_x, inv_y, {scale:2});
|
|
|
|
}
|
2022-05-27 23:42:20 +00:00
|
|
|
}
|
2022-05-28 17:53:00 +00:00
|
|
|
else {
|
|
|
|
// - invader explosion
|
|
|
|
g.drawImage(boom, inv_x, inv_y, {scale:2});
|
2022-05-27 23:42:20 +00:00
|
|
|
}
|
|
|
|
// - invader shot
|
|
|
|
if (inv_fired) {
|
2022-05-28 17:53:00 +00:00
|
|
|
g.drawImage(inv_shot, inv_shot_x, inv_shot_y, {scale:2});
|
2022-05-27 23:42:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
g.drawImage(inv_shot, -32, -32, {scale:2});
|
2022-05-28 17:53:00 +00:00
|
|
|
}
|
2022-05-27 23:42:20 +00:00
|
|
|
|
2022-05-28 20:22:44 +00:00
|
|
|
// turret sprites
|
2022-05-28 17:53:00 +00:00
|
|
|
if(!(turret_been_hit)) {
|
|
|
|
// - undamaged turret
|
|
|
|
g.drawImage(turret, tur_x, tur_y, {scale:2});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(turret_exp_frame == 1) {
|
|
|
|
// - turret explosion frame 1
|
|
|
|
g.drawImage(tur_exp_a, tur_x, tur_y, {scale:2});
|
|
|
|
}
|
|
|
|
else if(turret_exp_frame == 2) {
|
|
|
|
// - turret explosion frame 2
|
|
|
|
g.drawImage(tur_exp_b, tur_x, tur_y, {scale:2});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// - turret shot
|
|
|
|
g.drawImage(shot, sx, sy, {scale:2});
|
|
|
|
|
|
|
|
|
|
|
|
// call function to make invader explode then randomly start somewhere else
|
|
|
|
invader_hit();
|
|
|
|
|
|
|
|
|
|
|
|
// call function to make turret explode (when hit) then start back in center
|
|
|
|
turret_hit();
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
// - draw text -------------------------------------
|
2022-05-28 17:53:00 +00:00
|
|
|
g.setFont("4x6", 2); // set font and size x 2
|
|
|
|
g.setColor(0,0,0); // set color (black)
|
|
|
|
g.drawString("SCORE:" + score ,5,5);
|
2022-05-28 20:22:44 +00:00
|
|
|
g.drawString("LIVES:" + lives ,117,5);
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
g.flip();
|
|
|
|
}
|
2022-05-28 20:22:44 +00:00
|
|
|
|
|
|
|
} // end main loop ---------------------------------------------------------
|
2022-05-27 19:28:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
gameStart();
|
|
|
|
|
|
|
|
|