From 1fdc4bb27fdea607fae6bc74208eceb1fc9fcbc2 Mon Sep 17 00:00:00 2001 From: jslightham <31053827+jslightham@users.noreply.github.com> Date: Mon, 25 May 2020 12:43:28 -0400 Subject: [PATCH] mostly finished --- index.html | 169 ++++++++++++++ main.js | 625 ++++++++++++++++++++++++++++++++++++++++++++++++++++ shot.mp3 | Bin 0 -> 22040 bytes wallhit.mp3 | Bin 0 -> 1896 bytes 4 files changed, 794 insertions(+) create mode 100644 index.html create mode 100644 main.js create mode 100644 shot.mp3 create mode 100644 wallhit.mp3 diff --git a/index.html b/index.html new file mode 100644 index 0000000..2715fa5 --- /dev/null +++ b/index.html @@ -0,0 +1,169 @@ + + + + + + + + Collision Simulation + + + + +
+
+

Welcome to the collision simulator!

+

A Project by: Johnathon Slightham

+

Visit the wiki on github for more information on how this works!

+

To use the simulator:

+ + +
+
+

Collision Simulator

+

Project by Johnathon Slightham

+
+ +
+
+ Your browser does not support HTML 5
+
+
+
+

Modifiers

+ Coefficient of Kinetic Friction:
+ + Collision Effectiveness (100% - No energy lost): %
+ Draw Velocity Vector: +

Placed Particles

+ + + + + + + + + +
ID #MassX VelocityY VelocityX AccelerationY Acceleration
+ Total Kinetic Energy: J +

Add Particles

+
+ Mass: X-Velocity: Y-Velocity: +
+

Modify Graph

+ Graph X Axis: + + + Graph Y Axis: + +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..0115d93 --- /dev/null +++ b/main.js @@ -0,0 +1,625 @@ +class Particle{ + constructor(id, x, y, vx, vy, m){ + this.id = id; + this.x = x; + this.y = y; + this.vx = vx; + this.vy = vy; + this.m = m; + this.r = getRadius(m); + this.v = Math.sqrt(Math.pow(this.vx, 2) + Math.pow(this.vy, 2)); + this.ek = []; + this.ek.push([0, 0]); + this.ax = 0 + this.ay = 0; + } +} + +// Functions to display or hide the welcome screen +function on() { + document.getElementById("playButton").style.display = "block"; +} + +function off() { + document.getElementById("playButton").style.display = "none"; +} + +var particles = []; +var ctx; +var canvas; +var table; +var a = 0; +var sa; +var ek = []; +var eff = 0.85; +var shot = new Audio("shot.mp3"); +var wallhit = new Audio("wallhit.mp3"); +var selector = document.getElementById('graph_type'); +var sfr = 0; +var fr = 0; +var drawVelocityVector = false; +var measurementData = []; +var chartX = "measurement"; +var chartY = "ekt" +measurementData.push('Measurement Number'); +measurementData.push(0); + +ek.push('Kientic Energy (J)'); +ek.push(0); + +var measurement = 0; + +// Load the google charts API +google.charts.load('current', {'packages':['corechart']}); + +function main(elem){ + off(); + canvas = document.getElementById(elem); + ctx = canvas.getContext("2d"); + table = document.getElementById("particles"); + + fr = document.getElementById("fr").value; + //sfr = document.getElementById("sfr").value; + + drawVelocityVector = document.getElementById("drawvelocity").checked; + + reloadDropdowns(); + + // Set a callback to run when the charts API is loaded + google.charts.setOnLoadCallback(drawKEChart); + + //canvas.addEventListener("mousedown", doMouseDown, false); + //canvas.addEventListener("onmouseup", doMouseUp, false); + + // Loop through each particle every 10 milliseconds, create measurements every 1 second + setInterval(loop, 10); + setInterval(measureData, 1000); +} + +// The main loop function that handles each particle +function loop(){ + + // Set volumes of sounds according to % energy transferred + eff = document.getElementById("effe").value/100; + shot.volume = 1 - eff; + wallhit.volume = 1 - eff; + + // Acceleration = 9.8*uk (derived from F=ma, -uk*g*m=m*a) + a = -(9.8)*fr; + sa = -(9.8)*sfr; + + chartX = document.getElementById("graphx").value; + chartY = document.getElementById("graphy").value; + drawVelocityVector = document.getElementById("drawvelocity").checked; + + // Write the current kinetic energy, then reset to 0 for recalculation + document.getElementById("ek").innerHTML = ek[ek.length-1]; + + // Draw board, then process collisions. + draw(); + separate(); + detectCollisions(); + + // Iterate through each particle, to change it's velocity from acceleration, and position from velocity + particles.forEach((elem, i) => { + + // Determine velocity vector and store for later use + elem.v = Math.sqrt(Math.pow(elem.vx, 2) + Math.pow(elem.vy, 2)); + + // Check for collisions with wall, and on collision set to - velocity + if(elem.x + elem.vx > canvas.width - elem.r || elem.x + elem.vx < elem.r){ + elem.vx = -eff*elem.vx; + let wallHitAudio = wallhit.cloneNode(); + wallHitAudio.volume = 1 - eff; + wallHitAudio.play() + + // Fix bug of balls getting stuck in walls, if a ball is in a wall move it out + if(elem.x + elem.vx > canvas.width - elem.r){ + elem.x = canvas.width - elem.r; + } + + if(elem.x + elem.vx < elem.r){ + elem.x = elem.r; + } + + } + if(elem.y + elem.vy > canvas.height - elem.r || elem.y + elem.vy < elem.r){ + elem.vy = -eff*elem.vy; + let wallHitAudio = wallhit.cloneNode(); + wallHitAudio.volume = 1 - eff; + wallHitAudio.play() + + // Fix bug of balls getting stuck in walls, if a ball is in a wall move it out + if(elem.y + elem.vy < elem.r){ + elem.y = elem.r; + } + if(elem.y + elem.vy > canvas.width - elem.r){ + elem.y = canvas.height - elem.r; + } + } + + // Calculate Theta, and acceleration values based on the direction of the velocity vector + elem.theta = Math.atan2(elem.vx,elem.vy); + elem.sax = sa*Math.abs(Math.sin(elem.theta)); + elem.say = sa*Math.abs(Math.cos(elem.theta)); + + elem.ax = a*Math.abs(Math.sin(elem.theta)); + elem.ay = a*Math.abs(Math.cos(elem.theta)); + + // If the particle has enough velocity to be decelerated, decelerate it + if(!Math.abs(elem.vx) < Math.abs(elem.ax) || !Math.abs(elem.vy) < Math.abs(elem.ay)){ + // Add acceleration to velocity each iteration + if(elem.vx > 0){ + elem.vx += elem.ax; + } + else{ + elem.vx -= elem.ax; + } + + // Add acceleration to velocity each iteration + if(elem.vy > 0){ + elem.vy += elem.ay; + } + else{ + elem.vy -= elem.ay; + } + + }else{ + elem.ax = 0; + elem.ay = 0; + + } + // Set velocity to zero if the acceleration is larger than it + if(Math.abs(elem.ay) > Math.abs(elem.vy) || Math.abs(elem.ax) > Math.abs(elem.vx)){ + elem.ax = 0; + elem.ay = 0; + elem.vx = 0; + elem.vy = 0; + }else{ + if((elem.vx == 0 || elem.vy == 0) && (Math.abs(elem.say) > Math.abs(elem.vy) || Math.abs(elem.sax) > Math.abs(elem.vx))){ + elem.ax = 0; + elem.ay = 0; + elem.vx = 0; + elem.vy = 0; + }else{ + // Each iteration add the velocity to the position + elem.x += elem.vx; + elem.y += elem.vy; + } + + } + + // Display data in the table + table.rows[i+1].cells[0].innerHTML = elem.id; + table.rows[i+1].cells[1].innerHTML = elem.m + " kg"; + table.rows[i+1].cells[2].innerHTML = Math.abs(elem.vx.toPrecision(2)); + table.rows[i+1].cells[3].innerHTML = Math.abs(elem.vy.toPrecision(2)); + table.rows[i+1].cells[4].innerHTML = elem.ax.toPrecision(2); + table.rows[i+1].cells[5].innerHTML = elem.ay.toPrecision(2); + }) +} + +// Function to draw all particles on the canvas, and draw velocity vectors +function draw(){ + ctx.clearRect(0, 0, canvas.width, canvas.height); + particles.forEach((elem, i) => + { + // Draw actual particle + ctx.beginPath(); + ctx.fillStyle = "black"; + ctx.strokeStyle = "black"; + ctx.arc(elem.x, elem.y, elem.r, 0, 2*Math.PI); + ctx.fill(); + ctx.stroke(); + + // Center mass in particle + ctx.font = elem.m*0.55 + 'px serif'; + ctx.fillStyle = "white"; + ctx.textAlign = "center"; + ctx.fillText(elem.m+"kg", elem.x, elem.y + elem.r/4); + + // Draw Velocity Vector, if this option is selected + if(drawVelocityVector){ + ctx.beginPath(); + ctx.strokeStyle = "red"; + ctx.moveTo(elem.x, elem.y); + ctx.lineTo(elem.x + elem.v*Math.sin(elem.theta)* 10, elem.y + elem.v*Math.cos(elem.theta) * 10); + ctx.stroke(); + } + + }); + +} + +// Function that returns the distance between the two particles given +function getDistance(p1, p2){ + let xDist = Math.abs(p1.x - p2.x); + let yDist = Math.abs(p1.y - p2.y); + + return Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2)); +} + +var collisions = []; + +// Function that will separate all particles on the canvas +function separate(){ + collisions = []; + let noOverlap = false; + while(!noOverlap){ + noOverlap = true; + particles.forEach((elem1, i) => { + for(var j = i+1; j < particles.length; j++){ + elem2 = particles[j]; + // Make sure not comparing the same element + if(elem1 != elem2){ + // If the particles are overlapping + if(getDistance(elem1, elem2) < elem1.r + elem2.r){ + collisions.push({element1: elem1, element2: elem2}); + console.log("overlap"); + + // Move the particle back to its previous position, only if doing so will not put it inside of a wall + if(!elem1.x - elem1.vx > canvas.width - elem1.r || !elem1.x - elem1.vx < elem1.r) + elem1.x -= elem1.vx; + + if(!elem2.x - elem2.vx > canvas.width - elem2.r || !elem2.x - elem2.vx < elem2.r) + elem2.x -= elem2.vx; + + if(!elem1.y - elem1.vy > canvas.height - elem1.r || !elem1.y - elem1.vy < elem1.r) + elem1.y -= elem1.vy; + + if(!elem2.y - elem2.vy > canvas.height - elem2.r || !elem2.y - elem2.vy < elem2.r) + elem2.y -= elem2.vy; + + noOverlap = false; + + draw(); + } + } + } + }) + } +} + +// Function that detects, and handles all collisions. +function detectCollisions(){ + + collisions.forEach((collision) => { + let shotAudio = shot.cloneNode() + shotAudio.volume = 1 - eff; + shotAudio.play() + elem1 = collision.element1; + elem2 = collision.element2; + + // Check if the particles being compared are the same, if they are don't run collision detection or particles will collide with themselves. + if(elem1 != elem2){ + elem1.px = elem1.x; + elem1.py = elem1.y; + elem2.px = elem2.x; + elem2.py = elem2.y; + + // Store previous velocities, this will be used later when detecting static friction + elem1.pvx = elem1.vx; + elem1.pvy = elem1.vy; + elem2.pvx = elem2.vx; + elem2.pvy = elem2.vy; + + // If the particles are still overlapping, separate them again + if(getDistance(elem1, elem2) < elem1.r + elem2.r){ + console.log("overlap"); + elem1.x -= elem1.vx; + elem1.y -= elem1.vy; + elem2.x -= elem2.vx; + elem2.y -= elem2.vy; + } + + // Theta = angle of velocity + let theta1 = Math.atan2(elem1.vx,elem1.vy); + let theta2 = Math.atan2(elem2.vx,elem2.vy); + + // Phi = angle of collision + let phi = Math.atan2((elem2.px - elem1.px),(elem2.py - elem1.py)); + + // Find rotated x & y components, with x axis parallel to the contact normal vector + let v1xr = elem1.v*Math.cos(theta1 - phi); + let v1yr = elem1.v*Math.sin(theta1 - phi); + let v2xr = elem2.v*Math.cos(theta2 - phi); + let v2yr = elem2.v*Math.sin(theta2 - phi); + + // Use the rotated components to solve a 1 dimensional collision. + let v1fxr = eff*(v1xr*(elem1.m - elem2.m) + 2*elem2.m*v2xr)/(elem1.m + elem2.m); + let v2fxr = eff*(v2xr*(elem2.m - elem1.m) + 2*elem1.m*v1xr)/(elem2.m + elem1.m); + + elem1.vy = v1fxr*Math.cos(phi) + v1yr*Math.cos(phi + Math.PI/2); + elem1.vx = v1fxr*Math.sin(phi) + v1yr*Math.sin(phi + Math.PI/2); + elem2.vy = v2fxr*Math.cos(phi) + v2yr*Math.cos(phi + Math.PI/2); + elem2.vx = v2fxr*Math.sin(phi) + v2yr*Math.sin(phi + Math.PI/2); + + // Calculate new theta, and static acceleration for static friction checking + elem1.theta = Math.atan2(elem1.vx,elem1.vy); + elem1.sax = sa*Math.abs(Math.sin(elem1.theta)); + elem1.say = sa*Math.abs(Math.cos(elem1.theta)); + + elem2.theta = Math.atan2(elem2.vx,elem2.vy); + elem2.sax = sa*Math.abs(Math.sin(elem2.theta)); + elem2.say = sa*Math.abs(Math.cos(elem2.theta)); + + if((elem2.sax > elem2.vx || elem2.say > elem2.vy) && (elem2.pvx == 0 || elem2.pvy == 0)){ + //elem2.vx = 0; + //elem2.vy = 0; + } + + if(elem1.sax > elem1.vx || elem1.say > elem1.vy && (elem1.pvx == 0 || elem1.pvy == 0)){ + //elem1.vx = 0; + //elem1.vy = 0; + } + + } + }); +} + +// Function called when the add particle button is submitted +function addParticle(){ + var form = document.getElementById("add"); + var errMsg = "Errors: "; // String to store all errors with entered data + // Mass cannot be less than 1 error + if(form["mass"].value < 1){ + errMsg += "Cannot Have Negative, or Zero Mass! " + } + // Mass is too large for the canvas size error + else if(getRadius(form["mass"].value)*2 + 10 > canvas.width || getRadius(form["mass"].value)*2 + 10 > canvas.height){ + errMsg += "That mass is too large for this canvas! " + }else if(!form["xvel"].value || !form["yvel"].value || !form["mass"].value){ + errMsg += "One or more values is not defined! " + } + // If no errors, add rows to the table and insert the particle into the array + else{ + + + var xv = parseInt(form["xvel"].value) + var yv = parseInt(form["yvel"].value) + + // Check if the acceleration is larger than the velocity, if so set velocity to 0 and not negative. + + let n = 1; + if(particles.length > 0){ + n = particles[particles.length-1].id +1; + } + + // Find a position that is not ontop of another ball, or inside of a wall. This will randomize the position 9 times or until a successful location is discovered. + let validPos = false; + let numtries = 0; + let tx = 0; let ty = 0; + while(!validPos && numtries < 9){ + numtries ++; + validPos = true; + tx = Math.round(Math.random()*((canvas.width - getRadius(parseInt(form["mass"].value))) - getRadius(parseInt(form["mass"].value)) - 5) + getRadius(parseInt(form["mass"].value)) + 5); + ty = Math.round(Math.random()*((canvas.height - getRadius(parseInt(form["mass"].value))) - getRadius(parseInt(form["mass"].value)) - 5) + getRadius(parseInt(form["mass"].value)) + 5); + let temp = new Particle(n, tx, ty, xv, yv, parseInt(form["mass"].value)+5); + particles.forEach(particle =>{ + if(getDistance(particle, temp) < particle.r + temp.r){ + validPos = false; + } + }) + } + // if a valid position was found create it + if(validPos){ + table.insertRow(); + table.rows[table.rows.length -1].insertCell(); + table.rows[table.rows.length -1].insertCell(); + table.rows[table.rows.length -1].insertCell(); + table.rows[table.rows.length -1].insertCell(); + table.rows[table.rows.length -1].insertCell(); + table.rows[table.rows.length -1].insertCell(); + particles.push(new Particle(n, tx, ty, xv, yv, parseInt(form["mass"].value))); + }else{ + errMsg += "Not enough room for that particle on the canvas! " + } + + reloadDropdowns(); + } + if(errMsg != "Errors: "){ + alert(errMsg); + } +} + +// Function that returns a radius, by multiplying the given mass by a constant +function getRadius(mass){ + return mass*0.8; +} + +// Function to remove a particle from the array by id +function remParticle(id){ + alert("remove"); + id = parseInt(id, 10); + + particles = particles.filter(function(element, i){ + eid = element.id; + + if(id == eid){ + table.deleteRow(i+1); + } + return id != eid; + }); + console.log(particles); +} + +// Function that adds the data at the current time to their respective array +function measureData(){ + measurement++; + let ekt = 0; + particles.forEach((elem, i) => { + ekt += 0.5*Math.pow(elem.v, 2)*elem.m; + // Ek=0.5mv^2, add to total + elem.ek.push(0.5*Math.pow(elem.v, 2)*elem.m); + measurementData.push(measurement); + + }) + ek.push(ekt.toPrecision(6)); + if(measurement > 100){ + measurement = 0; + measurementData = []; + measurementData.push('Time (s)'); + measurementData.push(0); + ek = []; + ek.push('Kientic Energy (J)'); + ek.push(0); + + particles.forEach((elem, i) => { + elem.ek = []; + elem.ek.push('Kientic Energy (J)'); + }) + } + drawKEChart(); +} + +// Function to draw the graph based on the selected values +function drawKEChart() { + //console.log(chartX); + let x = []; + if(chartX == "measurement"){ + x = [...measurementData]; + }else if(chartX == "ekt"){ + x = [...ek]; + }else{ + x = [...particles[parseInt(chartX, 10)-1].ek]; + } + + let y = []; + if(chartY == "measurement"){ + y = [...measurementData]; + }else if(chartY == "ekt"){ + y = [...ek]; + }else{ + y = [...particles[parseInt(chartY, 10)-1].ek]; + } + + var arr = []; + x.forEach((n, i) =>{ + arr.push([n, y[i]]); + }) + + var data = google.visualization.arrayToDataTable(arr); + + var options = { + title: 'Graph (Change X and Y Axis in the above form):', + legend: { position: 'bottom' } + }; + + var chart = new google.visualization.LineChart(document.getElementById('curve_chart')); + + chart.draw(data, options); + +} + +// Function called when static friction is changed, to make sure a valid number is selected +function sfrChange(){ + let element = document.getElementById("sfr"); + if(element.value >= 1){ + alert("The coefficient of static friction cannot be more than 1 for a billiard ball!"); + element.value = sfr; + }else if(element.value <= fr){ + alert("The coefficient of kinetic friction cannot be more than the coefficient of static friction!"); + element.value = sfr; + } + else{ + sfr = document.getElementById("sfr").value; + } +} + +// Function called when kinetic friction is changed, to make sure a valid number is selected +function frChange(){ + let element = document.getElementById("fr"); + if(element.value >= 1){ + alert("The coefficient of kinetic friction cannot be more than 1 for a billiard ball!"); + element.value = fr; + } + //else if(element.value >= sfr){ + // alert("The coefficient of kinetic friction cannot be more than the coefficient of static friction!"); + // element.value = fr; + //} + else{ + fr = element.value; + } +} + +// Function called when % effectiveness is changed, to make sure a valid number is selected +function effeChange(){ + let element = document.getElementById("effe"); + if(element.value > 100){ + alert("There cannot be more than 100% efficient collisions! "); + element.value = eff*100; + } + else if(element.value < 0){ + alert("There cannot be less than 0% effecient collisions! "); + element.value = eff*100; + }else{ + eff = element.value/100; + } +} + +// Function called to reset the dropdown menus when particles are added +function reloadDropdowns(){ + + let xSelect = document.getElementById("graphx"); + for(let i = 0; i < xSelect.options.length; i++){ + xSelect.options.remove(i); + i--; + } + + let ySelect = document.getElementById("graphy"); + for(let j = 0; j < ySelect.options.length; j++){ + ySelect.options.remove(j); + j--; + } + + let xtOption = document.createElement("option"); + xtOption.text = "Time" + xtOption.value = "measurement" + + let xeOption = document.createElement("option"); + xeOption.text = "Total Kinetic Energy" + xeOption.value = "ekt" + + let ytOption = document.createElement("option"); + ytOption.text = "Time" + ytOption.value = "measurement" + + let yeOption = document.createElement("option"); + yeOption.text = "Total Kinetic Energy" + yeOption.value = "ekt" + + xSelect.options.add(xtOption, 0); + xSelect.options.add(xeOption, 1); + + ySelect.options.add(ytOption, 1); + ySelect.options.add(yeOption, 0); + + particles.forEach((elem, i) =>{ + let temp = document.createElement("option"); + let temp2 = document.createElement("option"); + temp.text = "Particle " + (i+1).toString() + " Kinetic Energy" + temp.value = i+1; + temp2.text = "Particle " + (i+1).toString() + " Kinetic Energy" + temp2.value = i+1; + xSelect.options.add(temp, xSelect.options.length-1); + ySelect.options.add(temp2, ySelect.options.length-1); + }) +} + +function setVelocity(event){ + let x = event.clientX-25; + let y = event.clientX-25; + while(mouseIsDown){ + console.log(x); + } +} + +function doMouseDown(event){ + mouseIsDown = true; + setVelocity(event); +} + +function doMouseUp(event){ + alert(); + mouseIsDown = false; +} \ No newline at end of file diff --git a/shot.mp3 b/shot.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..58ab220ac4aa9885420637b81daeef68311d3df2 GIT binary patch literal 22040 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�kwd$!`8)h2hvbsOS`FmY>&88h3suacNgk7o1}1(jW}@ zc%#3ce?gv7dRE1nk-_o=(c~GDXVH7?Vif1&@b==c9WM9PTX%>dtM&Rr2T$|rCUQ%R-{uNeW0io~b$q5HLwi&5;V+skYv0ma#t+X) z=WiZIAa>60VKoREz>d>7uBdWpU=O}rT6Ig!)Eiy z%8%5YiYc$jFM_-K^J6D(^T2b7mfEX{@K%4asrkv)&+%Z^bwWu6*h)j9ZbA07*J^uB)2zu+e0u_bq&6r(Xqf{ducW`4!&Ohnx_q zf^V>b2+K{3VbG_$2hD2DwRuTY8gNJE_WT_4Uh};xIpw6W@nLrSiN|L*zlzQ@EeMA6OATu-_4l`|cV4_z=8&0sMNtFKo1<16XDKR*9zN>`q8 zP#1tg6vX6C8{q|ie7q);$N;bk(IasSNuue$IWCvTet;*+r!}XzDHlb@o=ADe;415D zCXA28iEEm0_1Qh(0J5eUv{VS8KkKAfVKiq35Ky>g%VouxsgSvo*;Y--(@b^B;Yd2I z*j=_2r(#DslB)I}ZZp4c3Lni78d@rMVSVSwah9GwRhO_n>(dlheq_jaFHcM)YSkl& z8&0+l-!D1*waopVw=R?ijTN!?s3{+YuFFp(Y)4J%NTFo%sR00}>q*N8ul5XT&<$i5 zHLMSY+QVL_mua>g1?&6fU+!7(k*+8heD|*d zO-o&lyuEm#0g~RC-71Bup&Da^~ z@zw+89!Bq=molUXQ<}$*G{J*Xp?rv1n>`Rus@GeOb>1SjpC%V8A=lYDQck){HP`Vc zjvUBS=*hySn_gEcNqD5;r?grbHcFd5WGYSicuU~_Buw+>>&jy`rge2wru%X~F8nf4 z@tCYF_hN9W$_Na&QcQp#a9$X@@Y%$%tVyfN=j%@3qH`s!{vtY)iOS3(IA&dT`Ck;m z06<-uFWB#MpJgIo0}2&oNTBGQky)FDN`t- ze!bc-LF~A|^X*GbBXG4B5%- zF$>%Uv`C}~HEtF*DiQ1{>Omohu|oqz@~ttm)h;Kh+Fns>A>=|PsIW^ z2{q6{`1BK;45EEJ)~dw^kUTT?dBx;JKHV9q`%H&2Oxszb~DtFc1QBPc{!jgr_$uwkLq2TvE@aqq`Do>5@Fj1@6{`v7WZv>AlvXb4~!6A&R|G0+* z05xSjqkcqq^KF{`nvKR&&HO8;64i+OU0vA&JApQQA%Wf4D6Y~j+@2Cfjk|$ajyU!#@R*5Ly zpH(b?xi=471ugpNlT9S?)7zzaZ22i&*OdJFT0Y?L)i9E_e!NYgxA+Su`0aCj2mH$1 z?3UXsIwkDs^K_*t$i;k>7q>ZxW=gz*2j3}&F46qx$Fi;IC%*HODs@v?N1TQsucMx% z7Y(wW6CRqyA_K|202=~vxQq%~vhhZ?%8&1Xh#_mwEaeBky*R)AahwMBTA5-Yu=S+` znPw%ZtVNmlR8!JnKNJ&DzXwm{m#aRd5y&yqK6~?6N@SVeW!mYk3Q<&&|LrLh@&KS& zi|0{&*lg<5lfjlSlwmdC=~^DVEFo)=b!iXXRnqQLwGd9uY@R;tv0P;GX_}!O=bHB; z?U=En&eLmmD9g+xuNIXFC|PmRaa!_gy+Q26(qosSZ1_9hm{6QUL9V%)pgIMq;D1P< z20)|P&S=6C-$gTaq7hL3Rj$n!KF(4--C;cm3`hOo$c@|Po!q=m(y|W)(dTu&vx31- zA3qI}#TxUZrG2QTIK*W}QH+vsIkY?nZpEES6pk7mlE2r$0(r&GQZ5a1QhLVbsV1qA zzCre#F~ta#UQ&&)N$gH3u@Yo~6md=|$uoM4F2?45w9IJpcW1C8C^G!mi99~U*Pcf7Oz<`S2;-#*{Q!LOYRw+;#ljC=fLxjw3^`BdcEoep*u+}FV z(O-4Y{;IbUu=C~P>}Ah@5{_i)a0ZQBn%uQHUje*u-o)Ap-lzxvKC+=`NYk7|ji}7f zK2VRY2~$)1t4@xp3DQ{R-mG!LqTvXcQ*mlrl=Taw?H&$3uKDAoWl?Zn^lr{^uibK3 z9-T~86y3Froz`Zxv!k~bLbjZ@S0(-xKCWIol~p1fG;h%T`XV>YPzqivMY| z|3@jSx0$yO{Zi#uMGr=yF;`757A?c~CckMYa~sHFn&`K0z6fT1@a3s5J5a)qaLU9d za~|a?l!z~euq%jO_STKqAo*4zwvvc0@DMXn2g1mdl?i}%D7d@gxunoUG?V8nVVqgE z|JN%iB&UcK2!_lXSn|w8eVdRSP%3uuQC&eXnB-A@gTC3=B zF^ndUs!FbyzB{tN#2cx3^v!=fK||IyaJWJU?{B{78~Ek$s(}I4b09}pB%76l7!v{z zBLUGb0fi<}0u>jIywi{&N{?<3Nwd@>nnp|@vZt$Ou@NvaZGoUf;c_H+j?5*7+$}R6 zlIx>gppKVmmjUweeax7^^~Sz*+Z<*3n%N;k$rCfI?EL|m0Kt%pt5yj z#u+CrZ04mKj;d>TUaPK^MP1LWv`#*~qs#nZx|QKUd_opStSmqwC>s0^ z310wEXSUOhP~3L`jQ)N2HcKl0nc~M;_PdwNwnF`&nO$#{uU~eq{4pb1nJa5JiXkjK}_vF6}H)}fEiu|})# zfRi$mI4X?#jj*YVtB11n-o$6V&bbrScuN5o)~tK*n3b8|QnQTZ<*wwg@5&8A&TZ@U z4el`-ijnNJk$Dr7TfnTV6n*7)0})=-xaMwG@6KjH-xwXs5e#3#rpDTNQ)t0yC+RW| zHNyN{iKSOS`5w80W#1`MG($%QKi|jnX`lZ9J_a5H2ML#6V}Ho~Ao;yb_*@G6@Bmvj zDpNcRE1{$m%q^uR8E{x8db~n8fEJ4>*ew{Eo!u4}st)GS4PCt}Q?&l^%(!8tf25us z>V+u>zfb;-j&GmsuT!l5BE>vA;pzP3>G7var-W|CmMTC4sHta=$nY|B^zl)QcB<(x zW&_aa_E!?VNp=M|6LeC3z5k^-xqT1$c>v$XEl ze@Gw=foe9Idx;?o@NnqZL8hTrVfGX~&hj`Np|*Z_$l_AvpqkqgfYyz`fZ4l@0w^Q| z_Hlv*q%@~M%Fo!(G?Lu<$Xe+2;R8^JS9|U<1k<7>4n04ih1X%tT+W*6s$H6B&0yrr z^~j3ozocj>mdKQ(S_H<02RRwpmtm$F%+)YKuJeA4+v$2hIVa916}l_E7#T(f;iqpU3`pGMp% z{5v#lA{Gl{qyvnW51u&Xpp$*qm`jmIvu^<#RbqY%pM_JXytSttaxQau)Q7*z^1>PT zN-)o!6Ryn%I5LFP0HVv|B=2j-ylM)j(fD16`rhuoYU^64F&t!w+_4Bz_!lNJ;2}yI zSY?oLsK4}3woI9x$8XHg3|nn*P>l)ylJQ>3En>xET0fp4)syh^Z`7vpgzLS~8evy; zaRczHV~2{V;t|=eFK?9GSHaA*tqRw-1GXU1i4DGW(&C1EyzFB zg8%&sf-wYYK}-4chz;KHj9*xo22t5uk-rSzaW}on#)}he=EqL(PQK^I>@UNJs9hmp z=zI-F>svR7zRyvIHft4mz+@xr{$4o~?~ zq1xz8{g1HXS(xW$AYAt5K~o-E)2;9bwm)sIhY!aGiNW9QmqzWJ@%0TKDk`r`pX+>c zNnOovRko~#yR~`V?}@KHO{%@WfqIFd6Dgw0*gk|EW%dBMmKxuMSn_u7hi5gX)nqO; zl>Vv;M;eY+;>ZQ*@uCT|AKH!Ez~Oc<_a7_Mmq{LMiOh(Wf}U@_BUXzY-$FV$dX$yq zr1^lzLySR1E0*JG$Yh@gv16kb+H$Ni%KQTHjfa3@*3@cazXv1J3L^|el;?KG_%2T#P+zKC%={H4TJd9-w;AGt>;z-R!Z+11{W`|o-Ib2V=;1VcSt(UiAuww9)+2#NlhVA z@=+OGsXp?%oxCRnf9@PBrNspf4Q(N323%(nd^ST@3lQ(y?yG>@Gvp8Z3z%Gmd48kj zr;IF>7L`2g;resN`g#(0-V)J8M3h}Xb4nF|1Myl;(Pi@Ntj5=h!tC4W+jhN;)*3T^ zW|^)RSawU&sqcrqxBR3raO5&Fx8o?Th^E&!25WgRIoWeDP;&8;Eu}yIrlmbbW9I+< z5=EM16&rGDY1wEKR>l*AXC^GC4Ndqr}F^bUGTPet1#`Fo9{2jh$GSS9*Vo?KpV6Zkz%BTgV_F;bk1F z%jFN{X?SrjIW%y!Er3^8NNahAiT0Y)&rjhU9&88*KFJ@72an0#iU1ANcsNW%@RDa` ztCXU6p0Tr#R0VbVju2f{Am@BrmkS-rPHL~5cptL9Uwt!IN%&JnM52X$KAWTsEYqz) zk+0PyOwaPF8$CukGv#?`j9CPKyWfChcd@+^uZ}+Zg33e1%AS)47z4h(=#hn&UV0AV zmpaS~pPj3^X-;GNTqJO292YD=t2#YUQ(4lfPTz;tP?6M?QUOwHA15Q&GgxpDTfj51 zJBzB?7v5&&4;KNC{g?Z6Ibs#&#;@YZRoY5Z9xKQC*AF|^n)nzjc`u%`C1M1NtJQ;( z-SrtLbkG~ng)#-41xqQ)DJaKEH}wmT??1EEO2iuZN2yqOy;93j?@K8OH)!kljP|R) zWt4h)ZTf}(Gk^12rk_=zJD4ouRBpWM7j#^C5eJjI|N7$+tYNhlNKk^-=qBhUQ zcGhYLLM(eHg8VE17kSljg^_>{_xxL3bXC^XE&Kwxx^9S|&*&N_mfnx_a22W)P}_WL zQxJH8-c~^<7+MZ(d`30tcHx_FU=P@#y74h26Twp2?pq)~G1=WiF;{Z50yVEg8v4jiYKv z{EA2AZahGD&nTgsc*~}u$doK$-YM5JVP@aGoDxv{wf>?bAN6H5z?&lyDlgZ!9?Kh! zCmx#6i-#aMN!W^<4)0Zt(%tkN1?9fmSFQyd3RubgBjoYHc`L7 ziUeNi(K3m`2e=cZVZXb2#|GwdR26UiDKx7)jDX-_8yO2c0OP9}f!{=v15E6-JqvRi zc9GKO;vs?A@H;j}uLlH(=+`YfsbeR3t@gGprYeD#Httpfw%8gzJOo?YvdZwHcy&@z zF&=)7Y1SJ@>1VLEw0&=xQhQYJ^X7#u#h_nOwG$UEmkT&)+bM#_1aCev^rDcS6|MfF zN_3w(mv|&SDq5795*C+PRux#26}n5z&#|*#4lp6~u+M0WK7wQN^NgB^0J3sr^0}{z zMPrLX!i&25EPU!2>1Av%rKATen$qvD*@P?h7;#$XvJR5|?J48sGI608l6vy;ns7iN zdNA?Oz3X;WmK`ybJAHbMwXek5G!|olpI=TwXr6n03xO+#_*7d-MVV zq6u`j{X}a~9TH{8lFAV@@k_YgD9k|66P_vkpm?y~=&|)o?dyU|Z+Kbh)vgGp8CYt^ zn8}2e>X~NAiL8U)VIuqwRhsYsT>6pJ%)7Y*mlPMuyK3fqD_=?m+xy~L4-ploH)c9a z_ylFr)eq&232KDw$+LA>)w|#Sk`r}W-Sb)ict8Q2_z!n(p=?GMoOqe1KttRyDQMcWJ-D`j+6hlhEHT?h&TeC$kLz z-=2Huf;LN33f0twD9C#;k~4<)YI^p)R~ZbCOedLS9xMD930*xw9M(jHtOLN}L+2(k zinOWm@loHGkz zan*s&0a?OjB@fQ`#Ar=&9(Xk8m<(x|!3&;k%qoD#II2lb%g(Fj^k? zA1kqn__u`ml$BsKPgm{6e03rCt!6)Bj|@!zB_nFuhts}0y3JcCu!n`teeH3*=+07O zQJ(4Ypz!(z9L<%zRf7lQ3UYg_9!?jPH;237lMa%n)TFODr%+nWFUGsWyMB^F>qWN( zK)nf6KFJY)w1bX%WAeFLIxJ@;?iY(1ymTlNsyO@AivhvG$->tZ;`Q#&=UK8O@W3)~ z-WPW|bTs6QY+-$$NZB<}w?ioe4HGS=$=Pxkaj}SbC76Ix1fX$Wmi%iAtZxq@gB};q zTf-c}5$&a!-#1-d3NQRw7%1OwKtsd zw+)Z@$KEOWR5^&nbObK6%r)Uqul;uK?p(2OJ{XHl4( zYk2(_L>%954iE))6cnB;W*$mnn3iR&&I0O(1R6o7FM zJeKw5kBkgs?OPW{^`bx1OTlPZU?XN{OJN?1sbs3k@b)^oSR#O)rT0^h&?krg8l zDTy*zBe1^U#nGD}pb$8xt7r-N8X<#BY(gi)pxIL5)^}c}B~=FB+xGM9psvMj*#ZC! zusX|C(@+Oj;U|A_$&>QYG*cfUD@~;yfN{LE+TRr`OQeMoqQ3@upXMWr`eShZwBAMIpq=JW>b|2y~ZDOq*&V=axiFW<|bIY92n5 z>ve>qqJ2){0T{rMAkCgsLnM#3ZMNF^9a+tH1I(C%@H7Tz68fO5MamR3_#Cb;czs0WE1%?I^H3m469!R|CshUOK6=9ZFHDf z&wldaG>O3DBboROa?m`#1)(#2FsKkr0dkfS<3qTfw9*75^52eOXdHCQ*7M7zT3)0` z9-k@E1KlI2D@W|sfVMLKp_%VkW+tOp$cPpz>b^F^w0f)ES}1hAg^Z^8bj%-pD;r}0 z%nZORqs81gWJ*A=!aZj*5rJbLs3ibF{d))4ZDgf!%rhIS0A6yxp_8iC?rGxXUT7o& zETDe%)Lj-~;T?Ly`j1{&1|&OOcF5!@qb$jz+CZPTCJG_Eh?)aL0B8=4#3`e;0A>(~ zhiQEBz4qw19X!DS@K#YD2>2muJ?-j_FX~G^T|b|Fkl=yePhF0MBiEC>?Kv3W3U10s z1}gYqM9Lh^w!ssIGd>_VT6Yd@FG7rs%f+1W6LS5#o!Ca`g+zd_4(-&>JAUI|o`@Lv zWOhWR!fm`V3#fu!dSc))+M5kYt_J#Ygjo@yWO@NW6ao#UVuKOT@c^-jiY?RnSx4Ok z{M%=}IRW?hN=c>E4xdPICB3qXGrwz+NCNLtXs4Y;&=EU>gq>%RbGVu0}KsYZ7EYeej zphD9@BTAtnAd;!PB;7 z1SbE((|V_p4eCvwll~-=haLuet-n`O^7ucoK+p8nNx07&!uNugLT^RI1`UQt5~y+N zNcJ$Mvg4=)D?@EqJ9q~n>hUkH*qx*rjYvv2WZsDYYk&w)dMfG3Hv`Dbb8$kDp|#v5 z+s?Y)rqD46R!Taq!gB=VW7M~pD4lk?$1`Lha35u4{8`E=fl=yl~-+c4VDR0Pl@;G3S1F-e-13WYU4TPp3NsIyupv0tNc7c=? zXXd#XDh5Y!JuYE(i7UJgqMnRmv6kibOSyi)B0_pj7LfTFCeoQTWOJr1+v<8}QJ?n9 zv=SR9Pcp^%gdF)0>{qQK9_}Hd$5&xEH%-M1{?7W%Yw;7{i4B!4=zJp)QehwJoHqF! zQz@^f*{S(UsXXsZ)2XVM5gl862Hp_<94_sPp8=5~=n6y_2lFA=lZnOv0_LxEqZkm# z!dA@oNW|v)3AENJr*Cn7gv7bwsN?e{!9JaVLy6ZYYKt%8LzXZ16qyDDFWo>&;B!H%Ff|c&j>E=zvqXSKP^)b)LMuC-Ma7j{-5KiwETbb0y}*U k8_N#>@S*ZSHK1WaQ>S?9UP?Ws9x9Ll0QTRm{r|N84=GsUtN;K2 literal 0 HcmV?d00001 diff --git a/wallhit.mp3 b/wallhit.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..da98b90e0a014e4d89b97860de3607ce7f3a66a2 GIT binary patch literal 1896 zcmds%X;9Ng7{)h;A%OtlP(Y8AeCcm30Ip55rM%p z2yHBJdBXsp6c79rWGc9 zxH%yV7?L9U3Q4i>Hj*rF{g66hfu!P$f&uLaYMvM42+V^~Uj29M;H7g69hN2yG>SWp zakC2;Yr-?!(bh^4U)eRswa@$@H55f25_^t~SGUT%w@1Cdp^2hVSRl%vff3`JxBbOV zSW=E)9yL66;dk1LxrbCNJQS&7*ta)o)ky089L|W;M;(BHNMlV(ye?9YP;V#Ii_)eS zMTGKqvFcd>XK?Cp*SD~$A(Rq{q*QzKdlsuvtm}@YP_#uoYFspnDoVp((UeSI$rGQ# zjW7(n-?8P%`Pmw{pUxf_{K0PLd=XG#JCpXq@87fVuHnTudLLhs^oI|H+sBy4Ud{>& z)}!7i`?>tw*U&cfrfu_*<&br+jm;;$KOP-ec6ikQt=ybw8{NP<1?Si1ie<64mQqYl zF{khRar)Ki6TxP^ijVr=h+;L?V*Ci;0sO{xpVq^wvZ)wbq{u5u`)qs5+7vI)h_IsvPDum(aNhcb{}h^e2sZ10_Mjt6?KfzV)Rym|j^)7dWf) z7LFB@lERk1-fU*uLuP5xs!p9un%8;*z;p5Ng-sE(6)=bd*y86_jpdlTL=9r+cYNS) zmod;))L!o<3CzeM(lv*8X{TwcmZkRQDdPI!;viGaT>(p!N26GJatJ-*c`V1_8UNOV z)TAeB{|nl<^8LkMzG_^ol$d(fr8{Nt3z(Ua;V*l}FG3!+YmEC^r3+Up{)t2p1?ZP# z7qgTr1xw(`RJNo@eIF>G<$wJG3eMF z`HQkgV*~BYNWsMQC1}fV5YGC1CgGqkUp$kGjV6n@=Q|j{+Vh%l>=4^MA-FWFs3`^t z;;>i)g4QPEbwS;Xvd-CqG;=i`GGAC>5P|wL8SeuKGCUgzD?Ci>hRNeW zl8A`wUGG_q38Ys9Y|MJ$0U}WzfD>W}s-bzFa*@|eGC{vrBgMOFtacJ%cCWf22&Wi#+6VEVEME^nqGp zvwN3-It~Gi4IhVaKR`+%(Ss literal 0 HcmV?d00001