<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <style>
        .mobile-message {
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 20px;
            font-size: 24px;
            color: #333;
        }
    </style>
    <script>
        function isMobile() {
            return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
        }
        if (isMobile()) {
            document.addEventListener('DOMContentLoaded', function() {
                document.body.innerHTML = "<div class='mobile-message'><h1>Доступ разрешен только с компьютера</h1></div>";
            });
        }
    </script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Виртуальная лабораторная работа</title>
    <link rel="icon" type="image/x-icon" href="extra/favicon.ico">
    <script>
        !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("Matter",[],t):"object"==typeof exports?exports.Matter=t():e.Matter=t()}(this,(function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=22)}([function(e,t){var n={};e.exports=n,function(){n._nextId=0,n._seed=0,n._nowStartTime=+new Date,n._warnedOnce={},n._decomp=null,n.extend=function(e,t){var i,o;"boolean"==typeof t?(i=2,o=t):(i=1,o=!0);for(var r=i;r<arguments.length;r++){var a=arguments[r];if(a)for(var s in a)o&&a[s]&&a[s].constructor===Object?e[s]&&e[s].constructor!==Object?e[s]=a[s]:(e[s]=e[s]||{},n.extend(e[s],o,a[s])):e[s]=a[s]}return e},n.clone=function(e,t){return n.extend({},t,e)},n.keys=function(e){if(Object.keys)return Object.keys(e);var t=[];for(var n in e)t.push(n);return t},n.values=function(e){var t=[];if(Object.keys){for(var n=Object.keys(e),i=0;i<n.length;i++)t.push(e[n[i]]);return t}for(var o in e)t.push(e[o]);return t},n.get=function(e,t,n,i){t=t.split(".").slice(n,i);for(var o=0;o<t.length;o+=1)e=e[t[o]];return e},n.set=function(e,t,i,o,r){var a=t.split(".").slice(o,r);return n.get(e,t,0,-1)[a[a.length-1]]=i,i},n.shuffle=function(e){for(var t=e.length-1;t>0;t--){var i=Math.floor(n.random()*(t+1)),o=e[t];e[t]=e[i],e[i]=o}return e},n.choose=function(e){return e[Math.floor(n.random()*e.length)]},n.isElement=function(e){return"undefined"!=typeof HTMLElement?e instanceof HTMLElement:!!(e&&e.nodeType&&e.nodeName)},n.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},n.isFunction=function(e){return"function"==typeof e},n.isPlainObject=function(e){return"object"==typeof e&&e.constructor===Object},n.isString=function(e){return"[object String]"===toString.call(e)},n.clamp=function(e,t,n){return e<t?t:e>n?n:e},n.sign=function(e){return e<0?-1:1},n.now=function(){if("undefined"!=typeof window&&window.performance){if(window.performance.now)return window.performance.now();if(window.performance.webkitNow)return window.performance.webkitNow()}return Date.now?Date.now():new Date-n._nowStartTime},n.random=function(t,n){return n=void 0!==n?n:1,(t=void 0!==t?t:0)+e()*(n-t)};var e=function(){return n._seed=(9301*n._seed+49297)%233280,n._seed/233280};n.colorToNumber=function(e){return 3==(e=e.replace("#","")).length&&(e=e.charAt(0)+e.charAt(0)+e.charAt(1)+e.charAt(1)+e.charAt(2)+e.charAt(2)),parseInt(e,16)},n.logLevel=1,n.log=function(){console&&n.logLevel>0&&n.logLevel<=3&&console.log.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},n.info=function(){console&&n.logLevel>0&&n.logLevel<=2&&console.info.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},n.warn=function(){console&&n.logLevel>0&&n.logLevel<=3&&console.warn.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},n.warnOnce=function(){var e=Array.prototype.slice.call(arguments).join(" ");n._warnedOnce[e]||(n.warn(e),n._warnedOnce[e]=!0)},n.deprecated=function(e,t,i){e[t]=n.chain((function(){n.warnOnce("🔅 deprecated 🔅",i)}),e[t])},n.nextId=function(){return n._nextId++},n.indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;n<e.length;n++)if(e[n]===t)return n;return-1},n.map=function(e,t){if(e.map)return e.map(t);for(var n=[],i=0;i<e.length;i+=1)n.push(t(e[i]));return n},n.topologicalSort=function(e){var t=[],i=[],o=[];for(var r in e)i[r]||o[r]||n._topologicalSort(r,i,o,e,t);return t},n._topologicalSort=function(e,t,i,o,r){var a=o[e]||[];i[e]=!0;for(var s=0;s<a.length;s+=1){var l=a[s];i[l]||(t[l]||n._topologicalSort(l,t,i,o,r))}i[e]=!1,t[e]=!0,r.push(e)},n.chain=function(){for(var e=[],t=0;t<arguments.length;t+=1){var n=arguments[t];n._chained?e.push.apply(e,n._chained):e.push(n)}var i=function(){for(var t,n=new Array(arguments.length),i=0,o=arguments.length;i<o;i++)n[i]=arguments[i];for(i=0;i<e.length;i+=1){var r=e[i].apply(t,n);void 0!==r&&(t=r)}return t};return i._chained=e,i},n.chainPathBefore=function(e,t,i){return n.set(e,t,n.chain(i,n.get(e,t)))},n.chainPathAfter=function(e,t,i){return n.set(e,t,n.chain(n.get(e,t),i))},n.setDecomp=function(e){n._decomp=e},n.getDecomp=function(){var e=n._decomp;try{e||"undefined"==typeof window||(e=window.decomp),e||"undefined"==typeof global||(e=global.decomp)}catch(t){e=null}return e}}()},function(e,t){var n={};e.exports=n,n.create=function(e){var t={min:{x:0,y:0},max:{x:0,y:0}};return e&&n.update(t,e),t},n.update=function(e,t,n){e.min.x=1/0,e.max.x=-1/0,e.min.y=1/0,e.max.y=-1/0;for(var i=0;i<t.length;i++){var o=t[i];o.x>e.max.x&&(e.max.x=o.x),o.x<e.min.x&&(e.min.x=o.x),o.y>e.max.y&&(e.max.y=o.y),o.y<e.min.y&&(e.min.y=o.y)}n&&(n.x>0?e.max.x+=n.x:e.min.x+=n.x,n.y>0?e.max.y+=n.y:e.min.y+=n.y)},n.contains=function(e,t){return t.x>=e.min.x&&t.x<=e.max.x&&t.y>=e.min.y&&t.y<=e.max.y},n.overlaps=function(e,t){return e.min.x<=t.max.x&&e.max.x>=t.min.x&&e.max.y>=t.min.y&&e.min.y<=t.max.y},n.translate=function(e,t){e.min.x+=t.x,e.max.x+=t.x,e.min.y+=t.y,e.max.y+=t.y},n.shift=function(e,t){var n=e.max.x-e.min.x,i=e.max.y-e.min.y;e.min.x=t.x,e.max.x=t.x+n,e.min.y=t.y,e.max.y=t.y+i}},function(e,t){var n={};e.exports=n,n.create=function(e,t){return{x:e||0,y:t||0}},n.clone=function(e){return{x:e.x,y:e.y}},n.magnitude=function(e){return Math.sqrt(e.x*e.x+e.y*e.y)},n.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y},n.rotate=function(e,t,n){var i=Math.cos(t),o=Math.sin(t);n||(n={});var r=e.x*i-e.y*o;return n.y=e.x*o+e.y*i,n.x=r,n},n.rotateAbout=function(e,t,n,i){var o=Math.cos(t),r=Math.sin(t);i||(i={});var a=n.x+((e.x-n.x)*o-(e.y-n.y)*r);return i.y=n.y+((e.x-n.x)*r+(e.y-n.y)*o),i.x=a,i},n.normalise=function(e){var t=n.magnitude(e);return 0===t?{x:0,y:0}:{x:e.x/t,y:e.y/t}},n.dot=function(e,t){return e.x*t.x+e.y*t.y},n.cross=function(e,t){return e.x*t.y-e.y*t.x},n.cross3=function(e,t,n){return(t.x-e.x)*(n.y-e.y)-(t.y-e.y)*(n.x-e.x)},n.add=function(e,t,n){return n||(n={}),n.x=e.x+t.x,n.y=e.y+t.y,n},n.sub=function(e,t,n){return n||(n={}),n.x=e.x-t.x,n.y=e.y-t.y,n},n.mult=function(e,t){return{x:e.x*t,y:e.y*t}},n.div=function(e,t){return{x:e.x/t,y:e.y/t}},n.perp=function(e,t){return{x:(t=!0===t?-1:1)*-e.y,y:t*e.x}},n.neg=function(e){return{x:-e.x,y:-e.y}},n.angle=function(e,t){return Math.atan2(t.y-e.y,t.x-e.x)},n._temp=[n.create(),n.create(),n.create(),n.create(),n.create(),n.create()]},function(e,t,n){var i={};e.exports=i;var o=n(2),r=n(0);i.create=function(e,t){for(var n=[],i=0;i<e.length;i++){var o=e[i],r={x:o.x,y:o.y,index:i,body:t,isInternal:!1};n.push(r)}return n},i.fromPath=function(e,t){var n=[];return e.replace(/L?\s*([-\d.e]+)[\s,]*([-\d.e]+)*/gi,(function(e,t,i){n.push({x:parseFloat(t),y:parseFloat(i)})})),i.create(n,t)},i.centre=function(e){for(var t,n,r,a=i.area(e,!0),s={x:0,y:0},l=0;l<e.length;l++)r=(l+1)%e.length,t=o.cross(e[l],e[r]),n=o.mult(o.add(e[l],e[r]),t),s=o.add(s,n);return o.div(s,6*a)},i.mean=function(e){for(var t={x:0,y:0},n=0;n<e.length;n++)t.x+=e[n].x,t.y+=e[n].y;return o.div(t,e.length)},i.area=function(e,t){for(var n=0,i=e.length-1,o=0;o<e.length;o++)n+=(e[i].x-e[o].x)*(e[i].y+e[o].y),i=o;return t?n/2:Math.abs(n)/2},i.inertia=function(e,t){for(var n,i,r=0,a=0,s=e,l=0;l<s.length;l++)i=(l+1)%s.length,r+=(n=Math.abs(o.cross(s[i],s[l])))*(o.dot(s[i],s[i])+o.dot(s[i],s[l])+o.dot(s[l],s[l])),a+=n;return t/6*(r/a)},i.translate=function(e,t,n){var i;if(n)for(i=0;i<e.length;i++)e[i].x+=t.x*n,e[i].y+=t.y*n;else for(i=0;i<e.length;i++)e[i].x+=t.x,e[i].y+=t.y;return e},i.rotate=function(e,t,n){if(0!==t){for(var i=Math.cos(t),o=Math.sin(t),r=0;r<e.length;r++){var a=e[r],s=a.x-n.x,l=a.y-n.y;a.x=n.x+(s*i-l*o),a.y=n.y+(s*o+l*i)}return e}},i.contains=function(e,t){for(var n=0;n<e.length;n++){var i=e[n],o=e[(n+1)%e.length];if((t.x-i.x)*(o.y-i.y)+(t.y-i.y)*(i.x-o.x)>0)return!1}return!0},i.scale=function(e,t,n,r){if(1===t&&1===n)return e;var a,s;r=r||i.centre(e);for(var l=0;l<e.length;l++)a=e[l],s=o.sub(a,r),e[l].x=r.x+s.x*t,e[l].y=r.y+s.y*n;return e},i.chamfer=function(e,t,n,i,a){t="number"==typeof t?[t]:t||[8],n=void 0!==n?n:-1,i=i||2,a=a||14;for(var s=[],l=0;l<e.length;l++){var c=e[l-1>=0?l-1:e.length-1],u=e[l],d=e[(l+1)%e.length],p=t[l<t.length?l:t.length-1];if(0!==p){var f=o.normalise({x:u.y-c.y,y:c.x-u.x}),v=o.normalise({x:d.y-u.y,y:u.x-d.x}),m=Math.sqrt(2*Math.pow(p,2)),y=o.mult(r.clone(f),p),g=o.normalise(o.mult(o.add(f,v),.5)),x=o.sub(u,o.mult(g,m)),h=n;-1===n&&(h=1.75*Math.pow(p,.32)),(h=r.clamp(h,i,a))%2==1&&(h+=1);for(var b=Math.acos(o.dot(f,v))/h,S=0;S<h;S++)s.push(o.add(o.rotate(y,b*S),x))}else s.push(u)}return s},i.clockwiseSort=function(e){var t=i.mean(e);return e.sort((function(e,n){return o.angle(t,e)-o.angle(t,n)})),e},i.isConvex=function(e){var t,n,i,o,r=0,a=e.length;if(a<3)return null;for(t=0;t<a;t++)if(i=(t+2)%a,o=(e[n=(t+1)%a].x-e[t].x)*(e[i].y-e[n].y),(o-=(e[n].y-e[t].y)*(e[i].x-e[n].x))<0?r|=1:o>0&&(r|=2),3===r)return!1;return 0!==r||null},i.hull=function(e){var t,n,i=[],r=[];for((e=e.slice(0)).sort((function(e,t){var n=e.x-t.x;return 0!==n?n:e.y-t.y})),n=0;n<e.length;n+=1){for(t=e[n];r.length>=2&&o.cross3(r[r.length-2],r[r.length-1],t)<=0;)r.pop();r.push(t)}for(n=e.length-1;n>=0;n-=1){for(t=e[n];i.length>=2&&o.cross3(i[i.length-2],i[i.length-1],t)<=0;)i.pop();i.push(t)}return i.pop(),r.pop(),i.concat(r)}},function(e,t,n){var i={};e.exports=i;var o=n(0);i.on=function(e,t,n){for(var i,o=t.split(" "),r=0;r<o.length;r++)i=o[r],e.events=e.events||{},e.events[i]=e.events[i]||[],e.events[i].push(n);return n},i.off=function(e,t,n){if(t){"function"==typeof t&&(n=t,t=o.keys(e.events).join(" "));for(var i=t.split(" "),r=0;r<i.length;r++){var a=e.events[i[r]],s=[];if(n&&a)for(var l=0;l<a.length;l++)a[l]!==n&&s.push(a[l]);e.events[i[r]]=s}}else e.events={}},i.trigger=function(e,t,n){var i,r,a,s,l=e.events;if(l&&o.keys(l).length>0){n||(n={}),i=t.split(" ");for(var c=0;c<i.length;c++)if(a=l[r=i[c]]){(s=o.clone(n,!1)).name=r,s.source=e;for(var u=0;u<a.length;u++)a[u].apply(e,[s])}}}},function(e,t,n){var i={};e.exports=i;var o=n(4),r=n(0),a=n(1),s=n(6);i.create=function(e){return r.extend({id:r.nextId(),type:"composite",parent:null,isModified:!1,bodies:[],constraints:[],composites:[],label:"Composite",plugin:{}},e)},i.setModified=function(e,t,n,o){if(e.isModified=t,n&&e.parent&&i.setModified(e.parent,t,n,o),o)for(var r=0;r<e.composites.length;r++){var a=e.composites[r];i.setModified(a,t,n,o)}},i.add=function(e,t){var n=[].concat(t);o.trigger(e,"beforeAdd",{object:t});for(var a=0;a<n.length;a++){var s=n[a];switch(s.type){case"body":if(s.parent!==s){r.warn("Composite.add: skipped adding a compound body part (you must add its parent instead)");break}i.addBody(e,s);break;case"constraint":i.addConstraint(e,s);break;case"composite":i.addComposite(e,s);break;case"mouseConstraint":i.addConstraint(e,s.constraint)}}return o.trigger(e,"afterAdd",{object:t}),e},i.remove=function(e,t,n){var r=[].concat(t);o.trigger(e,"beforeRemove",{object:t});for(var a=0;a<r.length;a++){var s=r[a];switch(s.type){case"body":i.removeBody(e,s,n);break;case"constraint":i.removeConstraint(e,s,n);break;case"composite":i.removeComposite(e,s,n);break;case"mouseConstraint":i.removeConstraint(e,s.constraint)}}return o.trigger(e,"afterRemove",{object:t}),e},i.addComposite=function(e,t){return e.composites.push(t),t.parent=e,i.setModified(e,!0,!0,!1),e},i.removeComposite=function(e,t,n){var o=r.indexOf(e.composites,t);if(-1!==o&&(i.removeCompositeAt(e,o),i.setModified(e,!0,!0,!1)),n)for(var a=0;a<e.composites.length;a++)i.removeComposite(e.composites[a],t,!0);return e},i.removeCompositeAt=function(e,t){return e.composites.splice(t,1),i.setModified(e,!0,!0,!1),e},i.addBody=function(e,t){return e.bodies.push(t),i.setModified(e,!0,!0,!1),e},i.removeBody=function(e,t,n){var o=r.indexOf(e.bodies,t);if(-1!==o&&(i.removeBodyAt(e,o),i.setModified(e,!0,!0,!1)),n)for(var a=0;a<e.composites.length;a++)i.removeBody(e.composites[a],t,!0);return e},i.removeBodyAt=function(e,t){return e.bodies.splice(t,1),i.setModified(e,!0,!0,!1),e},i.addConstraint=function(e,t){return e.constraints.push(t),i.setModified(e,!0,!0,!1),e},i.removeConstraint=function(e,t,n){var o=r.indexOf(e.constraints,t);if(-1!==o&&i.removeConstraintAt(e,o),n)for(var a=0;a<e.composites.length;a++)i.removeConstraint(e.composites[a],t,!0);return e},i.removeConstraintAt=function(e,t){return e.constraints.splice(t,1),i.setModified(e,!0,!0,!1),e},i.clear=function(e,t,n){if(n)for(var o=0;o<e.composites.length;o++)i.clear(e.composites[o],t,!0);return t?e.bodies=e.bodies.filter((function(e){return e.isStatic})):e.bodies.length=0,e.constraints.length=0,e.composites.length=0,i.setModified(e,!0,!0,!1),e},i.allBodies=function(e){for(var t=[].concat(e.bodies),n=0;n<e.composites.length;n++)t=t.concat(i.allBodies(e.composites[n]));return t},i.allConstraints=function(e){for(var t=[].concat(e.constraints),n=0;n<e.composites.length;n++)t=t.concat(i.allConstraints(e.composites[n]));return t},i.allComposites=function(e){for(var t=[].concat(e.composites),n=0;n<e.composites.length;n++)t=t.concat(i.allComposites(e.composites[n]));return t},i.get=function(e,t,n){var o,r;switch(n){case"body":o=i.allBodies(e);break;case"constraint":o=i.allConstraints(e);break;case"composite":o=i.allComposites(e).concat(e)}return o?0===(r=o.filter((function(e){return e.id.toString()===t.toString()}))).length?null:r[0]:null},i.move=function(e,t,n){return i.remove(e,t),i.add(n,t),e},i.rebase=function(e){for(var t=i.allBodies(e).concat(i.allConstraints(e)).concat(i.allComposites(e)),n=0;n<t.length;n++)t[n].id=r.nextId();return i.setModified(e,!0,!0,!1),e},i.translate=function(e,t,n){for(var o=n?i.allBodies(e):e.bodies,r=0;r<o.length;r++)s.translate(o[r],t);return i.setModified(e,!0,!0,!1),e},i.rotate=function(e,t,n,o){for(var r=Math.cos(t),a=Math.sin(t),l=o?i.allBodies(e):e.bodies,c=0;c<l.length;c++){var u=l[c],d=u.position.x-n.x,p=u.position.y-n.y;s.setPosition(u,{x:n.x+(d*r-p*a),y:n.y+(d*a+p*r)}),s.rotate(u,t)}return i.setModified(e,!0,!0,!1),e},i.scale=function(e,t,n,o,r){for(var a=r?i.allBodies(e):e.bodies,l=0;l<a.length;l++){var c=a[l],u=c.position.x-o.x,d=c.position.y-o.y;s.setPosition(c,{x:o.x+u*t,y:o.y+d*n}),s.scale(c,t,n)}return i.setModified(e,!0,!0,!1),e},i.bounds=function(e){for(var t=i.allBodies(e),n=[],o=0;o<t.length;o+=1){var r=t[o];n.push(r.bounds.min,r.bounds.max)}return a.create(n)}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(2),a=n(7),s=(n(16),n(0)),l=n(1),c=n(10);!function(){i._inertiaScale=4,i._nextCollidingGroupId=1,i._nextNonCollidingGroupId=-1,i._nextCategory=1,i.create=function(t){var n={id:s.nextId(),type:"body",label:"Body",parts:[],plugin:{},angle:0,vertices:o.fromPath("L 0 0 L 40 0 L 40 40 L 0 40"),position:{x:0,y:0},force:{x:0,y:0},torque:0,positionImpulse:{x:0,y:0},constraintImpulse:{x:0,y:0,angle:0},totalContacts:0,speed:0,angularSpeed:0,velocity:{x:0,y:0},angularVelocity:0,isSensor:!1,isStatic:!1,isSleeping:!1,motion:0,sleepThreshold:60,density:.001,restitution:0,friction:.1,frictionStatic:.5,frictionAir:.01,collisionFilter:{category:1,mask:4294967295,group:0},slop:.05,timeScale:1,render:{visible:!0,opacity:1,strokeStyle:null,fillStyle:null,lineWidth:null,sprite:{xScale:1,yScale:1,xOffset:0,yOffset:0}},events:null,bounds:null,chamfer:null,circleRadius:0,positionPrev:null,anglePrev:0,parent:null,axes:null,area:0,mass:0,inertia:0,_original:null},i=s.extend(n,t);return e(i,t),i},i.nextGroup=function(e){return e?i._nextNonCollidingGroupId--:i._nextCollidingGroupId++},i.nextCategory=function(){return i._nextCategory=i._nextCategory<<1,i._nextCategory};var e=function(e,t){t=t||{},i.set(e,{bounds:e.bounds||l.create(e.vertices),positionPrev:e.positionPrev||r.clone(e.position),anglePrev:e.anglePrev||e.angle,vertices:e.vertices,parts:e.parts||[e],isStatic:e.isStatic,isSleeping:e.isSleeping,parent:e.parent||e}),o.rotate(e.vertices,e.angle,e.position),c.rotate(e.axes,e.angle),l.update(e.bounds,e.vertices,e.velocity),i.set(e,{axes:t.axes||e.axes,area:t.area||e.area,mass:t.mass||e.mass,inertia:t.inertia||e.inertia});var n=e.isStatic?"#14151f":s.choose(["#f19648","#f5d259","#f55a3c","#063e7b","#ececd1"]),a=e.isStatic?"#555":"#ccc",u=e.isStatic&&null===e.render.fillStyle?1:0;e.render.fillStyle=e.render.fillStyle||n,e.render.strokeStyle=e.render.strokeStyle||a,e.render.lineWidth=e.render.lineWidth||u,e.render.sprite.xOffset+=-(e.bounds.min.x-e.position.x)/(e.bounds.max.x-e.bounds.min.x),e.render.sprite.yOffset+=-(e.bounds.min.y-e.position.y)/(e.bounds.max.y-e.bounds.min.y)};i.set=function(e,t,n){var o;for(o in"string"==typeof t&&(o=t,(t={})[o]=n),t)if(Object.prototype.hasOwnProperty.call(t,o))switch(n=t[o],o){case"isStatic":i.setStatic(e,n);break;case"isSleeping":a.set(e,n);break;case"mass":i.setMass(e,n);break;case"density":i.setDensity(e,n);break;case"inertia":i.setInertia(e,n);break;case"vertices":i.setVertices(e,n);break;case"position":i.setPosition(e,n);break;case"angle":i.setAngle(e,n);break;case"velocity":i.setVelocity(e,n);break;case"angularVelocity":i.setAngularVelocity(e,n);break;case"parts":i.setParts(e,n);break;case"centre":i.setCentre(e,n);break;default:e[o]=n}},i.setStatic=function(e,t){for(var n=0;n<e.parts.length;n++){var i=e.parts[n];i.isStatic=t,t?(i._original={restitution:i.restitution,friction:i.friction,mass:i.mass,inertia:i.inertia,density:i.density,inverseMass:i.inverseMass,inverseInertia:i.inverseInertia},i.restitution=0,i.friction=1,i.mass=i.inertia=i.density=1/0,i.inverseMass=i.inverseInertia=0,i.positionPrev.x=i.position.x,i.positionPrev.y=i.position.y,i.anglePrev=i.angle,i.angularVelocity=0,i.speed=0,i.angularSpeed=0,i.motion=0):i._original&&(i.restitution=i._original.restitution,i.friction=i._original.friction,i.mass=i._original.mass,i.inertia=i._original.inertia,i.density=i._original.density,i.inverseMass=i._original.inverseMass,i.inverseInertia=i._original.inverseInertia,i._original=null)}},i.setMass=function(e,t){var n=e.inertia/(e.mass/6);e.inertia=n*(t/6),e.inverseInertia=1/e.inertia,e.mass=t,e.inverseMass=1/e.mass,e.density=e.mass/e.area},i.setDensity=function(e,t){i.setMass(e,t*e.area),e.density=t},i.setInertia=function(e,t){e.inertia=t,e.inverseInertia=1/e.inertia},i.setVertices=function(e,t){t[0].body===e?e.vertices=t:e.vertices=o.create(t,e),e.axes=c.fromVertices(e.vertices),e.area=o.area(e.vertices),i.setMass(e,e.density*e.area);var n=o.centre(e.vertices);o.translate(e.vertices,n,-1),i.setInertia(e,i._inertiaScale*o.inertia(e.vertices,e.mass)),o.translate(e.vertices,e.position),l.update(e.bounds,e.vertices,e.velocity)},i.setParts=function(e,t,n){var r;for(t=t.slice(0),e.parts.length=0,e.parts.push(e),e.parent=e,r=0;r<t.length;r++){var a=t[r];a!==e&&(a.parent=e,e.parts.push(a))}if(1!==e.parts.length){if(n=void 0===n||n){var s=[];for(r=0;r<t.length;r++)s=s.concat(t[r].vertices);o.clockwiseSort(s);var l=o.hull(s),c=o.centre(l);i.setVertices(e,l),o.translate(e.vertices,c)}var u=i._totalProperties(e);e.area=u.area,e.parent=e,e.position.x=u.centre.x,e.position.y=u.centre.y,e.positionPrev.x=u.centre.x,e.positionPrev.y=u.centre.y,i.setMass(e,u.mass),i.setInertia(e,u.inertia),i.setPosition(e,u.centre)}},i.setCentre=function(e,t,n){n?(e.positionPrev.x+=t.x,e.positionPrev.y+=t.y,e.position.x+=t.x,e.position.y+=t.y):(e.positionPrev.x=t.x-(e.position.x-e.positionPrev.x),e.positionPrev.y=t.y-(e.position.y-e.positionPrev.y),e.position.x=t.x,e.position.y=t.y)},i.setPosition=function(e,t){var n=r.sub(t,e.position);e.positionPrev.x+=n.x,e.positionPrev.y+=n.y;for(var i=0;i<e.parts.length;i++){var a=e.parts[i];a.position.x+=n.x,a.position.y+=n.y,o.translate(a.vertices,n),l.update(a.bounds,a.vertices,e.velocity)}},i.setAngle=function(e,t){var n=t-e.angle;e.anglePrev+=n;for(var i=0;i<e.parts.length;i++){var a=e.parts[i];a.angle+=n,o.rotate(a.vertices,n,e.position),c.rotate(a.axes,n),l.update(a.bounds,a.vertices,e.velocity),i>0&&r.rotateAbout(a.position,n,e.position,a.position)}},i.setVelocity=function(e,t){e.positionPrev.x=e.position.x-t.x,e.positionPrev.y=e.position.y-t.y,e.velocity.x=t.x,e.velocity.y=t.y,e.speed=r.magnitude(e.velocity)},i.setAngularVelocity=function(e,t){e.anglePrev=e.angle-t,e.angularVelocity=t,e.angularSpeed=Math.abs(e.angularVelocity)},i.translate=function(e,t){i.setPosition(e,r.add(e.position,t))},i.rotate=function(e,t,n){if(n){var o=Math.cos(t),r=Math.sin(t),a=e.position.x-n.x,s=e.position.y-n.y;i.setPosition(e,{x:n.x+(a*o-s*r),y:n.y+(a*r+s*o)}),i.setAngle(e,e.angle+t)}else i.setAngle(e,e.angle+t)},i.scale=function(e,t,n,r){var a=0,s=0;r=r||e.position;for(var u=0;u<e.parts.length;u++){var d=e.parts[u];o.scale(d.vertices,t,n,r),d.axes=c.fromVertices(d.vertices),d.area=o.area(d.vertices),i.setMass(d,e.density*d.area),o.translate(d.vertices,{x:-d.position.x,y:-d.position.y}),i.setInertia(d,i._inertiaScale*o.inertia(d.vertices,d.mass)),o.translate(d.vertices,{x:d.position.x,y:d.position.y}),u>0&&(a+=d.area,s+=d.inertia),d.position.x=r.x+(d.position.x-r.x)*t,d.position.y=r.y+(d.position.y-r.y)*n,l.update(d.bounds,d.vertices,e.velocity)}e.parts.length>1&&(e.area=a,e.isStatic||(i.setMass(e,e.density*a),i.setInertia(e,s))),e.circleRadius&&(t===n?e.circleRadius*=t:e.circleRadius=null)},i.update=function(e,t,n,i){var a=Math.pow(t*n*e.timeScale,2),s=1-e.frictionAir*n*e.timeScale,u=e.position.x-e.positionPrev.x,d=e.position.y-e.positionPrev.y;e.velocity.x=u*s*i+e.force.x/e.mass*a,e.velocity.y=d*s*i+e.force.y/e.mass*a,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.position.x+=e.velocity.x,e.position.y+=e.velocity.y,e.angularVelocity=(e.angle-e.anglePrev)*s*i+e.torque/e.inertia*a,e.anglePrev=e.angle,e.angle+=e.angularVelocity,e.speed=r.magnitude(e.velocity),e.angularSpeed=Math.abs(e.angularVelocity);for(var p=0;p<e.parts.length;p++){var f=e.parts[p];o.translate(f.vertices,e.velocity),p>0&&(f.position.x+=e.velocity.x,f.position.y+=e.velocity.y),0!==e.angularVelocity&&(o.rotate(f.vertices,e.angularVelocity,e.position),c.rotate(f.axes,e.angularVelocity),p>0&&r.rotateAbout(f.position,e.angularVelocity,e.position,f.position)),l.update(f.bounds,f.vertices,e.velocity)}},i.applyForce=function(e,t,n){e.force.x+=n.x,e.force.y+=n.y;var i=t.x-e.position.x,o=t.y-e.position.y;e.torque+=i*n.y-o*n.x},i._totalProperties=function(e){for(var t={mass:0,area:0,inertia:0,centre:{x:0,y:0}},n=1===e.parts.length?0:1;n<e.parts.length;n++){var i=e.parts[n],o=i.mass!==1/0?i.mass:1;t.mass+=o,t.area+=i.area,t.inertia+=i.inertia,t.centre=r.add(t.centre,r.mult(i.position,o))}return t.centre=r.div(t.centre,t.mass),t}}()},function(e,t,n){var i={};e.exports=i;var o=n(4);i._motionWakeThreshold=.18,i._motionSleepThreshold=.08,i._minBias=.9,i.update=function(e,t){for(var n=t*t*t,o=0;o<e.length;o++){var r=e[o],a=r.speed*r.speed+r.angularSpeed*r.angularSpeed;if(0===r.force.x&&0===r.force.y){var s=Math.min(r.motion,a),l=Math.max(r.motion,a);r.motion=i._minBias*s+(1-i._minBias)*l,r.sleepThreshold>0&&r.motion<i._motionSleepThreshold*n?(r.sleepCounter+=1,r.sleepCounter>=r.sleepThreshold&&i.set(r,!0)):r.sleepCounter>0&&(r.sleepCounter-=1)}else i.set(r,!1)}},i.afterCollisions=function(e,t){for(var n=t*t*t,o=0;o<e.length;o++){var r=e[o];if(r.isActive){var a=r.collision,s=a.bodyA.parent,l=a.bodyB.parent;if(!(s.isSleeping&&l.isSleeping||s.isStatic||l.isStatic)&&(s.isSleeping||l.isSleeping)){var c=s.isSleeping&&!s.isStatic?s:l,u=c===s?l:s;!c.isStatic&&u.motion>i._motionWakeThreshold*n&&i.set(c,!1)}}}},i.set=function(e,t){var n=e.isSleeping;t?(e.isSleeping=!0,e.sleepCounter=e.sleepThreshold,e.positionImpulse.x=0,e.positionImpulse.y=0,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.anglePrev=e.angle,e.speed=0,e.angularSpeed=0,e.motion=0,n||o.trigger(e,"sleepStart")):(e.isSleeping=!1,e.sleepCounter=0,n&&o.trigger(e,"sleepEnd"))}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(2),a=n(7),s=n(1),l=n(10),c=n(0);i._warming=.4,i._torqueDampen=1,i._minLength=1e-6,i.create=function(e){var t=e;t.bodyA&&!t.pointA&&(t.pointA={x:0,y:0}),t.bodyB&&!t.pointB&&(t.pointB={x:0,y:0});var n=t.bodyA?r.add(t.bodyA.position,t.pointA):t.pointA,i=t.bodyB?r.add(t.bodyB.position,t.pointB):t.pointB,o=r.magnitude(r.sub(n,i));t.length=void 0!==t.length?t.length:o,t.id=t.id||c.nextId(),t.label=t.label||"Constraint",t.type="constraint",t.stiffness=t.stiffness||(t.length>0?1:.7),t.damping=t.damping||0,t.angularStiffness=t.angularStiffness||0,t.angleA=t.bodyA?t.bodyA.angle:t.angleA,t.angleB=t.bodyB?t.bodyB.angle:t.angleB,t.plugin={};var a={visible:!0,lineWidth:2,strokeStyle:"#ffffff",type:"line",anchors:!0};return 0===t.length&&t.stiffness>.1?(a.type="pin",a.anchors=!1):t.stiffness<.9&&(a.type="spring"),t.render=c.extend(a,t.render),t},i.preSolveAll=function(e){for(var t=0;t<e.length;t+=1){var n=e[t],i=n.constraintImpulse;n.isStatic||0===i.x&&0===i.y&&0===i.angle||(n.position.x+=i.x,n.position.y+=i.y,n.angle+=i.angle)}},i.solveAll=function(e,t){for(var n=0;n<e.length;n+=1){var o=e[n],r=!o.bodyA||o.bodyA&&o.bodyA.isStatic,a=!o.bodyB||o.bodyB&&o.bodyB.isStatic;(r||a)&&i.solve(e[n],t)}for(n=0;n<e.length;n+=1)r=!(o=e[n]).bodyA||o.bodyA&&o.bodyA.isStatic,a=!o.bodyB||o.bodyB&&o.bodyB.isStatic,r||a||i.solve(e[n],t)},i.solve=function(e,t){var n=e.bodyA,o=e.bodyB,a=e.pointA,s=e.pointB;if(n||o){n&&!n.isStatic&&(r.rotate(a,n.angle-e.angleA,a),e.angleA=n.angle),o&&!o.isStatic&&(r.rotate(s,o.angle-e.angleB,s),e.angleB=o.angle);var l=a,c=s;if(n&&(l=r.add(n.position,a)),o&&(c=r.add(o.position,s)),l&&c){var u=r.sub(l,c),d=r.magnitude(u);d<i._minLength&&(d=i._minLength);var p,f,v,m,y,g=(d-e.length)/d,x=e.stiffness<1?e.stiffness*t:e.stiffness,h=r.mult(u,g*x),b=(n?n.inverseMass:0)+(o?o.inverseMass:0),S=b+((n?n.inverseInertia:0)+(o?o.inverseInertia:0));if(e.damping){var w=r.create();v=r.div(u,d),y=r.sub(o&&r.sub(o.position,o.positionPrev)||w,n&&r.sub(n.position,n.positionPrev)||w),m=r.dot(v,y)}n&&!n.isStatic&&(f=n.inverseMass/b,n.constraintImpulse.x-=h.x*f,n.constraintImpulse.y-=h.y*f,n.position.x-=h.x*f,n.position.y-=h.y*f,e.damping&&(n.positionPrev.x-=e.damping*v.x*m*f,n.positionPrev.y-=e.damping*v.y*m*f),p=r.cross(a,h)/S*i._torqueDampen*n.inverseInertia*(1-e.angularStiffness),n.constraintImpulse.angle-=p,n.angle-=p),o&&!o.isStatic&&(f=o.inverseMass/b,o.constraintImpulse.x+=h.x*f,o.constraintImpulse.y+=h.y*f,o.position.x+=h.x*f,o.position.y+=h.y*f,e.damping&&(o.positionPrev.x+=e.damping*v.x*m*f,o.positionPrev.y+=e.damping*v.y*m*f),p=r.cross(s,h)/S*i._torqueDampen*o.inverseInertia*(1-e.angularStiffness),o.constraintImpulse.angle+=p,o.angle+=p)}}},i.postSolveAll=function(e){for(var t=0;t<e.length;t++){var n=e[t],c=n.constraintImpulse;if(!(n.isStatic||0===c.x&&0===c.y&&0===c.angle)){a.set(n,!1);for(var u=0;u<n.parts.length;u++){var d=n.parts[u];o.translate(d.vertices,c),u>0&&(d.position.x+=c.x,d.position.y+=c.y),0!==c.angle&&(o.rotate(d.vertices,c.angle,n.position),l.rotate(d.axes,c.angle),u>0&&r.rotateAbout(d.position,c.angle,n.position,d.position)),s.update(d.bounds,d.vertices,n.velocity)}c.angle*=i._warming,c.x*=i._warming,c.y*=i._warming}}},i.pointAWorld=function(e){return{x:(e.bodyA?e.bodyA.position.x:0)+e.pointA.x,y:(e.bodyA?e.bodyA.position.y:0)+e.pointA.y}},i.pointBWorld=function(e){return{x:(e.bodyB?e.bodyB.position.x:0)+e.pointB.x,y:(e.bodyB?e.bodyB.position.y:0)+e.pointB.y}}},function(e,t,n){var i={};e.exports=i;var o=n(17);i.create=function(e,t){var n=e.bodyA,o=e.bodyB,r=e.parentA,a=e.parentB,s={id:i.id(n,o),bodyA:n,bodyB:o,contacts:{},activeContacts:[],separation:0,isActive:!0,confirmedActive:!0,isSensor:n.isSensor||o.isSensor,timeCreated:t,timeUpdated:t,inverseMass:r.inverseMass+a.inverseMass,friction:Math.min(r.friction,a.friction),frictionStatic:Math.max(r.frictionStatic,a.frictionStatic),restitution:Math.max(r.restitution,a.restitution),slop:Math.max(r.slop,a.slop)};return i.update(s,e,t),s},i.update=function(e,t,n){var r=e.contacts,a=t.supports,s=e.activeContacts,l=t.parentA,c=t.parentB;if(e.collision=t,e.inverseMass=l.inverseMass+c.inverseMass,e.friction=Math.min(l.friction,c.friction),e.frictionStatic=Math.max(l.frictionStatic,c.frictionStatic),e.restitution=Math.max(l.restitution,c.restitution),e.slop=Math.max(l.slop,c.slop),s.length=0,t.collided){for(var u=0;u<a.length;u++){var d=a[u],p=o.id(d),f=r[p];f?s.push(f):s.push(r[p]=o.create(d))}e.separation=t.depth,i.setActive(e,!0,n)}else!0===e.isActive&&i.setActive(e,!1,n)},i.setActive=function(e,t,n){t?(e.isActive=!0,e.timeUpdated=n):(e.isActive=!1,e.activeContacts.length=0)},i.id=function(e,t){return e.id<t.id?"A"+e.id+"B"+t.id:"A"+t.id+"B"+e.id}},function(e,t,n){var i={};e.exports=i;var o=n(2),r=n(0);i.fromVertices=function(e){for(var t={},n=0;n<e.length;n++){var i=(n+1)%e.length,a=o.normalise({x:e[i].y-e[n].y,y:e[n].x-e[i].x}),s=0===a.y?1/0:a.x/a.y;t[s=s.toFixed(3).toString()]=a}return r.values(t)},i.rotate=function(e,t){if(0!==t)for(var n=Math.cos(t),i=Math.sin(t),o=0;o<e.length;o++){var r,a=e[o];r=a.x*n-a.y*i,a.y=a.x*i+a.y*n,a.x=r}}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(0),a=n(6),s=n(1),l=n(2);i.rectangle=function(e,t,n,i,s){s=s||{};var l={label:"Rectangle Body",position:{x:e,y:t},vertices:o.fromPath("L 0 0 L "+n+" 0 L "+n+" "+i+" L 0 "+i)};if(s.chamfer){var c=s.chamfer;l.vertices=o.chamfer(l.vertices,c.radius,c.quality,c.qualityMin,c.qualityMax),delete s.chamfer}return a.create(r.extend({},l,s))},i.trapezoid=function(e,t,n,i,s,l){l=l||{};var c,u=n*(s*=.5),d=u+(1-2*s)*n,p=d+u;c=s<.5?"L 0 0 L "+u+" "+-i+" L "+d+" "+-i+" L "+p+" 0":"L 0 0 L "+d+" "+-i+" L "+p+" 0";var f={label:"Trapezoid Body",position:{x:e,y:t},vertices:o.fromPath(c)};if(l.chamfer){var v=l.chamfer;f.vertices=o.chamfer(f.vertices,v.radius,v.quality,v.qualityMin,v.qualityMax),delete l.chamfer}return a.create(r.extend({},f,l))},i.circle=function(e,t,n,o,a){o=o||{};var s={label:"Circle Body",circleRadius:n};a=a||25;var l=Math.ceil(Math.max(10,Math.min(a,n)));return l%2==1&&(l+=1),i.polygon(e,t,l,n,r.extend({},s,o))},i.polygon=function(e,t,n,s,l){if(l=l||{},n<3)return i.circle(e,t,s,l);for(var c=2*Math.PI/n,u="",d=.5*c,p=0;p<n;p+=1){var f=d+p*c,v=Math.cos(f)*s,m=Math.sin(f)*s;u+="L "+v.toFixed(3)+" "+m.toFixed(3)+" "}var y={label:"Polygon Body",position:{x:e,y:t},vertices:o.fromPath(u)};if(l.chamfer){var g=l.chamfer;y.vertices=o.chamfer(y.vertices,g.radius,g.quality,g.qualityMin,g.qualityMax),delete l.chamfer}return a.create(r.extend({},y,l))},i.fromVertices=function(e,t,n,i,c,u,d,p){var f,v,m,y,g,x,h,b,S,w,A=r.getDecomp();for(f=Boolean(A&&A.quickDecomp),i=i||{},m=[],c=void 0!==c&&c,u=void 0!==u?u:.01,d=void 0!==d?d:10,p=void 0!==p?p:.01,r.isArray(n[0])||(n=[n]),S=0;S<n.length;S+=1)if(g=n[S],!(y=o.isConvex(g))&&!f&&r.warnOnce("Bodies.fromVertices: Install the 'poly-decomp' library and use Common.setDecomp or provide 'decomp' as a global to decompose concave vertices."),y||!f)g=y?o.clockwiseSort(g):o.hull(g),m.push({position:{x:e,y:t},vertices:g});else{var P=g.map((function(e){return[e.x,e.y]}));A.makeCCW(P),!1!==u&&A.removeCollinearPoints(P,u),!1!==p&&A.removeDuplicatePoints&&A.removeDuplicatePoints(P,p);var M=A.quickDecomp(P);for(x=0;x<M.length;x++){var C=M[x].map((function(e){return{x:e[0],y:e[1]}}));d>0&&o.area(C)<d||m.push({position:o.centre(C),vertices:C})}}for(x=0;x<m.length;x++)m[x]=a.create(r.extend(m[x],i));if(c)for(x=0;x<m.length;x++){var B=m[x];for(h=x+1;h<m.length;h++){var _=m[h];if(s.overlaps(B.bounds,_.bounds)){var k=B.vertices,I=_.vertices;for(b=0;b<B.vertices.length;b++)for(w=0;w<_.vertices.length;w++){var T=l.magnitudeSquared(l.sub(k[(b+1)%k.length],I[w])),R=l.magnitudeSquared(l.sub(k[b],I[(w+1)%I.length]));T<5&&R<5&&(k[b].isInternal=!0,I[w].isInternal=!0)}}}}return m.length>1?(v=a.create(r.extend({parts:m.slice(0)},i)),a.setPosition(v,{x:e,y:t}),v):m[0]}},function(e,t,n){var i={};e.exports=i;var o=n(0);i.create=function(e){var t={};return e||o.log("Mouse.create: element was undefined, defaulting to document.body","warn"),t.element=e||document.body,t.absolute={x:0,y:0},t.position={x:0,y:0},t.mousedownPosition={x:0,y:0},t.mouseupPosition={x:0,y:0},t.offset={x:0,y:0},t.scale={x:1,y:1},t.wheelDelta=0,t.button=-1,t.pixelRatio=parseInt(t.element.getAttribute("data-pixel-ratio"),10)||1,t.sourceEvents={mousemove:null,mousedown:null,mouseup:null,mousewheel:null},t.mousemove=function(e){var n=i._getRelativeMousePosition(e,t.element,t.pixelRatio);e.changedTouches&&(t.button=0,e.preventDefault()),t.absolute.x=n.x,t.absolute.y=n.y,t.position.x=t.absolute.x*t.scale.x+t.offset.x,t.position.y=t.absolute.y*t.scale.y+t.offset.y,t.sourceEvents.mousemove=e},t.mousedown=function(e){var n=i._getRelativeMousePosition(e,t.element,t.pixelRatio);e.changedTouches?(t.button=0,e.preventDefault()):t.button=e.button,t.absolute.x=n.x,t.absolute.y=n.y,t.position.x=t.absolute.x*t.scale.x+t.offset.x,t.position.y=t.absolute.y*t.scale.y+t.offset.y,t.mousedownPosition.x=t.position.x,t.mousedownPosition.y=t.position.y,t.sourceEvents.mousedown=e},t.mouseup=function(e){var n=i._getRelativeMousePosition(e,t.element,t.pixelRatio);e.changedTouches&&e.preventDefault(),t.button=-1,t.absolute.x=n.x,t.absolute.y=n.y,t.position.x=t.absolute.x*t.scale.x+t.offset.x,t.position.y=t.absolute.y*t.scale.y+t.offset.y,t.mouseupPosition.x=t.position.x,t.mouseupPosition.y=t.position.y,t.sourceEvents.mouseup=e},t.mousewheel=function(e){t.wheelDelta=Math.max(-1,Math.min(1,e.wheelDelta||-e.detail)),e.preventDefault()},i.setElement(t,t.element),t},i.setElement=function(e,t){e.element=t,t.addEventListener("mousemove",e.mousemove),t.addEventListener("mousedown",e.mousedown),t.addEventListener("mouseup",e.mouseup),t.addEventListener("mousewheel",e.mousewheel),t.addEventListener("DOMMouseScroll",e.mousewheel),t.addEventListener("touchmove",e.mousemove),t.addEventListener("touchstart",e.mousedown),t.addEventListener("touchend",e.mouseup)},i.clearSourceEvents=function(e){e.sourceEvents.mousemove=null,e.sourceEvents.mousedown=null,e.sourceEvents.mouseup=null,e.sourceEvents.mousewheel=null,e.wheelDelta=0},i.setOffset=function(e,t){e.offset.x=t.x,e.offset.y=t.y,e.position.x=e.absolute.x*e.scale.x+e.offset.x,e.position.y=e.absolute.y*e.scale.y+e.offset.y},i.setScale=function(e,t){e.scale.x=t.x,e.scale.y=t.y,e.position.x=e.absolute.x*e.scale.x+e.offset.x,e.position.y=e.absolute.y*e.scale.y+e.offset.y},i._getRelativeMousePosition=function(e,t,n){var i,o,r=t.getBoundingClientRect(),a=document.documentElement||document.body.parentNode||document.body,s=void 0!==window.pageXOffset?window.pageXOffset:a.scrollLeft,l=void 0!==window.pageYOffset?window.pageYOffset:a.scrollTop,c=e.changedTouches;return c?(i=c[0].pageX-r.left-s,o=c[0].pageY-r.top-l):(i=e.pageX-r.left-s,o=e.pageY-r.top-l),{x:i/(t.clientWidth/(t.width||t.clientWidth)*n),y:o/(t.clientHeight/(t.height||t.clientHeight)*n)}}},function(e,t,n){var i={};e.exports=i;var o=n(14),r=n(9),a=n(1);i.collisions=function(e,t){for(var n=[],s=t.pairs.table,l=0;l<e.length;l++){var c=e[l][0],u=e[l][1];if((!c.isStatic&&!c.isSleeping||!u.isStatic&&!u.isSleeping)&&i.canCollide(c.collisionFilter,u.collisionFilter)&&a.overlaps(c.bounds,u.bounds))for(var d=c.parts.length>1?1:0;d<c.parts.length;d++)for(var p=c.parts[d],f=u.parts.length>1?1:0;f<u.parts.length;f++){var v=u.parts[f];if(p===c&&v===u||a.overlaps(p.bounds,v.bounds)){var m,y=s[r.id(p,v)];m=y&&y.isActive?y.collision:null;var g=o.collides(p,v,m);g.collided&&n.push(g)}}}return n},i.canCollide=function(e,t){return e.group===t.group&&0!==e.group?e.group>0:0!=(e.mask&t.category)&&0!=(t.mask&e.category)}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(2);i.collides=function(e,t,n){var a,s,l,c,u=!1;if(n){var d=e.parent,p=t.parent,f=d.speed*d.speed+d.angularSpeed*d.angularSpeed+p.speed*p.speed+p.angularSpeed*p.angularSpeed;u=n&&n.collided&&f<.2,c=n}else c={collided:!1,bodyA:e,bodyB:t};if(n&&u){var v=c.axisBody,m=v===e?t:e,y=[v.axes[n.axisNumber]];if(l=i._overlapAxes(v.vertices,m.vertices,y),c.reused=!0,l.overlap<=0)return c.collided=!1,c}else{if((a=i._overlapAxes(e.vertices,t.vertices,e.axes)).overlap<=0)return c.collided=!1,c;if((s=i._overlapAxes(t.vertices,e.vertices,t.axes)).overlap<=0)return c.collided=!1,c;a.overlap<s.overlap?(l=a,c.axisBody=e):(l=s,c.axisBody=t),c.axisNumber=l.axisNumber}c.bodyA=e.id<t.id?e:t,c.bodyB=e.id<t.id?t:e,c.collided=!0,c.depth=l.overlap,c.parentA=c.bodyA.parent,c.parentB=c.bodyB.parent,e=c.bodyA,t=c.bodyB,r.dot(l.axis,r.sub(t.position,e.position))<0?c.normal={x:l.axis.x,y:l.axis.y}:c.normal={x:-l.axis.x,y:-l.axis.y},c.tangent=r.perp(c.normal),c.penetration=c.penetration||{},c.penetration.x=c.normal.x*c.depth,c.penetration.y=c.normal.y*c.depth;var g=i._findSupports(e,t,c.normal),x=[];if(o.contains(e.vertices,g[0])&&x.push(g[0]),o.contains(e.vertices,g[1])&&x.push(g[1]),x.length<2){var h=i._findSupports(t,e,r.neg(c.normal));o.contains(t.vertices,h[0])&&x.push(h[0]),x.length<2&&o.contains(t.vertices,h[1])&&x.push(h[1])}return x.length<1&&(x=[g[0]]),c.supports=x,c},i._overlapAxes=function(e,t,n){for(var o,a,s=r._temp[0],l=r._temp[1],c={overlap:Number.MAX_VALUE},u=0;u<n.length;u++){if(a=n[u],i._projectToAxis(s,e,a),i._projectToAxis(l,t,a),(o=Math.min(s.max-l.min,l.max-s.min))<=0)return c.overlap=o,c;o<c.overlap&&(c.overlap=o,c.axis=a,c.axisNumber=u)}return c},i._projectToAxis=function(e,t,n){for(var i=r.dot(t[0],n),o=i,a=1;a<t.length;a+=1){var s=r.dot(t[a],n);s>o?o=s:s<i&&(i=s)}e.min=i,e.max=o},i._findSupports=function(e,t,n){for(var i,o,a,s,l=Number.MAX_VALUE,c=r._temp[0],u=t.vertices,d=e.position,p=0;p<u.length;p++)o=u[p],c.x=o.x-d.x,c.y=o.y-d.y,(i=-r.dot(n,c))<l&&(l=i,a=o);return o=u[a.index-1>=0?a.index-1:u.length-1],c.x=o.x-d.x,c.y=o.y-d.y,l=-r.dot(n,c),s=o,o=u[(a.index+1)%u.length],c.x=o.x-d.x,c.y=o.y-d.y,(i=-r.dot(n,c))<l&&(s=o),[a,s]}},function(e,t,n){var i={};e.exports=i;var o=n(0);i._registry={},i.register=function(e){if(i.isPlugin(e)||o.warn("Plugin.register:",i.toString(e),"does not implement all required fields."),e.name in i._registry){var t=i._registry[e.name],n=i.versionParse(e.version).number,r=i.versionParse(t.version).number;n>r?(o.warn("Plugin.register:",i.toString(t),"was upgraded to",i.toString(e)),i._registry[e.name]=e):n<r?o.warn("Plugin.register:",i.toString(t),"can not be downgraded to",i.toString(e)):e!==t&&o.warn("Plugin.register:",i.toString(e),"is already registered to different plugin object")}else i._registry[e.name]=e;return e},i.resolve=function(e){return i._registry[i.dependencyParse(e).name]},i.toString=function(e){return"string"==typeof e?e:(e.name||"anonymous")+"@"+(e.version||e.range||"0.0.0")},i.isPlugin=function(e){return e&&e.name&&e.version&&e.install},i.isUsed=function(e,t){return e.used.indexOf(t)>-1},i.isFor=function(e,t){var n=e.for&&i.dependencyParse(e.for);return!e.for||t.name===n.name&&i.versionSatisfies(t.version,n.range)},i.use=function(e,t){if(e.uses=(e.uses||[]).concat(t||[]),0!==e.uses.length){for(var n=i.dependencies(e),r=o.topologicalSort(n),a=[],s=0;s<r.length;s+=1)if(r[s]!==e.name){var l=i.resolve(r[s]);l?i.isUsed(e,l.name)||(i.isFor(l,e)||(o.warn("Plugin.use:",i.toString(l),"is for",l.for,"but installed on",i.toString(e)+"."),l._warned=!0),l.install?l.install(e):(o.warn("Plugin.use:",i.toString(l),"does not specify an install function."),l._warned=!0),l._warned?(a.push("🔶 "+i.toString(l)),delete l._warned):a.push("✅ "+i.toString(l)),e.used.push(l.name)):a.push("❌ "+r[s])}a.length>0&&o.info(a.join("  "))}else o.warn("Plugin.use:",i.toString(e),"does not specify any dependencies to install.")},i.dependencies=function(e,t){var n=i.dependencyParse(e),r=n.name;if(!(r in(t=t||{}))){e=i.resolve(e)||e,t[r]=o.map(e.uses||[],(function(t){i.isPlugin(t)&&i.register(t);var r=i.dependencyParse(t),a=i.resolve(t);return a&&!i.versionSatisfies(a.version,r.range)?(o.warn("Plugin.dependencies:",i.toString(a),"does not satisfy",i.toString(r),"used by",i.toString(n)+"."),a._warned=!0,e._warned=!0):a||(o.warn("Plugin.dependencies:",i.toString(t),"used by",i.toString(n),"could not be resolved."),e._warned=!0),r.name}));for(var a=0;a<t[r].length;a+=1)i.dependencies(t[r][a],t);return t}},i.dependencyParse=function(e){return o.isString(e)?(/^[\w-]+(@(\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-]+)?))?$/.test(e)||o.warn("Plugin.dependencyParse:",e,"is not a valid dependency string."),{name:e.split("@")[0],range:e.split("@")[1]||"*"}):{name:e.name,range:e.range||e.version}},i.versionParse=function(e){var t=/^(\*)|(\^|~|>=|>)?\s*((\d+)\.(\d+)\.(\d+))(-[0-9A-Za-z-]+)?$/;t.test(e)||o.warn("Plugin.versionParse:",e,"is not a valid version or range.");var n=t.exec(e),i=Number(n[4]),r=Number(n[5]),a=Number(n[6]);return{isRange:Boolean(n[1]||n[2]),version:n[3],range:e,operator:n[1]||n[2]||"",major:i,minor:r,patch:a,parts:[i,r,a],prerelease:n[7],number:1e8*i+1e4*r+a}},i.versionSatisfies=function(e,t){t=t||"*";var n=i.versionParse(t),o=i.versionParse(e);if(n.isRange){if("*"===n.operator||"*"===e)return!0;if(">"===n.operator)return o.number>n.number;if(">="===n.operator)return o.number>=n.number;if("~"===n.operator)return o.major===n.major&&o.minor===n.minor&&o.patch>=n.patch;if("^"===n.operator)return n.major>0?o.major===n.major&&o.number>=n.number:n.minor>0?o.minor===n.minor&&o.patch>=n.patch:o.patch===n.patch}return e===t||"*"===e}},function(e,t,n){var i={};e.exports=i;var o=n(0),r=n(5),a=n(1),s=n(4),l=n(2),c=n(12);!function(){var e,t;"undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout((function(){e(o.now())}),1e3/60)},t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),i._goodFps=30,i._goodDelta=1e3/60,i.create=function(e){var t={controller:i,engine:null,element:null,canvas:null,mouse:null,frameRequestId:null,timing:{historySize:60,delta:0,deltaHistory:[],lastTime:0,lastTimestamp:0,lastElapsed:0,timestampElapsed:0,timestampElapsedHistory:[],engineDeltaHistory:[],engineElapsedHistory:[],elapsedHistory:[]},options:{width:800,height:600,pixelRatio:1,background:"#14151f",wireframeBackground:"#14151f",hasBounds:!!e.bounds,enabled:!0,wireframes:!0,showSleeping:!0,showDebug:!1,showStats:!1,showPerformance:!1,showBroadphase:!1,showBounds:!1,showVelocity:!1,showCollisions:!1,showSeparations:!1,showAxes:!1,showPositions:!1,showAngleIndicator:!1,showIds:!1,showVertexNumbers:!1,showConvexHulls:!1,showInternalEdges:!1,showMousePosition:!1}},n=o.extend(t,e);return n.canvas&&(n.canvas.width=n.options.width||n.canvas.width,n.canvas.height=n.options.height||n.canvas.height),n.mouse=e.mouse,n.engine=e.engine,n.canvas=n.canvas||d(n.options.width,n.options.height),n.context=n.canvas.getContext("2d"),n.textures={},n.bounds=n.bounds||{min:{x:0,y:0},max:{x:n.canvas.width,y:n.canvas.height}},1!==n.options.pixelRatio&&i.setPixelRatio(n,n.options.pixelRatio),o.isElement(n.element)?n.element.appendChild(n.canvas):n.canvas.parentNode||o.log("Render.create: options.element was undefined, render.canvas was created but not appended","warn"),n},i.run=function(t){!function o(r){t.frameRequestId=e(o),n(t,r),i.world(t,r),(t.options.showStats||t.options.showDebug)&&i.stats(t,t.context,r),(t.options.showPerformance||t.options.showDebug)&&i.performance(t,t.context,r)}()},i.stop=function(e){t(e.frameRequestId)},i.setPixelRatio=function(e,t){var n=e.options,i=e.canvas;"auto"===t&&(t=p(i)),n.pixelRatio=t,i.setAttribute("data-pixel-ratio",t),i.width=n.width*t,i.height=n.height*t,i.style.width=n.width+"px",i.style.height=n.height+"px"},i.lookAt=function(e,t,n,i){i=void 0===i||i,t=o.isArray(t)?t:[t],n=n||{x:0,y:0};for(var r={min:{x:1/0,y:1/0},max:{x:-1/0,y:-1/0}},a=0;a<t.length;a+=1){var s=t[a],l=s.bounds?s.bounds.min:s.min||s.position||s,u=s.bounds?s.bounds.max:s.max||s.position||s;l&&u&&(l.x<r.min.x&&(r.min.x=l.x),u.x>r.max.x&&(r.max.x=u.x),l.y<r.min.y&&(r.min.y=l.y),u.y>r.max.y&&(r.max.y=u.y))}var d=r.max.x-r.min.x+2*n.x,p=r.max.y-r.min.y+2*n.y,f=e.canvas.height,v=e.canvas.width/f,m=d/p,y=1,g=1;m>v?g=m/v:y=v/m,e.options.hasBounds=!0,e.bounds.min.x=r.min.x,e.bounds.max.x=r.min.x+d*y,e.bounds.min.y=r.min.y,e.bounds.max.y=r.min.y+p*g,i&&(e.bounds.min.x+=.5*d-d*y*.5,e.bounds.max.x+=.5*d-d*y*.5,e.bounds.min.y+=.5*p-p*g*.5,e.bounds.max.y+=.5*p-p*g*.5),e.bounds.min.x-=n.x,e.bounds.max.x-=n.x,e.bounds.min.y-=n.y,e.bounds.max.y-=n.y,e.mouse&&(c.setScale(e.mouse,{x:(e.bounds.max.x-e.bounds.min.x)/e.canvas.width,y:(e.bounds.max.y-e.bounds.min.y)/e.canvas.height}),c.setOffset(e.mouse,e.bounds.min))},i.startViewTransform=function(e){var t=e.bounds.max.x-e.bounds.min.x,n=e.bounds.max.y-e.bounds.min.y,i=t/e.options.width,o=n/e.options.height;e.context.setTransform(e.options.pixelRatio/i,0,0,e.options.pixelRatio/o,0,0),e.context.translate(-e.bounds.min.x,-e.bounds.min.y)},i.endViewTransform=function(e){e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0)},i.world=function(e,t){var n,u=o.now(),d=e.engine,p=d.world,f=e.canvas,m=e.context,y=e.options,g=e.timing,x=r.allBodies(p),h=r.allConstraints(p),b=y.wireframes?y.wireframeBackground:y.background,S=[],w=[],A={timestamp:d.timing.timestamp};if(s.trigger(e,"beforeRender",A),e.currentBackground!==b&&v(e,b),m.globalCompositeOperation="source-in",m.fillStyle="transparent",m.fillRect(0,0,f.width,f.height),m.globalCompositeOperation="source-over",y.hasBounds){for(n=0;n<x.length;n++){var P=x[n];a.overlaps(P.bounds,e.bounds)&&S.push(P)}for(n=0;n<h.length;n++){var M=h[n],C=M.bodyA,B=M.bodyB,_=M.pointA,k=M.pointB;C&&(_=l.add(C.position,M.pointA)),B&&(k=l.add(B.position,M.pointB)),_&&k&&((a.contains(e.bounds,_)||a.contains(e.bounds,k))&&w.push(M))}i.startViewTransform(e),e.mouse&&(c.setScale(e.mouse,{x:(e.bounds.max.x-e.bounds.min.x)/e.options.width,y:(e.bounds.max.y-e.bounds.min.y)/e.options.height}),c.setOffset(e.mouse,e.bounds.min))}else w=h,S=x,1!==e.options.pixelRatio&&e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0);!y.wireframes||d.enableSleeping&&y.showSleeping?i.bodies(e,S,m):(y.showConvexHulls&&i.bodyConvexHulls(e,S,m),i.bodyWireframes(e,S,m)),y.showBounds&&i.bodyBounds(e,S,m),(y.showAxes||y.showAngleIndicator)&&i.bodyAxes(e,S,m),y.showPositions&&i.bodyPositions(e,S,m),y.showVelocity&&i.bodyVelocity(e,S,m),y.showIds&&i.bodyIds(e,S,m),y.showSeparations&&i.separations(e,d.pairs.list,m),y.showCollisions&&i.collisions(e,d.pairs.list,m),y.showVertexNumbers&&i.vertexNumbers(e,S,m),y.showMousePosition&&i.mousePosition(e,e.mouse,m),i.constraints(w,m),y.showBroadphase&&i.grid(e,d.grid,m),y.hasBounds&&i.endViewTransform(e),s.trigger(e,"afterRender",A),g.lastElapsed=o.now()-u},i.stats=function(e,t,n){for(var i=e.engine,o=i.world,a=r.allBodies(o),s=0,l=0,c=0;c<a.length;c+=1)s+=a[c].parts.length;var u={Part:s,Body:a.length,Cons:r.allConstraints(o).length,Comp:r.allComposites(o).length,Pair:i.pairs.list.length};for(var d in t.fillStyle="#0e0f19",t.fillRect(l,0,302.5,44),t.font="12px Arial",t.textBaseline="top",t.textAlign="right",u){var p=u[d];t.fillStyle="#aaa",t.fillText(d,l+55,8),t.fillStyle="#eee",t.fillText(p,l+55,26),l+=55}},i.performance=function(e,t){var n=e.engine,o=e.timing,r=o.deltaHistory,a=o.elapsedHistory,s=o.timestampElapsedHistory,l=o.engineDeltaHistory,c=o.engineElapsedHistory,d=n.timing.lastDelta,p=u(r),f=u(a),v=u(l),m=u(c),y=u(s)/p||0,g=1e3/p||0;t.fillStyle="#0e0f19",t.fillRect(0,50,370,34),i.status(t,10,69,60,4,r.length,Math.round(g)+" fps",g/i._goodFps,(function(e){return r[e]/p-1})),i.status(t,82,69,60,4,l.length,d.toFixed(2)+" dt",i._goodDelta/d,(function(e){return l[e]/v-1})),i.status(t,154,69,60,4,c.length,m.toFixed(2)+" ut",1-m/i._goodFps,(function(e){return c[e]/m-1})),i.status(t,226,69,60,4,a.length,f.toFixed(2)+" rt",1-f/i._goodFps,(function(e){return a[e]/f-1})),i.status(t,298,69,60,4,s.length,y.toFixed(2)+" x",y*y*y,(function(e){return(s[e]/r[e]/y||0)-1}))},i.status=function(e,t,n,i,r,a,s,l,c){e.strokeStyle="#888",e.fillStyle="#444",e.lineWidth=1,e.fillRect(t,n+7,i,1),e.beginPath(),e.moveTo(t,n+7-r*o.clamp(.4*c(0),-2,2));for(var u=0;u<i;u+=1)e.lineTo(t+u,n+7-(u<a?r*o.clamp(.4*c(u),-2,2):0));e.stroke(),e.fillStyle="hsl("+o.clamp(25+95*l,0,120)+",100%,60%)",e.fillRect(t,n-7,4,4),e.font="12px Arial",e.textBaseline="middle",e.textAlign="right",e.fillStyle="#eee",e.fillText(s,t+i,n-5)},i.constraints=function(e,t){for(var n=t,i=0;i<e.length;i++){var r=e[i];if(r.render.visible&&r.pointA&&r.pointB){var a,s,c=r.bodyA,u=r.bodyB;if(a=c?l.add(c.position,r.pointA):r.pointA,"pin"===r.render.type)n.beginPath(),n.arc(a.x,a.y,3,0,2*Math.PI),n.closePath();else{if(s=u?l.add(u.position,r.pointB):r.pointB,n.beginPath(),n.moveTo(a.x,a.y),"spring"===r.render.type)for(var d,p=l.sub(s,a),f=l.perp(l.normalise(p)),v=Math.ceil(o.clamp(r.length/5,12,20)),m=1;m<v;m+=1)d=m%2==0?1:-1,n.lineTo(a.x+p.x*(m/v)+f.x*d*4,a.y+p.y*(m/v)+f.y*d*4);n.lineTo(s.x,s.y)}r.render.lineWidth&&(n.lineWidth=r.render.lineWidth,n.strokeStyle=r.render.strokeStyle,n.stroke()),r.render.anchors&&(n.fillStyle=r.render.strokeStyle,n.beginPath(),n.arc(a.x,a.y,3,0,2*Math.PI),n.arc(s.x,s.y,3,0,2*Math.PI),n.closePath(),n.fill())}}},i.bodies=function(e,t,n){var i,o,r,a,s=n,l=(e.engine,e.options),c=l.showInternalEdges||!l.wireframes;for(r=0;r<t.length;r++)if((i=t[r]).render.visible)for(a=i.parts.length>1?1:0;a<i.parts.length;a++)if((o=i.parts[a]).render.visible){if(l.showSleeping&&i.isSleeping?s.globalAlpha=.5*o.render.opacity:1!==o.render.opacity&&(s.globalAlpha=o.render.opacity),o.render.sprite&&o.render.sprite.texture&&!l.wireframes){var u=o.render.sprite,d=f(e,u.texture);s.translate(o.position.x,o.position.y),s.rotate(o.angle),s.drawImage(d,d.width*-u.xOffset*u.xScale,d.height*-u.yOffset*u.yScale,d.width*u.xScale,d.height*u.yScale),s.rotate(-o.angle),s.translate(-o.position.x,-o.position.y)}else{if(o.circleRadius)s.beginPath(),s.arc(o.position.x,o.position.y,o.circleRadius,0,2*Math.PI);else{s.beginPath(),s.moveTo(o.vertices[0].x,o.vertices[0].y);for(var p=1;p<o.vertices.length;p++)!o.vertices[p-1].isInternal||c?s.lineTo(o.vertices[p].x,o.vertices[p].y):s.moveTo(o.vertices[p].x,o.vertices[p].y),o.vertices[p].isInternal&&!c&&s.moveTo(o.vertices[(p+1)%o.vertices.length].x,o.vertices[(p+1)%o.vertices.length].y);s.lineTo(o.vertices[0].x,o.vertices[0].y),s.closePath()}l.wireframes?(s.lineWidth=1,s.strokeStyle="#bbb",s.stroke()):(s.fillStyle=o.render.fillStyle,o.render.lineWidth&&(s.lineWidth=o.render.lineWidth,s.strokeStyle=o.render.strokeStyle,s.stroke()),s.fill())}s.globalAlpha=1}},i.bodyWireframes=function(e,t,n){var i,o,r,a,s,l=n,c=e.options.showInternalEdges;for(l.beginPath(),r=0;r<t.length;r++)if((i=t[r]).render.visible)for(s=i.parts.length>1?1:0;s<i.parts.length;s++){for(o=i.parts[s],l.moveTo(o.vertices[0].x,o.vertices[0].y),a=1;a<o.vertices.length;a++)!o.vertices[a-1].isInternal||c?l.lineTo(o.vertices[a].x,o.vertices[a].y):l.moveTo(o.vertices[a].x,o.vertices[a].y),o.vertices[a].isInternal&&!c&&l.moveTo(o.vertices[(a+1)%o.vertices.length].x,o.vertices[(a+1)%o.vertices.length].y);l.lineTo(o.vertices[0].x,o.vertices[0].y)}l.lineWidth=1,l.strokeStyle="#bbb",l.stroke()},i.bodyConvexHulls=function(e,t,n){var i,o,r,a=n;for(a.beginPath(),o=0;o<t.length;o++)if((i=t[o]).render.visible&&1!==i.parts.length){for(a.moveTo(i.vertices[0].x,i.vertices[0].y),r=1;r<i.vertices.length;r++)a.lineTo(i.vertices[r].x,i.vertices[r].y);a.lineTo(i.vertices[0].x,i.vertices[0].y)}a.lineWidth=1,a.strokeStyle="rgba(255,255,255,0.2)",a.stroke()},i.vertexNumbers=function(e,t,n){var i,o,r,a=n;for(i=0;i<t.length;i++){var s=t[i].parts;for(r=s.length>1?1:0;r<s.length;r++){var l=s[r];for(o=0;o<l.vertices.length;o++)a.fillStyle="rgba(255,255,255,0.2)",a.fillText(i+"_"+o,l.position.x+.8*(l.vertices[o].x-l.position.x),l.position.y+.8*(l.vertices[o].y-l.position.y))}}},i.mousePosition=function(e,t,n){var i=n;i.fillStyle="rgba(255,255,255,0.8)",i.fillText(t.position.x+"  "+t.position.y,t.position.x+5,t.position.y-5)},i.bodyBounds=function(e,t,n){var i=n,o=(e.engine,e.options);i.beginPath();for(var r=0;r<t.length;r++){if(t[r].render.visible)for(var a=t[r].parts,s=a.length>1?1:0;s<a.length;s++){var l=a[s];i.rect(l.bounds.min.x,l.bounds.min.y,l.bounds.max.x-l.bounds.min.x,l.bounds.max.y-l.bounds.min.y)}}o.wireframes?i.strokeStyle="rgba(255,255,255,0.08)":i.strokeStyle="rgba(0,0,0,0.1)",i.lineWidth=1,i.stroke()},i.bodyAxes=function(e,t,n){var i,o,r,a,s=n,l=(e.engine,e.options);for(s.beginPath(),o=0;o<t.length;o++){var c=t[o],u=c.parts;if(c.render.visible)if(l.showAxes)for(r=u.length>1?1:0;r<u.length;r++)for(i=u[r],a=0;a<i.axes.length;a++){var d=i.axes[a];s.moveTo(i.position.x,i.position.y),s.lineTo(i.position.x+20*d.x,i.position.y+20*d.y)}else for(r=u.length>1?1:0;r<u.length;r++)for(i=u[r],a=0;a<i.axes.length;a++)s.moveTo(i.position.x,i.position.y),s.lineTo((i.vertices[0].x+i.vertices[i.vertices.length-1].x)/2,(i.vertices[0].y+i.vertices[i.vertices.length-1].y)/2)}l.wireframes?(s.strokeStyle="indianred",s.lineWidth=1):(s.strokeStyle="rgba(255, 255, 255, 0.4)",s.globalCompositeOperation="overlay",s.lineWidth=2),s.stroke(),s.globalCompositeOperation="source-over"},i.bodyPositions=function(e,t,n){var i,o,r,a,s=n,l=(e.engine,e.options);for(s.beginPath(),r=0;r<t.length;r++)if((i=t[r]).render.visible)for(a=0;a<i.parts.length;a++)o=i.parts[a],s.arc(o.position.x,o.position.y,3,0,2*Math.PI,!1),s.closePath();for(l.wireframes?s.fillStyle="indianred":s.fillStyle="rgba(0,0,0,0.5)",s.fill(),s.beginPath(),r=0;r<t.length;r++)(i=t[r]).render.visible&&(s.arc(i.positionPrev.x,i.positionPrev.y,2,0,2*Math.PI,!1),s.closePath());s.fillStyle="rgba(255,165,0,0.8)",s.fill()},i.bodyVelocity=function(e,t,n){var i=n;i.beginPath();for(var o=0;o<t.length;o++){var r=t[o];r.render.visible&&(i.moveTo(r.position.x,r.position.y),i.lineTo(r.position.x+2*(r.position.x-r.positionPrev.x),r.position.y+2*(r.position.y-r.positionPrev.y)))}i.lineWidth=3,i.strokeStyle="cornflowerblue",i.stroke()},i.bodyIds=function(e,t,n){var i,o,r=n;for(i=0;i<t.length;i++)if(t[i].render.visible){var a=t[i].parts;for(o=a.length>1?1:0;o<a.length;o++){var s=a[o];r.font="12px Arial",r.fillStyle="rgba(255,255,255,0.5)",r.fillText(s.id,s.position.x+10,s.position.y-10)}}},i.collisions=function(e,t,n){var i,o,r,a,s=n,l=e.options;for(s.beginPath(),r=0;r<t.length;r++)if((i=t[r]).isActive)for(o=i.collision,a=0;a<i.activeContacts.length;a++){var c=i.activeContacts[a].vertex;s.rect(c.x-1.5,c.y-1.5,3.5,3.5)}for(l.wireframes?s.fillStyle="rgba(255,255,255,0.7)":s.fillStyle="orange",s.fill(),s.beginPath(),r=0;r<t.length;r++)if((i=t[r]).isActive&&(o=i.collision,i.activeContacts.length>0)){var u=i.activeContacts[0].vertex.x,d=i.activeContacts[0].vertex.y;2===i.activeContacts.length&&(u=(i.activeContacts[0].vertex.x+i.activeContacts[1].vertex.x)/2,d=(i.activeContacts[0].vertex.y+i.activeContacts[1].vertex.y)/2),o.bodyB===o.supports[0].body||!0===o.bodyA.isStatic?s.moveTo(u-8*o.normal.x,d-8*o.normal.y):s.moveTo(u+8*o.normal.x,d+8*o.normal.y),s.lineTo(u,d)}l.wireframes?s.strokeStyle="rgba(255,165,0,0.7)":s.strokeStyle="orange",s.lineWidth=1,s.stroke()},i.separations=function(e,t,n){var i,o,r,a,s,l=n,c=e.options;for(l.beginPath(),s=0;s<t.length;s++)if((i=t[s]).isActive){r=(o=i.collision).bodyA;var u=1;(a=o.bodyB).isStatic||r.isStatic||(u=.5),a.isStatic&&(u=0),l.moveTo(a.position.x,a.position.y),l.lineTo(a.position.x-o.penetration.x*u,a.position.y-o.penetration.y*u),u=1,a.isStatic||r.isStatic||(u=.5),r.isStatic&&(u=0),l.moveTo(r.position.x,r.position.y),l.lineTo(r.position.x+o.penetration.x*u,r.position.y+o.penetration.y*u)}c.wireframes?l.strokeStyle="rgba(255,165,0,0.5)":l.strokeStyle="orange",l.stroke()},i.grid=function(e,t,n){var i=n;e.options.wireframes?i.strokeStyle="rgba(255,180,0,0.1)":i.strokeStyle="rgba(255,180,0,0.5)",i.beginPath();for(var r=o.keys(t.buckets),a=0;a<r.length;a++){var s=r[a];if(!(t.buckets[s].length<2)){var l=s.split(/C|R/);i.rect(.5+parseInt(l[1],10)*t.bucketWidth,.5+parseInt(l[2],10)*t.bucketHeight,t.bucketWidth,t.bucketHeight)}}i.lineWidth=1,i.stroke()},i.inspector=function(e,t){e.engine;var n,i=e.selected,o=e.render,r=o.options;if(r.hasBounds){var a=o.bounds.max.x-o.bounds.min.x,s=o.bounds.max.y-o.bounds.min.y,l=a/o.options.width,c=s/o.options.height;t.scale(1/l,1/c),t.translate(-o.bounds.min.x,-o.bounds.min.y)}for(var u=0;u<i.length;u++){var d=i[u].data;switch(t.translate(.5,.5),t.lineWidth=1,t.strokeStyle="rgba(255,165,0,0.9)",t.setLineDash([1,2]),d.type){case"body":n=d.bounds,t.beginPath(),t.rect(Math.floor(n.min.x-3),Math.floor(n.min.y-3),Math.floor(n.max.x-n.min.x+6),Math.floor(n.max.y-n.min.y+6)),t.closePath(),t.stroke();break;case"constraint":var p=d.pointA;d.bodyA&&(p=d.pointB),t.beginPath(),t.arc(p.x,p.y,10,0,2*Math.PI),t.closePath(),t.stroke()}t.setLineDash([]),t.translate(-.5,-.5)}null!==e.selectStart&&(t.translate(.5,.5),t.lineWidth=1,t.strokeStyle="rgba(255,165,0,0.6)",t.fillStyle="rgba(255,165,0,0.1)",n=e.selectBounds,t.beginPath(),t.rect(Math.floor(n.min.x),Math.floor(n.min.y),Math.floor(n.max.x-n.min.x),Math.floor(n.max.y-n.min.y)),t.closePath(),t.stroke(),t.fill(),t.translate(-.5,-.5)),r.hasBounds&&t.setTransform(1,0,0,1,0,0)};var n=function(e,t){var n=e.engine,o=e.timing,r=o.historySize,a=n.timing.timestamp;o.delta=t-o.lastTime||i._goodDelta,o.lastTime=t,o.timestampElapsed=a-o.lastTimestamp||0,o.lastTimestamp=a,o.deltaHistory.unshift(o.delta),o.deltaHistory.length=Math.min(o.deltaHistory.length,r),o.engineDeltaHistory.unshift(n.timing.lastDelta),o.engineDeltaHistory.length=Math.min(o.engineDeltaHistory.length,r),o.timestampElapsedHistory.unshift(o.timestampElapsed),o.timestampElapsedHistory.length=Math.min(o.timestampElapsedHistory.length,r),o.engineElapsedHistory.unshift(n.timing.lastElapsed),o.engineElapsedHistory.length=Math.min(o.engineElapsedHistory.length,r),o.elapsedHistory.unshift(o.lastElapsed),o.elapsedHistory.length=Math.min(o.elapsedHistory.length,r)},u=function(e){for(var t=0,n=0;n<e.length;n+=1)t+=e[n];return t/e.length||0},d=function(e,t){var n=document.createElement("canvas");return n.width=e,n.height=t,n.oncontextmenu=function(){return!1},n.onselectstart=function(){return!1},n},p=function(e){var t=e.getContext("2d");return(window.devicePixelRatio||1)/(t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||t.backingStorePixelRatio||1)},f=function(e,t){var n=e.textures[t];return n||((n=e.textures[t]=new Image).src=t,n)},v=function(e,t){var n=t;/(jpg|gif|png)$/.test(t)&&(n="url("+t+")"),e.canvas.style.background=n,e.canvas.style.backgroundSize="contain",e.currentBackground=t}}()},function(e,t){var n={};e.exports=n,n.create=function(e){return{id:n.id(e),vertex:e,normalImpulse:0,tangentImpulse:0}},n.id=function(e){return e.body.id+"_"+e.index}},function(e,t,n){var i={};e.exports=i;var o=n(7),r=n(19),a=n(13),s=n(20),l=n(21),c=n(4),u=n(5),d=n(8),p=n(0),f=n(6);i.create=function(e){e=e||{};var t=p.extend({positionIterations:6,velocityIterations:4,constraintIterations:2,enableSleeping:!1,events:[],plugin:{},grid:null,gravity:{x:0,y:1,scale:.001},timing:{timestamp:0,timeScale:1,lastDelta:0,lastElapsed:0}},e);return t.world=e.world||u.create({label:"World"}),t.grid=l.create(e.grid||e.broadphase),t.pairs=s.create(),t.world.gravity=t.gravity,t.broadphase=t.grid,t.metrics={},t},i.update=function(e,t,n){var f=p.now();t=t||1e3/60,n=n||1;var v,m,y=e.world,g=e.timing,x=e.grid;g.timestamp+=t*g.timeScale,g.lastDelta=t*g.timeScale;var h={timestamp:g.timestamp};c.trigger(e,"beforeUpdate",h);var b=u.allBodies(y),S=u.allConstraints(y);for(e.enableSleeping&&o.update(b,g.timeScale),i._bodiesApplyGravity(b,e.gravity),i._bodiesUpdate(b,t,g.timeScale,n,y.bounds),d.preSolveAll(b),m=0;m<e.constraintIterations;m++)d.solveAll(S,g.timeScale);d.postSolveAll(b),y.isModified&&l.clear(x),l.update(x,b,e,y.isModified),v=x.pairsList,y.isModified&&u.setModified(y,!1,!1,!0);var w=a.collisions(v,e),A=e.pairs,P=g.timestamp;for(s.update(A,w,P),s.removeOld(A,P),e.enableSleeping&&o.afterCollisions(A.list,g.timeScale),A.collisionStart.length>0&&c.trigger(e,"collisionStart",{pairs:A.collisionStart}),r.preSolvePosition(A.list),m=0;m<e.positionIterations;m++)r.solvePosition(A.list,g.timeScale);for(r.postSolvePosition(b),d.preSolveAll(b),m=0;m<e.constraintIterations;m++)d.solveAll(S,g.timeScale);for(d.postSolveAll(b),r.preSolveVelocity(A.list),m=0;m<e.velocityIterations;m++)r.solveVelocity(A.list,g.timeScale);return A.collisionActive.length>0&&c.trigger(e,"collisionActive",{pairs:A.collisionActive}),A.collisionEnd.length>0&&c.trigger(e,"collisionEnd",{pairs:A.collisionEnd}),i._bodiesClearForces(b),c.trigger(e,"afterUpdate",h),e.timing.lastElapsed=p.now()-f,e},i.merge=function(e,t){if(p.extend(e,t),t.world){e.world=t.world,i.clear(e);for(var n=u.allBodies(e.world),r=0;r<n.length;r++){var a=n[r];o.set(a,!1),a.id=p.nextId()}}},i.clear=function(e){var t=e.world,n=u.allBodies(t);s.clear(e.pairs),l.clear(e.grid),l.update(e.grid,n,e,!0)},i._bodiesClearForces=function(e){for(var t=0;t<e.length;t++){var n=e[t];n.force.x=0,n.force.y=0,n.torque=0}},i._bodiesApplyGravity=function(e,t){var n=void 0!==t.scale?t.scale:.001;if((0!==t.x||0!==t.y)&&0!==n)for(var i=0;i<e.length;i++){var o=e[i];o.isStatic||o.isSleeping||(o.force.y+=o.mass*t.y*n,o.force.x+=o.mass*t.x*n)}},i._bodiesUpdate=function(e,t,n,i,o){for(var r=0;r<e.length;r++){var a=e[r];a.isStatic||a.isSleeping||f.update(a,t,n,i)}}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(2),a=n(0),s=n(1);i._restingThresh=4,i._restingThreshTangent=6,i._positionDampen=.9,i._positionWarming=.8,i._frictionNormalMultiplier=5,i.preSolvePosition=function(e){var t,n,i;for(t=0;t<e.length;t++)(n=e[t]).isActive&&(i=n.activeContacts.length,n.collision.parentA.totalContacts+=i,n.collision.parentB.totalContacts+=i)},i.solvePosition=function(e,t){var n,o,a,s,l,c,u,d,p,f=r._temp[0],v=r._temp[1],m=r._temp[2],y=r._temp[3];for(n=0;n<e.length;n++)(o=e[n]).isActive&&!o.isSensor&&(s=(a=o.collision).parentA,l=a.parentB,c=a.normal,u=r.sub(r.add(l.positionImpulse,l.position,f),r.add(s.positionImpulse,r.sub(l.position,a.penetration,v),m),y),o.separation=r.dot(c,u));for(n=0;n<e.length;n++)(o=e[n]).isActive&&!o.isSensor&&(s=(a=o.collision).parentA,l=a.parentB,c=a.normal,p=(o.separation-o.slop)*t,(s.isStatic||l.isStatic)&&(p*=2),s.isStatic||s.isSleeping||(d=i._positionDampen/s.totalContacts,s.positionImpulse.x+=c.x*p*d,s.positionImpulse.y+=c.y*p*d),l.isStatic||l.isSleeping||(d=i._positionDampen/l.totalContacts,l.positionImpulse.x-=c.x*p*d,l.positionImpulse.y-=c.y*p*d))},i.postSolvePosition=function(e){for(var t=0;t<e.length;t++){var n=e[t];if(n.totalContacts=0,0!==n.positionImpulse.x||0!==n.positionImpulse.y){for(var a=0;a<n.parts.length;a++){var l=n.parts[a];o.translate(l.vertices,n.positionImpulse),s.update(l.bounds,l.vertices,n.velocity),l.position.x+=n.positionImpulse.x,l.position.y+=n.positionImpulse.y}n.positionPrev.x+=n.positionImpulse.x,n.positionPrev.y+=n.positionImpulse.y,r.dot(n.positionImpulse,n.velocity)<0?(n.positionImpulse.x=0,n.positionImpulse.y=0):(n.positionImpulse.x*=i._positionWarming,n.positionImpulse.y*=i._positionWarming)}}},i.preSolveVelocity=function(e){var t,n,i,o,a,s,l,c,u,d,p,f,v,m,y=r._temp[0],g=r._temp[1];for(t=0;t<e.length;t++)if((i=e[t]).isActive&&!i.isSensor)for(o=i.activeContacts,s=(a=i.collision).parentA,l=a.parentB,c=a.normal,u=a.tangent,n=0;n<o.length;n++)p=(d=o[n]).vertex,f=d.normalImpulse,v=d.tangentImpulse,0===f&&0===v||(y.x=c.x*f+u.x*v,y.y=c.y*f+u.y*v,s.isStatic||s.isSleeping||(m=r.sub(p,s.position,g),s.positionPrev.x+=y.x*s.inverseMass,s.positionPrev.y+=y.y*s.inverseMass,s.anglePrev+=r.cross(m,y)*s.inverseInertia),l.isStatic||l.isSleeping||(m=r.sub(p,l.position,g),l.positionPrev.x-=y.x*l.inverseMass,l.positionPrev.y-=y.y*l.inverseMass,l.anglePrev-=r.cross(m,y)*l.inverseInertia))},i.solveVelocity=function(e,t){for(var n=t*t,o=r._temp[0],s=r._temp[1],l=r._temp[2],c=r._temp[3],u=r._temp[4],d=r._temp[5],p=0;p<e.length;p++){var f=e[p];if(f.isActive&&!f.isSensor){var v=f.collision,m=v.parentA,y=v.parentB,g=v.normal,x=v.tangent,h=f.activeContacts,b=1/h.length;m.velocity.x=m.position.x-m.positionPrev.x,m.velocity.y=m.position.y-m.positionPrev.y,y.velocity.x=y.position.x-y.positionPrev.x,y.velocity.y=y.position.y-y.positionPrev.y,m.angularVelocity=m.angle-m.anglePrev,y.angularVelocity=y.angle-y.anglePrev;for(var S=0;S<h.length;S++){var w=h[S],A=w.vertex,P=r.sub(A,m.position,s),M=r.sub(A,y.position,l),C=r.add(m.velocity,r.mult(r.perp(P),m.angularVelocity),c),B=r.add(y.velocity,r.mult(r.perp(M),y.angularVelocity),u),_=r.sub(C,B,d),k=r.dot(g,_),I=r.dot(x,_),T=Math.abs(I),R=a.sign(I),E=(1+f.restitution)*k,L=a.clamp(f.separation+k,0,1)*i._frictionNormalMultiplier,V=I,O=1/0;T>f.friction*f.frictionStatic*L*n&&(O=T,V=a.clamp(f.friction*R*n,-O,O));var F=r.cross(P,g),D=r.cross(M,g),H=b/(m.inverseMass+y.inverseMass+m.inverseInertia*F*F+y.inverseInertia*D*D);if(E*=H,V*=H,k<0&&k*k>i._restingThresh*n)w.normalImpulse=0;else{var j=w.normalImpulse;w.normalImpulse=Math.min(w.normalImpulse+E,0),E=w.normalImpulse-j}if(I*I>i._restingThreshTangent*n)w.tangentImpulse=0;else{var W=w.tangentImpulse;w.tangentImpulse=a.clamp(w.tangentImpulse+V,-O,O),V=w.tangentImpulse-W}o.x=g.x*E+x.x*V,o.y=g.y*E+x.y*V,m.isStatic||m.isSleeping||(m.positionPrev.x+=o.x*m.inverseMass,m.positionPrev.y+=o.y*m.inverseMass,m.anglePrev+=r.cross(P,o)*m.inverseInertia),y.isStatic||y.isSleeping||(y.positionPrev.x-=o.x*y.inverseMass,y.positionPrev.y-=o.y*y.inverseMass,y.anglePrev-=r.cross(M,o)*y.inverseInertia)}}}}},function(e,t,n){var i={};e.exports=i;var o=n(9),r=n(0);i._pairMaxIdleLife=1e3,i.create=function(e){return r.extend({table:{},list:[],collisionStart:[],collisionActive:[],collisionEnd:[]},e)},i.update=function(e,t,n){var i,r,a,s,l=e.list,c=e.table,u=e.collisionStart,d=e.collisionEnd,p=e.collisionActive;for(u.length=0,d.length=0,p.length=0,s=0;s<l.length;s++)l[s].confirmedActive=!1;for(s=0;s<t.length;s++)(i=t[s]).collided&&((a=c[r=o.id(i.bodyA,i.bodyB)])?(a.isActive?p.push(a):u.push(a),o.update(a,i,n),a.confirmedActive=!0):(a=o.create(i,n),c[r]=a,u.push(a),l.push(a)));for(s=0;s<l.length;s++)(a=l[s]).isActive&&!a.confirmedActive&&(o.setActive(a,!1,n),d.push(a))},i.removeOld=function(e,t){var n,o,r,a,s=e.list,l=e.table,c=[];for(a=0;a<s.length;a++)(o=(n=s[a]).collision).bodyA.isSleeping||o.bodyB.isSleeping?n.timeUpdated=t:t-n.timeUpdated>i._pairMaxIdleLife&&c.push(a);for(a=0;a<c.length;a++)delete l[(n=s[r=c[a]-a]).id],s.splice(r,1)},i.clear=function(e){return e.table={},e.list.length=0,e.collisionStart.length=0,e.collisionActive.length=0,e.collisionEnd.length=0,e}},function(e,t,n){var i={};e.exports=i;var o=n(9),r=n(0);i.create=function(e){return r.extend({buckets:{},pairs:{},pairsList:[],bucketWidth:48,bucketHeight:48},e)},i.update=function(e,t,n,o){var r,a,s,l,c,u=n.world,d=e.buckets,p=!1;for(r=0;r<t.length;r++){var f=t[r];if((!f.isSleeping||o)&&(!u.bounds||!(f.bounds.max.x<u.bounds.min.x||f.bounds.min.x>u.bounds.max.x||f.bounds.max.y<u.bounds.min.y||f.bounds.min.y>u.bounds.max.y))){var v=i._getRegion(e,f);if(!f.region||v.id!==f.region.id||o){f.region&&!o||(f.region=v);var m=i._regionUnion(v,f.region);for(a=m.startCol;a<=m.endCol;a++)for(s=m.startRow;s<=m.endRow;s++){l=d[c=i._getBucketId(a,s)];var y=a>=v.startCol&&a<=v.endCol&&s>=v.startRow&&s<=v.endRow,g=a>=f.region.startCol&&a<=f.region.endCol&&s>=f.region.startRow&&s<=f.region.endRow;!y&&g&&g&&l&&i._bucketRemoveBody(e,l,f),(f.region===v||y&&!g||o)&&(l||(l=i._createBucket(d,c)),i._bucketAddBody(e,l,f))}f.region=v,p=!0}}}p&&(e.pairsList=i._createActivePairsList(e))},i.clear=function(e){e.buckets={},e.pairs={},e.pairsList=[]},i._regionUnion=function(e,t){var n=Math.min(e.startCol,t.startCol),o=Math.max(e.endCol,t.endCol),r=Math.min(e.startRow,t.startRow),a=Math.max(e.endRow,t.endRow);return i._createRegion(n,o,r,a)},i._getRegion=function(e,t){var n=t.bounds,o=Math.floor(n.min.x/e.bucketWidth),r=Math.floor(n.max.x/e.bucketWidth),a=Math.floor(n.min.y/e.bucketHeight),s=Math.floor(n.max.y/e.bucketHeight);return i._createRegion(o,r,a,s)},i._createRegion=function(e,t,n,i){return{id:e+","+t+","+n+","+i,startCol:e,endCol:t,startRow:n,endRow:i}},i._getBucketId=function(e,t){return"C"+e+"R"+t},i._createBucket=function(e,t){return e[t]=[]},i._bucketAddBody=function(e,t,n){for(var i=0;i<t.length;i++){var r=t[i];if(!(n.id===r.id||n.isStatic&&r.isStatic)){var a=o.id(n,r),s=e.pairs[a];s?s[2]+=1:e.pairs[a]=[n,r,1]}}t.push(n)},i._bucketRemoveBody=function(e,t,n){t.splice(r.indexOf(t,n),1);for(var i=0;i<t.length;i++){var a=t[i],s=o.id(n,a),l=e.pairs[s];l&&(l[2]-=1)}},i._createActivePairsList=function(e){var t,n,i=[];t=r.keys(e.pairs);for(var o=0;o<t.length;o++)(n=e.pairs[t[o]])[2]>0?i.push(n):delete e.pairs[t[o]];return i}},function(e,t,n){var i=e.exports=n(23);i.Axes=n(10),i.Bodies=n(11),i.Body=n(6),i.Bounds=n(1),i.Common=n(0),i.Composite=n(5),i.Composites=n(24),i.Constraint=n(8),i.Contact=n(17),i.Detector=n(13),i.Engine=n(18),i.Events=n(4),i.Grid=n(21),i.Mouse=n(12),i.MouseConstraint=n(25),i.Pair=n(9),i.Pairs=n(20),i.Plugin=n(15),i.Query=n(26),i.Render=n(16),i.Resolver=n(19),i.Runner=n(27),i.SAT=n(14),i.Sleeping=n(7),i.Svg=n(28),i.Vector=n(2),i.Vertices=n(3),i.World=n(29),i.Engine.run=i.Runner.run,i.Common.deprecated(i.Engine,"run","Engine.run ➤ use Matter.Runner.run(engine) instead")},function(e,t,n){var i={};e.exports=i;var o=n(15),r=n(0);i.name="matter-js",i.version="0.17.1",i.uses=[],i.used=[],i.use=function(){o.use(i,Array.prototype.slice.call(arguments))},i.before=function(e,t){return e=e.replace(/^Matter./,""),r.chainPathBefore(i,e,t)},i.after=function(e,t){return e=e.replace(/^Matter./,""),r.chainPathAfter(i,e,t)}},function(e,t,n){var i={};e.exports=i;var o=n(5),r=n(8),a=n(0),s=n(6),l=n(11),c=a.deprecated;i.stack=function(e,t,n,i,r,a,l){for(var c,u=o.create({label:"Stack"}),d=e,p=t,f=0,v=0;v<i;v++){for(var m=0,y=0;y<n;y++){var g=l(d,p,y,v,c,f);if(g){var x=g.bounds.max.y-g.bounds.min.y,h=g.bounds.max.x-g.bounds.min.x;x>m&&(m=x),s.translate(g,{x:.5*h,y:.5*x}),d=g.bounds.max.x+r,o.addBody(u,g),c=g,f+=1}else d+=r}p+=m+a,d=e}return u},i.chain=function(e,t,n,i,s,l){for(var c=e.bodies,u=1;u<c.length;u++){var d=c[u-1],p=c[u],f=d.bounds.max.y-d.bounds.min.y,v=d.bounds.max.x-d.bounds.min.x,m=p.bounds.max.y-p.bounds.min.y,y={bodyA:d,pointA:{x:v*t,y:f*n},bodyB:p,pointB:{x:(p.bounds.max.x-p.bounds.min.x)*i,y:m*s}},g=a.extend(y,l);o.addConstraint(e,r.create(g))}return e.label+=" Chain",e},i.mesh=function(e,t,n,i,s){var l,c,u,d,p,f=e.bodies;for(l=0;l<n;l++){for(c=1;c<t;c++)u=f[c-1+l*t],d=f[c+l*t],o.addConstraint(e,r.create(a.extend({bodyA:u,bodyB:d},s)));if(l>0)for(c=0;c<t;c++)u=f[c+(l-1)*t],d=f[c+l*t],o.addConstraint(e,r.create(a.extend({bodyA:u,bodyB:d},s))),i&&c>0&&(p=f[c-1+(l-1)*t],o.addConstraint(e,r.create(a.extend({bodyA:p,bodyB:d},s)))),i&&c<t-1&&(p=f[c+1+(l-1)*t],o.addConstraint(e,r.create(a.extend({bodyA:p,bodyB:d},s))))}return e.label+=" Mesh",e},i.pyramid=function(e,t,n,o,r,a,l){return i.stack(e,t,n,o,r,a,(function(t,i,a,c,u,d){var p=Math.min(o,Math.ceil(n/2)),f=u?u.bounds.max.x-u.bounds.min.x:0;if(!(c>p||a<(c=p-c)||a>n-1-c))return 1===d&&s.translate(u,{x:(a+(n%2==1?1:-1))*f,y:0}),l(e+(u?a*f:0)+a*r,i,a,c,u,d)}))},i.newtonsCradle=function(e,t,n,i,a){for(var s=o.create({label:"Newtons Cradle"}),c=0;c<n;c++){var u=l.circle(e+c*(1.9*i),t+a,i,{inertia:1/0,restitution:1,friction:0,frictionAir:1e-4,slop:1}),d=r.create({pointA:{x:e+c*(1.9*i),y:t},bodyB:u});o.addBody(s,u),o.addConstraint(s,d)}return s},c(i,"newtonsCradle","Composites.newtonsCradle ➤ moved to newtonsCradle example"),i.car=function(e,t,n,i,a){var c=s.nextGroup(!0),u=.5*-n+20,d=.5*n-20,p=o.create({label:"Car"}),f=l.rectangle(e,t,n,i,{collisionFilter:{group:c},chamfer:{radius:.5*i},density:2e-4}),v=l.circle(e+u,t+0,a,{collisionFilter:{group:c},friction:.8}),m=l.circle(e+d,t+0,a,{collisionFilter:{group:c},friction:.8}),y=r.create({bodyB:f,pointB:{x:u,y:0},bodyA:v,stiffness:1,length:0}),g=r.create({bodyB:f,pointB:{x:d,y:0},bodyA:m,stiffness:1,length:0});return o.addBody(p,f),o.addBody(p,v),o.addBody(p,m),o.addConstraint(p,y),o.addConstraint(p,g),p},c(i,"car","Composites.car ➤ moved to car example"),i.softBody=function(e,t,n,o,r,s,c,u,d,p){d=a.extend({inertia:1/0},d),p=a.extend({stiffness:.2,render:{type:"line",anchors:!1}},p);var f=i.stack(e,t,n,o,r,s,(function(e,t){return l.circle(e,t,u,d)}));return i.mesh(f,n,o,c,p),f.label="Soft Body",f},c(i,"softBody","Composites.softBody ➤ moved to softBody and cloth examples")},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(7),a=n(12),s=n(4),l=n(13),c=n(8),u=n(5),d=n(0),p=n(1);i.create=function(e,t){var n=(e?e.mouse:null)||(t?t.mouse:null);n||(e&&e.render&&e.render.canvas?n=a.create(e.render.canvas):t&&t.element?n=a.create(t.element):(n=a.create(),d.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected")));var o={type:"mouseConstraint",mouse:n,element:null,body:null,constraint:c.create({label:"Mouse Constraint",pointA:n.position,pointB:{x:0,y:0},length:.01,stiffness:.1,angularStiffness:1,render:{strokeStyle:"#90EE90",lineWidth:3}}),collisionFilter:{category:1,mask:4294967295,group:0}},r=d.extend(o,t);return s.on(e,"beforeUpdate",(function(){var t=u.allBodies(e.world);i.update(r,t),i._triggerEvents(r)})),r},i.update=function(e,t){var n=e.mouse,i=e.constraint,a=e.body;if(0===n.button){if(i.bodyB)r.set(i.bodyB,!1),i.pointA=n.position;else for(var c=0;c<t.length;c++)if(a=t[c],p.contains(a.bounds,n.position)&&l.canCollide(a.collisionFilter,e.collisionFilter))for(var u=a.parts.length>1?1:0;u<a.parts.length;u++){var d=a.parts[u];if(o.contains(d.vertices,n.position)){i.pointA=n.position,i.bodyB=e.body=a,i.pointB={x:n.position.x-a.position.x,y:n.position.y-a.position.y},i.angleB=a.angle,r.set(a,!1),s.trigger(e,"startdrag",{mouse:n,body:a});break}}}else i.bodyB=e.body=null,i.pointB=null,a&&s.trigger(e,"enddrag",{mouse:n,body:a})},i._triggerEvents=function(e){var t=e.mouse,n=t.sourceEvents;n.mousemove&&s.trigger(e,"mousemove",{mouse:t}),n.mousedown&&s.trigger(e,"mousedown",{mouse:t}),n.mouseup&&s.trigger(e,"mouseup",{mouse:t}),a.clearSourceEvents(t)}},function(e,t,n){var i={};e.exports=i;var o=n(2),r=n(14),a=n(1),s=n(11),l=n(3);i.collides=function(e,t){for(var n=[],i=0;i<t.length;i++){var o=t[i];if(a.overlaps(o.bounds,e.bounds))for(var s=1===o.parts.length?0:1;s<o.parts.length;s++){var l=o.parts[s];if(a.overlaps(l.bounds,e.bounds)){var c=r.collides(l,e);if(c.collided){n.push(c);break}}}}return n},i.ray=function(e,t,n,r){r=r||1e-100;for(var a=o.angle(t,n),l=o.magnitude(o.sub(t,n)),c=.5*(n.x+t.x),u=.5*(n.y+t.y),d=s.rectangle(c,u,l,r,{angle:a}),p=i.collides(d,e),f=0;f<p.length;f+=1){var v=p[f];v.body=v.bodyB=v.bodyA}return p},i.region=function(e,t,n){for(var i=[],o=0;o<e.length;o++){var r=e[o],s=a.overlaps(r.bounds,t);(s&&!n||!s&&n)&&i.push(r)}return i},i.point=function(e,t){for(var n=[],i=0;i<e.length;i++){var o=e[i];if(a.contains(o.bounds,t))for(var r=1===o.parts.length?0:1;r<o.parts.length;r++){var s=o.parts[r];if(a.contains(s.bounds,t)&&l.contains(s.vertices,t)){n.push(o);break}}}return n}},function(e,t,n){var i={};e.exports=i;var o=n(4),r=n(18),a=n(0);!function(){var e,t,n;("undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),e)||(e=function(e){n=setTimeout((function(){e(a.now())}),1e3/60)},t=function(){clearTimeout(n)});i.create=function(e){var t=a.extend({fps:60,correction:1,deltaSampleSize:60,counterTimestamp:0,frameCounter:0,deltaHistory:[],timePrev:null,timeScalePrev:1,frameRequestId:null,isFixed:!1,enabled:!0},e);return t.delta=t.delta||1e3/t.fps,t.deltaMin=t.deltaMin||1e3/t.fps,t.deltaMax=t.deltaMax||1e3/(.5*t.fps),t.fps=1e3/t.delta,t},i.run=function(t,n){return void 0!==t.positionIterations&&(n=t,t=i.create()),function o(r){t.frameRequestId=e(o),r&&t.enabled&&i.tick(t,n,r)}(),t},i.tick=function(e,t,n){var i,a=t.timing,s=1,l={timestamp:a.timestamp};o.trigger(e,"beforeTick",l),e.isFixed?i=e.delta:(i=n-e.timePrev||e.delta,e.timePrev=n,e.deltaHistory.push(i),e.deltaHistory=e.deltaHistory.slice(-e.deltaSampleSize),s=(i=(i=(i=Math.min.apply(null,e.deltaHistory))<e.deltaMin?e.deltaMin:i)>e.deltaMax?e.deltaMax:i)/e.delta,e.delta=i),0!==e.timeScalePrev&&(s*=a.timeScale/e.timeScalePrev),0===a.timeScale&&(s=0),e.timeScalePrev=a.timeScale,e.correction=s,e.frameCounter+=1,n-e.counterTimestamp>=1e3&&(e.fps=e.frameCounter*((n-e.counterTimestamp)/1e3),e.counterTimestamp=n,e.frameCounter=0),o.trigger(e,"tick",l),o.trigger(e,"beforeUpdate",l),r.update(t,i,s),o.trigger(e,"afterUpdate",l),o.trigger(e,"afterTick",l)},i.stop=function(e){t(e.frameRequestId)},i.start=function(e,t){i.run(e,t)}}()},function(e,t,n){var i={};e.exports=i;n(1);var o=n(0);i.pathToVertices=function(e,t){"undefined"==typeof window||"SVGPathSeg"in window||o.warn("Svg.pathToVertices: SVGPathSeg not defined, a polyfill is required.");var n,r,a,s,l,c,u,d,p,f,v,m=[],y=0,g=0,x=0;t=t||15;var h=function(e,t,n){var i=n%2==1&&n>1;if(!p||e!=p.x||t!=p.y){p&&i?(f=p.x,v=p.y):(f=0,v=0);var o={x:f+e,y:v+t};!i&&p||(p=o),m.push(o),g=f+e,x=v+t}},b=function(e){var t=e.pathSegTypeAsLetter.toUpperCase();if("Z"!==t){switch(t){case"M":case"L":case"T":case"C":case"S":case"Q":g=e.x,x=e.y;break;case"H":g=e.x;break;case"V":x=e.y}h(g,x,e.pathSegType)}};for(i._svgPathToAbsolute(e),a=e.getTotalLength(),c=[],n=0;n<e.pathSegList.numberOfItems;n+=1)c.push(e.pathSegList.getItem(n));for(u=c.concat();y<a;){if((l=c[e.getPathSegAtLength(y)])!=d){for(;u.length&&u[0]!=l;)b(u.shift());d=l}switch(l.pathSegTypeAsLetter.toUpperCase()){case"C":case"T":case"S":case"Q":case"A":s=e.getPointAtLength(y),h(s.x,s.y,0)}y+=t}for(n=0,r=u.length;n<r;++n)b(u[n]);return m},i._svgPathToAbsolute=function(e){for(var t,n,i,o,r,a,s=e.pathSegList,l=0,c=0,u=s.numberOfItems,d=0;d<u;++d){var p=s.getItem(d),f=p.pathSegTypeAsLetter;if(/[MLHVCSQTA]/.test(f))"x"in p&&(l=p.x),"y"in p&&(c=p.y);else switch("x1"in p&&(i=l+p.x1),"x2"in p&&(r=l+p.x2),"y1"in p&&(o=c+p.y1),"y2"in p&&(a=c+p.y2),"x"in p&&(l+=p.x),"y"in p&&(c+=p.y),f){case"m":s.replaceItem(e.createSVGPathSegMovetoAbs(l,c),d);break;case"l":s.replaceItem(e.createSVGPathSegLinetoAbs(l,c),d);break;case"h":s.replaceItem(e.createSVGPathSegLinetoHorizontalAbs(l),d);break;case"v":s.replaceItem(e.createSVGPathSegLinetoVerticalAbs(c),d);break;case"c":s.replaceItem(e.createSVGPathSegCurvetoCubicAbs(l,c,i,o,r,a),d);break;case"s":s.replaceItem(e.createSVGPathSegCurvetoCubicSmoothAbs(l,c,r,a),d);break;case"q":s.replaceItem(e.createSVGPathSegCurvetoQuadraticAbs(l,c,i,o),d);break;case"t":s.replaceItem(e.createSVGPathSegCurvetoQuadraticSmoothAbs(l,c),d);break;case"a":s.replaceItem(e.createSVGPathSegArcAbs(l,c,p.r1,p.r2,p.angle,p.largeArcFlag,p.sweepFlag),d);break;case"z":case"Z":l=t,c=n}"M"!=f&&"m"!=f||(t=l,n=c)}}},function(e,t,n){var i={};e.exports=i;var o=n(5);n(0);i.create=o.create,i.add=o.add,i.remove=o.remove,i.clear=o.clear,i.addComposite=o.addComposite,i.addBody=o.addBody,i.addConstraint=o.addConstraint}])}));
    </script>

    <style>
        body {
            font-family: 'Roboto', Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #E0FFFF;
            color: #333;
            min-height: 100vh;
            box-sizing: border-box;
            overflow: hidden;
        }
        h1 {
            color: #2c3e50;
            text-align: center;
            font-size: 4em;
            margin-bottom: 30px;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
        }
        h2 {
            font-size: 2.5em; /* Увеличенный размер для заголовков второго уровня */
        }
        h3 {
            font-size: 2em; /* Увеличенный размер для заголовков третьего уровня */
        }
        p, label, input, button, table, th, td {
            font-size: 1.2em; /* Увеличенный размер для основного текста и элементов форм */
        }
        .modal-content {
            font-size: 1.1em; /* Увеличенный размер шрифта для содержимого модальных окон */
        }
        #controls label {
            font-size: 1.6em; /* Увеличенный размер шрифта для меток в панели управления */
        }

        #resultsTable th, #resultsTable td {
            font-size: 1.3em; /* Увеличенный размер шрифта для таблицы результатов */
            font-weight: 550;
        }

        .container {
            display: flex;
            gap: 20px;
            height: 100vh;
            width: 100%;
        }
        .left-panel {
            flex: 0 0 800px;
            height: 730px;
            background-color: #ffffff;
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            margin-left: 10px; /* Добавляем отступ слева */
        }
        .right-panel {
            flex: 1;
            min-width: 300px;
            display: flex;
            flex-direction: column;
            gap: 20px;
        }

        .panel-section {
            background-color: #ffffff;
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            display: flex;
            flex-direction: column;
            overflow: hidden; /* Предотвращает выход содержимого за пределы секции */
            border-bottom: 2px solid #3498db;
            border-left: 2px solid #3498db;
            border-right: 2px solid #3498db;
            border-top: 2px solid #3498db;
            min-height: 230px;
            margin-right: 10px;
        }

        .section-title {
            font-size: 1.4em;
            color: #2c3e50;
            text-align: center;
            background-color: #E0FFFF;
            padding: 9px;
            margin: 0;
            border-bottom: 4px solid #3498db;
        }

        .table-section {
            flex-grow: 1;
            display: flex;
            flex-direction: column;
            padding: 0;
            margin: 0;
            min-height: 200px;
        }

        .table-container {
            flex-grow: 1;
            border: none;
            border-radius: 0;
            margin: 0;
            overflow: hidden;
            height: 159px;
            overflow-y: auto;
            background: linear-gradient(to bottom, #ffffff, #f8f9fa);
            box-shadow:
                    inset 0 2px 4px rgba(0,0,0,0.05),
                    0 4px 8px rgba(52, 152, 219, 0.1);
            padding: 0; /* Убираем отступы у контейнера */
        }

        #resultsTable {
            width: 100%;
            border-collapse: separate;
            border-spacing: 0;
            background-color: transparent;
            margin: 0; /* Убираем отступы у таблицы */
        }

        #resultsTable thead {
            position: sticky;
            top: 0;
            z-index: 2;
            background-color: #3498db;
            margin: 0;
        }

        #resultsTable thead th {
            background: linear-gradient(to bottom, #3498db, #2980b9);
            color: white;
            font-weight: bold;
            padding: 8px;
            text-align: center;
            font-size: 1.2em;
            border-bottom: 2px solid #2980b9;
            text-shadow: 0 1px 2px rgba(0,0,0,0.2);
            top: 0;
            z-index: 1;
        }

        #resultsTable td {
            padding: 6px;
            text-align: center;
            border-bottom: 1px solid #e0e0e0;
            font-size: 1.1em;
            transition: background-color 0.2s;
        }

        @keyframes newRowAppear {
            0% {
                transform: scale(0.98);
                background-color: #3498db;
                opacity: 0;
            }
            30% {
                transform: scale(1.01);
                background-color: #d4e9f7;
                opacity: 1;
            }
            70% {
                transform: scale(0.99);
                background-color: #f0f9ff;
            }
            100% {
                transform: scale(1);
                background-color: transparent;
            }
        }

        @keyframes textFadeIn {
            0% {
                opacity: 0;
                color: #2980b9;
                text-shadow: 0 0 6px rgba(52, 152, 219, 0.6);
            }
            50% {
                opacity: 1;
                color: #2980b9;
                text-shadow: 0 0 3px rgba(52, 152, 219, 0.4);
            }
            100% {
                opacity: 1;
                color: inherit;
                text-shadow: none;
            }
        }

        @keyframes newRowAppear {
            0% {
                transform: scale(0.98);
                background-color: #3498db;
                opacity: 0;
            }
            30% {
                transform: scale(1.01);
                background-color: #d4e9f7;
                opacity: 1;
            }
            70% {
                transform: scale(0.99);
                background-color: #f0f9ff;
            }
            100% {
                transform: scale(1);
                background-color: transparent;
            }
        }

        #resultsTable tbody tr:last-child {
            animation: newRowAppear 0.5s ease-out forwards;
            transform-origin: center;
        }

        #resultsTable tbody tr:last-child td {
            animation: textFadeIn 1s ease-out forwards;
            border-bottom: 1px solid #2980b9;
        }

        /* Добавляем плавный переход для всех строк */
        #resultsTable tbody tr {
            transition: all 0.3s ease-out;
        }

        /* Стили при наведении для всех строк */
        #resultsTable tbody tr:hover {
            background-color: #f5f9ff;
            transform: translateY(-1px);
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        #resultsTable tbody tr:last-child td {
            animation: textGlow 1.5s ease-out;
        }
        /* Обновим стили для ячеек последней строки */
        #resultsTable tbody tr:last-child td {
            position: relative;
            overflow: hidden;
        }

        #resultsTable tbody tr:nth-child(even) {
            background-color: #f8f9fa;
        }

        #resultsTable tr:first-child th {
            border-top: 0; /* Убираем верхнюю границу у первой строки */
        }

        /* Стилизация скролла таблицы */
        .table-container::-webkit-scrollbar {
            width: 10px;
        }

        .table-container::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 5px;
        }

        .table-container::-webkit-scrollbar-thumb {
            background: #3498db;
            border-radius: 5px;
        }

        .table-container::-webkit-scrollbar-thumb:hover {
            background: #2980b9;
        }

        #clearTableBtn {
            margin: 13px auto 12px auto;
            border-radius: 8px;
            padding: 9px 20px;
            background-color: #3498db; /* Синий цвет */
            width: calc(100% - 80px); /* Одинаковая ширина для обеих кнопок */
            color: white;
            border: none;
            cursor: pointer;
            font-size: 1.2em;
            font-weight: bold;
            transition: all 0.3s ease;
            text-transform: uppercase;
            letter-spacing: 1px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        #clearTableBtn:hover {
            background-color: #e74c3c; /* Красный цвет при наведении */
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
        }

        #clearTableBtn:active {
            transform: translateY(0);
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        .separator {
            width: 100%; /* или другую нужную ширину */
            height: 3px; /* толщина линии */
            background-color: #3498db; /* цвет линии */
            margin: 0px auto 0 auto;
        }

        .back-to-title-container {
            display: flex;
            justify-content: center; /* Горизонтальное центрирование */
            align-items: center; /* Вертикальное центрирование */
            background-color: #E0FFFF;
            border-radius: 8px;
            transition: background-color 0.3s ease;
        }

        #backToTitleBtn {
            margin: 8px auto 8px auto;
            border-radius: 8px;
            padding: 9px 20px;
            background-color: #3498db;
            width: calc(100% - 80px);
            color: white;
            border: none;
            cursor: pointer;
            font-size: 1.2em;
            font-weight: bold;
            transition: all 0.3s ease;
            text-transform: uppercase;
            letter-spacing: 1px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        #backToTitleBtn:hover {
            background-color: #3498db;
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
        }

        #backToTitleBtn:active {
            transform: translateY(0);
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        canvas {
            border: 3px solid #3498db;
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            background-color: #ffffff; /* Убираем черный фон */
        }
        #controls {
            margin: 0;
            padding: 20px;
            flex-grow: 1;
            display: flex;
            flex-direction: column;
        }
        label {
            display: block;
            margin-bottom: 15px;
            font-weight: bold;
            color: #2c3e50;
        }
        input[type="number"] {
            width: 100%;
            padding: 10px;
            border: 2px solid #3498db;
            border-radius: 5px;
            font-size: 16px;
            transition: border-color 0.3s;
        }
        input[type="number"]:focus {
            border-color: #2980b9;
            outline: none;
        }
        #shootBtn {
            display: block;
            width: calc(100% - 40px); /* Учитываем отступы слева и справа */
            padding: 12px;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            margin: auto;
            font-size: 1.2em;
            font-weight: bold;
            transition: all 0.3s ease;
            text-transform: uppercase;
            letter-spacing: 1px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }


        #shootBtn:hover {
            background-color: #2ecc71; /* Зеленый цвет при наведении */
            transform: scale(1.05);
        }

        #shootBtn:active {
            transform: scale(1);
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
        }
        th, td {
            border: 1px solid #3498db;
            padding: 10px;
            text-align: center;
        }
        th {
            background-color: #3498db;
            color: white;
        }
        tbody tr:nth-child(even) {
            background-color: #f2f2f2;
        }
        tbody tr:hover {
            background-color: #e0e0e0;
        }
        .slider {
            -webkit-appearance: none;
            width: 100%;
            height: 8px;
            border-radius: 5px;
            background: #d3d3d3;
            outline: none;
            margin-top: 10px;
        }

        .slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #3498db;
            cursor: pointer;
            transition: background .15s ease-in-out;
        }

        .slider::-webkit-slider-thumb:hover {
            background: #2980b9;
        }

        .slider::-moz-range-thumb {
            width: 20px;
            height: 20px;
            border: 0;
            border-radius: 50%;
            background: #3498db;
            cursor: pointer;
            transition: background .15s ease-in-out;
        }

        .slider::-moz-range-thumb:hover {
            background: #2980b9;
        }

        #controls label {
            display: block;
            margin-bottom: 20px;
        }

        #controls span {
            display: inline-block;
            width: 100px;
            text-align: right;
            margin-left: 10px;
        }


        /*@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap');*/

        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            font-family: 'Roboto', sans-serif;
        }

        .title-page {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            background: linear-gradient(135deg,
            #e8f1f8 0%,
            #d9e8f5 25%,
            #bdd8f0 50%,
            #a7cef0 75%,
            #ADD8E6 100%
            );
            background-size: 400% 400%;
            animation: gradientAnimation 18s ease infinite;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 1000;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }

        @keyframes gradientAnimation {
            0% {
                background-position: 0% 50%;
            }
            50% {
                background-position: 100% 50%;
            }
            100% {
                background-position: 0% 50%;
            }
        }

        .title-page::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background:
                    radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.03) 0%, transparent 20%),
                    radial-gradient(circle at 80% 80%, rgba(255, 255, 255, 0.03) 0%, transparent 20%);
            z-index: -1;
        }

        .title-content {
            text-align: center;
            width: 90%;
            max-width: 70%; /* Изменено с 1000px на 90% */
            height: 90vh; /* Добавлено для высоты */
            margin: 0 auto;
            padding: 7vh 5vw;
            background-color: rgba(255, 255, 255, 0.95);
            border-radius: 4vh;
            box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15);
            position: relative;
            overflow: hidden;
            font-size: 2vmin;
            display: flex; /* Добавлено */
            flex-direction: column; /* Добавлено */
            justify-content: space-between; /* Добавлено */
        }

        .title-content::before {
            content: '';
            position: absolute;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, transparent 60%);
            transform: rotate(30deg);
            z-index: -1;
        }

        .ministry-text {
            font-size: 1.5em; /* Увеличиваем размер шрифта */
            margin-bottom: 1.5vh;
            line-height: 1.6;
            color: #2c3e50;
        }

        .university-name {
            font-size: 2em; /* Увеличиваем размер шрифта */
            font-weight: 700;
            margin-bottom: 3vh;
            color: #2c3e50;
            line-height: 1.4;
        }

        .department-name {
            font-size: 1.7em; /* Увеличиваем размер шрифта */
            font-weight: 500;
            margin-bottom: 4vh;
            color: #34495e;
        }

        .virtual-lab {
            font-size: 1.6em; /* Увеличиваем размер шрифта */
            color: #34495e;
            text-align: center;
            margin-bottom: 1vh;
            font-style: italic;
        }

        .lab-name {
            font-size: 1.8em; /* Увеличиваем размер шрифта */
            font-weight: 700;
            margin-bottom: 4vh;
            color: #2c3e50;
            text-align: center;
            line-height: 1.5;
        }

        .button-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 3vh;
            margin-top: 0.1vh;
        }

        .secondary-buttons {
            display: flex;
            gap: 30px;
            justify-content: center;
        }

        .title-button {
            padding: 2.4vh 2vw;
            min-width: 15vw;
            font-size: 1.3em;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 4.5vh;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 8px 20px rgba(52, 152, 219, 0.3);
        }

        .instruction-title h2 {
            text-align: center;
            color: #2c3e50;
            font-size: 22px;
            line-height: 1.4;
            margin-bottom: 30px;
        }

        .instruction-title .work-name {
            display: block;
            font-size: 26px; /* Увеличенный размер для названия работы */
            font-weight: 700; /* Делаем шрифт жирнее */
        }

        .instruction-title h2 br {
            margin-bottom: 5px;
        }

        .main-button {
            background-color: #3498db;
            width: 28vw;
            font-size: 1.3em;
            padding: 2vh 4vw;
        }

        .main-button:hover {
            background-color: #3498db;
        }

        .title-button:hover {
            transform: translateY(-5px);
            box-shadow: 0 12px 25px rgba(41, 128, 185, 0.4);
        }

        .instruction-button {
            background-color: #3498db;
        }

        .authors-button {
            position: absolute;
            bottom: 2vh;
            right: 2vw;
            padding: 1vh 1vw;
            min-width: auto;
            font-size: 0.8em;
            background-color: #87CEEB;
            box-shadow: 0 4px 10px rgba(149, 165, 166, 0.3);
        }

        .parameters-list {
            display: flex;
            flex-direction: column;
            gap: 8px;
            margin-top: 10px;
            color: #7f8c8d;
        }

        .parameters-list span {
            font-size: 16px;
            padding-left: 10px;
        }
        .experiment-title {
            color: #2c3e50;
            text-align: center;
            font-size: 2em; /* уменьшаем размер шрифта */
            margin-bottom: 10px;
            margin-top: 10px;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
            white-space: nowrap; /* запрещаем перенос строки */
        }

        .logo-container {
            position: absolute;
            top: 2vh;
            right: 2vw;
            display: flex;
            align-items: center;
            background-color: transparent;
            z-index: 10;
        }

        .logo {
            width: 12vmin; /* Размер логотипа */
            height: auto;
        }

        .text_logo {
            font-size: 13px; /* Текст около логотипа */
            line-height: 1.3;
            color: #333;
        }
    </style>
</head>
<body>
<div class="title-page" id="titlePage">
    <div class="title-content">
        <div class="logo-container">
            <img src="extra/emblem.png" alt="Логотип" class="logo">
        </div>
        <div class="ministry-text">
            Министерство науки и высшего образования Российской Федерации
        </div>
        <div class="university-name">
            Кузбасский государственный технический университет <br>имени Т.Ф. Горбачева
        </div>
        <div class="department-name">
            Кафедра физики<br><br>
        </div>
        <div class="virtual-lab">
            Виртуальная лабораторная работа
        </div>
        <div class="lab-name">
            ОПРЕДЕЛЕНИЕ СКОРОСТИ ПУЛИ C ПОМОЩЬЮ<br>
            БАЛЛИСТИЧЕСКОГО МАЯТНИКА<br><br>
        </div>
        <div class="button-container">
            <button class="title-button main-button" onclick="startLab()">Начать выполнение работы</button>
            <div class="main-buttons">
                <button class="title-button instruction-button" onclick="showInstructions()">Просмотреть <br>инструкцию к работе</button>
                <button class="title-button method-button" onclick="downloadMethodical()">Скачать <br>методические указания</button>
            </div>
        </div>
        <button class="title-button authors-button" onclick="showAuthors()">О программе</button>
    </div>
</div>
<h1 class="experiment-title">ОПРЕДЕЛЕНИЕ СКОРОСТИ ПУЛИ С ПОМОЩЬЮ БАЛЛИСТИЧЕСКОГО МАЯТНИКА</h1>
<audio id="gunshotSound" src="extra/spring.mp3" preload="auto"></audio>
<div class="container">
    <div class="left-panel" id="canvas-container">
        <!-- Сюда будет добавлен canvas через Matter.js -->
    </div>
    <div class="right-panel">
        <div class="panel-section">
            <h2 class="section-title">Параметры лабораторной установки</h2>
            <div id="controls">
                <label>
                    Масса пули <i style="margin: 0; padding: 0; font-family: 'Times New Roman';">m</i>: <span id="bulletMassValue">0.1 кг</span>
                    <input type="range" id="bulletMass" min="0.025" max="0.25" value="0.1" step="0.005" class="slider">
                </label>
                <label>
                    Масса маятника <i style="margin: 0; padding: 0; font-family: 'Times New Roman';">M</i>: <span id="pendulumMassValue">3 кг</span>
                    <input type="range" id="pendulumMass" min="2" max="5" value="3" step="0.1" class="slider">
                </label>
                <label>
                    Длина стержня маятника <i style="margin: 0; padding: 0; font-family: 'Times New Roman';">l</i>: <span id="pendulumLengthValue">1.0 м</span>
                    <input type="range" id="pendulumLength" min="0.5" max="1.5" value="1.0" step="0.01" class="slider">
                </label>
                <button id="shootBtn">Выстрел</button>
            </div>
        </div>
        <div class="panel-section">
            <h2 class="section-title">Таблица результатов измерений</h2>
            <div class="table-section">
                <div class="table-container">
                    <table id="resultsTable">
                        <thead>
                        <tr>
                            <th>Номер опыта</th>
                            <th>Максимальное отклонение (м)</th>
                        </tr>
                        </thead>
                        <tbody>
                        <!-- Здесь будут результаты -->
                        </tbody>
                    </table>
                </div>
                <button id="clearTableBtn">Очистить таблицу</button>
                <div class="separator"></div>
                <div class="back-to-title-container">
                    <button id="backToTitleBtn">Вернуться на титульный лист</button>
                </div>
            </div>
        </div>
    </div>
</div>
<script>

    document.getElementById('backToTitleBtn').addEventListener('click', () => {
        // resetPendulum();
        // clearTable();
        // document.getElementById('titlePage').style.display = 'block';
        // document.getElementById('mainContent').style.display = 'none';
        if (confirm('Вы уверены, что хотите вернуться на титульный лист? \nДанные в таблице результатов измерений будут сброшены.')) {
            location.reload();
        }
    });

    function startLab() {
        document.getElementById('titlePage').style.display = 'none';
        document.getElementById('mainContent').style.display = 'block';
    }

    function downloadMethodical() {
        const link = document.createElement('a');
        link.href = 'extra/Методические указания.docx'; // Путь к файлу для скачивания
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }

    function downloadManual() {
        const link = document.createElement('a');
        link.href = 'extra/Инструкция.docx'; // Путь к файлу для скачивания
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }

    function downloadAbout() {
        const link = document.createElement('a');
        link.href = 'extra/О программе.docx'; // Путь к файлу для скачивания
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }

    function showInstructions() {
        const modalHtml = `
    <div id="instructionsModal" class="modal">
        <div class="modal-content instructions-content">
            <span class="close-button">&times;</span>
            <div class="instruction-title">
                <h2>
                    Инструкция <br>к виртуальной лабораторной работе<br>
                    <span class="work-name">
                        «ОПРЕДЕЛЕНИЕ СКОРОСТИ ПУЛИ С ПОМОЩЬЮ<br>
                        БАЛЛИСТИЧЕСКОГО МАЯТНИКА»
                    </span>
                </h2>
            </div>
            <div class="instruction-steps">
                <div class="step">
                    <div class="step-number">1</div>
                    <div class="step-content">
                        <h3>Установка параметров лабораторной установки</h3>
                        <ul>
                            <li>Установите массу пули (от 0.025 до 0.25 кг) с помощью первого ползунка.</li>
                            <li>Задайте массу маятника (от 2 до 5 кг) с помощью второго ползунка.</li>
                            <li>Задайте длину стержня маятника (от 0.5 до 1.5 м) с помощью третьего ползунка.</li>
                            <li>Обратите внимание, что изменение любого параметра приведет к сбросу эксперимента и очистке таблицы.</li>
                        </ul>
                    </div>
                </div>
                <div class="step">
                    <div class="step-number">2</div>
                    <div class="step-content">
                        <h3>Проведение эксперимента</h3>
                        <ul>
                            <li>Нажмите кнопку «Выстрел» или же клавишу «Enter» на клавиатуре компьютера для запуска эксперимента.</li>
                        </ul>
                    </div>
                </div>
                <div class="step">
                    <div class="step-number">3</div>
                    <div class="step-content">
                        <h3>Наблюдение и запись результатов</h3>
                        <ul>
                            <li>Следите за движением маятника после столкновения с пулей.</li>
                            <li>На линейке красной вертикальной линией будет показано максимальное отклонение маятника, эта же линейка продублирована снизу для удобства.</li>
                            <li>В таблице результатов измерений отобразится номер опыта и максимальное отклонение маятника в метрах.</li>
                        </ul>
                    </div>
                </div>
                <div class="step">
                    <div class="step-number">4</div>
                    <div class="step-content">
                        <h3>Повторение эксперимента</h3>
                        <ul>
                            <li>Для повторного проведения опыта снова нажмите кнопку «Выстрел» или же клавишу «Enter» на клавиатуре компьютера.</li>
                            <li>Вы можете изменить параметры лабораторной установки перед проведением каждой серией опытов.</li>
                            <li>Для очистки результатов после проведении серии опытов можно нажать кнопку «Очистить таблицу» или изменить какой-либо параметр установки.</li>
                        </ul>
                    </div>
                </div>
            </div>
            <button class="download-button" onclick="downloadManual()">Скачать инструкцию</button>
        </div>
    </div>
    `;

        const styles = `
        <style>
            .modal {
                display: flex;
                position: fixed;
                z-index: 1000;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
                background-color: rgba(0,0,0,0.5);
                animation: fadeIn 0.3s;
                justify-content: center;
                align-items: center;
            }

            @keyframes fadeIn {
                from {opacity: 0;}
                to {opacity: 1;}
            }

            .modal-content {
                background-color: #ffffff;
                padding: 40px;
                border-radius: 20px;
                width: 80%;
                max-width: 800px;
                max-height: 90vh;
                overflow-y: auto;
                box-shadow: 0 10px 30px rgba(0,0,0,0.2);
            }

            .instructions-content h2 {
                color: #2c3e50;
                text-align: center;
                margin-bottom: 30px;
                font-size: 29px;
                font-weight: 800;
            }

            .instruction-steps {
                display: flex;
                flex-direction: column;
                gap: 25px;
            }

            .step {
                display: flex;
                align-items: flex-start;
                background-color: #f8f9fa;
                border-radius: 15px;
                padding: 20px;
                transition: transform 0.2s, box-shadow 0.2s;
            }

            .step:hover {
                transform: translateY(-5px);
                box-shadow: 0 5px 15px rgba(0,0,0,0.1);
            }

            .step-number {
                background-color: #3498db;
                color: white;
                width: 40px;
                height: 40px;
                border-radius: 50%;
                display: flex;
                justify-content: center;
                align-items: center;
                font-size: 20px;
                font-weight: bold;
                margin-right: 20px;
                flex-shrink: 0;
            }

            .step-content {
                flex-grow: 1;
            }

            .step-content h3 {
                color: #2F4F4F;
                margin: 0 0 10px 0;
                font-size: 24px;
                font-weight: 700;
            }

            .step-content p, .step-content ul {
                color: #808080;
                margin: 0;
                font-size: 20px;
                font-weight: 600;
            }

            .step-content ul {
                padding-left: 20px;
                margin-top: 10px;
            }

            .close-modal {
                display: block;
                margin: 30px auto 0;
                padding: 10px 20px;
                background-color: #3498db;
                color: white;
                border: none;
                border-radius: 5px;
                font-size: 16px;
                cursor: pointer;
                transition: background-color 0.2s;
            }

            .close-modal:hover {
                background-color: #2980b9;
            }

            .close-button {
                position: absolute;
                top: 10px;
                right: 15px;
                font-size: 60px;
                font-weight: bold;
                color: #DC143C;
                cursor: pointer;
                transition: color 0.2s;
                z-index: 1001;
                padding: 5px;
                line-height: 20px;
            }

        .close-button:hover {
            color: #cc0000;
        }

        .download-button {
            display: block;
            margin: 30px auto 0;
            padding: 12px 24px;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 5px;
            font-size: 28px;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .download-button:hover {
            background-color: #2980b9;
        }

        .modal-content {
            position: relative;
            background-color: #ffffff;
            padding: 40px;
            border-radius: 20px;
            width: 80%;
            max-width: 800px;
            max-height: 90vh;
            overflow-y: auto;
        }
        </style>
    `;

        document.body.insertAdjacentHTML('beforeend', modalHtml + styles);

        const modal = document.getElementById('instructionsModal');
        const closeButton = modal.querySelector('.close-button');

        closeButton.onclick = function () {
            modal.remove();
        }

        window.onclick = function (event) {
            if (event.target == modal) {
                modal.remove();
            }
        }
    }

    function showMethodology() {
        const modalHtml = `
        <div id="methodologyModal" class="modal">
            <div class="modal-content methodology-content">
                <span class="close-button">&times;</span>
                <h2>
                    Методические указания <br>к виртуальной лабораторной работе<br>
                    <span class="work-name" style="margin-top: 10px; display: inline-block;">
                        «ОПРЕДЕЛЕНИЕ СКОРОСТИ ПУЛИ С ПОМОЩЬЮ<br>
                        БАЛЛИСТИЧЕСКОГО МАЯТНИКА»
                    </span>
                </h2>
                <div class="methodology-container">
                    <div class="instruction-steps">
                        <div class="step">
                            <div class="step-number">1</div>
                            <div class="step-content">
                                <h3>Подготовка к работе</h3>
                                <p>Перед началом эксперимента убедитесь, что вы:</p>
                                <ul>
                                    <li>Знаете законы сохранения энергии и импульса</li>
                                    <li>Умеете пользоваться измерительными приборами</li>
                                    <li>Умеете рассчитывать погрешности измерений</li>
                                    <li>Знаете устройство установки и порядок измерений</li>
                                </ul>
                            </div>
                        </div>

                        <div class="step">
                            <div class="step-number">2</div>
                            <div class="step-content">
                                <h3>Цель работы</h3>
                                <p>Освоить метод определения скорости пули с помощью баллистического маятника</p>
                            </div>
                        </div>

                        <div class="step">
                            <div class="step-number">3</div>
                            <div class="step-content">
                                <h3>Проведение эксперимента</h3>
                                <ol>
                                    <li>Установите параметры установки согласно указаниям преподавателя, используя ползунки для массы пули, массы маятника и длины жесткого стержня</li>
                                    <li>Произведите пять выстрелов, нажимая кнопку "Выстрел" или клавишу Enter</li>
                                    <li>Наблюдайте за отклонением маятника после каждого выстрела</li>
                                    <li>Заполните таблицу 1, представленную в файле методических указаний, данными о максимальном отклонении маятника и о текущей массе пули</li>
                                    <li>Рассчитайте постоянную установки C, среднее значение смещения ⟨x⟩ и среднюю скорость пули ⟨v⟩</li>
                                </ol>
                            </div>
                        </div>

                        <div class="step">
                            <div class="step-number">4</div>
                            <div class="step-content">
                                <h3>Исследование зависимости скорости пули от её массы</h3>
                                <ol>
                                    <li>Проведите пять измерений для двух дополнительных масс пуль (m₂ и m₃), повышающихся минимум на 0.1 кг относительно друг друга</li>
                                    <li>Заполните таблицы 1.2 и 1.3, составленные аналогично таблице 1 из методических указаний, для каждой массы</li>
                                    <li>Вычислите скорости для каждой массы пули и занесите результаты в таблицу 4, представленную в методических указаниях.</li>
                                    <li>Постройте график зависимости скорости пули v от √(1/m)</li>
                                    <li>Рассчитайте абсолютную погрешность прямого измерения горизонтального смещения при выстреле первой пули и относительную погрешность определения скорости пули.</li>
                                </ol>
                            </div>
                        </div>
                        <div class="step">
                            <div class="step-number">5</div>
                            <div class="step-content">
                                <h3>Вывод</h3>
                                <p>Сформулируйте вывод к проделанной работе</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    `;

        const styles = `
        <style>
            .modal {
                display: flex;
                position: fixed;
                z-index: 1000;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
                background-color: rgba(0,0,0,0.5);
                justify-content: center;
                align-items: center;
            }

            .modal-content {
                background-color: #ffffff;
                padding: 40px;
                border-radius: 20px;
                width: 80%;
                max-width: 800px;
                max-height: 90vh;
                overflow-y: auto;
                position: relative;
            }

            .methodology-content h2 {
                color: #2c3e50;
                text-align: center;
                margin-bottom: 30px;
                font-size: 28px;
                font-weight: 700;
            }

            .instruction-steps {
                display: flex;
                flex-direction: column;
                gap: 25px;
            }

            .step {
                display: flex;
                align-items: flex-start;
                background-color: #f8f9fa;
                border-radius: 15px;
                padding: 20px;
                transition: transform 0.2s, box-shadow 0.2s;
            }

            .step:hover {
                transform: translateY(-5px);
                box-shadow: 0 5px 15px rgba(0,0,0,0.1);
            }

            .step-number {
                background-color: #3498db;
                color: white;
                width: 40px;
                height: 40px;
                border-radius: 50%;
                display: flex;
                justify-content: center;
                align-items: center;
                font-size: 20px;
                font-weight: bold;
                margin-right: 20px;
                flex-shrink: 0;
            }

            .step-content {
                flex-grow: 1;
            }

            .step-content h3 {
                color: #34495e;
                margin: 0 0 10px 0;
                font-size: 20px;
            }

            .step-content p,
            .step-content ul,
            .step-content ol {
                color: #7f8c8d;
                margin: 0;
                font-size: 16px;
                line-height: 1.6;
            }

            .step-content ul,
            .step-content ol {
                padding-left: 20px;
                margin-top: 10px;
            }

            .step-content li {
                margin-bottom: 8px;
            }

            .close-modal {
                display: block;
                margin: 30px auto 0;
                padding: 12px 24px;
                background-color: #3498db;
                color: white;
                border: none;
                border-radius: 5px;
                font-size: 16px;
                cursor: pointer;
                transition: background-color 0.2s;
            }

            .close-modal:hover {
                background-color: #2980b9;
            }

            .methodology-container {
                margin-bottom: 20px;
            }

            .close-button {
                position: absolute;
                top: 10px;
                right: 15px;
                font-size: 60px;
                font-weight: bold;
                color: #DC143C;
                cursor: pointer;
                transition: color 0.2s;
                z-index: 1001;
                padding: 5px;
                line-height: 20px;
            }

        .close-button:hover {
            color: #cc0000;
        }

        .download-button {
            display: block;
            margin: 30px auto 0;
            padding: 12px 24px;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 5px;
            font-size: 16px;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .download-button:hover {
            background-color: #2980b9;
        }

        .modal-content {
            position: relative;
            background-color: #ffffff;
            padding: 40px;
            border-radius: 20px;
            width: 80%;
            max-width: 800px;
            max-height: 90vh;
            overflow-y: auto;
        }
        </style>
    `;

        document.body.insertAdjacentHTML('beforeend', modalHtml + styles);

        const modal = document.getElementById('methodologyModal');
        const closeButton = modal.querySelector('.close-button');

        closeButton.onclick = function () {
            modal.remove();
        }

        window.onclick = function (event) {
            if (event.target == modal) {
                modal.remove();
            }
        }
    }

    // <p>Студент группы ПИб-232</p>
    // <a href="http://bishoni.ru/" target="_blank" className="author-link">Портфолио</a>

    // <p>Студентка группы ПИб-232</p>

    function showAuthors() {
    const modalHtml = `
    <div id="authorsModal" class="modal">
        <div class="modal-content authors-content">
            <span class="close-button">&times;</span>
            <h2>О программе</h2>
            <div class="author-card">
                <div class="author-info">
                    <h3>Виртуальная лабораторная работа «Определение скорости пули с помощью баллистического маятника» создана в ФГБОУ ВО Кузбасском государственном техническом университете имени Т.Ф. Горбачева, 2024 г., на кафедре физики, для выполнения лабораторного практикума по физике.
                    <br><br>Виртуальная лабораторная работа «Определение скорости пули с помощью баллистического маятника» предназначена для самостоятельной подготовки к выполнению лабораторной работы. Основная цель: определение скорости пули, используя специальную виртуальную установку, изучение законов сохранения энергии и импульса.
                    <br><br>Студенты получают возможность ознакомиться с лабораторной установкой «Баллистический Маятник», ее устройством и принципом работы, с последовательностью проведением опытов и измерений, с расчётом различных физических величин, в том числе, скорости.
                    <br><br>Основные требования к ЭВМ и оборудованию: минимальный объём памяти 2 Мб, операционная система Windows XP и выше.
                    </h3>
                </div>
            </div>
            <div class="author-card">
                <div class="author-info">
                    <h3>Елкин Иван Сергеевич</h3>
                    <p>Доцент (к.н.) ГИ: Физики</p>
                </div>
            </div>
            <div class="author-card">
                <div class="author-info">
                    <h3>Пачкин Евгений Дмитриевич</h3>
                    <p>Студент группы ПИб-232</p>
                </div>
            </div>
            <div class="author-card">
                <div class="author-info">
                    <h3>Тугбаева Эвелина Андреевна</h3>
                    <p>Студент группы ПИб-232</p>
                </div>
            </div>
            <button class="download-button" onclick="downloadAbout()">Скачать "О программе"</button>
        </div>
    </div>
    `;
        // Добавляем стили
        const styles = `
    <style>
        .modal {
            display: flex;
            position: fixed;
            z-index: 1000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.5);
            animation: fadeIn 0.3s;
            justify-content: center;
            align-items: center;
        }
        @keyframes fadeIn {
            from {opacity: 0;}
            to {opacity: 1;}
        }
        .modal-content {
            background-color: #fefefe;
            padding: 30px;
            border-radius: 15px;
            width: 100%;
            max-width: 65vw;
            position: relative;
            box-shadow: 0 4px 20px rgba(0,0,0,0.2);
            overflow-y: auto;
            max-height: 90vh;
        }
        .authors-content h2 {
            color: #2c3e50;
            text-align: center;
            margin-bottom: 30px;
            font-size: 40px;
        }
        .author-card {
            background-color: #f8f9fa;
            border-radius: 10px;
            padding: 20px;
            margin-bottom: 20px;
            transition: transform 0.2s;
        }
        .author-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }
        .author-info h3 {
            color: #34495e;
            margin: 0 0 10px 0;
            font-size: 24px;
        }
        .author-info p {
            color: #7f8c8d;
            margin: 5px 0;
            font-weight: 600;
        }
        .close-button {
            position: absolute;
            top: 10px;
            right: 15px;
            font-size: 60px;
            font-weight: bold;
            color: #DC143C;
            cursor: pointer;
            transition: color 0.2s;
            z-index: 1001;
            padding: 5px;
            line-height: 20px;
        }
        .close-button:hover {
            color: #cc0000;
        }
        .download-button {
            display: block;
            margin: 30px auto 0;
            padding: 12px 24px;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 5px;
            font-size: 16px;
            cursor: pointer;
            transition: background-color 0.2s;
        }
        .download-button:hover {
            background-color: #2980b9;
        }
    </style>
    `;
        // Добавляем модальное окно и стили в документ
        document.body.insertAdjacentHTML('beforeend', modalHtml + styles);
        // Добавляем обработчики событий
        const modal = document.getElementById('authorsModal');
        const closeButton = modal.querySelector('.close-button');
        closeButton.onclick = function () {
        modal.remove();
    }
        window.onclick = function (event) {
        if (event.target == modal) {
        modal.remove();
    }
    }
        // Добавление свайпа для закрытия
        let startX;
        modal.addEventListener('touchstart', (e) => {
        startX = e.touches[0].clientX;
    });
        modal.addEventListener('touchmove', (e) => {
        const moveX = e.touches[0].clientX;
        if (startX - moveX > 100) { // Если свайп влево
        modal.remove();
    }
    });

    }

    const {Engine, Render, World, Bodies, Body, Constraint, Events} = Matter;
    const engine = Engine.create({
        enableSleeping: false,
        constraintIterations: 10,
        positionIterations: 10,
        velocityIterations: 10,
        timing: {
            timeScale: 1,
            timestamp: 0,
            lastDelta: 16.666666666666668, // 60 FPS
        }
    });
    const render = Render.create({
        element: document.getElementById('canvas-container'),
        engine: engine,
        options: {
            width: 800,
            height: 730,
            wireframes: false,
            background: '#ffffff',
            fps: 60
        }
    });

    const randomFactor = 0.10; // рандомизация 10%

    const scaleY = 300;
    const scaleX = 300;
    const anchorX = 400;
    const anchorY = 50;
    const initialPendulumMass = parseFloat(document.getElementById('pendulumMass').value);
    const initialPendulumLength = parseFloat(document.getElementById('pendulumLength').value);

    let bob, string, constraintTop, constraintBottom, bullet;
    let initialBobPosition;
    let maxDisplacement = 0;
    let lastExtremum = 0;
    let oscillationCount = 0;
    let collided = false;
    let experimentNumber = 0;
    let resultAdded = false;
    let gunGraphics, springGraphics;
    let attachedBullet = null;
    let isShooting = false;
    let rulerGraphics = {
        visible: false,
        initialPendulumX: null,
        initialPendulumY: null,
        rulerLength: 300,
        divisionValue: 10,
        smallDivisionValue: 1,
        fixedDivisions: 10,
        topRulerConfig: {
            offsetX: 31 // Смещение для верхней линейки
        },

        bottomRulerConfig: {
            length: 750,
            startX: 25,
            startY: 625,
            divisions: 10,
            mainDivisionHeight: 25,
            smallDivisionHeight: 15,
            fontSize: '30px Arial',
            lineWidth: 2,
            valueMultiplier: 10,
            offsetX: 76.5 // Смещение для нижней линейки
        },

        formatNumber: function (num) {
            return Number.isInteger(num) ? num.toString() : num.toFixed(2);
        },

        // Функция для отрисовки верхней линейки
        drawTopRuler: function (ctx) {
            ctx.fillStyle = '#000000';
            ctx.fillRect(this.initialPendulumX, this.initialPendulumY + 30, this.rulerLength, 2);

            ctx.font = '18px Arial';
            ctx.textAlign = 'center';
            const divisionSpacing = this.rulerLength / this.fixedDivisions;

            // Подпись единиц измерения
            ctx.textAlign = 'left';
            ctx.fillText('Х, см', this.initialPendulumX + this.rulerLength + 10, this.initialPendulumY + 35);
            ctx.textAlign = 'center';

            // Основные деления
            for (let i = 0; i <= this.fixedDivisions; i++) {
                const divisionX = this.initialPendulumX + (i * divisionSpacing);
                ctx.fillRect(divisionX, this.initialPendulumY + 20, 1, 20);
                const value = i * this.divisionValue;
                ctx.fillText(this.formatNumber(value), divisionX, this.initialPendulumY + 15);

                // Промежуточные деления
                if (i < this.fixedDivisions) {
                    for (let j = 1; j < 10; j++) {
                        const smallDivisionX = divisionX + (j * divisionSpacing / 10);
                        const divisionHeight = j % 5 === 0 ? 15 : 10;
                        ctx.fillRect(smallDivisionX, this.initialPendulumY + 30 - divisionHeight / 2, 1, divisionHeight);
                    }
                }
            }

            // Отрисовка отклонения для верхней линейки
            this.drawDeviation(ctx, this.initialPendulumX, this.initialPendulumY, this.rulerLength, false);
        },

        // Функция для отрисовки нижней линейки
        drawBottomRuler: function (ctx) {
            const cfg = this.bottomRulerConfig;
            // Основная линия
            ctx.fillStyle = '#000000';
            ctx.fillRect(cfg.startX, cfg.startY + 30, cfg.length, 4); // Центральная линия

            ctx.font = cfg.fontSize;
            ctx.textAlign = 'center';
            const divisionSpacing = cfg.length / cfg.divisions;

            // Подпись единиц измерения
            ctx.textAlign = 'left';
            ctx.fillText('Х, см', cfg.startX + cfg.length - 50, cfg.startY + 80);
            ctx.textAlign = 'center';

            // Основные деления
            for (let i = 0; i <= cfg.divisions; i++) {
                const divisionX = cfg.startX + (i * divisionSpacing);
                // Центрируем основные деления относительно центральной линии
                ctx.fillRect(divisionX, cfg.startY + 30 - 25, 3, 50); // 25 пикселей вверх и 25 вниз от центра
                const value = i * cfg.valueMultiplier;
                ctx.fillText(value.toString(), divisionX, cfg.startY);

                // Промежуточные деления
                if (i < cfg.divisions) {
                    for (let j = 1; j < 10; j++) {
                        const smallDivisionX = divisionX + (j * divisionSpacing / 10);
                        const divisionHeight = j % 5 === 0 ? 40 : 30;
                        // Центрируем промежуточные деления
                        ctx.fillRect(
                            smallDivisionX,
                            cfg.startY + 30 - divisionHeight / 2, // Центрируем относительно основной линии
                            2,
                            divisionHeight
                        );
                    }
                }
            }

            // Отрисовка отклонения для нижней линейки
            this.drawDeviation(ctx, cfg.startX, cfg.startY, cfg.length, true);
        },

        // Общая функция для отрисовки отклонения
        drawDeviation: function (ctx, startX, startY, length, isBottom) {
            if (maxDisplacement !== undefined) {
                const divisionSpacing = isBottom ?
                    length / this.bottomRulerConfig.divisions :
                    this.rulerLength / this.fixedDivisions;

                const offset = isBottom ?
                    this.bottomRulerConfig.offsetX :
                    this.topRulerConfig.offsetX;

                const displacementX = startX + offset + (maxDisplacement / this.divisionValue) * divisionSpacing * 100;

                ctx.strokeStyle = 'red';
                ctx.lineWidth = isBottom ? 2 : 1;
                ctx.beginPath();

                if (isBottom) {
                    // Рисуем линию ниже для нижней линейки
                    ctx.moveTo(displacementX, startY - 30);
                    ctx.lineTo(displacementX, startY + 65);
                } else {
                    // Для верхней линейки оставляем как было
                    ctx.moveTo(displacementX, startY - 30);
                    ctx.lineTo(displacementX, startY + 50);
                }

                ctx.stroke();

                ctx.fillStyle = 'red';
                ctx.font = isBottom ? '22px Arial' : '18px Arial';

                if (isBottom) {
                    // Подпись для нижней линейки рисуем ниже
                    ctx.fillText(this.formatNumber(maxDisplacement * 100) + ' см', displacementX, startY + 85);
                } else {
                    // Для верхней линейки оставляем как было
                    ctx.fillText(this.formatNumber(maxDisplacement * 100) + ' см', displacementX, startY + 65);
                }
            }
        },

        // Основная функция отрисовки
        draw: function () {
            const ctx = render.context;
            if (this.visible && this.initialPendulumX !== null && this.initialPendulumY !== null) {
                this.drawTopRuler(ctx);
                this.drawBottomRuler(ctx);
            }
        }
    };

    function updatePendulumAngle() {
        if (bob && initialBobPosition) {
            // Вычисляем вектор от точки подвеса к текущей позиции маятника
            const dx = bob.position.x - string.vertices[0].x;
            const dy = bob.position.y - string.vertices[0].y;

            // Вычисляем угол отклонения от вертикали
            const angle = Math.atan2(dx, -dy);

            // Устанавливаем угол для тела маятника
            Body.setAngle(bob, angle);
        }
    }

    function createPendulum(length, mass) {
        createStaticSupport(anchorX, anchorY);
        bob = Bodies.circle(anchorX, anchorY + length * scaleY, 30, {
            mass: mass,
            restitution: 0,
            friction: 0,
            frictionAir: 0,
            render: {
                visible: false
            }
        });

        initialBobPosition = {x: bob.position.x, y: bob.position.y};


        string = Bodies.rectangle(anchorX, anchorY + (length * scaleY) / 2, 2, length * scaleY, {
            isStatic: false,
            isSensor: true,
            collisionFilter: {
                group: -1,
                category: 0x0002,
                mask: 0x0000
            },
            render: {
                fillStyle: '#000000'
            }
        });

        constraintTop = Constraint.create({
            bodyA: string,
            pointA: {x: 0, y: -length * scaleY / 2},
            pointB: {x: anchorX, y: anchorY},
            stiffness: 1,
            length: 0
        });

        constraintBottom = Constraint.create({
            bodyA: string,
            bodyB: bob,
            pointA: {x: 0, y: length * scaleY / 2},
            pointB: {x: 0, y: 0},
            stiffness: 1,
            length: 0
        });

        World.add(engine.world, [bob, string, constraintTop, constraintBottom]);
        createGun(anchorX);
        rulerGraphics.initialPendulumX = 400;
        rulerGraphics.initialPendulumY = anchorY + length * scaleY;
        rulerGraphics.visible = true;
        rulerGraphics.draw();
    }

    function updatePendulumLength() {
        const newLength = parseFloat(document.getElementById('pendulumLength').value);
        if (bob && string && constraintTop && constraintBottom) {
            // Обновляем позицию маятника
            Body.setPosition(bob, {x: anchorX, y: anchorY + newLength * scaleY});

            // Обновляем длину и позицию нити
            Body.setPosition(string, {x: anchorX, y: anchorY + (newLength * scaleY) / 2});
            Body.scale(string, 1, newLength / (string.bounds.max.y - string.bounds.min.y) * scaleY);

            // Обновляем верхнее ограничение
            constraintTop.pointA.y = -newLength * scaleY / 2;

            // Обновляем нижнее ограничение
            constraintBottom.pointA.y = newLength * scaleY / 2;

            // Обновляем позицию пистолета
            if (gunGraphics) {
                gunGraphics.y = bob.position.y;
            }

            // Обновляем позицию пружины
            if (springGraphics) {
                springGraphics.y = bob.position.y;
            }

            // Обновляем позицию линейки
            rulerGraphics.initialPendulumY = anchorY + newLength * scaleY;

            // Сбрасываем результаты
            resetResults();
        }
    }

    function createStaticSupport(anchorX, anchorY) {
        // Создаем горизонтальную балку
        const beam = Bodies.rectangle(anchorX, anchorY - 10, 350, 30, {
            isStatic: true,
            render: {
                fillStyle: '#666666',
                strokeStyle: '#444444',
                lineWidth: 1
            }
        });

        // Создаем вертикальную стойку
        const pole = Bodies.rectangle(anchorX, anchorY - 35, 30, 50, {
            isStatic: true,
            render: {
                fillStyle: '#666666',
                strokeStyle: '#444444',
                lineWidth: 1
            }
        });

        World.add(engine.world, [beam, pole]);
    }

    const g = 9.81;

    function createGun(anchorX, scale = 1.2) {
        const gunX = anchorX - 130;
        const gunY = bob.position.y;
        // Создаем графический объект для пистолета
        gunGraphics = {
            x: gunX,
            y: gunY,
            draw: function () {
                const ctx = render.context;

                // Рукоятка
                ctx.fillStyle = '#455A64';  // Сделал темнее
                ctx.strokeStyle = '#37474F';  // Сделал темнее
                ctx.lineWidth = 1;
                ctx.fillRect(this.x - 12 * scale, this.y + 5, 25 * scale, 40 * scale);
                ctx.strokeRect(this.x - 12 * scale, this.y + 5, 25 * scale, 40 * scale);

                // Основной корпус
                ctx.fillStyle = '#546E7A';  // Сделал темнее
                ctx.strokeStyle = '#455A64';  // Сделал темнее
                ctx.fillRect(this.x - 35 * scale, this.y - 12 * scale, 70 * scale, 25 * scale);
                ctx.strokeRect(this.x - 35 * scale, this.y - 12 * scale, 70 * scale, 25 * scale);

                // Ствол
                ctx.fillStyle = '#37474F';  // Сделал значительно темнее
                ctx.strokeStyle = '#263238';  // Сделал значительно темнее
                ctx.fillRect(this.x + 15 * scale, this.y - 7 * scale, 25 * scale, 15 * scale);
                ctx.strokeRect(this.x + 15 * scale, this.y - 7 * scale, 25 * scale, 15 * scale);

                // Курок
                ctx.fillStyle = '#78909C';  // Сделал немного темнее
                ctx.strokeStyle = '#546E7A';  // Сделал немного темнее
                ctx.fillRect(this.x - 20 * scale, this.y + 10 * scale, 12 * scale, 6 * scale);
                ctx.strokeRect(this.x - 20 * scale, this.y + 10 * scale, 12 * scale, 6 * scale);
            }
        };

        // Создаем графический объект для пружины
        springGraphics = {
            x: gunX - 30 * scale,
            y: gunY,
            width: 30 * scale,
            height: 10 * scale,
            maxX: gunX - 30 * scale,
            minX: gunX - 60 * scale,
            segments: 10, // количество сегментов пружины
            draw: function () {
                const ctx = render.context;
                const segmentWidth = 2 * scale;
                // Вычисляем расстояние между сегментами на основе текущей ширины пружины
                const gap = (this.width - (segmentWidth * this.segments)) / (this.segments - 1);

                ctx.fillStyle = '#37474F';
                ctx.strokeStyle = '#263238';
                ctx.lineWidth = 1;

                // Рисуем каждый сегмент пружины
                for (let i = 0; i < this.segments; i++) {
                    const segmentX = this.x + i * (segmentWidth + gap);
                    ctx.fillRect(segmentX, this.y - this.height / 2, segmentWidth, this.height);
                }

                // Рисуем обводку всей пружины
                ctx.strokeRect(this.x, this.y - this.height / 2, this.width, this.height);
            }
        };
    }

    function calculateBulletRadius(mass) {
        const minRadius = 5; // Минимальный радиус
        const maxRadius = 9; // Максимальный радиус
        const minMass = 0.025; // Минимальная масса
        const maxMass = 0.25; // Максимальная масса

        // Нормализуем массу в диапазоне от 0 до 1
        const normalizedMass = (mass - minMass) / (maxMass - minMass);
        // Ограничиваем значение от 0 до 1
        const clampedNormalizedMass = Math.max(0, Math.min(1, normalizedMass));

        // Вычисляем радиус на основе нормализованной массы
        return Math.round(minRadius + (clampedNormalizedMass * (maxRadius - minRadius)));
    }

    function calculateBulletSpeed(displacement) {
        const bulletMass = parseFloat(document.getElementById('bulletMass').value);
        const pendulumMass = parseFloat(document.getElementById('pendulumMass').value);
        const pendulumLength = parseFloat(document.getElementById('pendulumLength').value);
        const C = ((bulletMass + pendulumMass) / bulletMass) * Math.sqrt(g / pendulumLength);
        const velocity = C * displacement;
        // console.log('bullet speed: ', velocity);
    }

    function shootBullet() {
        if (isShooting) return;
        isShooting = true;

        // Останавливаем текущее воспроизведение звука
        const gunshotSound = document.getElementById('gunshotSound');
        gunshotSound.pause();
        gunshotSound.currentTime = 0;

        engine.world.gravity.y = 0;
        const scale = 1.2;
        const bulletMass = parseFloat(document.getElementById('bulletMass').value);
        // const bulletMass = (getMass >= 0.08 && getMass <= 0.09) ? 0.07 :
        //     (getMass >= 0.1 && getMass <= 0.12) ? 0.13 : getMass;
        const startX = gunGraphics.x + 40;
        const startY = gunGraphics.y;
        const bulletRadius = calculateBulletRadius(bulletMass);

        bullet = Bodies.circle(startX, startY, bulletRadius, {
            mass: bulletMass,
            restitution: 1,
            friction: 0,
            frictionAir: 0,
            render: {
                fillStyle: '#ff0000',
                strokeStyle: '#cc0000',
                lineWidth: 1
            },
            isSensor: true,
            collisionFilter: {
                group: -1
            }
        });

        gunshotSound.volume = 0.1;

        let loadingStep = 0;
        const maxSteps = 20;
        const totalDistance = springGraphics.maxX - springGraphics.minX;
        const stepDistance = totalDistance / maxSteps;
        const initialWidth = 30 * scale;
        const maxWidth = initialWidth * 2;

        springGraphics.x = springGraphics.maxX;
        springGraphics.width = initialWidth;

        const loadingInterval = setInterval(() => {
            loadingStep++;
            springGraphics.x = springGraphics.maxX - (stepDistance * loadingStep);
            const progress = loadingStep / maxSteps;
            springGraphics.width = initialWidth + (maxWidth - initialWidth) * progress;

            if (loadingStep >= maxSteps) {
                clearInterval(loadingInterval);
                // Воспроизводим звук только после полной загрузки пружины
                if (isShooting) {
                    gunshotSound.play();
                }

                setTimeout(() => {
                    const stiffness = 10000;
                    const deformation = (totalDistance / 300) * (1 + (Math.random() * 2 - 1) * randomFactor);

                    const gunEnergy = 0.5 * stiffness * deformation * deformation;
                    // const gunEnergy = 80;
                    let velocityX = Math.sqrt(2 * gunEnergy / bulletMass);
                    // console.log('enegry: ', gunEnergy, '; deformation:', deformation, 'm; start speed: ', velocityX, 'm/s; bullet mass:', bulletMass, 'kg; current random:', (1 + (Math.random() * 2 - 1) * randomFactor));

                    World.add(engine.world, bullet);
                    Body.setVelocity(bullet, {x: velocityX, y: 0});

                    springGraphics.x = springGraphics.maxX;
                    springGraphics.width = initialWidth;

                    setTimeout(() => {
                        isShooting = false;
                    }, 500);
                }, 200);
            }
        }, 50);
    }

    function clearTable() {
        const tbody = document.getElementById('resultsTable').getElementsByTagName('tbody')[0];
        tbody.innerHTML = ''; // Очищаем содержимое таблицы
        experimentNumber = 0; // Сбрасываем номер эксперимента
    }


    function drawAttachedBullet(ctx) {
        if (attachedBullet && bob) {
            // Устанавливаем фиксированное смещение по X для пули
            const fixedOffsetX = bob.circleRadius + attachedBullet.radius - 3; // Пуля будет рисоваться с фиксированным смещением в 2 пикселя
            const fixedOffsetY = 0; // Пуля будет на том же уровне, что и центр маятника
            ctx.save();
            // Перемещаем в центр маятника
            ctx.translate(bob.position.x, bob.position.y);
            // Поворачиваем на угол маятника
            ctx.rotate(bob.angle);
            // Рисуем пулю
            ctx.beginPath();
            ctx.arc(
                fixedOffsetX,
                fixedOffsetY,
                attachedBullet.radius,
                0,
                2 * Math.PI
            );
            // Добавляем градиент для более реалистичного вида
            const bulletGradient = ctx.createRadialGradient(
                fixedOffsetX,
                fixedOffsetY,
                0,
                fixedOffsetX,
                fixedOffsetY,
                attachedBullet.radius
            );
            bulletGradient.addColorStop(0, '#ff3333');
            bulletGradient.addColorStop(1, '#cc0000');
            ctx.fillStyle = bulletGradient;
            ctx.fill();
            // Добавляем обводку
            ctx.strokeStyle = '#990000';
            ctx.lineWidth = 1;
            ctx.stroke();
            ctx.restore();
        }
    }

    function validateBulletPosition() {
        if (attachedBullet && bob) {
            const distance = Math.sqrt(
                attachedBullet.offsetX * attachedBullet.offsetX +
                attachedBullet.offsetY * attachedBullet.offsetY
            );

            // Если позиция пули сильно отклоняется от ожидаемой
            if (Math.abs(distance - bob.circleRadius) > 5) {
                // Корректируем позицию
                const scale = bob.circleRadius / distance;
                attachedBullet.offsetX *= scale;
                attachedBullet.offsetY *= scale;
            }
        }
    }

    function resetPendulum() {
        resetResults();
        const pendulumMass = parseFloat(document.getElementById('pendulumMass').value);
        const pendulumLength = parseFloat(document.getElementById('pendulumLength').value);
        World.clear(engine.world);
        initialBobPosition = {x: 400, y: anchorY + pendulumLength * scaleY};
        createPendulum(pendulumLength, pendulumMass);
        createGun(400);
        attachedBullet = null;
        rulerGraphics.initialPendulumX = 400;
        rulerGraphics.initialPendulumY = anchorY + pendulumLength * scaleY;
        if (!rulerGraphics.visible) {
            rulerGraphics.visible = true;
        }
        rulerGraphics.draw();
        collided = false;
    }

    function resetResults() {
        oscillationCount = 0;
        maxDisplacement = 0;
        lastExtremum = 0;
        resultAdded = false;
    }

    function validateInputs() {
        const bulletMass = parseFloat(document.getElementById('bulletMass').value);
        const pendulumMass = parseFloat(document.getElementById('pendulumMass').value);
        const pendulumLength = parseFloat(document.getElementById('pendulumLength').value);

        if (bulletMass < 0.025 || bulletMass > 1) {
            return false;
        }
        if (pendulumMass < 2 || pendulumMass > 5) {
            return false;
        }
        if (pendulumLength < 0.5 || pendulumLength > 1.5) {
            return false;
        }
        return true;
    }

    function addResultToTable(displacement) {
        if (resultAdded) return;
        experimentNumber++;
        const table = document.getElementById('resultsTable').getElementsByTagName('tbody')[0];
        const newRow = table.insertRow();

        // Добавляем класс для новой строки
        newRow.className = 'new-result';

        // Создаем ячейки с данными
        const cell1 = newRow.insertCell(0);
        const cell2 = newRow.insertCell(1);

        // Заполняем данными
        cell1.textContent = experimentNumber;
        cell2.textContent = displacement.toFixed(3);

        // Прокручиваем к новой записи с плавной анимацией
        const tableContainer = document.querySelector('.table-container');
        tableContainer.scrollTo({
            top: tableContainer.scrollHeight,
            behavior: 'smooth'
        });

        // Удаляем класс new-result у предыдущей "новой" строки
        const previousNewRow = table.querySelector('.new-result:not(:last-child)');
        if (previousNewRow) {
            previousNewRow.classList.remove('new-result');
        }
        calculateBulletSpeed(displacement)
    }


    // Обновите функцию, чтобы показывать линейку перед выстрелом
    document.getElementById('shootBtn').addEventListener('click', () => {
        if (!validateInputs()) {
            return;
        }
        if (isShooting) return;
        resetResults();
        // experimentNumber++;
        const pendulumMass = parseFloat(document.getElementById('pendulumMass').value);
        const pendulumLength = parseFloat(document.getElementById('pendulumLength').value);
        World.clear(engine.world);
        createPendulum(pendulumLength, pendulumMass);
        createGun(400);
        attachedBullet = null; // Сбрасываем "приклеенную" пулю

        // Устанавливаем начальные координаты маятника
        rulerGraphics.initialPendulumX = 400; // Позиция X якоря
        rulerGraphics.initialPendulumY = anchorY + pendulumLength * scaleY; // Позиция Y под маятником

        // Делаем линейку видимой только один раз
        if (!rulerGraphics.visible) {
            rulerGraphics.visible = true; // Делаем линейку видимой только один раз
            rulerGraphics.draw(maxDisplacement); // Рисуем линейку и деления перед выстрелом
        }

        shootBullet();
        collided = false;
    });

    function updateSliderValue(sliderId, valueId, unit) {
        const slider = document.getElementById(sliderId);
        const valueDisplay = document.getElementById(valueId);
        const value = parseFloat(slider.value);

        // Форматируем значение в зависимости от его типа
        let formattedValue;
        if (Number.isInteger(value)) {
            formattedValue = value.toString(); // Отображаем целое число без десятичных знаков
        } else {
            formattedValue = value.toFixed(3).replace(/\.?0+$/, ''); // Убираем лишние нули
        }

        // Добавляем единицу измерения
        valueDisplay.textContent = formattedValue + ' ' + unit;
    }

    document.getElementById('bulletMass').addEventListener('input', () => {
        updateSliderValue('bulletMass', 'bulletMassValue', 'кг');
        resetPendulum();
        clearTable();
    });

    document.getElementById('pendulumMass').addEventListener('input', () => {
        updateSliderValue('pendulumMass', 'pendulumMassValue', 'кг');
        resetPendulum();
        clearTable();
    });

    document.getElementById('pendulumLength').addEventListener('input', () => {
        updateSliderValue('pendulumLength', 'pendulumLengthValue', 'м');
        resetPendulum();
        updatePendulumLength();
        clearTable();
    });

    document.getElementById('clearTableBtn').addEventListener('click', function () {
        if (confirm('Вы уверены, что хотите очистить все данные в таблице результатов измерений?')) {
            clearTable();
        }
    });

    let notificationTimeout;
    let lastNotificationType = null;

    function checkElementsFit() {
        const titlePage = document.getElementById('titlePage');
        if (titlePage && titlePage.style.display !== 'none') {
            return;
        }

        const currentNotification = document.getElementById('fitNotification');
        if (currentNotification) {
            currentNotification.style.display = 'none';
        }

        const elements = document.querySelectorAll('.container, .left-panel, .right-panel, .panel-section');
        let allFit = true;
        const maxOverflowPercent = 11;

        elements.forEach(element => {
            const rect = element.getBoundingClientRect();
            const elementHeight = rect.bottom - rect.top;
            const overflow = Math.max(0, rect.bottom - window.innerHeight);
            const overflowPercent = (overflow / elementHeight) * 100;
            if (overflowPercent > maxOverflowPercent) {
                allFit = false;
            }
        });

        clearTimeout(notificationTimeout);
        notificationTimeout = setTimeout(() => {
            const baseFontSize = Math.min(window.innerWidth, window.innerHeight) * 0.025;
            if (!allFit) {
                const message = "Внимание! Элементы выходят за границы монитора. Уменьшите масштаб страницы!";
                showNotification(message, `${baseFontSize}px`, 'warning');
                lastNotificationType = 'warning';
            } else if (lastNotificationType === 'warning') {
                const message = "Масштаб страницы успешно настроен!";
                showNotification(message, `${baseFontSize}px`, 'success');
                lastNotificationType = 'success';
            }
        }, 300);
    }

    function showNotification(message, fontSize, type) {
        let notification = document.getElementById('fitNotification');
        if (notification) {
            notification.remove();
        }

        notification = document.createElement('div');
        notification.id = 'fitNotification';

        const backgroundColor = type === 'warning' ?
            'linear-gradient(45deg, #ff6b6b, #ff9800)' :
            'linear-gradient(45deg, #4CAF50, #45a049)';

        const icon = type === 'warning' ? '⚠️' : '✅';

        notification.style.cssText = `
        position: fixed;
        top: 15px;
        left: 50%;
        transform: translateX(-50%);
        background: ${backgroundColor};
        color: white;
        padding: 15px 45px 15px 25px;
        border-radius: 10px;
        z-index: 1000;
        font-size: ${fontSize};
        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
        transition: all 0.3s ease-in-out;
        border: 2px solid rgba(255, 255, 255, 0.2);
        backdrop-filter: blur(5px);
        animation: notificationAppear 0.5s ease-out forwards;
        font-weight: 500;
        text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
        min-width: 300px;
        text-align: center;
    `;

        // Добавляем стили анимации (если еще не добавлены)
        if (!document.getElementById('notificationStyles')) {
            const styleSheet = document.createElement('style');
            styleSheet.id = 'notificationStyles';
            styleSheet.textContent = `
            @keyframes notificationAppear {
                0% {
                    transform: translateX(-50%) translateY(-20px);
                    opacity: 0;
                }
                50% {
                    transform: translateX(-50%) translateY(5px);
                }
                100% {
                    transform: translateX(-50%) translateY(0);
                    opacity: 1;
                }
            }
        `;
            document.head.appendChild(styleSheet);
        }

        const iconSpan = document.createElement('span');
        iconSpan.innerHTML = icon;
        iconSpan.style.cssText = `
        margin-right: 10px;
        font-size: ${parseInt(fontSize) * 1.2}px;
        vertical-align: middle;
    `;

        const messageSpan = document.createElement('span');
        messageSpan.textContent = message;
        messageSpan.style.verticalAlign = 'middle';

        const closeButton = document.createElement('span');
        closeButton.innerHTML = '×';
        closeButton.style.cssText = `
        position: absolute;
        right: 12px;
        top: 50%;
        transform: translateY(-50%);
        cursor: pointer;
        font-size: ${parseInt(fontSize) * 1.8}px;
        font-weight: bold;
        color: white;
        padding: 0 5px;
        transition: all 0.2s ease;
        text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
    `;

        closeButton.onmouseover = function () {
            this.style.transform = 'translateY(-50%) scale(1.2)';
            this.style.color = '#ffcccc';
        };
        closeButton.onmouseout = function () {
            this.style.transform = 'translateY(-50%) scale(1)';
            this.style.color = 'white';
        };

        function closeNotification() {
            notification.style.transform = 'translateX(-50%) translateY(-20px)';
            notification.style.opacity = '0';
            setTimeout(() => {
                notification.remove();
            }, 300);
        }

        closeButton.onclick = closeNotification;

        notification.appendChild(iconSpan);
        notification.appendChild(messageSpan);
        notification.appendChild(closeButton);
        document.body.appendChild(notification);

        const closeTimeout = type === 'success' ? 5000 : 30000;

        setTimeout(closeNotification, closeTimeout);
    }

    // Добавляем throttle для предотвращения слишком частых вызовов при ресайзе
    function throttle(func, limit) {
        let inThrottle;
        return function () {
            const args = arguments;
            const context = this;
            if (!inThrottle) {
                func.apply(context, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        }
    }

    Events.on(engine, 'afterUpdate', () => {
        if (collided && bob) {
            const currentDisplacement = (bob.position.x - 400) / scaleX;

            if (Math.abs(currentDisplacement) > Math.abs(maxDisplacement)) {
                maxDisplacement = Math.abs(currentDisplacement);
                lastExtremum = currentDisplacement;
            } else if (Math.sign(currentDisplacement) !== Math.sign(lastExtremum) && lastExtremum !== 0) {
                oscillationCount++;
                lastExtremum = currentDisplacement;
            }

            if (!resultAdded &&
                ((oscillationCount >= 1 && maxDisplacement > 0) ||
                    (Math.abs(bob.velocity.x) < 0.1 && Math.abs(bob.velocity.y) < 0.1 && maxDisplacement > 0))) {
                // console.log(maxDisplacement);
                addResultToTable(maxDisplacement);
                resultAdded = true;
            }
        }
        updatePendulumAngle();
        validateBulletPosition();
    });


    Events.on(engine, 'collisionStart', (event) => {
        engine.world.gravity.y = 1;
        const pairs = event.pairs;
        for (let i = 0; i < pairs.length; i++) {
            const pair = pairs[i];
            if ((pair.bodyA === bullet && pair.bodyB === bob) || (pair.bodyA === bob && pair.bodyB === bullet)) {
                if (!collided) {
                    collided = true;

                    // Вычисляем вектор направления столкновения
                    const collisionVector = {
                        x: bullet.position.x - bob.position.x,
                        y: bullet.position.y - bob.position.y
                    };

                    // Нормализуем вектор
                    const magnitude = Math.sqrt(collisionVector.x * collisionVector.x + collisionVector.y * collisionVector.y);
                    const normalizedVector = {
                        x: collisionVector.x / magnitude,
                        y: collisionVector.y / magnitude
                    };

                    // Вычисляем точку крепления на противоположной стороне
                    const attachmentPoint = {
                        x: -normalizedVector.x * bob.circleRadius,
                        y: -normalizedVector.y * bob.circleRadius
                    };

                    attachedBullet = {
                        offsetX: attachmentPoint.x,
                        offsetY: attachmentPoint.y,
                        radius: bullet.circleRadius
                    };

                    // Расчет новой скорости
                    const bulletVelocity = {
                        x: bullet.velocity.x,
                        y: bullet.velocity.y
                    };
                    const totalMass = bob.mass + bullet.mass;
                    const newVelocity = {
                        x: (bulletVelocity.x * bullet.mass) / totalMass,
                        y: (bulletVelocity.y * bullet.mass) / totalMass
                    };
                    // console.log('bulletVelocity: ', bulletVelocity, '; newVelocity: ', newVelocity);
                    Body.setVelocity(bob, newVelocity);
                    World.remove(engine.world, bullet);
                }
                break;
            }
        }
    });

    Events.on(render, 'afterRender', function () {
        if (gunGraphics) gunGraphics.draw();
        if (springGraphics) springGraphics.draw();
        if (bob) {
            const ctx = render.context;

            // Рисуем нить
            ctx.beginPath();
            ctx.moveTo(string.vertices[0].x, string.vertices[0].y);
            ctx.lineTo(string.vertices[1].x, string.vertices[1].y);
            ctx.strokeStyle = '#000000';
            ctx.lineWidth = 2;
            ctx.stroke();

            // Сохраняем состояние контекста
            ctx.save();

            // Перемещаем точку отсчета в центр маятника
            ctx.translate(bob.position.x, bob.position.y);

            // Поворачиваем контекст на угол маятника
            ctx.rotate(bob.angle);

            // Вычисляем скорость движения маятника
            const velocity = Math.sqrt(bob.velocity.x * bob.velocity.x + bob.velocity.y * bob.velocity.y);

            // Рисуем основной серый шар с металлическим оттенком
            const baseGradient = ctx.createRadialGradient(
                0, 0, 0,
                0, 0, bob.circleRadius
            );
            baseGradient.addColorStop(0, '#A0A0A0');
            baseGradient.addColorStop(0.7, '#808080');
            baseGradient.addColorStop(1, '#606060');

            ctx.beginPath();
            ctx.arc(0, 0, bob.circleRadius, 0, 2 * Math.PI);
            ctx.fillStyle = baseGradient;
            ctx.fill();

            // Обводка
            ctx.strokeStyle = '#555555';
            ctx.lineWidth = 2;
            ctx.stroke();

            // Добавим метку для отслеживания вращения (маленькая точка на шаре)
            // ctx.beginPath();
            // ctx.arc(0, bob.circleRadius * 0.5, 3, 0, 2 * Math.PI);
            // ctx.fillStyle = '#000000';
            // ctx.fill();

            // Блики с учётом вращения
            const blikOffsetX = -bob.velocity.x * 0.5;
            const blikOffsetY = -bob.velocity.y * 0.5;

            const blikIntensity = Math.min(0.7, 0.3 + velocity * 0.08);
            const blikGradient = ctx.createRadialGradient(
                blikOffsetX, blikOffsetY, 2,
                blikOffsetX, blikOffsetY, bob.circleRadius * 0.8
            );
            blikGradient.addColorStop(0, `rgba(255, 255, 255, ${blikIntensity})`);
            blikGradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.2)');
            blikGradient.addColorStop(1, 'rgba(255, 255, 255, 0)');

            ctx.beginPath();
            ctx.arc(0, 0, bob.circleRadius, 0, 2 * Math.PI);
            ctx.fillStyle = blikGradient;
            ctx.fill();

            // Восстанавливаем состояние контекста
            ctx.restore();
        }

        drawAttachedBullet(render.context);
        rulerGraphics.draw(maxDisplacement);
    });

    document.addEventListener('keydown', (event) => {
        if (event.key === 'Enter') {
            if (isShooting) return;
            // Проверяем, отображается ли титульная страница
            const titlePage = document.getElementById('titlePage');
            if (titlePage && titlePage.style.display !== 'none') {
                // Если да, то нажимаем кнопку "Начать выполнение работы"
                const startButton = document.querySelector('.main-button');
                if (startButton) {
                    startButton.click();
                }
            } else {
                // Если титульная страница скрыта, то запускаем эксперимент
                const shootBtn = document.getElementById('shootBtn');
                if (shootBtn && !shootBtn.disabled) {
                    shootBtn.click();
                }
            }
        }
    });

    // Создание маятника
    createPendulum(initialPendulumLength, initialPendulumMass);


    Engine.run(engine);
    Render.run(render);
    window.addEventListener('load', () => {
        checkElementsFit();
    });
    window.addEventListener('resize', () => {
        checkElementsFit();
    });

    document.querySelector('.main-button').addEventListener('click', () => {
        // Даем небольшую задержку, чтобы DOM успел обновиться
        setTimeout(() => {
            checkElementsFit();
        }, 100);
    });
</script>
</body>
</html>