🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@armniko/ticker

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@armniko/ticker - npm Package Compare versions

Comparing version
2.0.0
to
2.1.0
+155
-1
dist/index.esm.js

@@ -1,1 +0,155 @@

var s={d:(e,t)=>{for(var i in t)s.o(t,i)&&!s.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},o:(s,e)=>Object.prototype.hasOwnProperty.call(s,e)},e={};s.d(e,{R:()=>i,D:()=>a});class t{_minFps;_currentFps=60;_lastChecks=[];_calculateFpsEachMs=2e3;_msSinceLastCalculation=0;_lowFpsInRow=0;_lowFpsCallback;currentFps(){return this._currentFps}calculate(s){this.collectFps(s),this._msSinceLastCalculation+=s.deltaMs,this._msSinceLastCalculation>=this._calculateFpsEachMs&&(this._msSinceLastCalculation=0,this.calculateAverageFps(),this.checkAndNotifyLowFps())}onLowFps(s){this._lowFpsCallback=s}setMinFps(s){return this._minFps=s,this}collectFps(s){this._lastChecks.push(Math.round(1e3/s.deltaMs))}calculateAverageFps(){const s=this._lastChecks.reduce(((s,e)=>s+e),0);this._currentFps=Math.round(s/this._lastChecks.length),this._lastChecks=[]}checkAndNotifyLowFps(){this._minFps&&this._currentFps<this._minFps&&(this._lowFpsInRow++,5===this._lowFpsInRow&&(this._lowFpsInRow=0,this._lowFpsCallback&&this._lowFpsCallback()))}}class i{_fps=new t;_drawQueue=[];_logicQueue=[];_lowFpsQueue=[];_maxFps;_expectedFps;_time={delta:0,deltaMs:0};_lastTimestamp=0;_logicTicksAccumulatedMs=0;_requestFrameId;constructor(s){this.setFps({min:s?.minFps||0,max:s?.maxFps||60,expected:s?.expectedFps||60}),s?.onDrawTick&&this.addDrawTask(s.onDrawTick),s?.onLogicTick&&this.addLogicTask(s.onLogicTick),s?.onLowFps&&this.addLowFpsTask(s.onLowFps),this._fps.onLowFps((()=>{this._lowFpsQueue.forEach((s=>s.callback(this.fps())))}))}start(){this._lastTimestamp=performance.now(),this.loop(this._lastTimestamp)}stop(){this._requestFrameId&&(window.cancelAnimationFrame(this._requestFrameId),this._requestFrameId=void 0)}isStarted(){return!!this._requestFrameId}setFps(s){return s.min&&s.min>0&&this._fps.setMinFps(s.min),s.max&&s.max>0&&(this._maxFps=this.compensatedMaxFps(s.max)),s.expected&&s.expected>0&&(this._expectedFps=s.expected),this}addDrawTask(s){return{index:this._drawQueue.push({callback:s})-1,type:"draw"}}addLogicTask(s){return{index:this._logicQueue.push({callback:s})-1,type:"logic"}}addLowFpsTask(s){return{index:this._lowFpsQueue.push({callback:s})-1,type:"low-fps"}}remove(s){switch(s.type){case"draw":this._drawQueue.splice(s.index,1);break;case"logic":this._logicQueue.splice(s.index,1);break;case"low-fps":this._lowFpsQueue.splice(s.index,1)}}fps(){return this._fps.currentFps()}msBetweenTicks(){return this._time.deltaMs}ticksMissed(){return this._time.deltaMs/(1e3/this._expectedFps)}loop(s){const e=1e3/this._maxFps,t=s-this._lastTimestamp;t>=e&&(this._time={delta:t/1e3,deltaMs:t},this._lastTimestamp=s,this._fps.calculate(this._time),this.runQueue()),this._requestFrameId=window.requestAnimationFrame(this.loop.bind(this))}runQueue(){this._logicQueue.length>0&&this.runLogicQueue(),this._drawQueue.length>0&&this.runDrawQueue()}runLogicQueue(){const s=1e3/this._expectedFps;this._logicTicksAccumulatedMs+=this._time.deltaMs;const e={delta:s/1e3,deltaMs:s};for(;this._logicTicksAccumulatedMs>=s;)this._logicQueue.forEach((s=>s.callback(e))),this._logicTicksAccumulatedMs-=s}runDrawQueue(){this._drawQueue.forEach((s=>s.callback(this._time)))}compensatedMaxFps(s){return Math.floor(1.1*s)+10*Math.floor(s/100)}}class a extends i{_isStarted=!1;start(){this._isStarted=!0}stop(){this._isStarted=!1}isStarted(){return this._isStarted}fps(){return 60}msBetweenTicks(){return 1e3/60}ticksMissed(){return 1}simulateLogicTick(){this._logicQueue.forEach((s=>s.callback({delta:1/this.fps(),deltaMs:1e3/this.fps()})))}simulateDrawTick(){this._drawQueue.forEach((s=>s.callback({delta:1/this.fps(),deltaMs:1e3/this.fps()})))}simulateLowFps(){this._lowFpsQueue.forEach((s=>s.callback(this.fps())))}}var c=e.R,l=e.D;export{c as Ticker,l as TickerMock};
class a {
_minFps;
_currentFps = 60;
_lastChecks = [];
_calculateFpsEachMs = 2e3;
_msSinceLastCalculation = 0;
_lowFpsInRow = 0;
_lowFpsCallback;
currentFps() {
return this._currentFps;
}
calculate(s) {
this.collectFps(s), this._msSinceLastCalculation += s.deltaMs, this._msSinceLastCalculation >= this._calculateFpsEachMs && (this._msSinceLastCalculation = 0, this.calculateAverageFps(), this.checkAndNotifyLowFps());
}
onLowFps(s) {
this._lowFpsCallback = s;
}
setMinFps(s) {
return this._minFps = s, this;
}
collectFps(s) {
this._lastChecks.push(Math.round(1e3 / s.deltaMs));
}
calculateAverageFps() {
const s = this._lastChecks.reduce((e, t) => e + t, 0);
this._currentFps = Math.round(s / this._lastChecks.length), this._lastChecks = [];
}
checkAndNotifyLowFps() {
this._minFps && this._currentFps < this._minFps && (this._lowFpsInRow++, this._lowFpsInRow === 5 && (this._lowFpsInRow = 0, this._lowFpsCallback && this._lowFpsCallback()));
}
}
class c {
_fps = new a();
_drawQueue = [];
_logicQueue = [];
_lowFpsQueue = [];
_maxFps;
_expectedFps;
_time = { delta: 0, deltaMs: 0 };
_lastTimestamp = 0;
_logicTicksAccumulatedMs = 0;
_requestFrameId;
constructor(s) {
this.setFps({ min: s?.minFps || 0, max: s?.maxFps || 60, expected: s?.expectedFps || 60 }), s?.onDrawTick && this.addDrawTask(s.onDrawTick), s?.onLogicTick && this.addLogicTask(s.onLogicTick), s?.onLowFps && this.addLowFpsTask(s.onLowFps), this._fps.onLowFps(() => {
this._lowFpsQueue.forEach((e) => e.callback(this.fps()));
});
}
start() {
this._lastTimestamp = performance.now(), this.loop(this._lastTimestamp);
}
stop() {
this._requestFrameId && (window.cancelAnimationFrame(this._requestFrameId), this._requestFrameId = void 0);
}
isStarted() {
return !!this._requestFrameId;
}
setFps(s) {
return s.min && s.min > 0 && this._fps.setMinFps(s.min), s.max && s.max > 0 && (this._maxFps = this.compensatedMaxFps(s.max)), s.expected && s.expected > 0 && (this._expectedFps = s.expected), this;
}
addDrawTask(s) {
return { index: this._drawQueue.push({ callback: s }) - 1, type: "draw" };
}
addLogicTask(s) {
return { index: this._logicQueue.push({ callback: s }) - 1, type: "logic" };
}
addLowFpsTask(s) {
return { index: this._lowFpsQueue.push({ callback: s }) - 1, type: "low-fps" };
}
remove(s) {
switch (s.type) {
case "draw":
this._drawQueue.splice(s.index, 1);
break;
case "logic":
this._logicQueue.splice(s.index, 1);
break;
case "low-fps":
this._lowFpsQueue.splice(s.index, 1);
break;
}
}
fps() {
return this._fps.currentFps();
}
/**
* @deprecated Use `time.deltaMs` provided in draw/logic task callbacks instead.
*/
msBetweenTicks() {
return this._time.deltaMs;
}
/**
* @deprecated Use `time.deltaMs` provided in draw/logic task callbacks instead.
*/
ticksMissed() {
return this._time.deltaMs / (1e3 / this._expectedFps);
}
loop(s) {
const e = 1e3 / this._maxFps, t = s - this._lastTimestamp;
t >= e && (this._time = { delta: t / 1e3, deltaMs: t }, this._lastTimestamp = s, this._fps.calculate(this._time), this.runQueue()), this._requestFrameId = window.requestAnimationFrame(this.loop.bind(this));
}
runQueue() {
this._logicQueue.length > 0 && this.runLogicQueue(), this._drawQueue.length > 0 && this.runDrawQueue();
}
runLogicQueue() {
const s = 1e3 / this._expectedFps;
this._logicTicksAccumulatedMs += this._time.deltaMs;
const e = { delta: s / 1e3, deltaMs: s };
for (; this._logicTicksAccumulatedMs >= s; )
this._logicQueue.forEach((t) => t.callback(e)), this._logicTicksAccumulatedMs -= s;
}
runDrawQueue() {
this._drawQueue.forEach((s) => s.callback(this._time));
}
compensatedMaxFps(s) {
return Math.floor(s * 1.1) + Math.floor(s / 100) * 10;
}
}
class l extends c {
_isStarted = !1;
start() {
this._isStarted = !0;
}
stop() {
this._isStarted = !1;
}
isStarted() {
return this._isStarted;
}
fps() {
return 60;
}
msBetweenTicks() {
return 1e3 / 60;
}
ticksMissed() {
return 1;
}
simulateLogicTick(s = void 0) {
this._logicQueue.forEach(
(e) => e.callback(s || { delta: 1 / this.fps(), deltaMs: 1e3 / this.fps() })
);
}
simulateDrawTick(s = void 0) {
this._drawQueue.forEach(
(e) => e.callback(s || { delta: 1 / this.fps(), deltaMs: 1e3 / this.fps() })
);
}
simulateLowFps() {
this._lowFpsQueue.forEach((s) => s.callback(this.fps()));
}
}
export {
c as Ticker,
l as TickerMock
};
+1
-1

@@ -1,1 +0,1 @@

!function(e,s){"object"==typeof exports&&"object"==typeof module?module.exports=s():"function"==typeof define&&define.amd?define("Ticker",[],s):"object"==typeof exports?exports.Ticker=s():e.Ticker=s()}(self,(()=>(()=>{"use strict";var e={d:(s,t)=>{for(var i in t)e.o(t,i)&&!e.o(s,i)&&Object.defineProperty(s,i,{enumerable:!0,get:t[i]})},o:(e,s)=>Object.prototype.hasOwnProperty.call(e,s),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},s={};e.r(s),e.d(s,{Ticker:()=>i,TickerMock:()=>a});class t{_minFps;_currentFps=60;_lastChecks=[];_calculateFpsEachMs=2e3;_msSinceLastCalculation=0;_lowFpsInRow=0;_lowFpsCallback;currentFps(){return this._currentFps}calculate(e){this.collectFps(e),this._msSinceLastCalculation+=e.deltaMs,this._msSinceLastCalculation>=this._calculateFpsEachMs&&(this._msSinceLastCalculation=0,this.calculateAverageFps(),this.checkAndNotifyLowFps())}onLowFps(e){this._lowFpsCallback=e}setMinFps(e){return this._minFps=e,this}collectFps(e){this._lastChecks.push(Math.round(1e3/e.deltaMs))}calculateAverageFps(){const e=this._lastChecks.reduce(((e,s)=>e+s),0);this._currentFps=Math.round(e/this._lastChecks.length),this._lastChecks=[]}checkAndNotifyLowFps(){this._minFps&&this._currentFps<this._minFps&&(this._lowFpsInRow++,5===this._lowFpsInRow&&(this._lowFpsInRow=0,this._lowFpsCallback&&this._lowFpsCallback()))}}class i{_fps=new t;_drawQueue=[];_logicQueue=[];_lowFpsQueue=[];_maxFps;_expectedFps;_time={delta:0,deltaMs:0};_lastTimestamp=0;_logicTicksAccumulatedMs=0;_requestFrameId;constructor(e){this.setFps({min:e?.minFps||0,max:e?.maxFps||60,expected:e?.expectedFps||60}),e?.onDrawTick&&this.addDrawTask(e.onDrawTick),e?.onLogicTick&&this.addLogicTask(e.onLogicTick),e?.onLowFps&&this.addLowFpsTask(e.onLowFps),this._fps.onLowFps((()=>{this._lowFpsQueue.forEach((e=>e.callback(this.fps())))}))}start(){this._lastTimestamp=performance.now(),this.loop(this._lastTimestamp)}stop(){this._requestFrameId&&(window.cancelAnimationFrame(this._requestFrameId),this._requestFrameId=void 0)}isStarted(){return!!this._requestFrameId}setFps(e){return e.min&&e.min>0&&this._fps.setMinFps(e.min),e.max&&e.max>0&&(this._maxFps=this.compensatedMaxFps(e.max)),e.expected&&e.expected>0&&(this._expectedFps=e.expected),this}addDrawTask(e){return{index:this._drawQueue.push({callback:e})-1,type:"draw"}}addLogicTask(e){return{index:this._logicQueue.push({callback:e})-1,type:"logic"}}addLowFpsTask(e){return{index:this._lowFpsQueue.push({callback:e})-1,type:"low-fps"}}remove(e){switch(e.type){case"draw":this._drawQueue.splice(e.index,1);break;case"logic":this._logicQueue.splice(e.index,1);break;case"low-fps":this._lowFpsQueue.splice(e.index,1)}}fps(){return this._fps.currentFps()}msBetweenTicks(){return this._time.deltaMs}ticksMissed(){return this._time.deltaMs/(1e3/this._expectedFps)}loop(e){const s=1e3/this._maxFps,t=e-this._lastTimestamp;t>=s&&(this._time={delta:t/1e3,deltaMs:t},this._lastTimestamp=e,this._fps.calculate(this._time),this.runQueue()),this._requestFrameId=window.requestAnimationFrame(this.loop.bind(this))}runQueue(){this._logicQueue.length>0&&this.runLogicQueue(),this._drawQueue.length>0&&this.runDrawQueue()}runLogicQueue(){const e=1e3/this._expectedFps;this._logicTicksAccumulatedMs+=this._time.deltaMs;const s={delta:e/1e3,deltaMs:e};for(;this._logicTicksAccumulatedMs>=e;)this._logicQueue.forEach((e=>e.callback(s))),this._logicTicksAccumulatedMs-=e}runDrawQueue(){this._drawQueue.forEach((e=>e.callback(this._time)))}compensatedMaxFps(e){return Math.floor(1.1*e)+10*Math.floor(e/100)}}class a extends i{_isStarted=!1;start(){this._isStarted=!0}stop(){this._isStarted=!1}isStarted(){return this._isStarted}fps(){return 60}msBetweenTicks(){return 1e3/60}ticksMissed(){return 1}simulateLogicTick(){this._logicQueue.forEach((e=>e.callback({delta:1/this.fps(),deltaMs:1e3/this.fps()})))}simulateDrawTick(){this._drawQueue.forEach((e=>e.callback({delta:1/this.fps(),deltaMs:1e3/this.fps()})))}simulateLowFps(){this._lowFpsQueue.forEach((e=>e.callback(this.fps())))}}return s})()));
(function(t,a){typeof exports=="object"&&typeof module<"u"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(t=typeof globalThis<"u"?globalThis:t||self,a(t.Ticker={}))})(this,(function(t){"use strict";class a{_minFps;_currentFps=60;_lastChecks=[];_calculateFpsEachMs=2e3;_msSinceLastCalculation=0;_lowFpsInRow=0;_lowFpsCallback;currentFps(){return this._currentFps}calculate(e){this.collectFps(e),this._msSinceLastCalculation+=e.deltaMs,this._msSinceLastCalculation>=this._calculateFpsEachMs&&(this._msSinceLastCalculation=0,this.calculateAverageFps(),this.checkAndNotifyLowFps())}onLowFps(e){this._lowFpsCallback=e}setMinFps(e){return this._minFps=e,this}collectFps(e){this._lastChecks.push(Math.round(1e3/e.deltaMs))}calculateAverageFps(){const e=this._lastChecks.reduce((s,i)=>s+i,0);this._currentFps=Math.round(e/this._lastChecks.length),this._lastChecks=[]}checkAndNotifyLowFps(){this._minFps&&this._currentFps<this._minFps&&(this._lowFpsInRow++,this._lowFpsInRow===5&&(this._lowFpsInRow=0,this._lowFpsCallback&&this._lowFpsCallback()))}}class c{_fps=new a;_drawQueue=[];_logicQueue=[];_lowFpsQueue=[];_maxFps;_expectedFps;_time={delta:0,deltaMs:0};_lastTimestamp=0;_logicTicksAccumulatedMs=0;_requestFrameId;constructor(e){this.setFps({min:e?.minFps||0,max:e?.maxFps||60,expected:e?.expectedFps||60}),e?.onDrawTick&&this.addDrawTask(e.onDrawTick),e?.onLogicTick&&this.addLogicTask(e.onLogicTick),e?.onLowFps&&this.addLowFpsTask(e.onLowFps),this._fps.onLowFps(()=>{this._lowFpsQueue.forEach(s=>s.callback(this.fps()))})}start(){this._lastTimestamp=performance.now(),this.loop(this._lastTimestamp)}stop(){this._requestFrameId&&(window.cancelAnimationFrame(this._requestFrameId),this._requestFrameId=void 0)}isStarted(){return!!this._requestFrameId}setFps(e){return e.min&&e.min>0&&this._fps.setMinFps(e.min),e.max&&e.max>0&&(this._maxFps=this.compensatedMaxFps(e.max)),e.expected&&e.expected>0&&(this._expectedFps=e.expected),this}addDrawTask(e){return{index:this._drawQueue.push({callback:e})-1,type:"draw"}}addLogicTask(e){return{index:this._logicQueue.push({callback:e})-1,type:"logic"}}addLowFpsTask(e){return{index:this._lowFpsQueue.push({callback:e})-1,type:"low-fps"}}remove(e){switch(e.type){case"draw":this._drawQueue.splice(e.index,1);break;case"logic":this._logicQueue.splice(e.index,1);break;case"low-fps":this._lowFpsQueue.splice(e.index,1);break}}fps(){return this._fps.currentFps()}msBetweenTicks(){return this._time.deltaMs}ticksMissed(){return this._time.deltaMs/(1e3/this._expectedFps)}loop(e){const s=1e3/this._maxFps,i=e-this._lastTimestamp;i>=s&&(this._time={delta:i/1e3,deltaMs:i},this._lastTimestamp=e,this._fps.calculate(this._time),this.runQueue()),this._requestFrameId=window.requestAnimationFrame(this.loop.bind(this))}runQueue(){this._logicQueue.length>0&&this.runLogicQueue(),this._drawQueue.length>0&&this.runDrawQueue()}runLogicQueue(){const e=1e3/this._expectedFps;this._logicTicksAccumulatedMs+=this._time.deltaMs;const s={delta:e/1e3,deltaMs:e};for(;this._logicTicksAccumulatedMs>=e;)this._logicQueue.forEach(i=>i.callback(s)),this._logicTicksAccumulatedMs-=e}runDrawQueue(){this._drawQueue.forEach(e=>e.callback(this._time))}compensatedMaxFps(e){return Math.floor(e*1.1)+Math.floor(e/100)*10}}class u extends c{_isStarted=!1;start(){this._isStarted=!0}stop(){this._isStarted=!1}isStarted(){return this._isStarted}fps(){return 60}msBetweenTicks(){return 1e3/60}ticksMissed(){return 1}simulateLogicTick(e=void 0){this._logicQueue.forEach(s=>s.callback(e||{delta:1/this.fps(),deltaMs:1e3/this.fps()}))}simulateDrawTick(e=void 0){this._drawQueue.forEach(s=>s.callback(e||{delta:1/this.fps(),deltaMs:1e3/this.fps()}))}simulateLowFps(){this._lowFpsQueue.forEach(e=>e.callback(this.fps()))}}t.Ticker=c,t.TickerMock=u,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})}));
import { Ticker } from './ticker';
import { Time } from '../interfaces/time.interface';
export declare class TickerMock extends Ticker {

@@ -10,5 +11,5 @@ private _isStarted;

ticksMissed(): number;
simulateLogicTick(): void;
simulateDrawTick(): void;
simulateLogicTick(time?: Time | undefined): void;
simulateDrawTick(time?: Time | undefined): void;
simulateLowFps(): void;
}
{
"name": "@armniko/ticker",
"version": "2.0.0",
"description": "Javascript/typescript library for running app loop with separate logical/drawing ticks and FPS limitation.",
"author": "Armīns Nikolajevs <armins.nikolajevs@gmail.com>",
"license": "MIT",
"bugs": {
"email": "armins.nikolajevs@gmail.com"
},
"keywords": [
"ticker",
"loop",
"fps"
],
"main": "./dist/index.umd.js",
"module": "./dist/index.esm.js",
"typings": "./dist/index.d.ts",
"type": "module",
"files": [
"dist"
],
"scripts": {
"build": "rimraf dist && webpack",
"dev": "node test/server/main.js & webpack --watch",
"lint": "tsc --noEmit && eslint src --max-warnings=0",
"lint:fix": "npm run lint -- --fix",
"test": "npm run build && jest",
"test:coverage": "npm run test -- --collect-coverage"
},
"devDependencies": {
"@armniko/canvas": "^1.1.1",
"@types/jest": "^29.5.12",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^3.2.5",
"ts-jest": "^29.1.2",
"ts-loader": "^9.5.1",
"typescript": "^5.4.3",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
"name": "@armniko/ticker",
"version": "2.1.0",
"description": "Javascript/typescript library for running app loop with separate logical/drawing ticks and FPS limitation.",
"author": "Armīns Nikolajevs <armins.nikolajevs@gmail.com>",
"license": "MIT",
"bugs": {
"email": "armins.nikolajevs@gmail.com"
},
"keywords": [
"ticker",
"loop",
"fps"
],
"main": "./dist/index.umd.js",
"module": "./dist/index.esm.js",
"typings": "./dist/index.d.ts",
"type": "module",
"files": [
"dist"
],
"scripts": {
"build": "vite build",
"dev": "vite build --watch",
"lint": "tsc --noEmit && eslint ./src --max-warnings=0 && npm run lint --prefix=demo",
"lint:fix": "npm run lint -- --fix && npm run lint:fix --prefix=demo",
"test": "vitest",
"test:coverage": "vitest run --coverage"
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"@types/node": "^25.0.3",
"@vitest/coverage-v8": "^4.0.16",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"happy-dom": "^20.0.11",
"prettier": "^3.7.4",
"typescript": "^5.9.3",
"typescript-eslint": "^8.50.1",
"vite": "^7.3.0",
"vite-plugin-dts": "^4.5.4",
"vitest": "^4.0.16"
}
}

@@ -104,2 +104,9 @@ <h1 align="center">Ticker</h1>

<tr>
<td>v2.1.0</td>
<td>
Added option to provide Time for TickerMock<br>
Migrated from webpack to vite
</td>
</tr>
<tr>
<td>v2.0.0</td>

@@ -106,0 +113,0 @@ <td>