@checksub_team/peaks_timeline 2.1.1 → 2.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/peaks.js +33 -19
- package/src/components/waveform-shape.js +24 -20
- package/src/models/source.js +22 -3
- package/src/source-handler.js +3 -1
package/package.json
CHANGED
package/peaks.js
CHANGED
|
@@ -19828,18 +19828,16 @@ module.exports = function (Utils, Konva) {
|
|
|
19828
19828
|
WaveformShape.prototype._sceneFunc = function (context) {
|
|
19829
19829
|
var width = this._view.getWidth();
|
|
19830
19830
|
var waveformData = this._layer.getLoadedData(this._url).data;
|
|
19831
|
-
var startPixel = 0, startOffset = 0;
|
|
19831
|
+
var startPixel = 0, startOffset = 0, endPixel = width, targetSpeed = 1;
|
|
19832
19832
|
if (this._source) {
|
|
19833
|
-
|
|
19833
|
+
targetSpeed = this._source.targetSpeed || 1;
|
|
19834
|
+
startPixel = Math.floor((this._view.timeToPixels(this._source.mediaStartTime) + Math.max(this._view.getFrameOffset() - this._view.timeToPixels(this._source.startTime), 0)) * targetSpeed);
|
|
19834
19835
|
startOffset = this._view.timeToPixels(this._source.mediaStartTime);
|
|
19836
|
+
endPixel = Math.min(Math.ceil((this._view.timeToPixels(this._source.mediaEndTime) - Math.max(this._view.timeToPixels(this._source.endTime) - this._view.getFrameOffset() - this._view.getWidth(), 0)) * targetSpeed), waveformData.length);
|
|
19835
19837
|
}
|
|
19836
|
-
|
|
19837
|
-
if (this._source) {
|
|
19838
|
-
endPixel = Math.min(this._view.timeToPixels(this._source.mediaEndTime) - Math.max(this._view.timeToPixels(this._source.endTime) - this._view.getFrameOffset() - this._view.getWidth(), 0), waveformData.length);
|
|
19839
|
-
}
|
|
19840
|
-
this._drawWaveform(context, waveformData, startPixel, startOffset, endPixel, this._height);
|
|
19838
|
+
this._drawWaveform(context, waveformData, startPixel, startOffset, endPixel, targetSpeed, this._height);
|
|
19841
19839
|
};
|
|
19842
|
-
WaveformShape.prototype._drawWaveform = function (context, waveformData, startPixel, startOffset, endPixel, height) {
|
|
19840
|
+
WaveformShape.prototype._drawWaveform = function (context, waveformData, startPixel, startOffset, endPixel, targetSpeed, height) {
|
|
19843
19841
|
var channels = waveformData.channels;
|
|
19844
19842
|
var waveformTop = 0;
|
|
19845
19843
|
var waveformHeight = Math.floor(height / channels);
|
|
@@ -19847,21 +19845,21 @@ module.exports = function (Utils, Konva) {
|
|
|
19847
19845
|
if (i === channels - 1) {
|
|
19848
19846
|
waveformHeight = height - (channels - 1) * waveformHeight;
|
|
19849
19847
|
}
|
|
19850
|
-
this._drawChannel(context, waveformData.channel(i), startPixel, startOffset, endPixel, waveformTop, waveformHeight);
|
|
19848
|
+
this._drawChannel(context, waveformData.channel(i), startPixel, startOffset, endPixel, waveformTop, waveformHeight, targetSpeed);
|
|
19851
19849
|
waveformTop += waveformHeight;
|
|
19852
19850
|
}
|
|
19853
19851
|
};
|
|
19854
|
-
WaveformShape.prototype._drawChannel = function (context, channel, startPixel, startOffset, endPixel, top, height) {
|
|
19852
|
+
WaveformShape.prototype._drawChannel = function (context, channel, startPixel, startOffset, endPixel, top, height, targetSpeed) {
|
|
19855
19853
|
var x, val;
|
|
19856
19854
|
var amplitudeScale = this._view.getAmplitudeScale();
|
|
19857
19855
|
context.beginPath();
|
|
19858
|
-
for (x =
|
|
19856
|
+
for (x = startPixel; x < endPixel; x++) {
|
|
19859
19857
|
val = channel.min_sample(x);
|
|
19860
|
-
context.lineTo(x - startOffset + 0.5, top + scaleY(val, height, amplitudeScale) + 0.5);
|
|
19858
|
+
context.lineTo(x / targetSpeed - startOffset + 0.5, top + scaleY(val, height, amplitudeScale) + 0.5);
|
|
19861
19859
|
}
|
|
19862
|
-
for (x =
|
|
19860
|
+
for (x = endPixel - 1; x >= startPixel; x--) {
|
|
19863
19861
|
val = channel.max_sample(x);
|
|
19864
|
-
context.lineTo(x - startOffset + 0.5, top + scaleY(val, height, amplitudeScale) + 0.5);
|
|
19862
|
+
context.lineTo(x / targetSpeed - startOffset + 0.5, top + scaleY(val, height, amplitudeScale) + 0.5);
|
|
19865
19863
|
}
|
|
19866
19864
|
context.closePath();
|
|
19867
19865
|
context.fillShape(this);
|
|
@@ -20991,8 +20989,13 @@ module.exports = function (Utils) {
|
|
|
20991
20989
|
} else if (!Utils.isBoolean(options.loading)) {
|
|
20992
20990
|
throw new TypeError('peaks.sources.' + context + ': loading must be a boolean');
|
|
20993
20991
|
}
|
|
20992
|
+
if (Utils.isNullOrUndefined(options.targetSpeed)) {
|
|
20993
|
+
options.targetSpeed = 1;
|
|
20994
|
+
} else if (!Utils.isNumber(options.targetSpeed) || options.targetSpeed <= 0) {
|
|
20995
|
+
throw new TypeError('peaks.sources.' + context + ': targetSpeed must be a positive number');
|
|
20996
|
+
}
|
|
20994
20997
|
}
|
|
20995
|
-
function Source(peaks, id, lineId, originId, elementId, title, titleAlignments, url, previewUrl, binaryUrl, kind, subkind, duration, startTime, endTime, mediaStartTime, mediaEndTime, color, backgroundColor, hoverBackgroundColor, selectedBackgroundColor, borderColor, selectedBorderColor, warningColor, warningWidth, volumeSliderColor, volumeSliderWidth, volumeSliderDraggingWidth, textFont, textFontSize, textColor, textBackgroundColor, textPosition, textAutoScroll, borderWidth, borderRadius, wrapped, draggable, orderable, resizable, cuttable, deletable, wrapping, previewHeight, binaryHeight, indicators, markers, buttons, markerColor, markerWidth, volume, volumeRange, loading, ...customParams) {
|
|
20998
|
+
function Source(peaks, id, lineId, originId, elementId, title, titleAlignments, url, previewUrl, binaryUrl, kind, subkind, duration, startTime, endTime, mediaStartTime, mediaEndTime, color, backgroundColor, hoverBackgroundColor, selectedBackgroundColor, borderColor, selectedBorderColor, warningColor, warningWidth, volumeSliderColor, volumeSliderWidth, volumeSliderDraggingWidth, textFont, textFontSize, textColor, textBackgroundColor, textPosition, textAutoScroll, borderWidth, borderRadius, wrapped, draggable, orderable, resizable, cuttable, deletable, wrapping, previewHeight, binaryHeight, indicators, markers, buttons, markerColor, markerWidth, volume, volumeRange, loading, targetSpeed, ...customParams) {
|
|
20996
20999
|
var opts = {
|
|
20997
21000
|
title: title,
|
|
20998
21001
|
titleAlignments: titleAlignments,
|
|
@@ -21041,7 +21044,8 @@ module.exports = function (Utils) {
|
|
|
21041
21044
|
markerWidth: markerWidth,
|
|
21042
21045
|
volume: volume,
|
|
21043
21046
|
volumeRange: volumeRange,
|
|
21044
|
-
loading: loading
|
|
21047
|
+
loading: loading,
|
|
21048
|
+
targetSpeed: targetSpeed
|
|
21045
21049
|
};
|
|
21046
21050
|
validateSource(peaks, opts, 'add()');
|
|
21047
21051
|
this._peaks = peaks;
|
|
@@ -21097,6 +21101,7 @@ module.exports = function (Utils) {
|
|
|
21097
21101
|
this._volume = opts.volume;
|
|
21098
21102
|
this._volumeRange = opts.volumeRange;
|
|
21099
21103
|
this._loading = opts.loading;
|
|
21104
|
+
this._targetSpeed = opts.targetSpeed;
|
|
21100
21105
|
this._minSize = peaks.options.minSourceSize;
|
|
21101
21106
|
this._selected = false;
|
|
21102
21107
|
for (var i = 0; i < customParams.length; i += 2) {
|
|
@@ -21521,6 +21526,12 @@ module.exports = function (Utils) {
|
|
|
21521
21526
|
set: function (selected) {
|
|
21522
21527
|
this._selected = selected;
|
|
21523
21528
|
}
|
|
21529
|
+
},
|
|
21530
|
+
targetSpeed: {
|
|
21531
|
+
enumerable: true,
|
|
21532
|
+
get: function () {
|
|
21533
|
+
return this._targetSpeed;
|
|
21534
|
+
}
|
|
21524
21535
|
}
|
|
21525
21536
|
});
|
|
21526
21537
|
Source.prototype.updateTimes = function (newStartTime, newEndTime) {
|
|
@@ -21656,7 +21667,8 @@ module.exports = function (Utils) {
|
|
|
21656
21667
|
markerWidth: this.markerWidth,
|
|
21657
21668
|
volume: this.volume,
|
|
21658
21669
|
volumeRange: this.volumeRange,
|
|
21659
|
-
loading: this.loading
|
|
21670
|
+
loading: this.loading,
|
|
21671
|
+
targetSpeed: this.targetSpeed
|
|
21660
21672
|
};
|
|
21661
21673
|
Utils.extend(opts, options);
|
|
21662
21674
|
validateSource(this._peaks, opts, 'update()');
|
|
@@ -21706,6 +21718,7 @@ module.exports = function (Utils) {
|
|
|
21706
21718
|
this._volume = opts.volume;
|
|
21707
21719
|
this._volumeRange = opts.volumeRange;
|
|
21708
21720
|
this._loading = opts.loading;
|
|
21721
|
+
this._targetSpeed = opts.targetSpeed;
|
|
21709
21722
|
if (options && typeof options === 'object') {
|
|
21710
21723
|
for (var key in options) {
|
|
21711
21724
|
if (Object.prototype.hasOwnProperty.call(options, key) && key.startsWith('custom_')) {
|
|
@@ -22019,7 +22032,8 @@ module.exports = function (Source, Utils) {
|
|
|
22019
22032
|
markerWidth: sourceToCut.markerWidth,
|
|
22020
22033
|
volume: sourceToCut.volume,
|
|
22021
22034
|
volumeRange: sourceToCut.volumeRange,
|
|
22022
|
-
loading: sourceToCut.loading
|
|
22035
|
+
loading: sourceToCut.loading,
|
|
22036
|
+
targetSpeed: sourceToCut.targetSpeed
|
|
22023
22037
|
};
|
|
22024
22038
|
for (var key in sourceToCut) {
|
|
22025
22039
|
if (key.startsWith('custom_')) {
|
|
@@ -22049,7 +22063,7 @@ module.exports = function (Source, Utils) {
|
|
|
22049
22063
|
customParams.push(key, value);
|
|
22050
22064
|
}
|
|
22051
22065
|
});
|
|
22052
|
-
var source = new Source(this._peaks, options.id || this._getNextSourceId(), options.lineId, options.originId, options.elementId, options.title, options.titleAlignments, options.url, options.previewUrl, options.binaryUrl, options.kind, options.subkind, options.duration, options.startTime, options.endTime, options.mediaStartTime, options.mediaEndTime, options.color, options.backgroundColor, options.hoverBackgroundColor, options.selectedBackgroundColor, options.borderColor, options.selectedBorderColor, options.warningColor, options.warningWidth, options.volumeSliderColor, options.volumeSliderWidth, options.volumeSliderDraggingWidth, options.textFont, options.textFontSize, options.textColor, options.textBackgroundColor, options.textPosition, options.textAutoScroll, options.borderWidth, options.borderRadius, options.wrapped, options.draggable, options.orderable, options.resizable, options.cuttable, options.deletable, options.wrapping, options.previewHeight, options.binaryHeight, options.indicators, options.markers, options.buttons, options.markerColor, options.markerWidth, options.volume, options.volumeRange, options.loading, ...customParams);
|
|
22066
|
+
var source = new Source(this._peaks, options.id || this._getNextSourceId(), options.lineId, options.originId, options.elementId, options.title, options.titleAlignments, options.url, options.previewUrl, options.binaryUrl, options.kind, options.subkind, options.duration, options.startTime, options.endTime, options.mediaStartTime, options.mediaEndTime, options.color, options.backgroundColor, options.hoverBackgroundColor, options.selectedBackgroundColor, options.borderColor, options.selectedBorderColor, options.warningColor, options.warningWidth, options.volumeSliderColor, options.volumeSliderWidth, options.volumeSliderDraggingWidth, options.textFont, options.textFontSize, options.textColor, options.textBackgroundColor, options.textPosition, options.textAutoScroll, options.borderWidth, options.borderRadius, options.wrapped, options.draggable, options.orderable, options.resizable, options.cuttable, options.deletable, options.wrapping, options.previewHeight, options.binaryHeight, options.indicators, options.markers, options.buttons, options.markerColor, options.markerWidth, options.volume, options.volumeRange, options.loading, options.targetSpeed, ...customParams);
|
|
22053
22067
|
return source;
|
|
22054
22068
|
};
|
|
22055
22069
|
SourceHandler.prototype.getSources = function () {
|
|
@@ -73,26 +73,28 @@ define(['../utils', 'konva'], function(Utils, Konva) {
|
|
|
73
73
|
var width = this._view.getWidth();
|
|
74
74
|
var waveformData = this._layer.getLoadedData(this._url).data;
|
|
75
75
|
|
|
76
|
-
var startPixel = 0, startOffset = 0;
|
|
76
|
+
var startPixel = 0, startOffset = 0, endPixel = width, targetSpeed = 1.0;
|
|
77
77
|
|
|
78
78
|
if (this._source) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
targetSpeed = this._source.targetSpeed || 1.0;
|
|
80
|
+
|
|
81
|
+
startPixel = Math.floor(
|
|
82
|
+
(this._view.timeToPixels(this._source.mediaStartTime) + Math.max(
|
|
83
|
+
this._view.getFrameOffset() - this._view.timeToPixels(this._source.startTime),
|
|
84
|
+
0
|
|
85
|
+
)) * targetSpeed
|
|
82
86
|
);
|
|
83
87
|
|
|
84
88
|
startOffset = this._view.timeToPixels(this._source.mediaStartTime);
|
|
85
|
-
}
|
|
86
89
|
|
|
87
|
-
var endPixel = width;
|
|
88
|
-
|
|
89
|
-
if (this._source) {
|
|
90
90
|
endPixel = Math.min(
|
|
91
|
-
|
|
92
|
-
this._view.timeToPixels(this._source.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
Math.ceil(
|
|
92
|
+
(this._view.timeToPixels(this._source.mediaEndTime) - Math.max(
|
|
93
|
+
this._view.timeToPixels(this._source.endTime)
|
|
94
|
+
- this._view.getFrameOffset()
|
|
95
|
+
- this._view.getWidth(),
|
|
96
|
+
0
|
|
97
|
+
)) * targetSpeed
|
|
96
98
|
),
|
|
97
99
|
waveformData.length
|
|
98
100
|
);
|
|
@@ -104,6 +106,7 @@ define(['../utils', 'konva'], function(Utils, Konva) {
|
|
|
104
106
|
startPixel,
|
|
105
107
|
startOffset,
|
|
106
108
|
endPixel,
|
|
109
|
+
targetSpeed,
|
|
107
110
|
this._height
|
|
108
111
|
);
|
|
109
112
|
};
|
|
@@ -124,7 +127,7 @@ define(['../utils', 'konva'], function(Utils, Konva) {
|
|
|
124
127
|
*/
|
|
125
128
|
|
|
126
129
|
WaveformShape.prototype._drawWaveform = function(context, waveformData,
|
|
127
|
-
startPixel, startOffset, endPixel, height) {
|
|
130
|
+
startPixel, startOffset, endPixel, targetSpeed, height) {
|
|
128
131
|
var channels = waveformData.channels;
|
|
129
132
|
|
|
130
133
|
var waveformTop = 0;
|
|
@@ -142,7 +145,8 @@ define(['../utils', 'konva'], function(Utils, Konva) {
|
|
|
142
145
|
startOffset,
|
|
143
146
|
endPixel,
|
|
144
147
|
waveformTop,
|
|
145
|
-
waveformHeight
|
|
148
|
+
waveformHeight,
|
|
149
|
+
targetSpeed
|
|
146
150
|
);
|
|
147
151
|
|
|
148
152
|
waveformTop += waveformHeight;
|
|
@@ -150,23 +154,23 @@ define(['../utils', 'konva'], function(Utils, Konva) {
|
|
|
150
154
|
};
|
|
151
155
|
|
|
152
156
|
WaveformShape.prototype._drawChannel = function(context, channel,
|
|
153
|
-
startPixel, startOffset, endPixel, top, height) {
|
|
157
|
+
startPixel, startOffset, endPixel, top, height, targetSpeed) {
|
|
154
158
|
var x, val;
|
|
155
159
|
|
|
156
160
|
var amplitudeScale = this._view.getAmplitudeScale();
|
|
157
161
|
|
|
158
162
|
context.beginPath();
|
|
159
163
|
|
|
160
|
-
for (x =
|
|
164
|
+
for (x = startPixel; x < endPixel; x++) {
|
|
161
165
|
val = channel.min_sample(x);
|
|
162
166
|
|
|
163
|
-
context.lineTo(x - startOffset + 0.5, top + scaleY(val, height, amplitudeScale) + 0.5);
|
|
167
|
+
context.lineTo(x / targetSpeed - startOffset + 0.5, top + scaleY(val, height, amplitudeScale) + 0.5);
|
|
164
168
|
}
|
|
165
169
|
|
|
166
|
-
for (x =
|
|
170
|
+
for (x = endPixel - 1; x >= startPixel; x--) {
|
|
167
171
|
val = channel.max_sample(x);
|
|
168
172
|
|
|
169
|
-
context.lineTo(x - startOffset + 0.5, top + scaleY(val, height, amplitudeScale) + 0.5);
|
|
173
|
+
context.lineTo(x / targetSpeed - startOffset + 0.5, top + scaleY(val, height, amplitudeScale) + 0.5);
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
context.closePath();
|
package/src/models/source.js
CHANGED
|
@@ -368,6 +368,13 @@ define([
|
|
|
368
368
|
else if (!Utils.isBoolean(options.loading)) {
|
|
369
369
|
throw new TypeError('peaks.sources.' + context + ': loading must be a boolean');
|
|
370
370
|
}
|
|
371
|
+
|
|
372
|
+
if (Utils.isNullOrUndefined(options.targetSpeed)) {
|
|
373
|
+
options.targetSpeed = 1.0;
|
|
374
|
+
}
|
|
375
|
+
else if (!Utils.isNumber(options.targetSpeed) || options.targetSpeed <= 0) {
|
|
376
|
+
throw new TypeError('peaks.sources.' + context + ': targetSpeed must be a positive number');
|
|
377
|
+
}
|
|
371
378
|
}
|
|
372
379
|
|
|
373
380
|
/**
|
|
@@ -427,6 +434,8 @@ define([
|
|
|
427
434
|
* @param {Number} volume Current volume level of the source.
|
|
428
435
|
* @param {Array<Number>} volumeRange Array containing min and max volume values.
|
|
429
436
|
* @param {Boolean} loading If <code>true</code> the source is currently loading.
|
|
437
|
+
* @param {Number} targetSpeed The playback speed multiplier for the source (default 1.0).
|
|
438
|
+
* Values > 1.0 speed up playback (compress waveform), values < 1.0 slow down (expand waveform).
|
|
430
439
|
*/
|
|
431
440
|
|
|
432
441
|
function Source(peaks, id, lineId, originId, elementId, title, titleAlignments, url, previewUrl, binaryUrl, kind,
|
|
@@ -435,7 +444,7 @@ define([
|
|
|
435
444
|
volumeSliderWidth, volumeSliderDraggingWidth, textFont, textFontSize, textColor, textBackgroundColor, textPosition,
|
|
436
445
|
textAutoScroll, borderWidth, borderRadius, wrapped, draggable, orderable, resizable,
|
|
437
446
|
cuttable, deletable, wrapping, previewHeight, binaryHeight, indicators, markers, buttons, markerColor,
|
|
438
|
-
markerWidth, volume, volumeRange, loading, ...customParams) {
|
|
447
|
+
markerWidth, volume, volumeRange, loading, targetSpeed, ...customParams) {
|
|
439
448
|
var opts = {
|
|
440
449
|
title: title,
|
|
441
450
|
titleAlignments: titleAlignments,
|
|
@@ -484,7 +493,8 @@ define([
|
|
|
484
493
|
markerWidth: markerWidth,
|
|
485
494
|
volume: volume,
|
|
486
495
|
volumeRange: volumeRange,
|
|
487
|
-
loading: loading
|
|
496
|
+
loading: loading,
|
|
497
|
+
targetSpeed: targetSpeed
|
|
488
498
|
};
|
|
489
499
|
|
|
490
500
|
validateSource(peaks, opts, 'add()');
|
|
@@ -542,6 +552,7 @@ define([
|
|
|
542
552
|
this._volume = opts.volume;
|
|
543
553
|
this._volumeRange = opts.volumeRange;
|
|
544
554
|
this._loading = opts.loading;
|
|
555
|
+
this._targetSpeed = opts.targetSpeed;
|
|
545
556
|
this._minSize = peaks.options.minSourceSize;
|
|
546
557
|
this._selected = false;
|
|
547
558
|
|
|
@@ -997,6 +1008,12 @@ define([
|
|
|
997
1008
|
set: function(selected) {
|
|
998
1009
|
this._selected = selected;
|
|
999
1010
|
}
|
|
1011
|
+
},
|
|
1012
|
+
targetSpeed: {
|
|
1013
|
+
enumerable: true,
|
|
1014
|
+
get: function() {
|
|
1015
|
+
return this._targetSpeed;
|
|
1016
|
+
}
|
|
1000
1017
|
}
|
|
1001
1018
|
});
|
|
1002
1019
|
|
|
@@ -1164,7 +1181,8 @@ define([
|
|
|
1164
1181
|
markerWidth: this.markerWidth,
|
|
1165
1182
|
volume: this.volume,
|
|
1166
1183
|
volumeRange: this.volumeRange,
|
|
1167
|
-
loading: this.loading
|
|
1184
|
+
loading: this.loading,
|
|
1185
|
+
targetSpeed: this.targetSpeed
|
|
1168
1186
|
};
|
|
1169
1187
|
|
|
1170
1188
|
Utils.extend(opts, options);
|
|
@@ -1217,6 +1235,7 @@ define([
|
|
|
1217
1235
|
this._volume = opts.volume;
|
|
1218
1236
|
this._volumeRange = opts.volumeRange;
|
|
1219
1237
|
this._loading = opts.loading;
|
|
1238
|
+
this._targetSpeed = opts.targetSpeed;
|
|
1220
1239
|
|
|
1221
1240
|
if (options && typeof options === 'object') {
|
|
1222
1241
|
for (var key in options) {
|
package/src/source-handler.js
CHANGED
|
@@ -109,7 +109,8 @@ define([
|
|
|
109
109
|
markerWidth: sourceToCut.markerWidth,
|
|
110
110
|
volume: sourceToCut.volume,
|
|
111
111
|
volumeRange: sourceToCut.volumeRange,
|
|
112
|
-
loading: sourceToCut.loading
|
|
112
|
+
loading: sourceToCut.loading,
|
|
113
|
+
targetSpeed: sourceToCut.targetSpeed
|
|
113
114
|
};
|
|
114
115
|
|
|
115
116
|
for (var key in sourceToCut) {
|
|
@@ -223,6 +224,7 @@ define([
|
|
|
223
224
|
options.volume,
|
|
224
225
|
options.volumeRange,
|
|
225
226
|
options.loading,
|
|
227
|
+
options.targetSpeed,
|
|
226
228
|
...customParams
|
|
227
229
|
);
|
|
228
230
|
|