fabric-rails 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/README.md +1 -1
- data/lib/fabric/rails/version.rb +2 -2
- data/vendor/assets/javascripts/fabric.js +139 -100
- metadata +6 -6
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
data/lib/fabric/rails/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/* build: `node build.js modules=ALL` */
|
2
2
|
/*! Fabric.js Copyright 2008-2012, Printio (Juriy Zaytsev, Maxim Chernyak) */
|
3
3
|
|
4
|
-
var fabric = fabric || { version: "0.9.
|
4
|
+
var fabric = fabric || { version: "0.9.8" };
|
5
5
|
|
6
6
|
if (typeof exports != 'undefined') {
|
7
7
|
exports.fabric = fabric;
|
@@ -8016,20 +8016,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8016
8016
|
: this.fill;
|
8017
8017
|
}
|
8018
8018
|
|
8019
|
-
if (
|
8020
|
-
|
8021
|
-
|
8022
|
-
-this.group.width / 2,
|
8023
|
-
-this.group.height / 2
|
8024
|
-
);
|
8025
|
-
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
8026
|
-
}
|
8027
|
-
else {
|
8028
|
-
ctx.translate(
|
8029
|
-
-this.group.width / 2 + this.width / 2,
|
8030
|
-
-this.group.height / 2 + this.height / 2
|
8031
|
-
);
|
8032
|
-
}
|
8019
|
+
if (m && this.group) {
|
8020
|
+
ctx.translate(-this.group.width/2, -this.group.height/2);
|
8021
|
+
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
8033
8022
|
}
|
8034
8023
|
|
8035
8024
|
this._render(ctx, noTransform);
|
@@ -8135,10 +8124,11 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8135
8124
|
*/
|
8136
8125
|
setCoords: function() {
|
8137
8126
|
|
8138
|
-
var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0
|
8127
|
+
var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0,
|
8128
|
+
padding = this.padding;
|
8139
8129
|
|
8140
|
-
this.currentWidth = (this.width + strokeWidth) * this.scaleX;
|
8141
|
-
this.currentHeight = (this.height + strokeWidth) * this.scaleY;
|
8130
|
+
this.currentWidth = (this.width + strokeWidth) * this.scaleX + padding * 2;
|
8131
|
+
this.currentHeight = (this.height + strokeWidth) * this.scaleY + padding * 2;
|
8142
8132
|
|
8143
8133
|
this._hypotenuse = Math.sqrt(
|
8144
8134
|
Math.pow(this.currentWidth / 2, 2) +
|
@@ -8249,8 +8239,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8249
8239
|
drawBorders: function(ctx) {
|
8250
8240
|
if (!this.hasBorders) return;
|
8251
8241
|
|
8252
|
-
var
|
8253
|
-
|
8242
|
+
var MIN_SCALE_LIMIT = fabric.Object.MIN_SCALE_LIMIT,
|
8243
|
+
padding = this.padding,
|
8244
|
+
padding2 = padding * 2,
|
8254
8245
|
strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0;
|
8255
8246
|
|
8256
8247
|
ctx.save();
|
@@ -8269,14 +8260,20 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8269
8260
|
h = this.getHeight();
|
8270
8261
|
|
8271
8262
|
ctx.strokeRect(
|
8272
|
-
~~(-(w / 2) -
|
8273
|
-
~~(-(h / 2) -
|
8263
|
+
~~(-(w / 2) - padding - strokeWidth / 2 * this.scaleX) + 0.5, // offset needed to make lines look sharper
|
8264
|
+
~~(-(h / 2) - padding - strokeWidth / 2 * this.scaleY) + 0.5,
|
8274
8265
|
~~(w + padding2 + strokeWidth * this.scaleX),
|
8275
8266
|
~~(h + padding2 + strokeWidth * this.scaleY)
|
8276
8267
|
);
|
8277
8268
|
|
8278
8269
|
if (this.hasRotatingPoint && !this.hideCorners && !this.lockRotation) {
|
8279
|
-
|
8270
|
+
|
8271
|
+
var rotateHeight = (
|
8272
|
+
this.flipY
|
8273
|
+
? h + (strokeWidth * this.scaleY) + (padding * 2)
|
8274
|
+
: -h - (strokeWidth * this.scaleY) - (padding * 2)
|
8275
|
+
) / 2;
|
8276
|
+
|
8280
8277
|
var rotateWidth = (-w/2);
|
8281
8278
|
|
8282
8279
|
ctx.beginPath();
|
@@ -8362,82 +8359,97 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8362
8359
|
var size = this.cornersize,
|
8363
8360
|
size2 = size / 2,
|
8364
8361
|
strokeWidth2 = this.strokeWidth / 2,
|
8365
|
-
padding = this.padding,
|
8366
8362
|
left = -(this.width / 2),
|
8367
8363
|
top = -(this.height / 2),
|
8368
8364
|
_left,
|
8369
8365
|
_top,
|
8370
8366
|
sizeX = size / this.scaleX,
|
8371
8367
|
sizeY = size / this.scaleY,
|
8372
|
-
|
8373
|
-
|
8374
|
-
|
8375
|
-
|
8376
|
-
|
8368
|
+
paddingX = this.padding / this.scaleX,
|
8369
|
+
paddingY = this.padding / this.scaleY,
|
8370
|
+
scaleOffsetY = size2 / this.scaleY,
|
8371
|
+
scaleOffsetX = size2 / this.scaleX,
|
8372
|
+
scaleOffsetSizeX = (size2 - size) / this.scaleX,
|
8373
|
+
scaleOffsetSizeY = (size2 - size) / this.scaleY,
|
8374
|
+
height = this.height,
|
8375
|
+
width = this.width;
|
8377
8376
|
|
8378
8377
|
ctx.save();
|
8379
8378
|
|
8379
|
+
ctx.lineWidth = 1 / Math.max(this.scaleX, this.scaleY);
|
8380
|
+
|
8380
8381
|
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
|
8381
|
-
ctx.fillStyle = this.cornerColor;
|
8382
|
+
ctx.strokeStyle = ctx.fillStyle = this.cornerColor;
|
8382
8383
|
|
8383
8384
|
// top-left
|
8384
|
-
_left = left - scaleOffsetX - strokeWidth2;
|
8385
|
-
_top = top - scaleOffsetY - strokeWidth2;
|
8386
|
-
|
8385
|
+
_left = left - scaleOffsetX - strokeWidth2 - paddingX;
|
8386
|
+
_top = top - scaleOffsetY - strokeWidth2 - paddingY;
|
8387
|
+
|
8388
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8389
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8387
8390
|
|
8388
8391
|
// top-right
|
8389
|
-
_left = left +
|
8390
|
-
_top = top - scaleOffsetY - strokeWidth2;
|
8391
|
-
|
8392
|
+
_left = left + width - scaleOffsetX + strokeWidth2 + paddingX;
|
8393
|
+
_top = top - scaleOffsetY - strokeWidth2 - paddingY;
|
8394
|
+
|
8395
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8396
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8392
8397
|
|
8393
8398
|
// bottom-left
|
8394
|
-
_left = left - scaleOffsetX - strokeWidth2;
|
8395
|
-
_top = top + height + scaleOffsetSizeY + strokeWidth2;
|
8396
|
-
|
8399
|
+
_left = left - scaleOffsetX - strokeWidth2 - paddingX;
|
8400
|
+
_top = top + height + scaleOffsetSizeY + strokeWidth2 + paddingY;
|
8401
|
+
|
8402
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8403
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8397
8404
|
|
8398
8405
|
// bottom-right
|
8399
|
-
_left = left +
|
8400
|
-
_top = top + height + scaleOffsetSizeY + strokeWidth2;
|
8401
|
-
|
8402
|
-
|
8403
|
-
|
8404
|
-
|
8405
|
-
|
8406
|
-
|
8407
|
-
|
8408
|
-
|
8409
|
-
|
8410
|
-
|
8411
|
-
|
8412
|
-
|
8413
|
-
|
8414
|
-
|
8415
|
-
|
8416
|
-
|
8417
|
-
|
8418
|
-
|
8419
|
-
|
8420
|
-
|
8421
|
-
|
8406
|
+
_left = left + width + scaleOffsetSizeX + strokeWidth2 + paddingX;
|
8407
|
+
_top = top + height + scaleOffsetSizeY + strokeWidth2 + paddingY;
|
8408
|
+
|
8409
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8410
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8411
|
+
|
8412
|
+
if (!this.lockUniScaling) {
|
8413
|
+
// middle-top
|
8414
|
+
_left = left + width/2 - scaleOffsetX;
|
8415
|
+
_top = top - scaleOffsetY - strokeWidth2 - paddingY;
|
8416
|
+
|
8417
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8418
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8419
|
+
|
8420
|
+
// middle-bottom
|
8421
|
+
_left = left + width/2 - scaleOffsetX;
|
8422
|
+
_top = top + height + scaleOffsetSizeY + strokeWidth2 + paddingY;
|
8423
|
+
|
8424
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8425
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8426
|
+
|
8427
|
+
// middle-right
|
8428
|
+
_left = left + width + scaleOffsetSizeX + strokeWidth2 + paddingX;
|
8429
|
+
_top = top + height/2 - scaleOffsetY;
|
8430
|
+
|
8431
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8432
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8433
|
+
|
8434
|
+
// middle-left
|
8435
|
+
_left = left - scaleOffsetX - strokeWidth2 - paddingX;
|
8436
|
+
_top = top + height/2 - scaleOffsetY;
|
8437
|
+
|
8438
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8439
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8440
|
+
}
|
8422
8441
|
|
8423
8442
|
// middle-top-rotate
|
8424
8443
|
if (this.hasRotatingPoint) {
|
8425
|
-
// _left = left + this.width/2;
|
8426
|
-
// _top = top - (45 / this.scaleY) + scaleOffsetY;
|
8427
|
-
|
8428
|
-
// ctx.save();
|
8429
|
-
// ctx.beginPath();
|
8430
|
-
// ctx.arc(_left, _top, sizeX / 2, 0, Math.PI * 2, false);
|
8431
|
-
// ctx.fill();
|
8432
|
-
// ctx.restore();
|
8433
8444
|
|
8434
|
-
_left = left +
|
8445
|
+
_left = left + width/2 - scaleOffsetX;
|
8435
8446
|
|
8436
8447
|
_top = this.flipY ?
|
8437
|
-
(top + height + (this.rotatingPointOffset / this.scaleY) - sizeY/2 + strokeWidth2)
|
8438
|
-
: (top - (this.rotatingPointOffset / this.scaleY) - sizeY/2 - strokeWidth2);
|
8448
|
+
(top + height + (this.rotatingPointOffset / this.scaleY) - sizeY/2 + strokeWidth2 + paddingY)
|
8449
|
+
: (top - (this.rotatingPointOffset / this.scaleY) - sizeY/2 - strokeWidth2 - paddingY);
|
8439
8450
|
|
8440
|
-
ctx.
|
8451
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8452
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8441
8453
|
}
|
8442
8454
|
|
8443
8455
|
ctx.restore();
|
@@ -8675,6 +8687,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8675
8687
|
if (i === 'mtr' && !this.hasRotatingPoint) {
|
8676
8688
|
return false;
|
8677
8689
|
}
|
8690
|
+
if (this.lockUniScaling && (i === 'mt' || i === 'mr' || i === 'mb' || i === 'ml')) {
|
8691
|
+
return false;
|
8692
|
+
}
|
8678
8693
|
|
8679
8694
|
lines = this._getImageLines(this.oCoords[i].corner, i);
|
8680
8695
|
// debugging
|
@@ -9248,6 +9263,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
9248
9263
|
_render: function(ctx) {
|
9249
9264
|
ctx.beginPath();
|
9250
9265
|
|
9266
|
+
if (this.group) {
|
9267
|
+
ctx.translate(-this.group.width/2 + this.left, -this.group.height / 2 + this.top);
|
9268
|
+
}
|
9269
|
+
|
9251
9270
|
// move from center (of virtual box) to its left/top corner
|
9252
9271
|
ctx.moveTo(this.width === 1 ? 0 : (-this.width / 2), this.height === 1 ? 0 : (-this.height / 2));
|
9253
9272
|
ctx.lineTo(this.width === 1 ? 0 : (this.width / 2), this.height === 1 ? 0 : (this.height / 2));
|
@@ -9714,6 +9733,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
9714
9733
|
ctx.beginPath();
|
9715
9734
|
ctx.save();
|
9716
9735
|
ctx.globalAlpha *= this.opacity;
|
9736
|
+
if (this.transformMatrix && this.group) {
|
9737
|
+
ctx.translate(this.cx, this.cy);
|
9738
|
+
}
|
9717
9739
|
ctx.transform(1, 0, 0, this.ry/this.rx, 0, 0);
|
9718
9740
|
ctx.arc(noTransform ? this.left : 0, noTransform ? this.top : 0, this.rx, 0, piBy2, false);
|
9719
9741
|
if (this.stroke) {
|
@@ -9752,14 +9774,24 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
9752
9774
|
*/
|
9753
9775
|
fabric.Ellipse.fromElement = function(element, options) {
|
9754
9776
|
options || (options = { });
|
9777
|
+
|
9755
9778
|
var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);
|
9779
|
+
var cx = parsedAttributes.left;
|
9780
|
+
var cy = parsedAttributes.top;
|
9781
|
+
|
9756
9782
|
if ('left' in parsedAttributes) {
|
9757
9783
|
parsedAttributes.left -= (options.width / 2) || 0;
|
9758
9784
|
}
|
9759
9785
|
if ('top' in parsedAttributes) {
|
9760
9786
|
parsedAttributes.top -= (options.height / 2) || 0;
|
9761
9787
|
}
|
9762
|
-
|
9788
|
+
|
9789
|
+
var ellipse = new fabric.Ellipse(extend(parsedAttributes, options));
|
9790
|
+
|
9791
|
+
ellipse.cx = cx || 0;
|
9792
|
+
ellipse.cy = cy || 0;
|
9793
|
+
|
9794
|
+
return ellipse;
|
9763
9795
|
};
|
9764
9796
|
|
9765
9797
|
/**
|
@@ -9860,8 +9892,15 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
9860
9892
|
ctx.beginPath();
|
9861
9893
|
ctx.globalAlpha *= this.opacity;
|
9862
9894
|
|
9863
|
-
if (this.group) {
|
9864
|
-
ctx.translate(
|
9895
|
+
if (this.transformMatrix && this.group) {
|
9896
|
+
ctx.translate(
|
9897
|
+
this.width / 2 + this.x,
|
9898
|
+
this.height / 2 + this.y);
|
9899
|
+
}
|
9900
|
+
if (!this.transformMatrix && this.group) {
|
9901
|
+
ctx.translate(
|
9902
|
+
-this.group.width / 2 + this.width / 2 + this.x,
|
9903
|
+
-this.group.height / 2 + this.height / 2 + this.y);
|
9865
9904
|
}
|
9866
9905
|
|
9867
9906
|
ctx.moveTo(x+rx, y);
|
@@ -11101,6 +11140,12 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
11101
11140
|
*/
|
11102
11141
|
type: 'path-group',
|
11103
11142
|
|
11143
|
+
/**
|
11144
|
+
* @property
|
11145
|
+
* @type String
|
11146
|
+
*/
|
11147
|
+
fill: '',
|
11148
|
+
|
11104
11149
|
/**
|
11105
11150
|
* @property
|
11106
11151
|
* @type Boolean
|
@@ -11157,24 +11202,21 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
11157
11202
|
|
11158
11203
|
/**
|
11159
11204
|
* Sets certain property to a certain value
|
11160
|
-
* @method
|
11205
|
+
* @method _set
|
11161
11206
|
* @param {String} prop
|
11162
11207
|
* @param {Any} value
|
11163
11208
|
* @return {fabric.PathGroup} thisArg
|
11164
11209
|
*/
|
11165
|
-
|
11166
|
-
|
11167
|
-
|
11210
|
+
_set: function(prop, value) {
|
11211
|
+
|
11212
|
+
if ((prop === 'fill' || prop === 'overlayFill') && value && this.isSameColor()) {
|
11168
11213
|
var i = this.paths.length;
|
11169
11214
|
while (i--) {
|
11170
|
-
this.paths[i].
|
11215
|
+
this.paths[i]._set(prop, value);
|
11171
11216
|
}
|
11172
11217
|
}
|
11173
|
-
|
11174
|
-
|
11175
|
-
parentSet.call(this, prop, value);
|
11176
|
-
}
|
11177
|
-
return this;
|
11218
|
+
|
11219
|
+
return this.callSuper('_set', prop, value);
|
11178
11220
|
},
|
11179
11221
|
|
11180
11222
|
/**
|
@@ -11928,6 +11970,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
11928
11970
|
ctx.save();
|
11929
11971
|
var m = this.transformMatrix;
|
11930
11972
|
this._resetWidthHeight();
|
11973
|
+
if (this.group) {
|
11974
|
+
ctx.translate(-this.group.width/2 + this.width/2, -this.group.height/2 + this.height/2);
|
11975
|
+
}
|
11931
11976
|
if (m) {
|
11932
11977
|
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
11933
11978
|
}
|
@@ -12973,7 +13018,7 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|
12973
13018
|
this._initStateProperties();
|
12974
13019
|
this.text = text;
|
12975
13020
|
this.setOptions(options || { });
|
12976
|
-
this.
|
13021
|
+
this._theta = this.angle * Math.PI / 180;
|
12977
13022
|
this._initDimensions();
|
12978
13023
|
this.setCoords();
|
12979
13024
|
},
|
@@ -13555,6 +13600,7 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|
13555
13600
|
*/
|
13556
13601
|
setFontsize: function(value) {
|
13557
13602
|
this.set('fontSize', value);
|
13603
|
+
this._initDimensions();
|
13558
13604
|
this.setCoords();
|
13559
13605
|
return this;
|
13560
13606
|
},
|
@@ -13577,6 +13623,7 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|
13577
13623
|
*/
|
13578
13624
|
setText: function(value) {
|
13579
13625
|
this.set('text', value);
|
13626
|
+
this._initDimensions();
|
13580
13627
|
this.setCoords();
|
13581
13628
|
return this;
|
13582
13629
|
},
|
@@ -13589,19 +13636,11 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|
13589
13636
|
* @return {fabric.Text} thisArg
|
13590
13637
|
* @chainable
|
13591
13638
|
*/
|
13592
|
-
|
13593
|
-
if (
|
13594
|
-
|
13595
|
-
this.set(prop, name[prop]);
|
13596
|
-
}
|
13639
|
+
_set: function(name, value) {
|
13640
|
+
if (name === 'fontFamily' && this.path) {
|
13641
|
+
this.path = this.path.replace(/(.*?)([^\/]*)(\.font\.js)/, '$1' + value + '$3');
|
13597
13642
|
}
|
13598
|
-
|
13599
|
-
this[name] = value;
|
13600
|
-
if (name === 'fontFamily' && this.path) {
|
13601
|
-
this.path = this.path.replace(/(.*?)([^\/]*)(\.font\.js)/, '$1' + value + '$3');
|
13602
|
-
}
|
13603
|
-
}
|
13604
|
-
return this;
|
13643
|
+
this.callSuper('_set', name, value);
|
13605
13644
|
}
|
13606
13645
|
});
|
13607
13646
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fabric-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: railties
|
16
|
-
requirement: &
|
16
|
+
requirement: &70348217761760 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
version: '5.0'
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *70348217761760
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: thor
|
30
|
-
requirement: &
|
30
|
+
requirement: &70348217896960 !ruby/object:Gem::Requirement
|
31
31
|
none: false
|
32
32
|
requirements:
|
33
33
|
- - ~>
|
@@ -35,7 +35,7 @@ dependencies:
|
|
35
35
|
version: '0.14'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *70348217896960
|
39
39
|
description: This gem provides fabric.js for your Rails 3 application via the asset
|
40
40
|
pipeline.
|
41
41
|
email:
|