Added the CanvasUtils class and moved some stuff out of Stage into it.

This commit is contained in:
Richard Davey 2013-08-09 17:47:08 +01:00
parent 8b2f1cca51
commit f9776f30fc
7 changed files with 246 additions and 208 deletions

View file

@ -16,6 +16,10 @@
<IISExpressUseClassicPipelineMode />
</PropertyGroup>
<ItemGroup>
<TypeScriptCompile Include="utils\CanvasUtils.ts" />
<Content Include="utils\CanvasUtils.js">
<DependentUpon>CanvasUtils.ts</DependentUpon>
</Content>
<Content Include="_definitions.ts" />
<TypeScriptCompile Include="Phaser.ts" />
<TypeScriptCompile Include="particles\Emitter.ts" />

View file

@ -32,26 +32,13 @@ module Phaser {
this.canvas = <HTMLCanvasElement> document.createElement('canvas');
this.canvas.width = width;
this.canvas.height = height;
if ((parent !== '' || parent !== null) && document.getElementById(parent))
{
document.getElementById(parent).appendChild(this.canvas);
document.getElementById(parent).style.overflow = 'hidden';
}
else
{
document.body.appendChild(this.canvas);
}
// Consume default actions on the canvas
this.canvas.style.msTouchAction = 'none';
this.canvas.style['ms-touch-action'] = 'none';
this.canvas.style['touch-action'] = 'none';
this.canvas.style.backgroundColor = 'rgb(0,0,0)';
this.canvas.oncontextmenu = function(event) { event.preventDefault(); };
this.context = this.canvas.getContext('2d');
Phaser.CanvasUtils.addToDOM(this.canvas, parent, true);
Phaser.CanvasUtils.setTouchAction(this.canvas);
this.canvas.oncontextmenu = function(event) { event.preventDefault(); };
this.css3 = new Phaser.Display.CSS3Filters(this.canvas);
this.scaleMode = StageScaleMode.NO_SCALE;
@ -280,13 +267,6 @@ module Phaser {
}
public setImageRenderingCrisp() {
this.canvas.style['image-rendering'] = 'crisp-edges';
this.canvas.style['image-rendering'] = '-moz-crisp-edges';
this.canvas.style['image-rendering'] = '-webkit-optimize-contrast';
this.canvas.style['-ms-interpolation-mode'] = 'nearest-neighbor';
}
public pauseGame() {
this.game.paused = true;

View file

@ -93,6 +93,7 @@
/// <reference path="ui/Button.ts" />
/// <reference path="utils/CanvasUtils.ts" />
/// <reference path="utils/CircleUtils.ts" />
/// <reference path="utils/ColorUtils.ts" />
/// <reference path="utils/PointUtils.ts" />

View file

@ -0,0 +1,19 @@
var Shapes;
(function (Shapes) {
var Point = Shapes.Point = (function () {
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.getDist = function () {
return Math.sqrt((this.x * this.x) + (this.y * this.y));
};
Point.origin = new Point(0, 0);
return Point;
})();
})(Shapes || (Shapes = {}));
var p = new Shapes.Point(3, 4);
var dist = p.getDist();

View file

@ -0,0 +1,93 @@
/// <reference path="../_definitions.ts" />
/**
* Phaser - CanvasUtils
*
* A collection of methods useful for manipulating canvas objects.
*/
module Phaser {
export class CanvasUtils {
public static getAspectRatio(canvas: HTMLCanvasElement): number {
return canvas.width / canvas.height;
}
public static setBackgroundColor(canvas: HTMLCanvasElement, color: string = 'rgb(0,0,0)'): HTMLCanvasElement {
canvas.style.backgroundColor = color;
return canvas;
}
public static setTouchAction(canvas: HTMLCanvasElement, value: string= 'none'): HTMLCanvasElement {
canvas.style.msTouchAction = value;
canvas.style['ms-touch-action'] = value;
canvas.style['touch-action'] = value;
return canvas;
}
public static addToDOM(canvas: HTMLCanvasElement, parent: string = '', overflowHidden: boolean = true): HTMLCanvasElement {
if ((parent !== '' || parent !== null) && document.getElementById(parent))
{
document.getElementById(parent).appendChild(canvas);
if (overflowHidden)
{
document.getElementById(parent).style.overflow = 'hidden';
}
}
else
{
document.body.appendChild(canvas);
}
return canvas;
}
public static setTransform(context: CanvasRenderingContext2D, translateX: number, translateY: number, scaleX: number, scaleY: number, skewX: number, skewY: number): CanvasRenderingContext2D {
context.setTransform(scaleX, skewX, skewY, scaleY, translateX, translateY);
return context;
}
public static setSmoothingEnabled(context: CanvasRenderingContext2D, value: boolean): CanvasRenderingContext2D {
context['imageSmoothingEnabled'] = value;
context['mozImageSmoothingEnabled'] = value;
context['oImageSmoothingEnabled'] = value;
context['webkitImageSmoothingEnabled'] = value;
context['msImageSmoothingEnabled'] = value;
return context;
}
public static setImageRenderingCrisp(canvas: HTMLCanvasElement): HTMLCanvasElement {
canvas.style['image-rendering'] = 'crisp-edges';
canvas.style['image-rendering'] = '-moz-crisp-edges';
canvas.style['image-rendering'] = '-webkit-optimize-contrast';
canvas.style.msInterpolationMode = 'nearest-neighbor';
return canvas;
}
public static setImageRenderingBicubic(canvas: HTMLCanvasElement): HTMLCanvasElement {
canvas.style['image-rendering'] = 'auto';
canvas.style.msInterpolationMode = 'bicubic';
return canvas;
}
}
}

View file

@ -13120,6 +13120,10 @@ var Phaser;
* @type {string}
*/
this.crossOrigin = '';
// If you want to append a URL before the path of any asset you can set this here.
// Useful if you need to allow an asset url to be configured outside of the game code.
// MUST have / on the end of it!
this.baseURL = '';
this.game = game;
this._keys = [];
@ -13326,7 +13330,7 @@ var Phaser;
return _this.fileError(file.key);
};
file.data.crossOrigin = this.crossOrigin;
file.data.src = file.url;
file.data.src = this.baseURL + file.url;
break;
case 'audio':
@ -13334,7 +13338,7 @@ var Phaser;
if (file.url !== null) {
if (this.game.sound.usingWebAudio) {
this._xhr.open("GET", file.url, true);
this._xhr.open("GET", this.baseURL + file.url, true);
this._xhr.responseType = "arraybuffer";
this._xhr.onload = function () {
return _this.fileComplete(file.key);
@ -13349,7 +13353,7 @@ var Phaser;
file.data = new Audio();
file.data.name = file.key;
file.data.preload = 'auto';
file.data.src = file.url;
file.data.src = this.baseURL + file.url;
this.fileComplete(file.key);
} else {
file.data = new Audio();
@ -13358,7 +13362,7 @@ var Phaser;
return _this.fileError(file.key);
};
file.data.preload = 'auto';
file.data.src = file.url;
file.data.src = this.baseURL + file.url;
file.data.addEventListener('canplaythrough', Phaser.GAMES[this.game.id].load.fileComplete(file.key), false);
file.data.load();
}
@ -13368,7 +13372,7 @@ var Phaser;
break;
case 'text':
this._xhr.open("GET", file.url, true);
this._xhr.open("GET", this.baseURL + file.url, true);
this._xhr.responseType = "text";
this._xhr.onload = function () {
return _this.fileComplete(file.key);
@ -13442,7 +13446,7 @@ var Phaser;
} else {
// Load the JSON or XML before carrying on with the next file
loadNext = false;
this._xhr.open("GET", file.atlasURL, true);
this._xhr.open("GET", this.baseURL + file.atlasURL, true);
this._xhr.responseType = "text";
if (file.format == Loader.TEXTURE_ATLAS_JSON_ARRAY) {
@ -14796,71 +14800,6 @@ var Phaser;
enumerable: true,
configurable: true
});
// MOVE THESE TO A UTIL
Body.prototype.render = function (context) {
context.beginPath();
context.strokeStyle = 'rgb(0,255,0)';
context.strokeRect(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight, this.bounds.width, this.bounds.height);
context.stroke();
context.closePath();
// center point
context.fillStyle = 'rgb(0,255,0)';
context.fillRect(this.position.x, this.position.y, 2, 2);
if (this.touching & Phaser.Types.LEFT) {
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight);
context.lineTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight);
context.stroke();
context.closePath();
}
if (this.touching & Phaser.Types.RIGHT) {
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight);
context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight);
context.stroke();
context.closePath();
}
if (this.touching & Phaser.Types.UP) {
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight);
context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight);
context.stroke();
context.closePath();
}
if (this.touching & Phaser.Types.DOWN) {
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight);
context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight);
context.stroke();
context.closePath();
}
};
/**
* Render debug infos. (including name, bounds info, position and some other properties)
* @param x {number} X position of the debug info to be rendered.
* @param y {number} Y position of the debug info to be rendered.
* @param [color] {number} color of the debug info to be rendered. (format is css color string)
*/
Body.prototype.renderDebugInfo = function (x, y, color) {
if (typeof color === "undefined") { color = 'rgb(255,255,255)'; }
this.sprite.texture.context.fillStyle = color;
this.sprite.texture.context.fillText('Sprite: (' + this.sprite.width + ' x ' + this.sprite.height + ')', x, y);
//this.sprite.texture.context.fillText('x: ' + this._sprite.frameBounds.x.toFixed(1) + ' y: ' + this._sprite.frameBounds.y.toFixed(1) + ' rotation: ' + this._sprite.rotation.toFixed(1), x, y + 14);
this.sprite.texture.context.fillText('x: ' + this.bounds.x.toFixed(1) + ' y: ' + this.bounds.y.toFixed(1) + ' rotation: ' + this.sprite.transform.rotation.toFixed(0), x, y + 14);
this.sprite.texture.context.fillText('vx: ' + this.velocity.x.toFixed(1) + ' vy: ' + this.velocity.y.toFixed(1), x, y + 28);
this.sprite.texture.context.fillText('acx: ' + this.acceleration.x.toFixed(1) + ' acy: ' + this.acceleration.y.toFixed(1), x, y + 42);
this.sprite.texture.context.fillText('angVx: ' + this.angularVelocity.toFixed(1) + ' angAc: ' + this.angularAcceleration.toFixed(1), x, y + 56);
};
return Body;
})();
Physics.Body = Body;
@ -15013,7 +14952,7 @@ var Phaser;
*/
Sprite.prototype.bringToTop = function () {
if (this.group) {
//this.group.bringToTop(this);
this.group.bringToTop(this);
}
};
@ -19757,7 +19696,7 @@ var Phaser;
//this.physics = new Phaser.Physics.Manager(this);
this.plugins = new Phaser.PluginManager(this, this);
this.load.onLoadComplete.addOnce(this.loadComplete, this);
this.load.onLoadComplete.add(this.loadComplete, this);
this.setRenderer(Phaser.Types.RENDERER_CANVAS);
@ -19883,6 +19822,7 @@ var Phaser;
this._loadComplete = true;
} else {
// Start the loader going as we have something in the queue
this.load.onLoadComplete.add(this.loadComplete, this);
this.load.start();
}
} else {

View file

@ -1,5 +1,29 @@
/// <reference path="_definitions.ts" />
/**
* Phaser - http://www.phaser.io
*
* v1.0.0 - August 12th 2013
*
* A feature-packed 2D canvas game framework born from the firey pits of Flixel and
* constructed via plenty of blood, sweat, tears and coffee by Richard Davey (@photonstorm).
*
* Many thanks to Adam Saltsman (@ADAMATOMIC) for releasing Flixel, from both which Phaser
* and my love of game development originate.
*
* Follow Phaser progress at http://www.photonstorm.com
*
* "If you want your children to be intelligent, read them fairy tales."
* "If you want them to be more intelligent, read them more fairy tales."
* -- Albert Einstein
*/
var Phaser;
(function (Phaser) {
Phaser.VERSION = 'Phaser version 1.0.0';
Phaser.GAMES = [];
})(Phaser || (Phaser = {}));
/// <reference path="_definitions.ts" />
/**
* Types
*
* This file contains all constants used through-out Phaser.
@ -13120,6 +13144,10 @@ var Phaser;
* @type {string}
*/
this.crossOrigin = '';
// If you want to append a URL before the path of any asset you can set this here.
// Useful if you need to allow an asset url to be configured outside of the game code.
// MUST have / on the end of it!
this.baseURL = '';
this.game = game;
this._keys = [];
@ -13326,7 +13354,7 @@ var Phaser;
return _this.fileError(file.key);
};
file.data.crossOrigin = this.crossOrigin;
file.data.src = file.url;
file.data.src = this.baseURL + file.url;
break;
case 'audio':
@ -13334,7 +13362,7 @@ var Phaser;
if (file.url !== null) {
if (this.game.sound.usingWebAudio) {
this._xhr.open("GET", file.url, true);
this._xhr.open("GET", this.baseURL + file.url, true);
this._xhr.responseType = "arraybuffer";
this._xhr.onload = function () {
return _this.fileComplete(file.key);
@ -13349,7 +13377,7 @@ var Phaser;
file.data = new Audio();
file.data.name = file.key;
file.data.preload = 'auto';
file.data.src = file.url;
file.data.src = this.baseURL + file.url;
this.fileComplete(file.key);
} else {
file.data = new Audio();
@ -13358,7 +13386,7 @@ var Phaser;
return _this.fileError(file.key);
};
file.data.preload = 'auto';
file.data.src = file.url;
file.data.src = this.baseURL + file.url;
file.data.addEventListener('canplaythrough', Phaser.GAMES[this.game.id].load.fileComplete(file.key), false);
file.data.load();
}
@ -13368,7 +13396,7 @@ var Phaser;
break;
case 'text':
this._xhr.open("GET", file.url, true);
this._xhr.open("GET", this.baseURL + file.url, true);
this._xhr.responseType = "text";
this._xhr.onload = function () {
return _this.fileComplete(file.key);
@ -13442,7 +13470,7 @@ var Phaser;
} else {
// Load the JSON or XML before carrying on with the next file
loadNext = false;
this._xhr.open("GET", file.atlasURL, true);
this._xhr.open("GET", this.baseURL + file.atlasURL, true);
this._xhr.responseType = "text";
if (file.format == Loader.TEXTURE_ATLAS_JSON_ARRAY) {
@ -14796,71 +14824,6 @@ var Phaser;
enumerable: true,
configurable: true
});
// MOVE THESE TO A UTIL
Body.prototype.render = function (context) {
context.beginPath();
context.strokeStyle = 'rgb(0,255,0)';
context.strokeRect(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight, this.bounds.width, this.bounds.height);
context.stroke();
context.closePath();
// center point
context.fillStyle = 'rgb(0,255,0)';
context.fillRect(this.position.x, this.position.y, 2, 2);
if (this.touching & Phaser.Types.LEFT) {
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight);
context.lineTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight);
context.stroke();
context.closePath();
}
if (this.touching & Phaser.Types.RIGHT) {
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight);
context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight);
context.stroke();
context.closePath();
}
if (this.touching & Phaser.Types.UP) {
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight);
context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight);
context.stroke();
context.closePath();
}
if (this.touching & Phaser.Types.DOWN) {
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight);
context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight);
context.stroke();
context.closePath();
}
};
/**
* Render debug infos. (including name, bounds info, position and some other properties)
* @param x {number} X position of the debug info to be rendered.
* @param y {number} Y position of the debug info to be rendered.
* @param [color] {number} color of the debug info to be rendered. (format is css color string)
*/
Body.prototype.renderDebugInfo = function (x, y, color) {
if (typeof color === "undefined") { color = 'rgb(255,255,255)'; }
this.sprite.texture.context.fillStyle = color;
this.sprite.texture.context.fillText('Sprite: (' + this.sprite.width + ' x ' + this.sprite.height + ')', x, y);
//this.sprite.texture.context.fillText('x: ' + this._sprite.frameBounds.x.toFixed(1) + ' y: ' + this._sprite.frameBounds.y.toFixed(1) + ' rotation: ' + this._sprite.rotation.toFixed(1), x, y + 14);
this.sprite.texture.context.fillText('x: ' + this.bounds.x.toFixed(1) + ' y: ' + this.bounds.y.toFixed(1) + ' rotation: ' + this.sprite.transform.rotation.toFixed(0), x, y + 14);
this.sprite.texture.context.fillText('vx: ' + this.velocity.x.toFixed(1) + ' vy: ' + this.velocity.y.toFixed(1), x, y + 28);
this.sprite.texture.context.fillText('acx: ' + this.acceleration.x.toFixed(1) + ' acy: ' + this.acceleration.y.toFixed(1), x, y + 42);
this.sprite.texture.context.fillText('angVx: ' + this.angularVelocity.toFixed(1) + ' angAc: ' + this.angularAcceleration.toFixed(1), x, y + 56);
};
return Body;
})();
Physics.Body = Body;
@ -15013,7 +14976,7 @@ var Phaser;
*/
Sprite.prototype.bringToTop = function () {
if (this.group) {
//this.group.bringToTop(this);
this.group.bringToTop(this);
}
};
@ -19223,25 +19186,15 @@ var Phaser;
this.canvas = document.createElement('canvas');
this.canvas.width = width;
this.canvas.height = height;
this.context = this.canvas.getContext('2d');
if ((parent !== '' || parent !== null) && document.getElementById(parent)) {
document.getElementById(parent).appendChild(this.canvas);
document.getElementById(parent).style.overflow = 'hidden';
} else {
document.body.appendChild(this.canvas);
}
Phaser.CanvasUtils.addToDOM(this.canvas, parent, true);
Phaser.CanvasUtils.setTouchAction(this.canvas);
// Consume default actions on the canvas
this.canvas.style.msTouchAction = 'none';
this.canvas.style['ms-touch-action'] = 'none';
this.canvas.style['touch-action'] = 'none';
this.canvas.style.backgroundColor = 'rgb(0,0,0)';
this.canvas.oncontextmenu = function (event) {
event.preventDefault();
};
this.context = this.canvas.getContext('2d');
this.css3 = new Phaser.Display.CSS3Filters(this.canvas);
this.scaleMode = Phaser.StageScaleMode.NO_SCALE;
@ -19352,13 +19305,6 @@ var Phaser;
}
};
Stage.prototype.setImageRenderingCrisp = function () {
this.canvas.style['image-rendering'] = 'crisp-edges';
this.canvas.style['image-rendering'] = '-moz-crisp-edges';
this.canvas.style['image-rendering'] = '-webkit-optimize-contrast';
this.canvas.style['-ms-interpolation-mode'] = 'nearest-neighbor';
};
Stage.prototype.pauseGame = function () {
this.game.paused = true;
@ -19757,7 +19703,7 @@ var Phaser;
//this.physics = new Phaser.Physics.Manager(this);
this.plugins = new Phaser.PluginManager(this, this);
this.load.onLoadComplete.addOnce(this.loadComplete, this);
this.load.onLoadComplete.add(this.loadComplete, this);
this.setRenderer(Phaser.Types.RENDERER_CANVAS);
@ -19883,6 +19829,7 @@ var Phaser;
this._loadComplete = true;
} else {
// Start the loader going as we have something in the queue
this.load.onLoadComplete.add(this.loadComplete, this);
this.load.start();
}
} else {
@ -20079,27 +20026,81 @@ var Phaser;
})();
Phaser.Game = Game;
})(Phaser || (Phaser = {}));
/// <reference path="_definitions.ts" />
/// <reference path="../_definitions.ts" />
/**
* Phaser - http://www.phaser.io
* Phaser - CanvasUtils
*
* v1.0.0 - August 12th 2013
*
* A feature-packed 2D canvas game framework born from the firey pits of Flixel and
* constructed via plenty of blood, sweat, tears and coffee by Richard Davey (@photonstorm).
*
* Many thanks to Adam Saltsman (@ADAMATOMIC) for releasing Flixel, from both which Phaser
* and my love of game development originate.
*
* Follow Phaser progress at http://www.photonstorm.com
*
* "If you want your children to be intelligent, read them fairy tales."
* "If you want them to be more intelligent, read them more fairy tales."
* -- Albert Einstein
* A collection of methods useful for manipulating canvas objects.
*/
var Phaser;
(function (Phaser) {
Phaser.VERSION = 'Phaser version 1.0.0';
var CanvasUtils = (function () {
function CanvasUtils() {
}
CanvasUtils.getAspectRatio = function (canvas) {
return canvas.width / canvas.height;
};
Phaser.GAMES = [];
CanvasUtils.setBackgroundColor = function (canvas, color) {
if (typeof color === "undefined") { color = 'rgb(0,0,0)'; }
canvas.style.backgroundColor = color;
return canvas;
};
CanvasUtils.setTouchAction = function (canvas, value) {
if (typeof value === "undefined") { value = 'none'; }
canvas.style.msTouchAction = value;
canvas.style['ms-touch-action'] = value;
canvas.style['touch-action'] = value;
return canvas;
};
CanvasUtils.addToDOM = function (canvas, parent, overflowHidden) {
if (typeof parent === "undefined") { parent = ''; }
if (typeof overflowHidden === "undefined") { overflowHidden = true; }
if ((parent !== '' || parent !== null) && document.getElementById(parent)) {
document.getElementById(parent).appendChild(canvas);
if (overflowHidden) {
document.getElementById(parent).style.overflow = 'hidden';
}
} else {
document.body.appendChild(canvas);
}
return canvas;
};
CanvasUtils.setTransform = function (context, translateX, translateY, scaleX, scaleY, skewX, skewY) {
context.setTransform(scaleX, skewX, skewY, scaleY, translateX, translateY);
return context;
};
CanvasUtils.setSmoothingEnabled = function (context, value) {
context['imageSmoothingEnabled'] = value;
context['mozImageSmoothingEnabled'] = value;
context['oImageSmoothingEnabled'] = value;
context['webkitImageSmoothingEnabled'] = value;
context['msImageSmoothingEnabled'] = value;
return context;
};
CanvasUtils.setImageRenderingCrisp = function (canvas) {
canvas.style['image-rendering'] = 'crisp-edges';
canvas.style['image-rendering'] = '-moz-crisp-edges';
canvas.style['image-rendering'] = '-webkit-optimize-contrast';
canvas.style.msInterpolationMode = 'nearest-neighbor';
return canvas;
};
CanvasUtils.setImageRenderingBicubic = function (canvas) {
canvas.style['image-rendering'] = 'auto';
canvas.style.msInterpolationMode = 'bicubic';
return canvas;
};
return CanvasUtils;
})();
Phaser.CanvasUtils = CanvasUtils;
})(Phaser || (Phaser = {}));